I have implemented the AccessDeniedHandler interface and added the interface to the WebSecurityConfigurerAdapter, and I also have an ExceptionHandler of RuntimeException in my ControllerAdvice. When I receive accessDeniedException from MethodSecurity, ExceptionHandler calls RuntimeException before running AccessDeniedHandler.
How to call AccessDeniedHandler without deleting ExceptionHandler?
this is my WebSecurityConfig:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
public static final String TOKEN_BASED_AUTH_ENTRY_POINT = "/api/**";
public static final String JWT_TOKEN_HEADER_PARAM = "X-Authorization";
@Value("${payment.gateway.callback-path}")
private String paymentCallbackPath;
@Autowired
private ThingspodAccessDeniedHandler accessDeniedHandler;
@Autowired
private RestAuthenticationFailureHandler authenticationFailureHandler;
@Autowired
private JwtAuthenticationProvider jwtAuthenticationProvider;
protected JwtAuthenticationFilter jwtAuthenticationFilter() throws Exception {
List<String> pathsToSkip = new ArrayList<>(Collections.singletonList(paymentCallbackPath));
SkipPathRequestMatcher matcher = new SkipPathRequestMatcher(pathsToSkip, TOKEN_BASED_AUTH_ENTRY_POINT);
JwtAuthenticationFilter filter = new JwtAuthenticationFilter(matcher, JWT_TOKEN_HEADER_PARAM, authenticationFailureHandler);
filter.setAuthenticationManager(authenticationManager());
return filter;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(jwtAuthenticationProvider);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.headers().cacheControl().and().frameOptions().disable()
.and()
.cors()
.and()
.csrf().disable()
.exceptionHandling()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(paymentCallbackPath).permitAll()
.and()
.authorizeRequests()
.antMatchers(TOKEN_BASED_AUTH_ENTRY_POINT).authenticated()
.and()
.authorizeRequests()
.and()
.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.exceptionHandling().accessDeniedHandler(accessDeniedHandler);
}
}
and this is my AccessDeniedHander and ExceptionHandler in ControllerAdvice:
@Component
public class ThingspodAccessDeniedHandler implements AccessDeniedHandler {
private final ObjectMapper mapper;
public ThingspodAccessDeniedHandler(ObjectMapper mapper) {
this.mapper = mapper;
}
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException {
Object res = buildResponse(accessDeniedException, "You don't have permission to perform this operation!", HttpStatus.FORBIDDEN, ThingspodErrorCode.PERMISSION_DENIED, request);
response.setStatus(HttpStatus.FORBIDDEN.value());
mapper.writeValue(response.getWriter(), res);
}
}
@ExceptionHandler(RuntimeException.class)
public ResponseEntity<Object> handleAllUncaughtRuntimeException(
RuntimeException ex, WebRequest request){
return buildApiErrorResponse(ex, HttpStatus.INTERNAL_SERVER_ERROR, ThingspodErrorCode.GENERAL, request);
}