Spring Security OAuth2

OAuth2 overview

1.1. Basic flow of OAuth2

Without further ado, above:

Analyze a wave:

  • Client: a third-party application (App or interface provided externally)
  • Resource Owner: The user who owns the Resource
  • Authentication Server: Provides Access tokens.
  • Resource Server: a Resource Server that stores user Resource information.

In fact, whether wechat or QQ are generally the basic process of using this OAuth2:

  1. Third-party applications request user authorization;
  2. The user agrees to authorize and returns an authorization code.
  3. The third-party application authorizes the authentication service based on the authorization code.
  4. The authorization server authenticates the application based on the authorization code and returns the Access Token to the third-party application.
  5. Third-party applications request related resources from resource services based on Access tokens.
  6. The resource server validates the Access Token and returns the requested resource to the third party.

1.2. Type of service

OAuth2 falls into two categories of service providers:

  • Authentication service: AuthenticationServer

@Configuration
@EnableAuthorizationServer
public class CustomAuthenticationServerConfig extends AuthorizationServerConfigurerAdapter 
Copy the code
  • Resource acquisition service: ResourceServer

@Configuration
@EnableResourceServer
public class CustomResourceServerConfig extends ResourceServerConfigurerAdapter
Copy the code

Note: The two may sometimes exist in the same application (i.e., SOA architecture). In Spring OAuth it is easy to distribute between two applications (i.e., microservices), and multiple resource retrieval services can share one authorization service.

1.3. Authorization service

Major operations:

  1. Obtain the authorization code and identifier of the third-party application
  2. Verification is performed according to the authorization code and identifier
  3. Pass the verification and send the Access Token.

Analyze a wave: 1) The first step operation:

  • Code: When a third-party application performs the first Authorization Request and requests the callback link in parameter redirect_URI, the service generates the relevant user credentials and adds the code to the callback link
  • Third Party User Id:
    • Client_id: id of a third-party user
    • Client_secret: A security certificate between a third-party application and an authorized server (interpreted as a password)

Note: Client_id and client_secret are both sent by the authorized server to third-party applications, such as wechat and a series of authorization. Register on its platform and obtain its AppID and secret in the same way (personally understood as account password).

Since it is a secret account, the total can not get request, also too insecure. Therefore, OAuth2 requires that the request must be a POST request and an HTTPS service to ensure the security of the Access Token obtained.

2) The second step:

  • The authentication server verifies the authenticity of third-party applications based on identifiers
  • The authentication server verifies user credentials based on the authorization code

3) Step 3 operation:

  • Generate Access tokens (MD5, UUID, JWT, etc.)

1.4. Resource acquisition service

Major operations:

  • Check the Access Token
  • Provisioning Resource Information

Spring Security OAuth2

1. Authentication service

In Spring OAuth2, we configure an authorization service. We have the following three main points:

  1. Third party user Client details → Client
  2. Token generation management → Access Token
  3. Endpoint access → endPoints

There are three configurations in Spring that correspond to this point:

  • ClientDetailsServiceConfigurer: used to configure the client details service.
  • AuthorizationServerSecurityConfigurer: used to configure the Token Endpoint (Token) the Endpoint security constraints.
  • AuthorizationServerEndpointsConfigurer: (authorization) to configure authorization and access token (token) endpoint and token service (token services)

1.1. Review of third-party users

In addition to the client_id and client_secret mentioned above, some services are required with some authorization parameters.

1).Grant Type

In fact, OAuth2 provides not only the authorization code format, but also several other types of authorization. Grant Type represents the current Grant Type. Grant Type includes:

  • Authorization_code: traditional authorization code mode
  • Implicit: indicates the implicit authorization mode
  • Password: indicates the password mode of the resource owner (user)
  • Client_credentials: Client credentials (client IDS and keys) mode
  • Refresh_token: used to refresh the new token mode when the access token is obtained

2).scope

In fact, authorization allows third-party users to fetch resources from the resource server, often by invoking the Api with a token. However, the fetched Api can add, delete, check, and run the scopes at all, read, and write. It is a permission for a third party to access resources.


