Authentication
One of the fundamental ways to secure a resource is to make sure that the caller is who they claim to be. This process of checking credentials and making sure that they are genuine is called authentication.
The following diagram shows the fundamental process Spring Security uses to address this core security requirement. The figure is generic and can be used to explain all the various authentication methods that the framework supports:
As detailed in Chapter 1, Overview of Spring 5 and Spring Security 5 (in the Working of Spring Security section), Spring Security has a series of servlet filters (a filter chain). When a request reaches the server, it is intercepted by this series of filters (Step 1 in the preceding diagram).
In the reactive world (with the new Spring WebFlux web application framework), filters are written quite differently than traditional filters (such as those used in the Spring MVC web application framework). Having said that, the fundamental mechanism remains the same for both. We have a dedicated chapter explaining how to convert a Spring Security application to Spring MVC and Spring WebFlux where we will cover these aspects in a bit more detail.
The Servlet filter code execution in the filter chain keeps skipping until the right filter is reached. Once it reaches the right authentication filter based on the authentication mechanism used, it extracts the supplied credentials (most commonly a username and password) from the caller. Using the supplied values (here, we have a username and password), the filter (UsernamePasswordAuthenticationFilter) creates an Authentication object (in the preceding diagram, UsernamePasswordAuthenticationToken is created using the username and password supplied in Step 2). The Authentication object created in Step 2 is then used to call the authenticate method in theAuthenticationManager interface:
public interface AuthenticationManager {
Authentication authenticate(Authentication authentication)
throws AuthenticationException;
}
The actual implementation is provided by ProviderManager, which has a list of configured AuthenticationProvider.
public interface AuthenticationProvider {
Authentication authenticate(Authentication authentication)
throws AuthenticationException;
boolean supports(Class<?> authentication);
}
The request passes through various providers and, in due course, tries to authenticate the request. There are a number of AuthenticationProvider as part of Spring Security.
In the diagram at the start of the chapter, AuthenticationProvider requires user details (some providers require this, but some don't), which are provided in UserDetailsService:
public interface UserDetailsService {
UserDetails loadUserByUsername(String username) throws
UsernameNotFoundException;
}
UserDetailsService retrieves UserDetails (and implements the User interface) using the supplied username.
If all goes well, Spring Security creates a fully populated Authentication object (authenticate: true, granted authority list and username), which will contain various necessary details. The Authentication object is stored in the SecurityContext object by the filter for future use.
The authenticate method in AuthenticationManager can return the following:
- An Authentication object with authenticated=true, if Spring Security can validate the supplied user credentials
- An AuthenticationException, if Spring Security finds that the supplied user credentials are invalid
- null, if Spring Security cannot decide whether it is true or false (confused state)