[JAVA] Learn Spring Security authentication processing architecture

Spring Security is an image that works for some reason, but I'm addicted to trying to customize it, so I investigated and summarized it from the idea that if you know the architecture, you will be able to understand it somehow.

Investigate what kind of class plays what kind of role according to the following form authentication scenario.

  1. Access a page that requires authentication without being authenticated
  2. Redirected to the login screen
  3. Enter the information and execute the login process
  4. Login is complete and you are redirected to the screen you were accessing in 1.

The version is confirmed in 5.2.1.RELEASE.

Until you are redirected to the login screen

How to jump to the login screen when an unauthenticated user accesses a page that requires authentication. The rough flow is as follows. This time, I will not explain the check process when accessing, but it will start from the place where ʻAuthenticationException` is thrown.

ログイン遷移.png

ExceptionTranslationFilter

Cause of the exception that occurred Check the exception, and if ʻAuthenticationException is included, start the authentication process using ʻAuthenticationEntryPoint while saving the contents of the request in RequestCache. RequestCache usually uses HttpSession to store the request contents. HttpSessionRequestCache is used. We will see what RequestCache is used for later.

AuthenticationEntryPoint

Start the authentication process. For example, LoginUrlAuthenticationEntryPoint redirects to the URL of the configured login page. BasicAuthenticationEntryPoint returns a response with a status code of 401 and a header with WWW-Authenticate to initiate Basic authentication.

Login screen transition summary

It is handled by ʻExceptionTranslationFilter, but it doesn't need to be conscious because it is not customized very much. It is necessary to properly select and set ʻAuthenticationEntryPoint as to how to start authentication. For example, if you want to transition to the login screen, you need to set the URL of the login screen using LoginUrlAuthenticationEntryPoint, and if you do not need to start the authentication process on the assumption that you will be authenticated in advance like SSO. For example, use Http403ForbiddenEntryPoint.

It seems that you can also define the implementation class to be used for the request by using DelegatingAuthenticationEntryPoint.

Authentication process

First of all, the flow until the information entered by the user is received and the authentication is OK. It is roughly as follows.

認証.png

AuthenticationManager

Authentication is managed by ʻAuthenticationManager. Receives the ʻAuthentication object and returns the ʻAuthentication object if authentication is OK. The argument ʻAuthentication contains only the principal and credentials required for authentication, and the return value ʻAuthentication` also contains information such as authorities and details.

ProviderManager

ʻThere is ProviderManager as an implementation class of AuthenticationManager. This class is used by default. This class delegates the authentication process to multiple ʻAuthenticationProvider, and if even one authentication is OK, the authentication is successful. By doing so, it is possible to combine a plurality of authentication processes such as Form authentication using information stored in a database and authentication by LDAP. You can also remove credentials from the return value ʻAuthentication` to prevent sensitive information from being persisted.

AuthenticationProvider

Authenticate. If password verification is required, use this class.

There is also a method to determine if it is an authenticateable implementation class of ʻAuthentication. For example, in the case of normal Form authentication, the authentication process can be performed with a user name and password, but not all authentication processes are sufficient. Therefore, the supports (Class <?> Authentication)` method is used to determine whether the authentication process can be performed.

Implementation classes are provided for general authentication methods, so basically you can use them. However, since the part that acquires user information depends on the definition of the database used by the application, there are many patterns in which only that part is implemented.

UserDetailsService

An interface for processing the above-mentioned part related to the acquisition of user information. It is often used by creating an implementation class of this interface and setting it to ʻAuthenticationProvider`.

The information to be acquired must be a class that implements ʻUserDetails`.

An implementation class called JdbcDaoImpl is also provided, but since the information that can be obtained is limited, I think that I will implement it myself.

Call authentication process

Basically it is called by Filter. For example, when performing Form authentication, ʻUsernamePasswordAuthenticationFilter is called. This Filter creates an ʻUsernamePasswordAuthenticationToken object, which is an implementation class of ʻAuthenticaion, from the input information from the user, and calls the authentication process of ʻAuthenticationManager. If the authentication is successful, the task is to set the acquired authentication information in SecurityContextHolder. (See below for SecurityContextHolder)

Authentication process Summary so far

ʻIt is unlikely that you will implement AuthenticationManager. It seems that you should use the default implementation class ProviderManager. ʻAuthenticationProvider seems to provide the desired implementation class, so select it appropriately. However, if you want to create a new authentication method such as WebAuthn that Spring Security does not yet support, you will need to implement it. The same applies to Filter.

In many cases, the implementation class of ʻUserDetailsService` that acquires user information is created by yourself.

Persistence of credentials

By perpetuating the authentication information obtained after the authentication is completed, it becomes possible to determine whether or not the authentication has been completed, and the user information can also be accessed.

永続化.png

SecurityContext

An object that holds authentication information (ʻAuthentication). Instead of persisting the credentials as is, persist this SecurityContext`.

