4

I'm trying (without success) to customize the 403 Exception error on my spring boot application. This application is a rest server which return json response. It has custom AuthenticationProvider which check the validity of a JWT token. When the token is expired, I would like to return a custom JSON response and not the default one (which is {"timestamp":1494852457132,"status":403,"error":"Forbidden","message":"Access Denied","path":"/api/factory/application"} )

Here is the important part of the code:

The security configuration class:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private JwtAuthenticationProvider jwtAuthenticationProvider;

    @Autowired
    private JwtAuthFilter jwtAuthFilter;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        http.authorizeRequests()
                .antMatchers("/v2/api-docs").permitAll()
                //.anyRequest().authenticated()
                .antMatchers("/application/**").authenticated()
                //@JLC:add test in security
                .antMatchers("/test/**").permitAll()
                .and()
                .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);
    }

    @Override
    public void configure(AuthenticationManagerBuilder auth)  throws Exception {
        auth.authenticationProvider(jwtAuthenticationProvider);
    }
}

The filter:

@Component
public class JwtAuthFilter extends GenericFilterBean {

    private final Logger log = LoggerFactory.getLogger(this.getClass());

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest servletRequest = (HttpServletRequest) request;
        String authorization = servletRequest.getHeader("Authorization");
        if (authorization != null) {
            JwtAuthToken token = new JwtAuthToken(authorization.replaceAll("Bearer ", ""));
            SecurityContextHolder.getContext().setAuthentication(token);
        }
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {

    }
}

And the Authentication Provider: . This is in this class (during the call of the method jwtService.verify) where an exception may be raised if the token is expired.

@Component
public class JwtAuthenticationProvider implements AuthenticationProvider {
    private final Logger log = LoggerFactory.getLogger(this.getClass());

    private final JwtService jwtService;

    @SuppressWarnings("unused")
    public JwtAuthenticationProvider() {
        this(null);
    }

    @Autowired
    public JwtAuthenticationProvider(JwtService jwtService) {
        this.jwtService = jwtService;
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        log.info("authenticate ... entering" + authentication.getCredentials());
        try {
            AuthenticationInfo authentInfo = jwtService.verify((String) authentication.getCredentials());
            Authentication profile = new JwtAuthenticatedProfile(authentInfo);

            return profile;
        } catch (Exception e) {
            log.error("Error authenticate", e);
            throw new JwtAuthenticationException("Failed to verify token", e);
        }
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return JwtAuthToken.class.equals(authentication);
    }
}

I tried to catch the exception in the filter, but I never enter in the catch clause, I also tried to follow instruction in this post Handle Security exceptions in Spring Boot Resource Server, but without success : when the exception is raised, the code not enter in the onAuthenticationFailure method of the RestAuthenticationFailureHandler class.

Remark: The JWT token has been generated by another server

Community
  • 1
  • 1
franck31
  • 41
  • 4
  • I can see in the log that my AuthenticationManager is called. I guess, this is due to the *configure* method of the *WebSecurityConfig* class which set the *AuthenticationProvider* to use. – franck31 May 15 '17 at 20:07
  • this may be helpful too. http://stackoverflow.com/questions/42839910/customize-authentication-failure-response-in-spring-security-using-authenticatio/42843551#42843551 – Jason White May 16 '17 at 11:11
  • yes, I have tried. But my custom AccessDeniedHandler is never called. – franck31 May 16 '17 at 15:13
  • It seems this question is already asked. Check this answer please > https://stackoverflow.com/a/41274409/889556 – gokhansari May 17 '17 at 11:02

0 Answers0