Skip to content

Commit ac65495

Browse files
author
chu3la
committed
Improve documentation about CredentialsContainer
1 parent 08b8b09 commit ac65495

File tree

3 files changed

+97
-17
lines changed

3 files changed

+97
-17
lines changed

docs/modules/ROOT/pages/servlet/authentication/architecture.adoc

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -117,13 +117,13 @@ However, if you do, take a look at the JavaDoc for `SecurityContextHolder` to le
117117
[[servlet-authentication-securitycontext]]
118118
== SecurityContext
119119

120-
The javadoc:org.springframework.security.core.context.SecurityContext[] is obtained from the <<servlet-authentication-securitycontextholder>>.
120+
The {security-api-url}org/springframework/security/core/context/SecurityContext.html[`SecurityContext`] is obtained from the <<servlet-authentication-securitycontextholder>>.
121121
The `SecurityContext` contains an <<servlet-authentication-authentication>> object.
122122

123123
[[servlet-authentication-authentication]]
124124
== Authentication
125125

126-
The javadoc:org.springframework.security.core.Authentication[] interface serves two main purposes within Spring Security:
126+
The {security-api-url}org/springframework/security/core/Authentication.html[`Authentication`] interface serves two main purposes within Spring Security:
127127

128128
* An input to <<servlet-authentication-authenticationmanager,`AuthenticationManager`>> to provide the credentials a user has provided to authenticate.
129129
When used in this scenario, `isAuthenticated()` returns `false`.
@@ -141,7 +141,7 @@ Two examples are roles and scopes.
141141

142142
[[servlet-authentication-granted-authority]]
143143
== GrantedAuthority
144-
javadoc:org.springframework.security.core.GrantedAuthority[] instances are high-level permissions that the user is granted.
144+
{security-api-url}org/springframework/security/core/GrantedAuthority.html[`GrantedAuthority`] instances are high-level permissions that the user is granted.
145145
Two examples are roles and scopes.
146146

147147
You can obtain `GrantedAuthority` instances from the <<servlet-authentication-authentication,`Authentication.getAuthorities()`>> method.
@@ -160,7 +160,7 @@ Of course, Spring Security is expressly designed to handle this common requireme
160160
[[servlet-authentication-authenticationmanager]]
161161
== AuthenticationManager
162162

