Spring Security: forward to original page after login with admin user after access was denied

access-denied, authentication, spring-security

Solution

I think your requirements should be satisfied by using the `RequestCache` API.

If you modify your `http` configuration you can use the `request-cache` namespace element:

<security:http>
    ...
    <security:request-cache ref="requestCache"
</security:http>

<bean id="requestCache" class="org.springframework.security.web.savedrequest.HttpSessionRequestCache" />

You can also inject it into your `AccessDeniedHandler`. Then all you should need is a simple to `saveRequest` to setup the cached request which should be restored post-authentication:

public class AccessDeniedServletRequestHandler implements AccessDeniedHandler {
    // Inject this into your class.
    private RequestCache requestCache;

    @Override
    public void handle(HttpServletRequest req, HttpServletResponse resp,
            AccessDeniedException accessDeniedException) throws IOException, ServletException {
        requestCache.saveRequest(req, resp);

        RequestDispatcher d = req.getRequestDispatcher("/loginView");
        d.forward(req, resp);
    }
}

Strictly speaking, you don't actually need to do the bit with the namespace at all, since `HttpSessionRequestCache` is stateless (it's the internal implementation which is used if you don't override it in the namespace). So you could just create one directly in your `AccessDeniedHandler` class and it would still work.

Problem

I use Spring security to authenticate users. If a user requests a secured page, he has to authenticate over a login page. If the user is always authenticated, he will be redirected to the requested page immediatly. Moreover some pages need special access rights, and so I setup an access-denied-page temporarily. So far so good. The scenario: The scenario definies, that the user will get a login-form instead of a static access-denied page, so that a different user can authenticate and if authentication is successful the requested page that needs the higher privileges will open. The actual spring configuration reads: ``` <security:http auto-config="true" use-expressions="true" disable-url-rewriting="true"> <security:intercept-url pattern="/index.jsp" access="permitAll" /> <security:intercept-url pattern="/loginView" access="permitAll" /> <security:intercept-url pattern="/accessDenied" access="permitAll"/> <security:intercept-url pattern="/user" access="hasRole('ROLE_USER')" /> <security:intercept-url pattern="/admin" access="hasRole('ROLE_ADMIN')" /> <security:intercept-url pattern="/**" access="denyAll"/> <security:form-login login-page="/loginView" authentication-failure-url="/loginView" default-target-url="/dirView" /> <security:logout /> <security:access-denied-handler ref="accessDeniedHandler" /> </security:http> ``` The accessDeniedHandler-Bean: ``` public class AccessDeniedServletRequestHandler implements AccessDeniedHandler { /** {@inheritDoc} */ @Override public void handle(HttpServletRequest req, HttpServletResponse resp, AccessDeniedException accessDeniedException) throws IOException, ServletException { RequestDispatcher d = req.getRequestDispatcher("/loginView"); d.forward(req, resp); } } ``` But that implementation of AccessDeniedHandler only forwards to the loginView. After authentication of an admin the default-success-page is openend and not the original requested page. I also tried to save the original request by calling HttpServletRequest#getAttribute("javax.servlet.forward.servlet_path"), but I don't understand how to force spring security to use that original request instead of the default target url. Besides I read about org.springframework.security.web.savedrequest.SavedRequest that is used inside spring authentication to remember the original request if an unauthenticated user requests a page. But I don't find a valid way how to use the SavedRequest in the same manner for my access denied scenario. Thanks in advance for suggestions and solutions.

Original source