Introduction :#
In a Spring Boot application, SecurityFilterAutoConfiguration automatically registers the DelegatingFilterProxy filter as springSecurityFilterChain. When a request reaches this filter, it delegates processing to the FilterChainProxy bean, which utilizes the SecurityFilterChain to execute a sequence of security filters. These filters are part of the core Spring Security components that manage authentication, authorization, and overall security within the application.
Core Spring Security Components:#
Core Spring Security components are used throughout a Spring Boot application to manage authentication, authorization, and overall security. Here’s where and how these components are typically used:
- UserDetails
- The UserDetails interface represents a user in the Spring Security framework. It provides methods to get user information such as username, password, and authorities.
- Purpose: To encapsulate user information, including authentication and authorization details.
- Implementation: You can use it to extend your User Entity.
- UserDetailsService
- The UserDetailsService interface is a core component in Spring Security that is used to retrieve user-related data. It has a single method: loadUserByUsername.
- Purpose: To fetch user details from a datasource (e.g., database) based on the username.
- Implementation: You typically implement this interface to load user details, such as username, password, and roles, from your own user repository.
- InMemoryUserDetailsManager
- The InMemoryUserDetailsManager is a Spring Security provided implementation of UserDetailsService that stores user information in memory.
- Purpose: To store user details in memory, typically for testing or small applications. You define users directly in the configuration.
- PasswordEncoder
- The PasswordEncoder interface is used for encoding and validating passwords. It has methods for encoding raw passwords and matching encoded passwords.
- Purpose: To securely hash passwords before storing them and to verify hashed passwords during authentication.
- Common Implementations:
• BCryptPasswordEncoder
• Pbkdf2PasswordEncoder
• SCryptPasswordEncoder
Internal Working Flow of Spring Security:#
This screenshot provides a flow of how authentication is handled in Spring Security:
This screenshot depicts the general flow of how authentication is handled in Spring Security, starting from the HTTP request and moving through various components like the Security Filters Chain, AuthenticationManager, and finally storing the authenticated user in the SecurityContext.
Let’s talking about in details:
- HTTP Request:
- An incoming HTTP request is received.
- An incoming HTTP request is received.
- Security Filters Chain:
- The request passes through a chain of security filters, such as:
WebAsyncManagerIntegrationFilter
SecurityContextPersistenceFilter
HeaderWriterFilter
LogoutFilter
UsernamePasswordAuthenticationFilter
- ...and others.
- The request passes through a chain of security filters, such as:
- AuthenticationManager:
- The request's authentication responsibility is delegated to the
AuthenticationManager
. TheAuthenticationManager
is the central component that delegates authentication to variousAuthenticationProvider
s.
- The request's authentication responsibility is delegated to the
- AuthenticationProvider:
- The
AuthenticationManager
uses one or moreAuthenticationProvider
s to authenticate the request. DifferentAuthenticationProvider
s are used depending on the type of authentication required (e.g.,DaoAuthenticationProvider
,InMemoryAuthenticationProvider
,OAuth2AuthenticationProvider
, etc.).
- The
- Return Authenticated User:
- If the authentication is successful, the authenticated user is returned to the
AuthenticationManager
.
- If the authentication is successful, the authenticated user is returned to the
- SecurityContext:
- The authenticated user is then set into the
SecurityContext
, which is stored in theSecurityContextHolder
. TheSecurityContext
is now accessible throughout the application and is used to retrieve the authenticated user's details.
- The authenticated user is then set into the
- Dispatcher Servlet and Controllers:
- Finally, the authenticated user is passed to the Dispatcher Servlet, which handles the request with the appropriate controllers.
- Finally, the authenticated user is passed to the Dispatcher Servlet, which handles the request with the appropriate controllers.
Zoomed in Flow:#
This flow provides a more detailed breakdown of the components involved in the authentication process:
Here, all the Rectangle boxes are the implementations by Spring Security and the dark boxes are that what I am going to implement.
Pill boxes are interfaces.
This screenshot gives a more detailed look into the specific components involved in the authentication process, such as AuthenticationManager, AuthenticationProvider, UserDetailsService, UserDetails, and PasswordEncoder, showing how they interact to authenticate a user. Let’s see:
- Client /login:
- The process begins when a client submits a login request.
- The process begins when a client submits a login request.
- AuthenticationManager:
- The
AuthenticationManager
is responsible for authenticating the login request. It delegates this responsibility to aProviderManager
. Inside thisAuthenticationManager
we have a method that is calledauthenticate()
and this method will take an object ofAuthentication
(Authentication obj
). So, we will create anAuthentication Object
inside our controller only. That will contain our user information for example login, email and password.
Basically, thisAuthenticationManager
is given the task to authenticate the login request. - If you go to the implementations part (5 implementations) of this interface you can see there is a class named ProviderManager .
- The
- ProviderManager:
- The
ProviderManager
holds a list ofAuthenticationProvider
s and loops through each one until authentication is successful or all have been tried. - This ProviderManager will implement authenticate() method.
- If you go to this method you can see, this takes the providers iterator so, it goes to the each providers using the while loop. In this loop, you can see the AuthenticationProvider .
- If you go to this particular AuthenticationProvider you will see that this AuthenticationProvider is an interface. Each AuthenticationProvider will implement this two methods authenticate() and supports() .
- If you go to the implementations of this interface, you can see all of the implementing classes. Most of the important classes are DaoAuthenticationProvider and OidcAuthenticationRequestChecker .
Here we talking about the DaoAuthenticationProvider class. The DaoAuthenticationProvider is commonly used to authenticate users from a database.
- The
- DaoAuthenticationProvider:
- One of the
AuthenticationProvider
s in Spring Security isDaoAuthenticationProvider
. - This provider is useful when you want to authenticate users using their email as the "username" and their password.
DaoAuthenticationProvider
works by using aUserDetailsService
to load user details, typically from a database or any other data source, to verify the credentials. - The
UserDetailsService
loads the user’s information and returns aUserDetails
object, which includes the username, password, and authorities (roles or permissions). - After retrieving the user details, the
DaoAuthenticationProvider
compares the password provided by the user during login with the stored (encoded) password from theUserDetails
object. - This comparison is done using a
PasswordEncoder
, likeBCryptPasswordEncoder
, to ensure that the password is securely checked. - If the password matches, the user is successfully authenticated, and the authentication information is stored in the
SecurityContext
, allowing access to the application. - If the password doesn’t match, an authentication exception is thrown, and the user is denied access.
- One of the
- UserDetailsService:
TheUserDetailsService
is an interface that defines the methodloadUserByUsername(String username)
, which is used to retrieve user details for authentication.
- If it is a
InMemoryUserDetailsManager
class then it will get the source from the inmemory. Same forMyUserDetailsServiceImpl
class.
- Example:
We're setting up an InMemoryUserDetailsManager with a user named "user" and a password "password". The password is made secure using a special encoding method called BCryptPasswordEncoder. When someone tries to log in with the username "user", the system checks this in-memory list to find and verify the user's details.
- UserDetails:
- The
UserDetails
interface represents the user retrieved by theUserDetailsService
. It includes methods likegetUsername()
,getPassword()
, andgetAuthorities()
to provide the necessary information for authentication.
- The
- PasswordEncoder:
- The
PasswordEncoder
(likeBCryptPasswordEncoder
) is used to encode or match passwords. It ensures that the password provided by the user matches the encoded password stored in the database. ThisPasswordEncoder
is also an interface. - That contains two methods (
encode()
is used when a user signs up to create a secure version of their password andmatches()
is used during login to check if the provided password matches the stored secure version).
- The
- UserEntity:
- The
UserDetails
is often implemented by aUser
entity class in your application, representing a user record in your database.
- The