Understanding Spring Security Authentication Flow
Spring Security is a powerful framework which can be used to secure Spring applications. It focuses on both authentication and authorization. It can be configured and customized to meet own demands. In this article we’ll be discussing different components which are used in authentication. It is very beneficial to have a good grasp of these concepts before moving on to actual implementation and customizations.
Without Spring Security
When we are not using Spring Security, the request is intercepted by the DispatcherServlet. The DispatcherServlet is the front controller which intercepts any HTTP Request and forwards it to the right controller. Spring Boot automatically configures the DispatcherServlet.
How DispatcherServlet works?
Before moving to Spring Security, lets understand how DispatcherServlet dispatches the requests. When we make a request at an endpoint (say /helloworld), how the front controller (DispatcherServlet) would handle it?
DispatcherServlet creates an IOC container. The IOC container is a central component of the Spring Framework that manages the creation and dependencies of beans. The DispatcherServlet creates a WebApplicationContext, which is a specialized IOC container that is used for web applications. The WebApplicationContext is configured by the DispatcherServlet based on the configuration files.
The IOC container creates an instance of the controller beans. The DispatcherServlet will use the IOC container to lookup the controller bean and to delegate requests to it.
With Spring Security
When Spring Security is added to the Spring Boot Application, all the request is intercepted by the Spring Security mechanism before it reaches DispatcherServlet and controller.
Whenever a request arrives at the application, it is first intercepted by a chain of filters called Filter Chain. Other than the filters provided by Spring Security, we can add our own custom filters. The FilterChain after authentication, forwards the request to the DisptacherServlet.
Authentication Flow: Steps
Although Spring Security can be used with different types of authentication methods, we are going to discuss Username and Password authentication to understand the complete flow.
- Filter Chain intercepts incoming request before forwarding it to the Dispatcher Servlet.
- Request goes to the authentication filters (one such filter is UsernamePasswordAuthenticationFilter).
- The filter extracts the username and password from the request (HttpServletRequest object).
- Next, a UsernamePasswordAuthenticationToken is created with the credentials.
- The AuthenticationManager authenticate() method is invoked.
- The AuthenticationManager authenticate() method implementation will then try to authenticate using one of the AuthenticationProvider it has.
- If one of the authentication providers is able to authenticate successfully, it returns a complete UsernamePasswordAuthenticationToken holding the credentials and authorities.
- This token which is returned from the provider is used to set the user as authenticated in the Spring Security Context.
- Once, the user is authenticated, the request is then forwarded to the DispatcherServlet which handles the request.
Different components of Authentication flow
Let’s understand the different components which were discussed in the previous section.
What are Filters?
A Spring Filter is a component which can intercept any incoming request and perform some operations before it is passed to the DispatcherServlet. A filter can process the request and then forward it to the next filter in the Filter Chain, or can stop and send back an HTTP Response. One such filter is the UsernamePasswordAuthenticationFilter which is present in the FilterChain. This filter tries to find the username and password passed in the HTTP Post request and if found, tries to authenticate the user with the credentials. Here is a snapshot of the authentication method present in this class.
We can create our own Filter and add it in the SecurityFilterChain to provide our own logic to handle the request.
What is AuthenticationManager?
The AuthenticationManager is an interface which processes the Authentication request. It has an authenticate() method which takes Authentication object as a parameter.
Authentication authenticate(Authentication authentication) throws AuthenticationException;
The implementation class of AuthenticationManager is the ProviderManager class which provides the logic for authenticate() method. We can provide our own implementation class of AuthenticationProvider or can use the default implementation.
What is ProviderManager?
This class implements the AuthenticationManager interface and overrides the authenticate() method. It uses a list of AuthenticationProviders to authenticate the sent credentials in the Authentication object. If one of the AuthenticationProvider supports the type of authentication, it will be used to authenticate the user. If none of the providers support the authentication type, an AuthenticationException will be thrown.
The supports() method of each authentication provider is used to check if it can support the desired kind of authentication.
What is AuthenticationProvider?
AuthenticationProvider is an interface that defines the contract for authenticating users. It is responsible for taking an Authentication object, which represents the user’s credentials, and returning an authenticated Authentication object if the credentials are valid. If the credentials are invalid, the AuthenticationProvider should throw an AuthenticationException.
The AuthenticationProvider interface has two methods:
- authenticate() : This method takes an Authentication object as input and returns an authenticated Authentication object if the credentials are valid. If the credentials are invalid, the AuthenticationProvider should throw an AuthenticationException.
- supports() : This method takes an Authentication object as input and returns true if the AuthenticationProvider can authenticate the object. If the AuthenticationProvider cannot authenticate the object, it should return false .
The default AuthenticationProvider in Spring Security is the DaoAuthenticationProvider. This provider uses a UserDetailsService to load the user's details from a database. If the user's credentials match the details in the database, the DaoAuthenticationProvider will return an authenticated Authentication object.
We can add our own implementations of AuthenticationProvider to provide different authentication methods.
Authentication and UsernamePasswordAuthenticationToken
What exactly is Authentication and UsernamePasswordAuthenticationToken?
- Authentication
It is an interface in Spring Security which represents token for incoming authentication request or an authenticated Principal (an interface which represents an entity like an individual) AuthenticationManager.authenticate() method.
Some methods provided are-
Collection<? extends GrantedAuthority> getAuthorities();
Object getCredentials();
boolean isAuthenticated();
void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
2. UsernamePasswordAuthenticationToken
This class extends the AbstractAuthenticationToken class (base class of authentication objects) and can be used with Username/Password authentication requests.
This class has two constructors-
public UsernamePasswordAuthenticationToken(Object principal, Object credentials) {
super((Collection)null);
this.principal = principal;
this.credentials = credentials;
this.setAuthenticated(false);
}
public UsernamePasswordAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
super(authorities);
this.principal = principal;
this.credentials = credentials;
super.setAuthenticated(true);
}
The first constructor can be used for incoming requests to create unauthenticated Authentication object.
Authentication authentication = new UsernamePasswordAuthenticationToken(username,password);
The second constructor can be used to create a fully authenticated Authentication object.
Authentication authToken = new UsernamePasswordAuthenticationToken(username, password, userAuthorities);
This fully authenticated Authentication object is then returned from AuthenticationProvider/AuthenticationManager and represents an authenticated user. This authenticated object is then set in the SecurityContext. The SecurityContext in Spring Security is a representation of the security context of the current thread of execution. It contains information about the currently authenticated user, such as their username, authorities, and session information.
Conclusion
This article provides a brief description of authentication flow and different components which are needed to set up authentication. Anyone who wants to use Spring Security must have a clear understanding of these concepts before moving to more customizations and implementation.
In future articles, we will explore Spring Security in more depth and show how to configure its components to meet specific needs.