163-
javadoc:org.springframework.security.authentication.AuthenticationManager[] is the API that defines how Spring Security's Filters perform xref:features/authentication/index.adoc#authentication[authentication].
163+
{security-api-url}org/springframework/security/authentication/AuthenticationManager.html[`AuthenticationManager`] is the API that defines how Spring Security's Filters perform xref:features/authentication/index.adoc#authentication[authentication].
164164
The <<servlet-authentication-authentication,`Authentication`>> that is returned is then set on the <<servlet-authentication-securitycontextholder>> by the controller (that is, by xref:servlet/architecture.adoc#servlet-security-filters[Spring Security's `Filters` instances]) that invoked the `AuthenticationManager`.
165165
If you are not integrating with Spring Security's `Filters` instances, you can set the `SecurityContextHolder` directly and are not required to use an `AuthenticationManager`.
166166

@@ -170,7 +170,7 @@ While the implementation of `AuthenticationManager` could be anything, the most
170170
[[servlet-authentication-providermanager]]
171171
== ProviderManager
172172

173-
javadoc:org.springframework.security.authentication.ProviderManager[] is the most commonly used implementation of <<servlet-authentication-authenticationmanager,`AuthenticationManager`>>.
173+
{security-api-url}org/springframework/security/authentication/ProviderManager.html[`ProviderManager`] is the most commonly used implementation of <<servlet-authentication-authenticationmanager,`AuthenticationManager`>>.
174174
`ProviderManager` delegates to a `List` of <<servlet-authentication-authenticationprovider,`AuthenticationProvider`>> instances.
175175
Each `AuthenticationProvider` has an opportunity to indicate that authentication should be successful, fail, or indicate it cannot make a decision and allow a downstream `AuthenticationProvider` to decide.
176176
If none of the configured `AuthenticationProvider` instances can authenticate, authentication fails with a `ProviderNotFoundException`, which is a special `AuthenticationException` that indicates that the `ProviderManager` was not configured to support the type of `Authentication` that was passed into it.
@@ -195,24 +195,26 @@ image::{figures}/providermanagers-parent.png[]
195195
By default, `ProviderManager` tries to clear any sensitive credentials information from the `Authentication` object that is returned by a successful authentication request.
196196
This prevents information, such as passwords, being retained longer than necessary in the `HttpSession`.
197197

198+
> **Note:** The `CredentialsContainer` interface plays a critical role in the authentication process. It allows for the erasure of credential information once it is no longer needed, thereby enhancing security by ensuring sensitive data is not retained longer than necessary.
199+
198200
This may cause issues when you use a cache of user objects, for example, to improve performance in a stateless application.
199201
If the `Authentication` contains a reference to an object in the cache (such as a `UserDetails` instance) and this has its credentials removed, it is no longer possible to authenticate against the cached value.
200202
You need to take this into account if you use a cache.
201203
An obvious solution is to first make a copy of the object, either in the cache implementation or in the `AuthenticationProvider` that creates the returned `Authentication` object.
202204
Alternatively, you can disable the `eraseCredentialsAfterAuthentication` property on `ProviderManager`.
203-
See the Javadoc for the javadoc:org.springframework.security.authentication.ProviderManager[] class.
205+
See the Javadoc for the {security-api-url}org/springframework/security/authentication/ProviderManager.html[ProviderManager] class.
204206

205207
[[servlet-authentication-authenticationprovider]]
206208
== AuthenticationProvider
207209

208-
You can inject multiple javadoc:org.springframework.security.authentication.AuthenticationProvider[] instances into <<servlet-authentication-providermanager,`ProviderManager`>>.
210+
You can inject multiple {security-api-url}org/springframework/security/authentication/AuthenticationProvider.html[``AuthenticationProvider``s] instances into <<servlet-authentication-providermanager,`ProviderManager`>>.
209211
Each `AuthenticationProvider` performs a specific type of authentication.
210212
For example, xref:servlet/authentication/passwords/dao-authentication-provider.adoc#servlet-authentication-daoauthenticationprovider[`DaoAuthenticationProvider`] supports username/password-based authentication, while `JwtAuthenticationProvider` supports authenticating a JWT token.
211213

212214
[[servlet-authentication-authenticationentrypoint]]
213215
== Request Credentials with `AuthenticationEntryPoint`
214216

215-
javadoc:org.springframework.security.web.AuthenticationEntryPoint[] is used to send an HTTP response that requests credentials from a client.
217+
{security-api-url}org/springframework/security/web/AuthenticationEntryPoint.html[`AuthenticationEntryPoint`] is used to send an HTTP response that requests credentials from a client.
216218

217219
Sometimes, a client proactively includes credentials (such as a username and password) to request a resource.
218220
In these cases, Spring Security does not need to provide an HTTP response that requests credentials from the client, since they are already included.
@@ -229,7 +231,7 @@ The `AuthenticationEntryPoint` implementation might perform a xref:servlet/authe
229231
[[servlet-authentication-abstractprocessingfilter]]
230232
== AbstractAuthenticationProcessingFilter
231233

232-
javadoc:org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter[] is used as a base `Filter` for authenticating a user's credentials.
234+
{security-api-url}org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilter.html[`AbstractAuthenticationProcessingFilter`] is used as a base `Filter` for authenticating a user's credentials.
233235
Before the credentials can be authenticated, Spring Security typically requests the credentials by using <<servlet-authentication-authenticationentrypoint,`AuthenticationEntryPoint`>>.
234236

235237
Next, the `AbstractAuthenticationProcessingFilter` can authenticate any authentication requests that are submitted to it.
@@ -245,26 +247,26 @@ image:{icondir}/number_2.png[] Next, the <<servlet-authentication-authentication
245247
image:{icondir}/number_3.png[] If authentication fails, then __Failure__.
246248

247249
* The <<servlet-authentication-securitycontextholder>> is cleared out.
248-
* `RememberMeServices.loginFail` is invoked.ƒ
250+
* `RememberMeServices.loginFail` is invoked.
249251
If remember me is not configured, this is a no-op.
250-
See the javadoc:org.springframework.security.web.authentication.rememberme.package-summary[rememberme] package.
252+
See the {security-api-url}org/springframework/security/web/authentication/rememberme/package-frame.html[`rememberme`] package.
251253
* `AuthenticationFailureHandler` is invoked.
252-
See the javadoc:org.springframework.security.web.authentication.AuthenticationFailureHandler[] interface.
254+
See the {security-api-url}org/springframework/security/web/authentication/AuthenticationFailureHandler.html[`AuthenticationFailureHandler`] interface.
253255

254256
image:{icondir}/number_4.png[] If authentication is successful, then __Success__.
255257

256258
* `SessionAuthenticationStrategy` is notified of a new login.
257-
See the javadoc:org.springframework.security.web.authentication.session.SessionAuthenticationStrategy[] interface.
259+
See the {security-api-url}org/springframework/security/web/authentication/session/SessionAuthenticationStrategy.html[`SessionAuthenticationStrategy`] interface.
258260
* The <<servlet-authentication-authentication>> is set on the <<servlet-authentication-securitycontextholder>>.
259261
Later, if you need to save the `SecurityContext` so that it can be automatically set on future requests, `SecurityContextRepository#saveContext` must be explicitly invoked.
260-
See the javadoc:org.springframework.security.web.context.SecurityContextHolderFilter[] class.
262+
See the {security-api-url}org/springframework/security/web/context/SecurityContextHolderFilter.html[`SecurityContextHolderFilter`] class.
261263

262264
* `RememberMeServices.loginSuccess` is invoked.
263265
If remember me is not configured, this is a no-op.
264-
See the javadoc:org.springframework.security.web.authentication.rememberme.package-summary[rememberme] package.
266+
See the {security-api-url}org/springframework/security/web/authentication/rememberme/package-frame.html[`rememberme`] package.
265267
* `ApplicationEventPublisher` publishes an `InteractiveAuthenticationSuccessEvent`.
266268
* `AuthenticationSuccessHandler` is invoked.
267-
See the javadoc:org.springframework.security.web.authentication.AuthenticationSuccessHandler[] interface.
269+
See the {security-api-url}org/springframework/security/web/authentication/AuthenticationSuccessHandler.html[`AuthenticationSuccessHandler`] interface.
268270

269271

270272
// daoauthenticationprovider (goes in username/password)
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
== Password Erasure
2+
3+
After successful authentication, it's a security best practice to erase credentials from memory to prevent them from being exposed to potential memory dump attacks. `ProviderManager` and most `AuthenticationProvider` implementations in Spring Security support this practice through the `eraseCredentials` method, which should be invoked after the authentication process completes.
4+
5+
=== Best Practices
6+
7+
. *Immediate Erasure*: Credentials should be erased immediately after they are no longer needed. This minimizes the window during which the credentials are exposed in memory.
8+
. *Automatic Erasure*: Configure `ProviderManager` to automatically erase credentials post-authentication by setting `eraseCredentialsAfterAuthentication` to `true`.
9+
. *Custom Erasure Strategies*: Implement custom erasure strategies in custom `AuthenticationProvider` implementations if the default erasure behavior does not meet specific security requirements.
10+
11+
=== Risk Assessment
12+
13+
Failure to properly erase credentials can lead to several risks:
14+
15+
. *Memory Access Attacks*: Attackers can access raw credentials from memory through exploits like buffer overflow attacks or memory dumps.
16+
. *Insider Threats*: Malicious insiders with access to systems could potentially extract credentials from application memory.
17+
. *Accidental Exposure*: In multi-tenant environments, lingering credentials in memory could accidentally be exposed to other tenants.
18+
19+
=== Implementation
20+
21+
[source,java]
22+
----
23+
public class CustomAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
24+
@Override
25+
protected void additionalAuthenticationChecks(UserDetails userDetails,
26+
UsernamePasswordAuthenticationToken authentication)
27+
throws AuthenticationException {
28+
// Perform authentication checks
29+
if (!passwordEncoder.matches(authentication.getCredentials().toString(), userDetails.getPassword())) {
30+
throw new BadCredentialsException(messages.getMessage(
31+
"AbstractUserDetailsAuthenticationProvider.badCredentials",
32+
"Bad credentials"));
33+
}
34+
35+
// Erase credentials post-check
36+
authentication.eraseCredentials();
37+
}
38+
}
39+
----
40+
41+
By implementing these practices, organizations can significantly enhance the security of their authentication systems by ensuring that credentials are not left exposed in system memory.
Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,42 @@
11
[[servlet-authentication-userdetails]]
22
= UserDetails
33

