I'm trying to configure my Spring Boot Security (with Kotlin), I've got a certain request mapping that doesn't require authentication. The following config works fine as long as the response of my endpoints is 200.
However, if any exception is thrown in the code, it always returns 403 with no message. For example, if a ResponseStatusException
with status code 400 is thrown, it still returns 403. Or for example if a request param is missing, it returns 403. Here's my config:
@Configuration
@EnableWebSecurity
class SecurityConfig {
@Bean
fun filterChain(http: HttpSecurity): SecurityFilterChain? {
http.authorizeHttpRequests().requestMatchers("/v1/resource/*").permitAll()
return http.build()
}
}
I've tried disabling exception handling with http.exceptionHandling().disable()
and I can see the correct status code and error message. However, the problem is that it's returned as HTML.
What am I doing wrong? See logs below:
2023-04-28T16:15:19.858-04:00 DEBUG 145941 --- [o-auto-1-exec-1] .m.m.a.ExceptionHandlerExceptionResolver : Using @ExceptionHandler test.exception.handler.RestResponseEntityExceptionHandler#handleUnhandledException(Exception, WebRequest)
2023-04-28T16:15:19.862-04:00 DEBUG 145941 --- [o-auto-1-exec-1] .w.s.m.a.ResponseStatusExceptionResolver : Resolved [test.exception.NotFoundException: Test error]
2023-04-28T16:15:19.863-04:00 DEBUG 145941 --- [o-auto-1-exec-1] o.s.web.servlet.DispatcherServlet : Completed 404 NOT_FOUND
2023-04-28T16:15:19.864-04:00 DEBUG 145941 --- [o-auto-1-exec-1] o.a.c.c.C.[Tomcat].[localhost] : Processing ErrorPage[errorCode=0, location=/error]
2023-04-28T16:15:19.868-04:00 DEBUG 145941 --- [o-auto-1-exec-1] o.s.security.web.FilterChainProxy : Securing GET /error
2023-04-28T16:15:19.869-04:00 DEBUG 145941 --- [o-auto-1-exec-1] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#error(HttpServletRequest)
2023-04-28T16:15:19.870-04:00 DEBUG 145941 --- [o-auto-1-exec-1] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#error(HttpServletRequest)
2023-04-28T16:15:19.873-04:00 DEBUG 145941 --- [o-auto-1-exec-1] o.s.s.w.a.AnonymousAuthenticationFilter : Set SecurityContextHolder to anonymous SecurityContext
2023-04-28T16:15:19.874-04:00 DEBUG 145941 --- [o-auto-1-exec-1] o.s.s.w.a.Http403ForbiddenEntryPoint : Pre-authenticated entry point called. Rejecting access
2023-04-28T16:15:19.874-04:00 DEBUG 145941 --- [o-auto-1-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Disabling the response for further output
2023-04-28T16:15:19.876-04:00 DEBUG 145941 --- [ main] org.apache.http.wire : << "HTTP/1.1 403 [\r][\n]"
In the end, I couldn't fix it via the Spring Security configuration. What I did instead was write my own custom exception handlers:
@ControllerAdvice
@RestController
class CustomExceptionHandlerResolver {
@ExceptionHandler(ResponseStatusException::class)
fun handleResponseStatusException(
exception: ResponseStatusException,
webRequest: WebRequest,
): ResponseEntity<ExceptionResponse>? {
val exceptionResponse = ExceptionResponse(Date(), exception.reason, webRequest.getDescription(false))
return ResponseEntity<ExceptionResponse>(exceptionResponse, exception.statusCode)
}
@ExceptionHandler(MissingServletRequestParameterException::class)
fun handleRequestParameterException(
exception: MissingServletRequestParameterException,
webRequest: WebRequest,
): ResponseEntity<ExceptionResponse>? {
val exceptionResponse = ExceptionResponse(Date(), exception.message, webRequest.getDescription(false))
return ResponseEntity<ExceptionResponse>(exceptionResponse, HttpStatus.BAD_REQUEST)
}
}
In the code above, ExceptionResponse
is just a data class (POJO):
data class ExceptionResponse(
val date: Date,
val message: String?,
val description: String,
)