Spring Boot Security does not throw 401 Unauthorized Exception, but 404 not found

My authentication is based on spring-boot-security-example . When I enter an invalid token, I would like to send a 401 Unauthorized exception. However, I always get a 404 resource that is not found. My configuration sets up exception handling, but is ignored - perhaps because my AuthenticationFilter has been added before and the request does not reach my exception handler.

What do I need to change to exclude instead of 401?

I have an authentication filter:

public class AuthenticationFilter extends GenericFilterBean { ... @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = asHttp(request); HttpServletResponse httpResponse = asHttp(response); Optional<String> token = Optional.fromNullable(httpRequest.getHeader("X-Auth-Token")); try { if (token.isPresent()) { logger.debug("Trying to authenticate user by X-Auth-Token method. Token: {}", token); processTokenAuthentication(token); addSessionContextToLogging(); } logger.debug("AuthenticationFilter is passing request down the filter chain"); chain.doFilter(request, response); } catch (InternalAuthenticationServiceException internalAuthenticationServiceException) { SecurityContextHolder.clearContext(); logger.error("Internal authentication service exception", internalAuthenticationServiceException); httpResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } catch (AuthenticationException authenticationException) { SecurityContextHolder.clearContext(); httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, authenticationException.getMessage()); } finally { MDC.remove(TOKEN_SESSION_KEY); MDC.remove(USER_SESSION_KEY); } } private void addSessionContextToLogging() { ... } ... private void processTokenAuthentication(Optional<String> token) { Authentication resultOfAuthentication = tryToAuthenticateWithToken(token); SecurityContextHolder.getContext().setAuthentication(resultOfAuthentication); } private Authentication tryToAuthenticateWithToken(Optional<String> token) { PreAuthenticatedAuthenticationToken requestAuthentication = new PreAuthenticatedAuthenticationToken(token, null); return tryToAuthenticate(requestAuthentication); } private Authentication tryToAuthenticate(Authentication requestAuthentication) { Authentication responseAuthentication = authenticationManager.authenticate(requestAuthentication); if (responseAuthentication == null || !responseAuthentication.isAuthenticated()) { throw new InternalAuthenticationServiceException("Unable to authenticate Domain User for provided credentials"); } logger.debug("User successfully authenticated"); return responseAuthentication; } 

Provider authentication implementation:

 @Provider public class TokenAuthenticationProvider implements AuthenticationProvider { @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { Optional<String> token = (Optional) authentication.getPrincipal(); if (!token.isPresent() || token.get().isEmpty()) { throw new BadCredentialsException("No token set."); } if (!myCheckHere()){ throw new BadCredentialsException("Invalid token"); } return new PreAuthenticatedAuthenticationToken(myConsumerObject, null, AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_API_USER")); } ... } 

and a configuration that looks like this:

 @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfiguration extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http. csrf().disable(). sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS). and(). anonymous().disable(). exceptionHandling().authenticationEntryPoint(unauthorizedEntryPoint()); http.addFilterBefore(new AuthenticationFilter(authenticationManager()), BasicAuthenticationFilter.class); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(tokenAuthenticationProvider()); } @Bean public AuthenticationProvider tokenAuthenticationProvider() { return new TokenAuthenticationProvider(); } @Bean public AuthenticationEntryPoint unauthorizedEntryPoint() { return (request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED); } } 
+6
source share
2 answers

I found the answer in this thread: Return HTTP 401 error code and skip filter chains

Instead

 httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, authenticationException.getMessage()); 

I need to call

 httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED); 

It seems that the chain will stop when I do not call it, and setting the status to a different code - the exception is thrown correctly

+5
source

I solved this by adding the following annotation to the top-level @SpringBootApplication class:

 @EnableAutoConfiguration(exclude = {ErrorMvcAutoConfiguration.class}) 

Could Spring load a problem with finding the default error page?

+6
source

All Articles