4-
javadoc:org.springframework.security.core.userdetails.UserDetails[] is returned by the xref:servlet/authentication/passwords/user-details-service.adoc#servlet-authentication-userdetailsservice[`UserDetailsService`].
4+
{security-api-url}org/springframework/security/core/userdetails/UserDetails.html[`UserDetails`] is returned by the xref:servlet/authentication/passwords/user-details-service.adoc#servlet-authentication-userdetailsservice[`UserDetailsService`].
55
The xref:servlet/authentication/passwords/dao-authentication-provider.adoc#servlet-authentication-daoauthenticationprovider[`DaoAuthenticationProvider`] validates the `UserDetails` and then returns an xref:servlet/authentication/architecture.adoc#servlet-authentication-authentication[`Authentication`] that has a principal that is the `UserDetails` returned by the configured `UserDetailsService`.
6+
7+
=== Credentials Management
8+
9+
Implementing the `CredentialsContainer` interface in classes that store user credentials, such as those extending or implementing `UserDetails`, is strongly recommended, especially in applications where user details are not cached. This practice enhances security by ensuring that sensitive data, such as passwords, are not retained in memory longer than necessary.
10+
11+
==== When to Implement CredentialsContainer
12+
13+
Applications that do not employ caching mechanisms for `UserDetails` should particularly consider implementing `CredentialsContainer`. This approach helps in mitigating the risk associated with retaining sensitive information in memory, which can be vulnerable to attack vectors such as memory dumps.
14+
15+
[source,java]
16+
----
17+
public class MyUserDetails implements UserDetails, CredentialsContainer {
18+
private String username;
19+
private String password;
20+
21+
// UserDetails implementation...
22+
23+
@Override
24+
public void eraseCredentials() {
25+
this.password = null; // Securely erase the password field
26+
}
27+
}
28+
----
29+
30+
==== Implementation Guidelines
31+
32+
* *Immediate Erasure*: Credentials should be erased immediately after they are no longer needed, typically post-authentication.
33+
* *Automatic Invocation*: Ensure that `eraseCredentials()` is automatically called by your authentication framework, such as `AuthenticationManager` or `AuthenticationProvider`, once the authentication process is complete.
34+
* *Consistency*: Apply this practice uniformly across all applications to prevent security lapses that could lead to data breaches.
35+
36+
==== Beyond Basic Interface Implementation
37+
38+
While interfaces like `CredentialsContainer` provide a framework for credential management, the practical implementation often depends on specific classes and their interactions. For example, the `DaoAuthenticationProvider` class, adhering to the `AuthenticationProvider`'s contract, does not perform credential erasure within its own `authenticate` method.
39+
40+
Instead, it relies on `ProviderManager`—Spring Security's default implementation of `AuthenticationManager`—to handle the erasure of credentials and other sensitive data post-authentication. This separation emphasizes the principle that the authentication process itself should not assume the responsibility for credential management. It is worth noting that the `AuthenticationManager` API documentation specifies that the implementation should return "a fully authenticated object including credentials" via the `authenticate` method, underscoring the distinction between authentication and credential management.
41+
42+
Incorporating `CredentialsContainer` into your `UserDetails` implementation aligns with security best practices, reducing potential exposure to data breaches by minimizing the lifespan of sensitive data in memory.

0 commit comments

Comments
 (0)