In my Spring Boot (v. 2.7.0) app, I'm using Spring Security for authentication. If a user attempts to login with invalid credentials, the server responds with a 403 (Forbidden) status code, but I would expect 401 (Unauthorized) to be used instead.
I can't find anything in my configuration that indicates the default behaviour of Spring Security has been overriden, but whether it has or not, I want 401 to be returned when authentication fails.
I stepped through the relevant Spring Security code and it appears the Spring Security
method SimpleUrlAuthenticationFailureHandler.onAuthenticationFailure
is called when authentication fails. This method includes the line
response.sendError(HttpStatus.UNAUTHORIZED.value(), HttpStatus.UNAUTHORIZED.getReasonPhrase());
But for some reason 403 is returned to the client - so I guess the response is being changed subsequent to the line above.
How can I change Spring Security to return 401 when authentication fails? I've included my security configuration below for reference.
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true, jsr250Enabled = true)
public class SecurityConfiguration {
@Autowired
private AuthenticationConfiguration authenticationConfiguration;
@Bean
public SecurityFilterChain configure(HttpSecurity http) throws Exception {
AuthenticationManager authenticationManager = authenticationConfiguration.getAuthenticationManager();
var jwtAuthenticationFilter = new JwtAuthenticationFilter(authenticationManager);
var jwtAuthorisationFilter = new JwtAuthorisationFilter();
http.cors().and().csrf().disable().authorizeRequests()
.anyRequest().authenticated().and()
.addFilter(jwtAuthenticationFilter)
.addFilterAfter(jwtAuthorisationFilter, BasicAuthenticationFilter.class)
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
return http.build();
}
}
The JwtAuthenticationFilter
calls authenticationManager.authenticate
which causes a org.springframework.security.authentication.BadCredentialsException
to be thrown if the credentials are invalid.
Update
I tried adding a custom AuthenticationFailureHandler
bean as described in this article, but my custom bean is never invoked (the default bean SimpleUrlAuthenticationFailureHandler
is called instead).
CodePudding user response:
You can provide your own custom AccessDeniedHandler
implementation.
@Bean
public SecurityFilterChain configure(HttpSecurity http) throws Exception {
AuthenticationManager authenticationManager = authenticationConfiguration.getAuthenticationManager();
var jwtAuthenticationFilter = new JwtAuthenticationFilter(authenticationManager);
var jwtAuthorisationFilter = new JwtAuthorisationFilter();
http.cors().and().csrf().disable().authorizeRequests()
.anyRequest().authenticated().and()
.addFilter(jwtAuthenticationFilter)
.addFilterAfter(jwtAuthorisationFilter, BasicAuthenticationFilter.class)
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.exceptionHandling()
.accessDeniedHandler( (request, response, exception) ->
response.sendError(HttpStatus.UNAUTHORIZED.value(), exception.getMessage()
));
return http.build();
}