For the latest stable version, please use Spring Security 6.2.0!
Servlet Authentication Architecture
This discussion expands on Servlet Security: The Big Picture to describe the main architectural components of Spring Security’s used in Servlet authentication. If you need concrete flows that explain how these pieces fit together, look at the Authentication Mechanism specific sections.
SecurityContext - is obtained from the
SecurityContextHolderand contains the
Authenticationof the currently authenticated user.
Authentication - Can be the input to
AuthenticationManagerto provide the credentials a user has provided to authenticate or the current user from the
GrantedAuthority - An authority that is granted to the principal on the
Authentication(i.e. roles, scopes, etc.)
ProviderManager - the most common implementation of
AuthenticationProvider - used by
ProviderManagerto perform a specific type of authentication.
Request Credentials with
AuthenticationEntryPoint- used for requesting credentials from a client (i.e. redirecting to a log in page, sending a
AbstractAuthenticationProcessingFilter - a base
Filterused for authentication. This also gives a good idea of the high level flow of authentication and how pieces work together.
At the heart of Spring Security’s authentication model is the
It contains the SecurityContext.
SecurityContextHolder is where Spring Security stores the details of who is authenticated.
Spring Security does not care how the
SecurityContextHolder is populated.
If it contains a value, then it is used as the currently authenticated user.
The simplest way to indicate a user is authenticated is to set the
SecurityContext context = SecurityContextHolder.createEmptyContext(); (1) Authentication authentication = new TestingAuthenticationToken("username", "password", "ROLE_USER"); (2) context.setAuthentication(authentication); SecurityContextHolder.setContext(context); (3)
val context: SecurityContext = SecurityContextHolder.createEmptyContext() (1) val authentication: Authentication = TestingAuthenticationToken("username", "password", "ROLE_USER") (2) context.authentication = authentication SecurityContextHolder.setContext(context) (3)
|1||We start by creating an empty
|2||Next we create a new
|3||Finally, we set the
If you wish to obtain information about the authenticated principal, you can do so by accessing the
SecurityContext context = SecurityContextHolder.getContext(); Authentication authentication = context.getAuthentication(); String username = authentication.getName(); Object principal = authentication.getPrincipal(); Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
val context = SecurityContextHolder.getContext() val authentication = context.authentication val username = authentication.name val principal = authentication.principal val authorities = authentication.authorities
By default the
SecurityContextHolder uses a
ThreadLocal to store these details, which means that the
SecurityContext is always available to methods in the same thread, even if the
SecurityContext is not explicitly passed around as an argument to those methods.
ThreadLocal in this way is quite safe if care is taken to clear the thread after the present principal’s request is processed.
Spring Security’s FilterChainProxy ensures that the
SecurityContext is always cleared.
Some applications aren’t entirely suitable for using a
ThreadLocal, because of the specific way they work with threads.
For example, a Swing client might want all threads in a Java Virtual Machine to use the same security context.
SecurityContextHolder can be configured with a strategy on startup to specify how you would like the context to be stored.
For a standalone application you would use the
Other applications might want to have threads spawned by the secure thread also assume the same security identity.
This is achieved by using
You can change the mode from the default
SecurityContextHolder.MODE_THREADLOCAL in two ways.
The first is to set a system property, the second is to call a static method on
Most applications won’t need to change from the default, but if you do, take a look at the Javadoc for
SecurityContextHolder to learn more.
Authentication serves two main purposes within Spring Security:
principal- identifies the user. When authenticating with a username/password this is often an instance of
credentials- often a password. In many cases this will be cleared after the user is authenticated to ensure it is not leaked.
GrantedAuthoritys are high level permissions the user is granted. A few examples are roles or scopes.
GrantedAuthoritys are high level permissions the user is granted. A few examples are roles or scopes.
GrantedAuthoritys can be obtained from the
This method provides a
GrantedAuthority is, not surprisingly, an authority that is granted to the principal.
Such authorities are usually "roles", such as
These roles are later on configured for web authorization, method authorization and domain object authorization.
Other parts of Spring Security are capable of interpreting these authorities, and expect them to be present.
When using username/password based authentication
GrantedAuthoritys are usually loaded by the
GrantedAuthority objects are application-wide permissions.
They are not specific to a given domain object.
Thus, you wouldn’t likely have a
GrantedAuthority to represent a permission to
Employee object number 54, because if there are thousands of such authorities you would quickly run out of memory (or, at the very least, cause the application to take a long time to authenticate a user).
Of course, Spring Security is expressly designed to handle this common requirement, but you’d instead use the project’s domain object security capabilities for this purpose.
AuthenticationManager is the API that defines how Spring Security’s Filters perform authentication.
Authentication that is returned is then set on the SecurityContextHolder by the controller (i.e. Spring Security’s
Filterss) that invoked the
If you are not integrating with Spring Security’s
Filterss you can set the
SecurityContextHolder directly and are not required to use an
While the implementation of
AuthenticationManager could be anything, the most common implementation is
ProviderManager is the most commonly used implementation of
ProviderManager delegates to a
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.
If none of the configured
AuthenticationProviders can authenticate, then authentication will fail with a
ProviderNotFoundException which is a special
AuthenticationException that indicates the
ProviderManager was not configured to support the type of
Authentication that was passed into it.
In practice each
AuthenticationProvider knows how to perform a specific type of authentication.
For example, one
AuthenticationProvider might be able to validate a username/password, while another might be able to authenticate a SAML assertion.
This allows each
AuthenticationProvider to do a very specific type of authentication, while supporting multiple types of authentication and only exposing a single
ProviderManager also allows configuring an optional parent
AuthenticationManager which is consulted in the event that no
AuthenticationProvider can perform authentication.
The parent can be any type of
AuthenticationManager, but it is often an instance of
In fact, multiple
ProviderManager instances might share the same parent
This is somewhat common in scenarios where there are multiple
SecurityFilterChain instances that have some authentication in common (the shared parent
AuthenticationManager), but also different authentication mechanisms (the different
ProviderManager will attempt to clear any sensitive credentials information from the
Authentication object which is returned by a successful authentication request.
This prevents information like passwords being retained longer than necessary in the
This may cause issues when you are using a cache of user objects, for example, to improve performance in a stateless application.
Authentication contains a reference to an object in the cache (such as a
UserDetails instance) and this has its credentials removed, then it will no longer be possible to authenticate against the cached value.
You need to take this into account if you are using a cache.
An obvious solution is to make a copy of the object first, either in the cache implementation or in the
AuthenticationProvider which creates the returned
Alternatively, you can disable the
eraseCredentialsAfterAuthentication property on
See the Javadoc for more information.
AuthenticationEntryPoint is used to send an HTTP response that requests credentials from a client.
Sometimes a client will proactively include credentials such as a username/password to request a resource. In these cases, Spring Security does not need to provide an HTTP response that requests credentials from the client since they are already included.
In other cases, a client will make an unauthenticated request to a resource that they are not authorized to access.
In this case, an implementation of
AuthenticationEntryPoint is used to request credentials from the client.
AuthenticationEntryPoint implementation might perform a redirect to a log in page, respond with an WWW-Authenticate header, etc.
AbstractAuthenticationProcessingFilter is used as a base
Filter for authenticating a user’s credentials.
Before the credentials can be authenticated, Spring Security typically requests the credentials using
AbstractAuthenticationProcessingFilter can authenticate any authentication requests that are submitted to it.
When the user submits their credentials, the
AbstractAuthenticationProcessingFilter creates an
Authentication from the
HttpServletRequest to be authenticated.
The type of
Authentication created depends on the subclass of
UsernamePasswordAuthenticationFilter creates a
UsernamePasswordAuthenticationToken from a username and password that are submitted in the
If authentication fails, then Failure
The SecurityContextHolder is cleared out.
RememberMeServices.loginFailis invoked. If remember me is not configured, this is a no-op.
If authentication is successful, then Success.
SessionAuthenticationStrategyis notified of a new log in.
RememberMeServices.loginSuccessis invoked. If remember me is not configured, this is a no-op.