Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring security 'remember me' cookie not avaiable in first request

I fail to retrieve the Spring remember me cookie after the login request, but it works fine in the next request to a protected page. Could anyone please tell me how I can get hold of it right away?

I am setting the remember me cookie in the login request, but fail to retrive it after Spring redirects back to the original (protected) url.

Step by step:

  1. Browser goes to example.com/protected
  2. Spring redirects to login form page
  3. Upon successful login, the SPRING_SECURITY_REMEMBER_ME_COOKIE is set in a very thin custom sub class of org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices
  4. It looks like Spring redirects back to example.com/protected, whithout a roundtrip to the browser, and both login "servlet" and protected page is handled by the same thread in Tomcat 6.
  5. Our subclass of org.springframework.security.web.access.expression.WebSecurityExpressionRoot has methods that is invoked from a <intercept-url pattern="..." access="method()" />
  6. In our method() request.getCookies() does not give the remember me cookie on the first request, but on all requests after that.
  7. Our app has some problems because the cookie is missing...

My theory so far is that I don't understand SavedRequest properly.

Condensed config here:

<http auto-config="false" use-expressions="true" authentication-manager-ref="myAuthenticationManager" path-type="regex">
    <form-login authentication-success-handler-ref="myAuthenticationSuccessHandler" login-page="..." login-processing-url="..." authentication-failure-url="..." username-parameter="username" password-parameter="password" />

    <custom-filter ref="logoutFilter" position="LOGOUT_FILTER"/>
    <expression-handler ref="myWebSecurityExpressionHandler" />

    <custom-filter ref="myCustomeFilter1" before="FORM_LOGIN_FILTER"/>
    <custom-filter ref="myCustomeFilter2" position="BASIC_AUTH_FILTER"/>
    <custom-filter ref="mySecurityClientTokenAuthenticationFilter" after="LOGOUT_FILTER" />

    <access-denied-handler ref="myAccessDeniedHandler"/>
    <intercept-url pattern="xxx"
                   access="method()"/>

    <intercept-url pattern="yyy"
                   access="method()"/>
    <remember-me services-ref="rememberMeServices"  key="my_remember"/>
</http>

I tried adding the following, with the only result that the user does not get redirected to the original page.

<http ...
    <request-cache ref="nullRequestCache"/>
</http>
<bean:bean id="nullRequestCache" class="org.springframework.security.web.savedrequest.NullRequestCache"/>
like image 639
frankern Avatar asked Nov 12 '22 17:11

frankern


1 Answers

When using request.getCookie() in autoLogin() method of RememberMeService, the request passed in is SavedRequestAwareWrapper which encapsulates original request and saved request and overrides the getCookies method.

@Override
public Cookie[] getCookies() {
    List<Cookie> cookies = savedRequest.getCookies();
    return cookies.toArray(new Cookie[cookies.size()]);
}

Therefore, when you want to get cookie from request, you actually get cookie from the savedRequest. However, the cookie may exist in the original request.

You probably should get the original request for getting cookies you want. For example:

public class ApplicationRememberMeServiceImpl implements RememberMeService, LogoutHandler {

    public Authentication autoLogin(HttpServletRequest request, HttpServletResponse response) {

        HttpServletRequestWrapper savedRequestWrapper = (HttpServletRequestWrapper) ((HttpServletRequestWrapper) request).getRequest();
        HttpServletRequest httpServletRequest = (HttpServletRequest) savedRequestWrapper.getRequest();

        Cookie cookie = WebUtils.getCookie(httpServletRequest, cookieName);
        // logic continues...

    }

}

Update 03/05/2015

Because spring security will wrap the original HttpServletRequest multiple times, it is more safe to extracting the original request in the way below:

public class ApplicationRememberMeServiceImpl implements RememberMeService, LogoutHandler {

    public Authentication autoLogin(HttpServletRequest request, HttpServletResponse response) {

        HttpServletRequest httpServletRequest = request;

        // Get the original request from multiple wrapped HttpServletRequest
        if(httpServletRequest instanceof HttpServletRequestWrapper) {

            HttpServletRequestWrapper httpServletRequestWrapper = (HttpServletRequestWrapper) httpServletRequest;
            while(httpServletRequestWrapper.getRequest() instanceof HttpServletRequestWrapper) {
                httpServletRequestWrapper = (HttpServletRequestWrapper) httpServletRequestWrapper.getRequest();
            }

            httpServletRequest = (HttpServletRequest) httpServletRequestWrapper.getRequest();

        }

        Cookie cookie = WebUtils.getCookie(httpServletRequest, cookieName);
        // logic continues...

    }

}
like image 80
lute Avatar answered Nov 14 '22 22:11

lute