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
* Setup an application with
* basic auth configuration and
* an endpoint that needs specific privileges (e.g. @Secured("ROLE_ADMIN"))
* Send a request to that endpoint
* with a valid user/auth but insufficient privileges and
* specify a request header Accept: application/problem+json, application/json
Expected behavior
* The Content-Type response header must reflect the actual type of the content
* When Problem Details are enabled, I'd expect that all errors (including 403 Forbidden) are returned as a Problem Detail response (RFC 7807). Also note that 401 Unauthorized does not contain a response body at all – I don't know if this is intended or another bug.
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"
Comment From: osiegmar
Maybe related: https://github.com/spring-projects/spring-framework/issues/29626
Comment From: singhbaljit
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.
Comment From: singhbaljit
Perhaps AccessDeniedException, AuthenticationException, etc. can extend ErrorResponseException.
Comment From: jzheaux
@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.
Comment From: singhbaljit
@jzheaux can you please share your configuration? I wonder if this is related to https://github.com/spring-projects/spring-boot/issues/32212.
Comment From: jzheaux
@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?
Comment From: osiegmar
@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.
Comment From: jzheaux
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.