4

In my web application I am using Spring Security and Spring MVC. I have secured a couple of methods with @Secured annotation and configured Spring Security in such a way that when one of those methods is accessed without the proper role, the user is taken to the login page. However, I do not want that behaviour when the offending request comes from Ajax, so I implemented the custom @ExceptionHandler annotated method to determine the request's context.

This is my exception handler:

@ExceptionHandler(AccessDeniedException.class)
public void handleAccessDeniedException(AccessDeniedException ex, HttpServletRequest request, HttpServletResponse response) throws Exception {

    if (isAjax(request)) {
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
    } else {
        throw ex;
    }
}

This way I can both handle the exception myself (for example, log an attempt of accessing the @Secured method) and then let Spring do its part and redirect the user to the login page by rethrowing the AccessDeniedException. Also, when the request comes from Ajax I set the response status to SC_UNAUTHORIZED and handle the error on the client side. Now, this seems to be working fine, but I am getting the following ERROR each time I rethrow the exception from the handleAccessDeniedException method:

ERROR org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver - Failed to invoke @ExceptionHandler method: public void app.controller.BaseController.handleAccessDeniedException(org.springframework.security.access.AccessDeniedException,javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) throws java.lang.Exception
org.springframework.security.access.AccessDeniedException: 
    at app.controller.BaseController.handleAccessDeniedException(BaseController.java:23)
    at app.controller.BaseController$$FastClassByCGLIB$$8f052058.invoke(<generated>)
    at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:191)
    (...)

I have not added any exception handling specifics to spring xml configuration files.

I do not see any issues with the app itself, but the error is there and since I am quite new to Spring MVC and Spring Security, I am guessing that I am not doing this properly. Any suggestions? Thanks!

AtomHeartFather
  • 954
  • 17
  • 35

1 Answers1

3

Your exception handler isn't supposed to throw another exception. It's supposed to deal with it and send a response. It's a good idea to check the code if you get an error from a class to see how it behaves.

For the non-ajax case, you'd be better to redirect the response to the login page, if that's what you want. Alternatively, you can customize the AuthenticationEntryPoint used by Spring Security instead and omit AccessDeniedExceptions from MVC handling. The behaviour would essentially be the same as the defaul LoginUrlAuthenticationEntryPoint but you would extend it to return a 403 when an ajax request is detected.

Shaun the Sheep
  • 22,353
  • 1
  • 72
  • 100
  • The problem is that if I manually redirect the response to the login page, the user, after logging in will NOT be redirected to the resource they were trying to access before. That's my only reason for propagating the exception. – AtomHeartFather Apr 19 '13 at 11:03
  • 1
    Ok, you never mentioned that in your question. In that case you should probably customize the `AuthenticationEntryPoint`. You'll find [examples on doing that](http://stackoverflow.com/a/15710847/241990) elsewhere on the site. – Shaun the Sheep Apr 19 '13 at 12:19
  • I did exactly what you suggested and extended LoginUrlAuthenticationEntryPoint. The logic that determines whether the request comes from Ajax is now in the overridden `commence` method. No need to handle the `AccessDeniedException` anymore. Thanks! – AtomHeartFather Apr 23 '13 at 22:29
  • Hi, I am trying to implement this in my application and have the access denied exceptionhandler method. I am trying to understand how this works. How do i let spring just deal with sending the user to entry point? I want spring to handle the redirect, instead of just throwing the access denied exception and then doing nothing. Any help is appritiated – Ankit May 25 '17 at 08:46