3).accessTokenValiditySeconds

You can also set a accessTokenValiditySeconds attribute to set the Access Token survival time.

@Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient("catalpaFlat") .secret("catalpaFlat-secret") .accessTokenValiditySeconds(7200) .authorizedGrantTypes("refresh_token","password") .scopes("all"); }Copy the code

1.2. Token generation and management

The significance of AccessToken:

  • Create AccessToken and save it in case any subsequent access requests are authenticated and the resource is obtained
  • Another potential function of AccessToken is that when a token is generated using JWT, it can be used to load some information and include some relevant permissions in AccessToken

1). AuthorizationServerTokenServices AuthorizationServerTokenServices provides the AccessToken create, refresh, obtain related operations.

public interface AuthorizationServerTokenServices {

	OAuth2AccessToken createAccessToken(OAuth2Authentication authentication) throws AuthenticationException;

	
	OAuth2AccessToken refreshAccessToken(String refreshToken, TokenRequest tokenRequest)
			throws AuthenticationException;

	
	OAuth2AccessToken getAccessToken(OAuth2Authentication authentication);

}
Copy the code

2).DefaultTokenServices

AuthorizationServerTokenServices can operate AccessToken, OAuth2 default DefaultTokenServices provides us with a default. Some useful implementations are included that can be used to modify token formatting, token storage, etc., but the tokens generated are random numbers.

3).TokenStore

Once you create AccessToken, in addition to giving it away to third parties, you definitely have to save it before you can use it. So TokenStore does this for us, saving or persisting tokens. TokenStore also has a default implementation class, InMemoryTokenStore, which, as its name suggests, implements saving Access tokens to memory. There are many types of TokenStore implementations, and the retention type of Access Tokens can be changed based on business requirements:

  • InMemoryTokenStore: This is the default implementation of OAuth2. This works well on a single service (that is, the concurrency is small and it does not take a backup in the event of a failure) and can be used on most projects. After all, it’s in memory, not disk, and easy to debug.
  • JdbcTokenStore: This is a JDBC-based implementation where Access tokens are saved to the database. In this way, token sharing can be implemented between multiple services.
  • JwtTokenStore: JWT Full JSON Web Token. This implementation does not matter how the storage is done (in memory or on disk) because it encodes the relevant information data in the token. JwtTokenStore does not hold any data, but it plays the same role as DefaultTokenServices in converting token values and authorization information. But there are two drawbacks:
    • Revoking an authorized token can be difficult, so it is only appropriate for dealing with a short lifetime and revoking a refresh token.
    • The token occupies a large space. If too much user credential information is added, there will be transmission redundancy

4).JWT Token

To use JWT tokens, you need to configure JwtTokenStore in the authorization service. As mentioned earlier, JWT encodes some information data and stores it in the token, which is not secure during transmission, so Spring OAuth2 provides JwtAccessTokenConverter to encode and decode the token. JWTS Access Converter allows you to customize the signature key. SigningKey is used in the authorization server to generate signature encoding, in the resource acquisition server according to the SigningKey decoding verification.

JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();

 jwtAccessTokenConverter.setSigningKey("CatalpaFlat")
Copy the code

1.3. Endpoint access – EndPoints

Authorization is the use of AuthorizationEndpoint this endpoint to control, general use AuthorizationServerEndpointsConfigurer for configuration.

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {}
Copy the code

1). Configuration of related attributes of endpoints:

  • AuthenticationManager: indicates the authenticationManager. If our Grant Type above was set to password, we would need to set an AuthenticationManager object
  • UserDetailsService: If we implement userDetailsService to manage user information, we should set our userDetailsService object
  • AuthorizationCodeServices: authorization code service. If we Grant Type set to authorization_code above, you can set a AuthorizationCodeServices object
  • TokenStore: This is what we said above, set the Access Token type we want to implement
  • AccessTokenConverter: Access Token encoder. Namely JwtAccessTokenConverter
  • TokenEnhancer: Extension of token. When using JWT, TokenEnhancer can be implemented to extend JWT to contain information
  • TokenGranter: When the default Grant Type is no longer sufficient for our business logic, implementing the tokenGranter interface will allow us to control authorization and ignore several Grant Type attributes.

