i have a GWT application using Spring Security3.1.2 running in a tomcat 7. i am using UsernamePasswordAuthenticationFilter and PersistentTokenBasedRememberMeServices to persists logins on the DB. moreover, i am using tomcat PersistentManager to save session in DB as well. now my problem is that every time i try to login i get Invalid remember-me token (Series/token) mismatch CookieTheftException (i added the stack below). i tried deleting the session from tomcat_sessions table as follows
i also noticed that even after deleting all records in tomcat_sessions table and when i restart tomcat, tomcat_sessions gets filled up with all the session i deleted earlier...
i also deleted all records in Spring persistent_logins table and disabled tomcat PersistentManager but still having the same problem...
any idea what might be the problem? thank you
SEVERE: Servlet.service() for servlet [springMvcServlet] in context with path [/brate] threw exception
org.springframework.security.web.authentication.rememberme.CookieTheftException: Invalid remember-me token (Series/token) mismatch. Implies previous cookie theft attack.
at org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices.processAutoLoginCookie(PersistentTokenBasedRememberMeServices.java:102)
at org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices.autoLogin(AbstractRememberMeServices.java:115)
at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:97)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:54)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:183)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at com.brate.admin.server.servlet.crawler.GoogleBotFilter.doFilter(GoogleBotFilter.java:202)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
at java.lang.Thread.run(Thread.java:695)
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.
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/**");
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With