Search code examples
javaspring-bootspring-securityspring-security-oauth2

How to remove a variable from Unauthorized response in springboot


I have this response when it comes to check the user Unauthorized.

i there any possibility to remove the Path from the Unauthorized response ? since it does not gives valuable information for the user

{
"timestamp": "2021-03-18T09:16:09.699+0000",
"status": 401,
"error": "Unauthorized",
"message": "Unauthorized",
"path": "/test/v1/api/test.com/config/settings"

}

this is how my config looks like

public class ResourceConfig extends ResourceServerConfigurerAdapter {


@Override
public void configure(HttpSecurity httpSecurity) throws Exception {
    httpSecurity
        .csrf().disable()
        .cors();

    httpSecurity
        .anonymous().disable()
        .requestMatchers().antMatchers("/api/**")
        .and()
        .authorizeRequests()
        .antMatchers("/api/**")
        .authenticated()
        .and()
        .exceptionHandling()
        .accessDeniedHandler(new OAuth2AccessDeniedHandler());

}

Solution

  • Adding on @linhx idea of using custom AuthenricationEntryPoint, you can use HandlerExceptionResolver which resolves to a page.

    You can get a detailed comparison of different approaches here.

    @Component
    public class ABAuthenticationEntryPoint implements AuthenticationEntryPoint {
    
        protected final Logger logger = LoggerFactory.getLogger(ABAuthenticationEntryPoint.class);
    
        private final String realmName = "CustomRealm";
    
         @Autowired
         @Qualifier("handlerExceptionResolver")
         private HandlerExceptionResolver resolver;
         
        @Override
        public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
            resolver.resolveException(request, response, null, authException);
        }
    }
    

    The HandlerExceptionResolver uses the handler (HandlerMethod) to obtain the Controller class and scan it for methods annotated with @ExceptionHandler. If one of this methods matches the exception (ex) then this methods get invoked in order to handle the exception. (else null get returned signaling that this exception resolver feels no responsible).

    So, add a class with @ControllerAdvice:

    @ExceptionHandler(value = InsufficientAuthenticationException.class)
    public ResponseEntity<Object> handleInsufficientAuthenticationException(InsufficientAuthenticationException ex) {
        String methodName = "handleInsufficientAuthenticationException()";
        return buildResponseEntity(HttpStatus.UNAUTHORIZED, null, null, ex.getMessage(), null);
    }
    
    private ResponseEntity<Object> buildResponseEntity(HttpStatus status, HttpHeaders headers, Integer internalCode, String message, List<Object> errors) {
            ResponseBase response = new ResponseBase()
                    .success(false)
                    .message(message)
                    .resultCode(internalCode != null ? internalCode : status.value())
                    .errors(errors != null
                            ? errors.stream().filter(Objects::nonNull).map(Objects::toString).collect(Collectors.toList())
                            : null);
            
            return new ResponseEntity<>((Object) response, headers, status);
        }
    

    SecurityConfig class:

    @Configuration
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    protected final Logger logger = LoggerFactory.getLogger(SecurityConfig.class);
        
        @Autowired
        private ABAuthenticationEntryPoint authenticationEntryPoint;
        
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.
            .....
            .and()
            .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint); //AuthenticationEntryPoint has to be the last
        }
    }
    

    Finally you will get something like the following, based on how you buildResponseEntity

    {
        "success": false,
        "resultCode": 401,
        "message": "Full authentication is required to access this resource"
    }