Spring Security ignoring access-denied-handler with Method Level Security
After several hours of searching around and tracing Spring code, I finally discovered what was happening. I am listing this here in case it is of value to someone else.
The access-denied-handler
is used by the ExceptionTranslationFilter
in case of an AccessDeniedException
. However, the org.springframework.web.servlet.DispatcherServlet
was first trying the handle the exception. Specifically, I had a org.springframework.web.servlet.handler.SimpleMappingExceptionResolver
defined with a defaultErrorView
. Consequently, the SimpleMappingExceptionResolver
was consuming the exception by redirecting to an appropriate view, and consequently, there was no exception left to bubble up to the ExceptionTranslationFilter
.
The fix was rather simple. Configure the SimpleMappingExceptionResolver
to ignore all AccessDeniedException
.
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="defaultErrorView" value="uncaughtException" />
<property name="excludedExceptions" value="org.springframework.security.access.AccessDeniedException" />
<property name="exceptionMappings">
<props>
<prop key=".DataAccessException">dataAccessFailure</prop>
<prop key=".NoSuchRequestHandlingMethodException">resourceNotFound</prop>
<prop key=".TypeMismatchException">resourceNotFound</prop>
<prop key=".MissingServletRequestParameterException">resourceNotFound</prop>
</props>
</property>
</bean>
Now, whenever an AccessDeniedException
is thrown, the resolver ignores it and allows it to bubble up the stack to the ExceptionTranslationFilter
which then calls upon the access-denied-handler
to handle the exception.
I run into the same issue. In my case there was already a @ControllerAdvise definied which should handle exceptions - so I added the AccessDeniedException directly:
@Component
@ControllerAdvice
public class ControllerBase {
...
@ExceptionHandler(value = AccessDeniedException.class)
public ModelAndView accessDenied() {
return new ModelAndView("redirect:login.html");
}
}
Good luck with it!