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!