title: Spring Security 3.1.0 - Remember-me does not work as expected
body: <p>I am having a problem with Spring Security's 3.1.0 remember-me cookies. I need to find a solution ASAP and I cannot find the cause of this problem.</p>
  
  <p>These are the steps I am following:</p>
  
  <ul>
  <li>Go to my app URL (e.g. <a href="http://myapp/app.htm" rel="nofollow">http://myapp/app.htm</a>)</li>
  <li>I am redirected to login page, so I log in</li>
  <li>Once logged in, close browser without logging out</li>
  <li>Open browser and go to my app URL</li>
  </ul>
  
  <p>At this point I expect to enter my app bypassing the login form since the remember-me cookie is still in my browser. Despite that fact, <strong>the login page appears again</strong>.</p>
  
  <ul>
  <li>Go to my app URL again</li>
  </ul>
  
  <p>Trying again, I can enter my app normally bypassing the login form.</p>
  
  <p>This is quite confusing, and I cannot find an explanation so far.</p>
  
  <p>I tried to debug both attempts and I found the following when Spring Security's RememberMeAuthenticationFilter was fired:</p>
  
  <p>Attempt 1<br/>
  request path = /app.htm: request.getCookies() did not contain my SPRING_SECURITY_REMEMBER_ME_COOKIE, therefore I was redirected to login page
  request path = /security/login.htm: at this point request.getCookies() DID have my SPRING_SECURITY_REMEMBER_ME_COOKIE, and it was accepted; anyway, I had already been redirected to the login page</p>
  
  <p>Attempt 2<br/>
  The remember-me cookie had already been accepted, so I could enter my app without problem.</p>
  
  <p>Below are the Spring Security XML configuration and the logs of both attempts.</p>
  
  <p>Any help on this will be very much appreciated!</p>
  
  <hr>
  
  <p>Spring Security configuration (I will omit everything about daoAuthenticationProvider and event listeners):</p>
  
  <pre><code>&lt;sec:http auto-config="false" use-expressions="true" authentication-manager-ref="authenticationManager"&gt;
      &lt;sec:custom-filter ref="sessionLocaleResolvingFilter" before="FORM_LOGIN_FILTER"/&gt;
  
      &lt;sec:intercept-url pattern="/security/*.htm" requires-channel="https" /&gt;
      &lt;sec:intercept-url pattern="/retrieve-password/*.htm" requires-channel="https" /&gt;
      &lt;sec:intercept-url pattern="/messagebroker/*" access="authenticated" requires-channel="http" /&gt;
      &lt;sec:intercept-url pattern="/platform/*.htm"
          access="hasRole('limited') or (authenticated and !hasRole('role1') and !hasRole('role2'))"
          requires-channel="http" /&gt;
      &lt;sec:intercept-url pattern="/app.htm" access="authenticated" requires-channel="http" /&gt;
      &lt;sec:intercept-url pattern="/**" requires-channel="http" /&gt;
      &lt;sec:form-login login-page="/security/login.htm" default-target-url="/app.htm"
          login-processing-url="/security/process-login.htm" authentication-failure-url="/security/login.htm?error=true" /&gt;
      &lt;sec:logout logout-url="/security/logout.htm" delete-cookies="JSESSIONID,SPRING_SECURITY_REMEMBER_ME_COOKIE"
          logout-success-url="/security/logout-success.htm" invalidate-session="true"/&gt;
      &lt;sec:anonymous/&gt;
      &lt;sec:remember-me use-secure-cookie="true" key="myAppServices" 
          services-ref="ipTokenBasedRememberMeServicesBean" /&gt;
      &lt;sec:session-management session-fixation-protection="none"/&gt;
      &lt;sec:access-denied-handler error-page="/denied-access.htm"/&gt;
  &lt;/sec:http&gt;
  
  &lt;bean id="sessionLocaleResolvingFilter" class="com.myapp.spring.security.SessionLocaleResolvingFilter" /&gt;
  &lt;bean class="com.myapp.spring.security.IPTokenBasedRememberMeServices"
      id="ipTokenBasedRememberMeServicesBean"&gt;
      &lt;constructor-arg value="myAppServices"/&gt;
      &lt;constructor-arg ref="myAppJdbcDaoImpl"/&gt;
  &lt;/bean&gt;
  &lt;bean id="myAppPasswordEncoder" class="com.myapp.spring.security.MyAppPasswordEncoder" /&gt;
  &lt;bean id="authenticationManager"
      class="o.s.s.authentication.ProviderManager"&gt;
      &lt;property name="providers"&gt;
          &lt;list&gt;
              &lt;ref local="daoAuthenticationProvider" /&gt;
          &lt;/list&gt;
      &lt;/property&gt;
  &lt;/bean&gt;
  &lt;!-- Other beans... --&gt;
  </code></pre>
  
  <p>Log for the first attempt (replaced org.springframework with o.s and org.springframework.security with o.s.s):</p>
  
  <pre><code>o.s.s.web.access.channel.ChannelProcessingFilter:134 - Request: FilterInvocation: URL: /app.htm?lang=en; ConfigAttributes: [REQUIRES_INSECURE_CHANNEL]
  o.s.s.web.context.HttpSessionSecurityContextRepository:127 - No HttpSession currently exists
  o.s.s.web.context.HttpSessionSecurityContextRepository:85 - No SecurityContext was available from the HttpSession: null. A new one will be created.
  o.s.s.web.FilterChainProxy:318 - /app.htm?lang=en at position 9 of 11 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
  o.s.s.web.authentication.AnonymousAuthenticationFilter:102 - Populated SecurityContextHolder with anonymous token: 'o.s.s.authentication.AnonymousAuthenticationToken@90550640: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: o.s.s.web.authentication.WebAuthenticationDetails@7798: RemoteIpAddress: fe80:0:0:0:ec09:25fb:3df4:323b; SessionId: 057E689401E69589BB7359F3E95B4A18; Granted Authorities: ROLE_ANONYMOUS'
  o.s.s.web.FilterChainProxy:318 - /app.htm?lang=en at position 10 of 11 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
  o.s.s.web.FilterChainProxy:318 - /app.htm?lang=en at position 11 of 11 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
  o.s.s.web.util.AntPathRequestMatcher:103 - Checking match of request : '/app.htm'; against '/messagebroker/*'
  o.s.s.web.util.AntPathRequestMatcher:103 - Checking match of request : '/app.htm'; against '/app.htm'
  o.s.s.web.access.intercept.FilterSecurityInterceptor:193 - Secure object: FilterInvocation: URL: /app.htm?lang=en; Attributes: [authenticated]
  o.s.s.web.access.intercept.FilterSecurityInterceptor:298 - Previously Authenticated: o.s.s.authentication.AnonymousAuthenticationToken@90550640: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: o.s.s.web.authentication.WebAuthenticationDetails@7798: RemoteIpAddress: fe80:0:0:0:ec09:25fb:3df4:323b; SessionId: 057E689401E69589BB7359F3E95B4A18; Granted Authorities: ROLE_ANONYMOUS
  o.s.s.access.vote.AffirmativeBased:65 - Voter: o.s.s.web.access.expression.WebExpressionVoter@1ce3388, returned: -1
  o.s.s.web.access.ExceptionTranslationFilter:165 - Access is denied (user is anonymous); redirecting to authentication entry point
  o.s.s.access.AccessDeniedException: Access is denied
      at o.s.s.access.vote.AffirmativeBased.decide(AffirmativeBased.java:83)
      at o.s.s.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:205)
      at o.s.s.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:114)
      at o.s.s.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83)
      at o.s.s.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
      at o.s.s.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
      at o.s.s.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
      (X more)
  
  o.s.s.web.DefaultRedirectStrategy:36 - Redirecting to 'http://arbad67464/services/security/login.htm'
  o.s.s.web.context.HttpSessionSecurityContextRepository:269 - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
  o.s.s.web.context.SecurityContextPersistenceFilter:97 - SecurityContextHolder now cleared, as request processing completed
  
  o.s.s.web.access.channel.RetryWithHttpsEntryPoint:55 - Redirecting to: https://arbad67464/services/security/login.htm
  o.s.s.web.DefaultRedirectStrategy:36 - Redirecting to 'https://arbad67464/services/security/login.htm'
  
  o.s.s.web.access.channel.ChannelProcessingFilter:134 - Request: FilterInvocation: URL: /security/login.htm; ConfigAttributes: [REQUIRES_SECURE_CHANNEL]
  o.s.s.web.FilterChainProxy:318 - /security/login.htm at position 2 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
  o.s.s.web.context.HttpSessionSecurityContextRepository:139 - HttpSession returned null object for SPRING_SECURITY_CONTEXT
  o.s.s.web.context.HttpSessionSecurityContextRepository:85 - No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade@16de87. A new one will be created.
  o.s.s.web.FilterChainProxy:318 - /security/login.htm at position 3 of 11 in additional filter chain; firing Filter: 'LogoutFilter'
  o.s.s.web.FilterChainProxy:318 - /security/login.htm at position 4 of 11 in additional filter chain; firing Filter: 'SessionLocaleResolvingFilter'
  o.s.s.web.FilterChainProxy:318 - /security/login.htm at position 5 of 11 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
  o.s.s.web.FilterChainProxy:318 - /security/login.htm at position 6 of 11 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
  
  o.s.s.web.FilterChainProxy:318 - /security/login.htm at position 7 of 11 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
  o.s.s.web.FilterChainProxy:318 - /security/login.htm at position 8 of 11 in additional filter chain; firing Filter: 'RememberMeAuthenticationFilter'
  com.myapp.spring.security.IPTokenBasedRememberMeServices:103 - Remember-me cookie detected
  com.myapp.spring.security.IPTokenBasedRememberMeServices:118 - Remember-me cookie accepted
  o.s.s.authentication.ProviderManager:152 - Authentication attempt using o.s.s.authentication.RememberMeAuthenticationProvider
  </code></pre>
  
  <p>Log of my second attempt:</p>
  
  <pre><code>o.s.s.web.access.channel.ChannelProcessingFilter:134 - Request: FilterInvocation: URL: /app.htm?lang=en; ConfigAttributes: [REQUIRES_INSECURE_CHANNEL]
  o.s.s.web.context.HttpSessionSecurityContextRepository:158 - Obtained a valid SecurityContext from SPRING_SECURITY_CONTEXT: 'o.s.s.core.context.SecurityContextImpl@7db9504: Authentication: o.s.s.authentication.RememberMeAuthenticationToken@7db9504: Principal: com.myapp.spring.security.MyAppUserImpl@9716c62c: Username: somebody@mail.com; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: limited,premium,special; Credentials: [PROTECTED]; Authenticated: true; Details: o.s.s.web.authentication.WebAuthenticationDetails@7798: RemoteIpAddress: fe80:0:0:0:ec09:25fb:3df4:323b; SessionId: 057E689401E69589BB7359F3E95B4A18; Granted Authorities: limited, premium, special'
  o.s.s.web.FilterChainProxy:318 - /app.htm?lang=en at position 8 of 11 in additional filter chain; firing Filter: 'RememberMeAuthenticationFilter'
  o.s.s.web.authentication.rememberme.RememberMeAuthenticationFilter:142 - SecurityContextHolder not populated with remember-me token, as it already contained: 'o.s.s.authentication.RememberMeAuthenticationToken@7db9504: Principal: com.myapp.spring.security.MyAppUserImpl@9716c62c: Username: somebody@mail.com; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: limited,premium,special; Credentials: [PROTECTED]; Authenticated: true; Details: o.s.s.web.authentication.WebAuthenticationDetails@7798: RemoteIpAddress: fe80:0:0:0:ec09:25fb:3df4:323b; SessionId: 057E689401E69589BB7359F3E95B4A18; Granted Authorities: limited, premium, special'
  o.s.s.web.FilterChainProxy:318 - /app.htm?lang=en at position 9 of 11 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
  o.s.s.web.authentication.AnonymousAuthenticationFilter:107 - SecurityContextHolder not populated with anonymous token, as it already contained: 'o.s.s.authentication.RememberMeAuthenticationToken@7db9504: Principal: com.myapp.spring.security.MyAppUserImpl@9716c62c: Username: somebody@mail.com; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: limited,premium,special; Credentials: [PROTECTED]; Authenticated: true; Details: o.s.s.web.authentication.WebAuthenticationDetails@7798: RemoteIpAddress: fe80:0:0:0:ec09:25fb:3df4:323b; SessionId: 057E689401E69589BB7359F3E95B4A18; Granted Authorities: limited, premium, special'
  o.s.s.web.access.intercept.FilterSecurityInterceptor:193 - Secure object: FilterInvocation: URL: /app.htm?lang=en; Attributes: [authenticated]
  o.s.s.web.access.intercept.FilterSecurityInterceptor:298 - Previously Authenticated: o.s.s.authentication.RememberMeAuthenticationToken@7db9504: Principal: com.myapp.spring.security.MyAppUserImpl@9716c62c: Username: somebody@mail.com; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: limited,premium,special; Credentials: [PROTECTED]; Authenticated: true; Details: o.s.s.web.authentication.WebAuthenticationDetails@7798: RemoteIpAddress: fe80:0:0:0:ec09:25fb:3df4:323b; SessionId: 057E689401E69589BB7359F3E95B4A18; Granted Authorities: limited, premium, special
  o.s.s.access.vote.AffirmativeBased:65 - Voter: o.s.s.web.access.expression.WebExpressionVoter@1ce3388, returned: 1
  o.s.s.web.access.intercept.FilterSecurityInterceptor:214 - Authorization successful
  </code></pre>