spring-projects / spring-security

Spring Security
http://spring.io/projects/spring-security
Apache License 2.0
8.82k stars 5.9k forks source link

Error response body does not match Content-Type #12450

Closed osiegmar closed 1 year ago

osiegmar commented 1 year ago

Describe the bug In an application (using Spring Boot 3.0.1) the response body does not match the Content-Type header for a 403 Forbidden response if the request contains the header Accept: application/problem+json, application/json:

Content-Type: application/problem+json

{"timestamp":"2022-12-23T07:44:25.247+00:00","status":403,"error":"Forbidden","path":"/secret"}

Note: I'm using the shown mime type order because of https://github.com/spring-projects/spring-framework/issues/29588

To Reproduce

Expected behavior

Sample

@SpringBootApplication
@RestController
@EnableWebSecurity
@EnableMethodSecurity
public class Application {

    @Bean
    public UserDetailsService userDetailsService() {
        return new InMemoryUserDetailsManager(User.withDefaultPasswordEncoder()
            .username("user").password("password").roles("USER").build());
    }

    @PreAuthorize("hasRole('ROLE_ADMIN')")
    @GetMapping("/secret")
    public String secret() {
        return "Secret";
    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

Request:

curl -i http://localhost:8080/secret \
     -u "user:password" \
     -H "Accept: application/problem+json, application/json"
osiegmar commented 1 year ago

Maybe related: https://github.com/spring-projects/spring-framework/issues/29626

singhbaljit commented 1 year ago

I think this is intentional, but I would like this feature as well. I'm using OAuth2, and it would be great for the consistency our APIs to have 401/403 return OAuth2Error mapped as ProblemDetail, instead of the WWW-Authenticate header.

singhbaljit commented 1 year ago

Perhaps AccessDeniedException, AuthenticationException, etc. can extend ErrorResponseException.

jzheaux commented 1 year ago

@osiegmar, there's something I'm not quite understanding.

When I create the specified application and run the specified command, this is the result I get:

HTTP/1.1 403 
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Connection: keep-alive
Content-Type: application/problem+json
Date: Thu, 05 Jan 2023 17:25:25 GMT
Expires: 0
Keep-Alive: timeout=60
Pragma: no-cache
Transfer-Encoding: chunked
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 0

{
    "error": "Forbidden",
    "path": "/secret",
    "status": 403,
    "timestamp": "2023-01-05T17:25:25.723+00:00"
}

It seems like a reasonable result, what am I missing?

Second, the response is created by Spring Boot's ErrorController, so it may be better to file an issue there.

singhbaljit commented 1 year ago

@jzheaux can you please share your configuration? I wonder if this is related to https://github.com/spring-projects/spring-boot/issues/32212.

jzheaux commented 1 year ago

@singhbaljit I copied the code posted in the issue.

Can someone please post a minimal sample (for example, a GitHub repo) that reproduces the issue?

osiegmar commented 1 year ago

@jzheaux You successfully reproduced the issue. The Content-Type response header has a value of application/problem+json but the response body is not a problem detail document as defined by RFC 7807. Either the Content-Type or the body is wrong and I'm unsure if it is caused by Spring Framework, Security or Boot.

jzheaux commented 1 year ago

I see, thanks for the clarification, @osiegmar.

The page is generated by Spring Boot, so it would be up to them to do the content negotiation. I'm not sure if Spring Boot supports RFC 7807.

I think it's clear enough now to close the issue, but if I've misunderstood and there is something more for Spring Security to do, we can reopen.