My SecurityConfig
class where I configure remember-me feature backed by userService
and persistenceTokenRepository()
:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(
"/js/**",
"/css/**",
"/img/**",
"/webjars/**").permitAll()
.anyRequest().authenticated()
// ... and login, and logout
.and()
.rememberMe()
.userDetailsService(userService)
.tokenRepository(persistentTokenRepository());
}
@Bean
public PersistentTokenRepository persistentTokenRepository() {
JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
tokenRepository.setDataSource(dataSource);
return tokenRepository;
}
Use case:
Expected result: [Back-end] No exceptions, the token in DB is matched with the remember-me cookie. [Front-end] The user is successfully authenticated and can proceed to homepage.
Actual result: [Back-end] CookieTheftException
is thrown. The token is deleted from DB. [Front-end] User is redirected to Login page.
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:119) ~[spring-security-web-5.0.9.RELEASE.jar:5.0.9.RELEASE]
This question is already answered here: Spring Security Invalid remember-me token (Series/token) mismatch. Implies previous cookie theft attack. "Remember Me" feature is explained in details in that answer, I recommend you to read it before applying the following solution.
I'd like to share my solution for Java configuration. Split static resources security from webapp pages security:
http
.authorizeRequests()
.antMatchers(
"/js/**",
"/css/**",
"/img/**",
"/webjars/**").permitAll();
http
.authorizeRequests()
.anyRequest().authenticated()
// ... and login, and logout
.and()
.rememberMe()
.userDetailsService(userService)
.tokenRepository(persistentTokenRepository());
It's up to you whether you define these two configurations in a single
configure(HttpSecurity http)
method or split them into two @Configuration
classes. If you choose the latter option, don't forget to put @Order(int)
annotations on these configurations, otherwise, you get a conflict.