1
0
mirror of synced 2026-08-31 14:35:18 +00:00
Files

130 lines
7.9 KiB
Plaintext
Raw Permalink Normal View History

2020-03-02 22:45:45 -06:00
[[servlet-rememberme]]
2021-07-30 13:52:15 -05:00
= Remember-Me Authentication
2018-03-06 10:57:57 -06:00
[[remember-me-overview]]
Remember-me or persistent-login authentication refers to web sites being able to remember the identity of a principal between sessions.
This is typically accomplished by sending a cookie to the browser, with the cookie being detected during future sessions and causing automated login to take place.
2021-04-21 16:01:26 -05:00
Spring Security provides the necessary hooks for these operations to take place and has two concrete remember-me implementations.
2018-03-06 10:57:57 -06:00
One uses hashing to preserve 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 a `UserDetailsService`.
2021-04-21 16:01:26 -05:00
If you use an authentication provider that does not use a `UserDetailsService` (for example, the LDAP provider), it does not work unless you also have a `UserDetailsService` bean in your application context.
2018-03-06 10:57:57 -06:00
[[remember-me-hash-token]]
2021-07-30 13:52:15 -05:00
== Simple Hash-Based Token Approach
2018-03-06 10:57:57 -06:00
This approach uses hashing to achieve a useful remember-me strategy.
2021-04-21 16:01:26 -05:00
In essence, a cookie is sent to the browser upon successful interactive authentication, with the cookie being composed as follows:
2018-03-06 10:57:57 -06:00
[source,txt]
----
base64(username + ":" + expirationTime + ":" + algorithmName + ":"
algorithmHex(username + ":" + expirationTime + ":" password + ":" + key))
2018-03-06 10:57:57 -06:00
username: As identifiable to the UserDetailsService
password: That matches the one in the retrieved UserDetails
expirationTime: The date and time when the remember-me token expires, expressed in milliseconds
key: A private key to prevent modification of the remember-me token
algorithmName: The algorithm used to generate and to verify the remember-me token signature
2018-03-06 10:57:57 -06:00
----
2021-04-21 16:01:26 -05:00
The remember-me token is valid only for the period specified and only if the username, password, and key do not change.
Notably, this has a potential security issue, in that a captured remember-me token is usable from any user agent until such time as the token expires.
2018-03-06 10:57:57 -06:00
This is the same issue as with digest authentication.
2021-04-21 16:01:26 -05:00
If a principal is aware that a token has been captured, they can easily change their password and immediately invalidate all remember-me tokens on issue.
If more significant security is needed, you should use the approach described in the next section.
Alternatively, remember-me services should not be used at all.
2018-03-06 10:57:57 -06:00
2021-12-13 16:57:36 -06:00
If you are familiar with the topics discussed in the chapter on xref:servlet/configuration/xml-namespace.adoc#ns-config[namespace configuration], you can enable remember-me authentication by adding the `<remember-me>` element:
2018-03-06 10:57:57 -06:00
[source,xml]
----
<http>
...
<remember-me key="myAppKey"/>
</http>
----
2021-04-21 16:01:26 -05:00
The `UserDetailsService` is normally selected automatically.
2018-03-06 10:57:57 -06:00
If you have more than one in your application context, you need to specify which one should be used with the `user-service-ref` attribute, where the value is the name of your `UserDetailsService` bean.
[[remember-me-persistent-token]]
2021-07-30 13:52:15 -05:00
== Persistent Token Approach
2024-11-09 23:28:30 +07:00
This approach is based on the article https://web.archive.org/web/20180819014446/http://jaspan.com/improved_persistent_login_cookie_best_practice[Improved Persistent Login Cookie Best Practice] with some minor modifications footnote:[Essentially, the username is not included in the cookie, to prevent exposing a valid login name unnecessarily.
2018-03-06 10:57:57 -06:00
There is a discussion on this in the comments section of this article.].
2024-05-23 14:02:11 -03:00
To use this approach with namespace configuration, you would supply a datasource reference:
2018-03-06 10:57:57 -06:00
[source,xml]
----
<http>
...
<remember-me data-source-ref="someDataSource"/>
</http>
----
2021-04-21 16:01:26 -05:00
The database should contain a `persistent_logins` table, created by using the following SQL (or equivalent):
2018-03-06 10:57:57 -06:00
[source,ddl]
----
create table persistent_logins (username varchar(64) not null,
series varchar(64) primary key,
token varchar(64) not null,
last_used timestamp not null)
----
[[remember-me-impls]]
2021-07-30 13:52:15 -05:00
== Remember-Me Interfaces and Implementations
2021-04-21 16:01:26 -05:00
Remember-me is used with `UsernamePasswordAuthenticationFilter` and is implemented through hooks in the `AbstractAuthenticationProcessingFilter` superclass.
2018-03-06 10:57:57 -06:00
It is also used within `BasicAuthenticationFilter`.
2021-04-21 16:01:26 -05:00
The hooks invoke a concrete `RememberMeServices` at the appropriate times.
The following listing shows the interface:
2018-03-06 10:57:57 -06:00
[source,java]
----
Authentication autoLogin(HttpServletRequest request, HttpServletResponse response);
void loginFail(HttpServletRequest request, HttpServletResponse response);
void loginSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication successfulAuthentication);
----
2024-07-09 13:23:24 -05:00
See the Javadoc for javadoc:org.springframework.security.web.authentication.RememberMeServices[] for a fuller discussion on what the methods do, although note that, at this stage, `AbstractAuthenticationProcessingFilter` calls only the `loginFail()` and `loginSuccess()` methods.
2018-03-06 10:57:57 -06:00
The `autoLogin()` method is called by `RememberMeAuthenticationFilter` whenever the `SecurityContextHolder` does not contain an `Authentication`.
2021-04-21 16:01:26 -05:00
This interface, therefore, provides the underlying remember-me implementation with sufficient notification of authentication-related events and delegates to the implementation whenever a candidate web request might contain a cookie and wish to be remembered.
2018-03-06 10:57:57 -06:00
This design allows any number of remember-me implementation strategies.
2021-04-21 16:01:26 -05:00
We have seen earlier that Spring Security provides two implementations.
We look at each of these in turn.
2018-03-06 10:57:57 -06:00
2026-02-04 20:15:06 +07:00
[[token-based-remember-me-services]]
2021-07-30 13:52:15 -05:00
=== TokenBasedRememberMeServices
2018-03-06 10:57:57 -06:00
This implementation supports the simpler approach described in <<remember-me-hash-token>>.
`TokenBasedRememberMeServices` generates a `RememberMeAuthenticationToken`, which is processed by `RememberMeAuthenticationProvider`.
A `key` is shared between this authentication provider and the `TokenBasedRememberMeServices`.
2021-04-21 16:01:26 -05:00
In addition, `TokenBasedRememberMeServices` requires a `UserDetailsService`, from which it can retrieve the username and password for signature comparison purposes and generate the `RememberMeAuthenticationToken` to contain the correct `GrantedAuthority` instances.
`TokenBasedRememberMeServices` also implements Spring Security's `LogoutHandler` interface so that it can be used with `LogoutFilter` to have the cookie cleared automatically.
2018-03-06 10:57:57 -06:00
2022-07-25 10:21:25 -03:00
By default, this implementation uses the SHA-256 algorithm to encode the token signature.
To verify the token signature, the algorithm retrieved from `algorithmName` is parsed and used.
2022-07-25 10:21:25 -03:00
If no `algorithmName` is present, the default matching algorithm will be used, which is SHA-256.
You can specify different algorithms for signature encoding and for signature matching, this allows users to safely upgrade to a different encoding algorithm while still able to verify old ones if there is no `algorithmName` present.
To do that you can specify your customized `TokenBasedRememberMeServices` as a Bean and use it in the configuration.
2026-02-04 20:15:06 +07:00
include-code::./CustomAlgorithmRememberMeServicesConfiguration[tag=snippet,indent=0]
2021-04-21 16:01:26 -05:00
The following beans are required in an application context to enable remember-me services:
2018-03-06 10:57:57 -06:00
2026-02-04 20:15:06 +07:00
include-code::./DefaultAlgorithmRememberMeServicesConfiguration[tag=snippet,indent=0]
2018-03-06 10:57:57 -06:00
2021-04-21 16:01:26 -05:00
Remember to add your `RememberMeServices` implementation to your `UsernamePasswordAuthenticationFilter.setRememberMeServices()` property, include the `RememberMeAuthenticationProvider` in your `AuthenticationManager.setProviders()` list, and add `RememberMeAuthenticationFilter` into your `FilterChainProxy` (typically immediately after your `UsernamePasswordAuthenticationFilter`).
2018-03-06 10:57:57 -06:00
2021-07-30 13:52:15 -05:00
=== PersistentTokenBasedRememberMeServices
2021-04-21 16:01:26 -05:00
You can use this class in the same way as `TokenBasedRememberMeServices`, but it additionally needs to be configured with a `PersistentTokenRepository` to store the tokens.
2018-03-06 10:57:57 -06:00
* `InMemoryTokenRepositoryImpl` which is intended for testing only.
* `JdbcTokenRepositoryImpl` which stores the tokens in a database.
2021-04-21 16:01:26 -05:00
See <<remember-me-persistent-token>> for the database schema.