Brief description
Remember-me or persistent-login authentication refers to websites that can remember a user's identity between sessions. This is typically achieved by sending a cookie to the browser, with the cookie being detected during subsequent sessions and resulting in automatic login. Spring Security provides the necessary interceptors to perform these operations and has two specific implementations of remember-me. One uses hashing to maintain the security of cookie-based tokens, and the other uses a database or other persistent storage mechanism to store the generated tokens.
Note that both implementations require UserDetailsService
. If you are using an authentication provider
that does not use UserDetailsService
(such as an LDAP provider), then it will not work unless there is
also a UserDetailsService
bean in the application context.
Simple approach using hash-based tokens
This approach uses hashing to successfully implement the useful remember-me strategy. Essentially, a cookie is sent to the browser after successful interactive authentication, and the cookie consists of the following elements:
base64(username + ":" + expirationTime + ":" +
md5Hex(username + ":" + expirationTime + ":" password + ":" + key))
username: Which can determine the UserDetailsService
password: Same as the one contained in the received UserDetails
expirationTime: Date and time of expiration of the remember-me token, expressed in milliseconds
key: Private key to prevent changes to the remember-me
Thus, the remember-me token is only valid for the specified period and provided that the username, password and key do not change. Notably, there is a potential security issue in this case, as the resulting remember-me token will be available for use by any user agent until the token expires. This is the same problem as with digest authentication. If the principal knows that the token has been intercepted, he can easily change his password and immediately revoke all issued remember-me tokens. If more advanced protection is required, the approach described in the next section should be used. Or remember-me services should not be used at all.
If you are familiar with the topics covered in the namespace configuration chapter, you can enable remember-me
authentication by simply adding a <remember-me>
element:
<http>
...
<remember-me key="myAppKey"/>
</http>
The specific UserDetailsService
is usually selected automatically. If you have more than one in your
application context, you need to specify which one to use using the user-service-ref
attribute, where
the value is the name of your bean for UserDetailsService
.
Persistent Token Approach
This approach is based on the article http://jaspan.com/improved_persistent_login_cookie_best_practice with some minor changes [1]. To use this approach with namespace configuration, you need to provide a reference to the datasource:
<http>
...
<remember-me data-source-ref="someDataSource"/>
</http>
The database must contain a persistent_logins
table created using the following SQL (or equivalent):
create table persistent_logins (username varchar(64) not null,
series varchar(64) primary key,
token varchar(64) not null,
last_used timestamp not null)
Interfaces and implementations of the Remember-Me method
The Remember-me method is used with UsernamePasswordAuthenticationFilter
and is implemented using
interceptors in the AbstractAuthenticationProcessingFilter
superclass. It is also used in BasicAuthenticationFilter
.
Interceptors will call specific RememberMeServices
at appropriate times. The interface looks like this:
Authentication autoLogin(HttpServletRequest request, HttpServletResponse response);
void loginFail(HttpServletRequest request, HttpServletResponse response);
void loginSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication successfulAuthentication);
Please refer to the Javadoc for a more complete description of how these methods work, although at this stage note
that AbstractAuthenticationProcessingFilter
only calls the loginFail()
and loginSuccess()
.
The autoLogin()
method is called by the RememberMeAuthenticationFilter
whenever the SecurityContextHolder
does not contain an Authentication
. Therefore, this interface provides a basic implementation of
remember-me with proper notification of authentication-related events and delegates authority to it in cases where a
candidate's web request may contain a cookie and needs to be remembered. This structure allows you to use any number
of remember-me implementation strategies. We learned above that Spring Security provides two implementations. We'll
look at them one by one.
TokenBasedRememberMeServices
TokenBasedRememberMeServices
generates a RememberMeAuthenticationToken
, which is handled by
the RememberMeAuthenticationProvider
. The key
instance is shared between this
authentication provider and TokenBasedRememberMeServices
. Additionally, TokenBasedRememberMeServices
requires an instance of UserDetailsService from which it can obtain the username and password for signature
matching, as well as generate a RememberMeAuthenticationToken
so that it contains the correct GrantedAuthority
.
The application must provide some kind of logout command that will invalidate the cookie if the user requests it.
TokenBasedRememberMeServices
also implements the LogoutHandler
interface from Spring
Security, so can be used in conjunction with LogoutFilter
to automatically clear cookies.
The following are the beans that must be in the application context in order to enable remember-me services:
<bean id="rememberMeFilter" class=
"org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter">
<property name="rememberMeServices" ref="rememberMeServices"/>
<property name="authenticationManager" ref="theAuthenticationManager" />
</bean>
<bean id="rememberMeServices" class=
"org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices">
<property name="userDetailsService" ref="myUserDetailsService"/>
<property name="key" value="springRocks"/>
</bean>
<bean id="rememberMeAuthenticationProvider" class=
"org.springframework.security.authentication.RememberMeAuthenticationProvider">
<property name="key" value="springRocks"/>
</bean>
Don't forget to add the RememberMeServices
implementation to the UsernamePasswordAuthenticationFilter.setRememberMeServices()
property, add RememberMeAuthenticationProvider
to the AuthenticationManager.setProviders()
and add RememberMeAuthenticationFilter
to FilterChainProxy
(usually right after UsernamePasswordAuthenticationFilter
).
PersistentTokenBasedRememberMeServices
This class can be used in the same way as TokenBasedRememberMeServices
, but additionally you need to add
a PersistentTokenRepository
to the configuration to store tokens. There are two standard
implementations.
-
InMemoryTokenRepositoryImpl
, which is intended for testing only. -
JdbcTokenRepositoryImpl
, which stores tokens in the database>