For the latest stable version, please use Spring Security 6.4.1! |
Persisting Authentication
The first time a user requests a protected resource, they are prompted for credentials. One of the most common ways to prompt for credentials is to redirect the user to a log in page. A summarized HTTP exchange for an unauthenticated user requesting a protected resource might look like this:
GET / HTTP/1.1
Host: example.com
Cookie: SESSION=91470ce0-3f3c-455b-b7ad-079b02290f7b
HTTP/1.1 302 Found
Location: /login
The user submits their username and password.
POST /login HTTP/1.1
Host: example.com
Cookie: SESSION=91470ce0-3f3c-455b-b7ad-079b02290f7b
username=user&password=password&_csrf=35942e65-a172-4cd4-a1d4-d16a51147b3e
Upon authenticating the user, the user is associated to a new session id to prevent session fixation attacks.
HTTP/1.1 302 Found
Location: /
Set-Cookie: SESSION=4c66e474-3f5a-43ed-8e48-cc1d8cb1d1c8; Path=/; HttpOnly; SameSite=Lax
Subsequent requests include the session cookie which is used to authenticate the user for the remainder of the session.
GET / HTTP/1.1
Host: example.com
Cookie: SESSION=4c66e474-3f5a-43ed-8e48-cc1d8cb1d1c8
SecurityContextRepository
In Spring Security the association of the user to future requests is made using SecurityContextRepository
.
HttpSecurityContextRepository
The default implementation of SecurityContextRepository
is HttpSessionSecurityContextRepository
which associates the SecurityContext
to the HttpSession
.
Users can replace HttpSessionSecurityContextRepository
with another implementation of SecurityContextRepository
if they wish to associate the user with subsequent requests in another way or not at all.
NullSecurityContextRepository
If it is not desirable to associate the SecurityContext
to an HttpSession
(i.e. when authenticating with OAuth) the NullSecurityContextRepository
is an implementation of SecurityContextRepository
that does nothing.
RequestAttributeSecurityContextRepository
The RequestAttributeSecurityContextRepository
saves the SecurityContext
as a request attribute to make sure the SecurityContext
is available for a single request that occurs across dispatch types that may clear out the SecurityContext
.
For example, assume that a client makes a request, is authenticated, and then an error occurs.
Depending on the servlet container implementation, the error means that any SecurityContext
that was established is cleared out and then the error dispatch is made.
When the error dispatch is made, there is no SecurityContext
established.
This means that the error page cannot use the SecurityContext
for authorization or displaying the current user unless the SecurityContext
is persisted somehow.
-
Java
-
XML
public SecurityFilterChain filterChain(HttpSecurity http) {
http
// ...
.securityContext((securityContext) -> securityContext
.securityContextRepository(new RequestAttributeSecurityContextRepository())
);
return http.build();
}
<http security-context-repository-ref="contextRepository">
<!-- ... -->
</http>
<b:bean name="contextRepository"
class="org.springframework.security.web.context.RequestAttributeSecurityContextRepository" />
SecurityContextPersistenceFilter
The SecurityContextPersistenceFilter
is responsible for persisting the SecurityContext
between requests using the SecurityContextRepository
.
Before running the rest of the application, SecurityContextPersistenceFilter
loads the SecurityContext
from the SecurityContextRepository
and sets it on the SecurityContextHolder
.
Next, the application is ran.
Finally, if the SecurityContext
has changed, we save the SecurityContext
using the SecurityContextPersistenceRepository
.
This means that when using SecurityContextPersistenceFilter
, just setting the SecurityContextHolder
will ensure that the SecurityContext
is persisted using SecurityContextRepository
.
In some cases a response is committed and written to the client before the SecurityContextPersistenceFilter
method completes.
For example, if a redirect is sent to the client the response is immediately written back to the client.
This means that establishing an HttpSession
would not be possible in step 3 because the session id could not be included in the already written response.
Another situation that can happen is that if a client authenticates successfully, the response is committed before SecurityContextPersistenceFilter
completes, and the client makes a second request before the SecurityContextPersistenceFilter
completes the wrong authentication could be present in the second request.
To avoid these problems, the SecurityContextPersistenceFilter
wraps both the HttpServletRequest
and the HttpServletResponse
to detect if the SecurityContext
has changed and if so save the SecurityContext
just before the response is committed.
SecurityContextHolderFilter
The SecurityContextHolderFilter
is responsible for loading the SecurityContext
between requests using the SecurityContextRepository
.
Before running the rest of the application, SecurityContextHolderFilter
loads the SecurityContext
from the SecurityContextRepository
and sets it on the SecurityContextHolder
.
Next, the application is ran.
Unlike, SecurityContextPersisteneFilter
, SecurityContextHolderFilter
only loads the SecurityContext
it does not save the SecurityContext
.
This means that when using SecurityContextHolderFilter
, it is required that the SecurityContext
is explicitly saved.
-
Java
-
XML
public SecurityFilterChain filterChain(HttpSecurity http) {
http
// ...
.securityContext((securityContext) -> securityContext
.requireExplicitSave(true)
);
return http.build();
}
<http security-context-explicit-save="true">
<!-- ... -->
</http>