SecurityContextRepository

An interface for making SecurityContext persistent. You may think of HttpSession as a place to persist authentication information, but Spring Security also provides HttpSessionSecurityContextRepository, which is an implementation class that uses HttpSession. (Use it by default)

SecurityContextHolder

The class that holds the SecurityContext. By default, it is retained using ThreadLocal. If you want to access the credentials, you can retrieve them from this SecurityContextHolder instead of accessing the HttpSession directly.

SecurityContextPersistenceFilter

Get SecurityContext from SecurityContextRepository and set it to SecurityContextHolder before any process starts. After all the processing is done, get SecurityContext from SecurityContextHolder, make it persistent using SecurityContextRepository, and delete SecurityContext from SecurityContextHolder. SecurityContextHolder uses ThreadLocal, but this Filter handles the deletion process.

Persistence summary

The authentication information is persisted as SecurityContext, and the processing related to persistence is performed by SecurityContextRepository, but you do not need to be aware of it. It's good to remember that you can get the SecurityContext from the SecurityContextHolder.

Behavior after successful or unsuccessful authentication

Some Filters that call the authentication process can define the behavior when authentication succeeds or fails. For example, it can be defined in ʻUsernamePasswordAuthenticationFilterthat performs Form authentication, but not inBasicAuthenticationFilter` that performs Basic authentication.

AuthenticationSuccessHandler

認証成功.png

Define the process when authentication is successful. Some implementation classes are provided, but SavedRequestAwareAuthenticationSuccessHandler is used by default. This class redirects the request if it is held in RequestCache. If it is not retained, redirect to the default URL set.

Access the page that requires authentication in the unauthenticated state and be redirected to the authentication screen. After that, when authentication is completed, you can move to the screen you were trying to display first because you are using this class.

AuthenticationFailureHandler

認証失敗.png

Define the processing when authentication fails. There are also some implementation classes provided, but SimpleUrlAuthenticationFailuerHandler is used by default. This class is pretty simple and redirects to the specified URL. Also, by storing the exception that occurred when authentication failed in HttpSession, it is possible to refer to it at the redirect destination.

Summary of operations after successful and unsuccessful authentication

Use ʻAuthenticationSuccessHandler and ʻAuthenticationFailuerHandler, respectively, to define the behavior after successful and unsuccessful authentication. The provided implementation class only redirects to the specified URL (forward depending on the setting), so if you want to do advanced things, you need to create an implementation class. Also, note that it may not be possible to set depending on the authentication method.

Log out

Also log out. ログアウト.png

LogoutFilter

After calling LogoutHandler which performs logout processing, callLogoutSuccessHandler which performs post-processing. You can define the URL to log out. (Default is / logout)

LogoutHandler

Log out processing. SecurityContextLogoutHandler discards HttpSession. Or is it a premise that the authentication information is stored in HttpSession? I don't think it is stored in HttpSession depending on the implementation of SecurityContextRepository. But there is no method for deleting. Hmm ...

Note that LogoutFilter uses a class called CompositeLogoutHandler that combines multiple LogoutHanlders, so multipleLogoutHandlers can be executed in sequence as needed.

LogoutSuccessHandler

Performs processing after logout is completed. SimpleUrlLogoutSuccessHandler redirects to the specified URL.

Logout summary

If you want to customize the logout process, implement LogoutHandler and set it to LogoutFilter. If you want to customize the screen transition after logout is completed, implement LogoutSuccessHandler and set it to LogoutFilter.

Reference URL

at the end

I feel like I've come to understand Spring Security! (Because of my mind)

Recommended Posts

Learn Spring Security authentication processing architecture
About Spring Security authentication
Spring Security usage memo Authentication / authorization
Implemented authentication function with Spring Security ②
Implemented authentication function with Spring Security ③
Spring Boot Tutorial Using Spring Security Authentication
Implemented authentication function with Spring Security ①
Authentication / authorization with Spring Security & Thymeleaf
Set Spring Security authentication result to JSON
DB authentication with Spring Security & hashing with BCrypt
Achieve BASIC authentication with Spring Boot + Spring Security
Try LDAP authentication with Spring Security (Spring Boot) + OpenLDAP
[Java / Spring Boot] Spring security ⑤ --Implementation of logout processing
Add your own authentication items with Spring Security
[Introduction to Spring Boot] Authentication function with Spring Security
Execute arbitrary processing after Basic authentication with Spring boot.
Spring Security causes 403 forbidden
Create API key authentication for Web API in Spring Security
Spring Security usage memo CSRF
Spring Security usage memo Run-As
Spring with Kotorin --6 Asynchronous processing
Spring Security Usage memo Method security
Spring Security usage memo Remember-Me
Login function with Spring Security
[Spring Security] Spring Security on GAE (SE)
Try using Spring Boot Security
Spring Security usage memo CORS
Spring Security usage memo test
I get a 404 error when testing forms authentication with Spring Security