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