2). Authorized URL of endpoints: To authorize authentication, it must be requested by URL before transmission. So OAuth2 provides the URL to configure the authorization endpoint. AuthorizationServerEndpointsConfigurer, or this configuration object is configured, which consists of a pathMapping () method to configure authorization endpoint URL path, the default defaultPath and customPath provides two parameters:

public AuthorizationServerEndpointsConfigurer pathMapping(String defaultPath, String customPath) {
		this.patternMap.put(defaultPath, customPath);
		return this;
}
Copy the code

The defaultPath of pathMapping is as follows:

  • /oauth/authorize: Authorize endpoints
  • /oauth/token: token endpoint
  • /oauth/confirm_access: User confirms authorization submission endpoint
  • /oauth/error: authorization service error message endpoint
  • /oauth/check_token: token resolution endpoint for resource service access
  • /oauth/token_key: Provides the endpoint of the public key, if the JWT token is used

Note: Both parameters to pathMapping will be strings starting with a “/” character

1.4. Custom Error Handling

In fact, the endpoints we mentioned above can be thought of as controllers, which are used to return the response content of the different endpoints.

Authorized service error information is handled by use the standard Spring MVC, namely @ ExceptionHandler annotations endpoint method, we can provide a WebResponseExceptionTranslator object. The best way to do this is to change the content of the response rather than rendering it directly.

  • If an exception occurs while rendering a token endpoint, the exception delegates an HttpMessageConverters object (which can be added to the MVC configuration) to output.
  • If the authorization endpoint is not authenticated when rendered, it is redirected to /oauth/error, the error message endpoint. Whitelabel Error (a default error page provided by the Spring framework) the error endpoint provides an HTML response, But we probably need to implement a custom error page (for example simply adding @Controller mapping to the request path @requestMapping (“/oauth/error”)).

2. Obtain resources

Resource server, in fact, is to store some token-protected resources, only the token is valid and correct to obtain resources. Internally, it is protected by the Spring Security Authentication filter chain of Spring OAuth2.

2.1. ResourceServerConfigurerAdapter

We can inherit ResourceServerConfigurerAdapter, to use ResourceServerSecurityConfigurer related configuration.

public class ResourceServerConfigurerAdapter implements ResourceServerConfigurer { @Override public void configure(ResourceServerSecurityConfigurer resources) throws Exception { } @Override public void configure(HttpSecurity http) throws Exception { http.authorizeRequests().anyRequest().authenticated(); }}Copy the code

2.2. ResourceServerSecurityConfigurer related properties

  • TokenServices: ResourceServerTokenServices instances of the class, which is used to realize the token service.
  • ResourceId: The ID of the resource service. This property is optional, but recommended and validated in the authorized service.
  • TokenExtractor tokenExtractor is used to extract tokens in requests.
  • The request matcher sets the path of the resource to be protected. By default, this is the entire path of the protected resource service.
  • Access rules for protected resources. The default rule is Plain Authenticated.
  • Other custom permission protection rules are configured using HttpSecurity.

2.3. ResourceServerTokenServices

ResourceServerTokenServices is composed of authorized service partner.

1). If the resource server and authorization service are in the same application, DefaultTokenServices can be used

2). If separated. ResourceServerTokenServices must know how to decode the token.

The method of ResourceServerTokenServices parsed token:

  • With RemoteTokenServices, the resource server decodes the token through HTTP requests. The endpoint of the authorization server -/oauth/check_toke is requested each time to decode the token
  • If there is a lot of traffic, the result will be obtained through HTTP and replaced with a token
  • For JWT tokens, request /oauth/token_key of the authorization service to obtain the key for decoding

Note: The authorization service needs to expose /oauth/check_toke with permission access.

@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
    oauthServer.tokenKeyAccess("isAnonymous() || hasAuthority('ROLE_TRUSTED_CLIENT')")
        .checkTokenAccess("hasAuthority('ROLE_TRUSTED_CLIENT')");
}
Copy the code

(~ ~ ▽ ~) ~ to be continued… .