i have a GWT application using Spring Security3.1.2 running in a tomcat 7. i am using UsernamePasswordAuthenticationFilter and PersistentTokenBasedRememberMeServices to pers
Just so that we are on the same page I will first take a minute to explain how I understand this persistent token mechanism to work.
Starting from scratch (no entries in the persistent_logins
table):
On login success: A persistent token will be created for the user with some random hash. A cookie is created for the user with the token details on it. A session is created for the user.
As long as the user still has an active session then no remember me functionality will be invoked upon authentication.
After the user's session has expired: The remember me functionality kicks in and uses the cookie to fetch the persistent token from the database. If the persisted token matches the one from the cookie then everyone is happy as the user gets authenticated, a new random hash is generated and the persistent token is updated with it and the user's cookie is updated as well for subsequent requests.
But if the token from the cookie doesn't match that of the persisted token then you get a CookieTheftException. The most common reason for the tokens not to match is that 2 or more request were fired off in quick succession, where the first request will get through, generating the new hash for following requests, but the second request will still have the old token on it and thus results in the exception.
To largely avoid the CookieTheftException, make sure that requests to your webapp's content (such as images, fonts, scripts etc.) don't go through Springs authentication filters. To do this simply add another <http>
config above your normal security configuration and specify that you don't want any security for requests to you resources (use your relevant path instead of /resources/**
):
<http pattern="/resources/**" security="none"/>
<http ... (normal config) ...
(For Java Config see here: How do I define http "security = 'none' in JavaConfig?)
If you delete an user's token from the database (and their session has expired), then the user will get logged out upon the next request. So what you are saying about your persistent tokens (in the persistent_logins
table) automatically getting recreated makes very little sense and I highly doubt that is the case. The PersistentTokenRepository
's createNewToken(PersistentRememberMeToken token)
method only get's called on login success.
Lastly if you're still getting the exception it helps to attach the sources for the PersistentTokenBasedRememberMeServices
and to put a break point in the processAutoLoginCookie
method to see which request is causing the CookieTheftException.
I hope this helps.
The missing part for my configurations was RememberMeAuthenticationProvider. (http://docs.spring.io/spring-security/site/docs/3.2.2.RELEASE/reference/htmlsingle/#remember-me-impls)
Please note the package for RememberMeAuthenticationProvider has changed and it's not the same as in the docs.
Don't forget to define the same key for PersistentTokenBasedRememberMeServices and RememberMeAuthenticationProvider
This is my configuration:
<s:http auto-config="false"
use-expressions="true"
create-session="ifRequired">
<s:remember-me services-ref="rememberMeServices"
authentication-success-handler-ref="rememberMeAuthenticationSuccessHandler"/>
...
</s:http>
<bean id="rememberMeServices"
class="org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices">
<constructor-arg index="0" value="${remember.me.key}" />
...
</bean>
<bean id="rememberMeAuthenticationProvider" class=
"org.springframework.security.authentication.RememberMeAuthenticationProvider">
<property name="key" value="${remember.me.key}"/>
</bean>
<s:authentication-manager alias="authenticationManager">
<s:authentication-provider ref="rememberMeAuthenticationProvider" />
...
</s:authentication-manager>
Markus Coetzee answer really cleared things up for me. Thanks!
I had the same error and notice that it was trying to auto login every request where the security chain was being ignored. You can see which ones by doing
public void configure(WebSecurity web) throws Exception {
web
.debug(true)
.ignoring()
.antMatchers("/css/**", "/js/**", "/img/**");
}
After this I notice js files and css files where skipping the security chain, I removed those mappings and remember me started working as it should.
public void configure(WebSecurity web) throws Exception {
web
.debug(true)
.ignoring()
.antMatchers("/img/**");
}