sequence

The previous article described the Client Credentials mode of Spring Security OAuth2, which is generally used in user-independent, open platform API authentication related authorization scenarios. This article focuses on one of the user-related authorization modes: password mode.

Review the four models

OAuth 2.0 defines four types of authorization.

  • Authorization Code
  • Simplified patterns (Implicit)
  • Password mode (Resource owner Password Credentials)
  • The Client credentials (It is mainly used for API authentication and has nothing to do with the user)

maven

        <dependency>
			<groupId>org.springframework.security.oauth</groupId>
			<artifactId>spring-security-oauth2</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>
Copy the code

configuration

security config

To support password mode, you need to configure AuthenticationManager

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfig extends WebSecurityConfigurerAdapter {/ / need to run normally, need to cancel this comment, // @override // public void configure(HttpSecurity HTTP) throws Exception {// http.csrf().disable(); // http.requestMatchers().antMatchers("/oauth/**")
//                .and()
//                .authorizeRequests()
//                .antMatchers("/oauth/**").authenticated(); } @bean@override protected UserDetailsServiceuserDetailsService(){
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withUsername("demoUser1").password("123456").authorities("USER").build());
        manager.createUser(User.withUsername("demoUser2").password("123456").authorities("USER").build());
        returnmanager; } /** ** support password granttype
     * @return
     * @throws Exception
     */
    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        returnsuper.authenticationManagerBean(); }}Copy the code

This is a new configuration over the Client Credentials mode, which configures the user as well as the authenticationManager

Auth server configuration

@Configuration @EnableAuthorizationServer / / / request/the authorize/request/token, / request/check_token, / request/confirm_access, / request/error public class OAuth2ServerConfig extends AuthorizationServerConfigurerAdapter { @Override public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception { oauthServer .tokenKeyAccess("permitAll()") //url:/oauth/token_key,exposes public key for token verification if using JWT tokens
                .checkTokenAccess("isAuthenticated()") //url:/oauth/check_token allow check token .allowFormAuthenticationForClients(); } /** * inject authenticationManager * to support password granttype
     */
    @Autowired
    private AuthenticationManager authenticationManager;

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager);
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                .withClient("demoApp")
                .secret("demoAppSecret")
                .authorizedGrantTypes("client_credentials"."password"."refresh_token")
                .scopes("all")
                .resourceIds("oauth2-resource")
                .accessTokenValiditySeconds(1200)
                .refreshTokenValiditySeconds(50000);
}
Copy the code

Remember to inject authenticationManager here to support password mode

Otherwise, an error is reported as follows

➜ ~ curl-i-x POST-d "username=demoUser1&password=123456&grant_type=password&client_id=demoApp&client_secret=demoAppSecret"http://localhost:8080/oauth/token HTTP / 1.1 400 X - the content-type - Options: nosniff X - XSS - Protection: 1; mode=block Cache-Control: no-cache, no-store, max-age=0, must-revalidate Pragma: no-cache Expires: 0 X-Frame-Options: DENY X-Application-Context: application Cache-Control: no-store Pragma: no-cache Content-Type: application/json; charset=UTF-8 Transfer-Encoding: chunked Date: Sun, 03 Dec 2017 07:01:27 GMT Connection: close {"error":"unsupported_grant_type"."error_description":"Unsupported grant type: password"}
Copy the code

The resource server configuration

@Configuration @EnableResourceServer public class ResourceServerConfig extends ResourceServerConfigurerAdapter { // /** // * To run properly, uncomment this section, See below specific reason analysis / / * this set need token authentication url / / * these screening in WebSecurityConfigurerAdapter off / / * Otherwise enter WebSecurityConfigurerAdapter priority, is the basic auth or forms authentication, rather than token authentication HTTP / / / / * @ param * @ throws the Exception / / * / / / @Override // public void configure(HttpSecurity http) throws Exception { // http.requestMatchers().antMatchers("/api/**")
//                .and()
//                .authorizeRequests()
//                .antMatchers("/api/**").authenticated(); / /}}Copy the code

validation

The request token

curl -i -X POST -d "username=demoUser1&password=123456&grant_type=password&client_id=demoApp&client_secret=demoAppSecret" http://localhost:8080/oauth/token
Copy the code

return

HTTP/1.1 200 X-Content-type-options: nosniffing X-xss-protection: 1; mode=block Cache-Control: no-cache, no-store, max-age=0, must-revalidate Pragma: no-cache Expires: 0 X-Frame-Options: DENY X-Application-Context: application Cache-Control: no-store Pragma: no-cache Content-Type: application/json; charset=UTF-8 Transfer-Encoding: chunked Date: Sun, 03 Dec 2017 04:53:40 GMT {"access_token":"4cfb16f9-116c-43cf-a8d4-270e824ce5d7"."token_type":"bearer"."refresh_token":"8e9bfbda-77e5-4d97-b061-4e319de7eb4a"."expires_in": 1199,"scope":"all"}
Copy the code

Use a token to access resources

curl -i http://localhost:8080/api/blog/1\? access_token\=4cfb16f9-116c-43cf-a8d4-270e824ce5d7
Copy the code

or

curl -i -H "Accept: application/json" -H "Authorization: Bearer 4cfb16f9-116c-43cf-a8d4-270e824ce5d7" -X GET http://localhost:8080/api/blog/1
Copy the code

return

HTTP/1.1 302 X-Content-Type-options: nosniffing X-xss-protection: 1; mode=block Cache-Control: no-cache, no-store, max-age=0, must-revalidate Pragma: no-cache Expires: 0 X-Frame-Options: DENY Set-Cookie: JSESSIONID=F168A54F0F3C3D96A053DB0CFE129FBF; Path=/; HttpOnly Location: http://localhost:8080/login Content-Length: 0 Date: Sun, 03 Dec 2017 05:20:19 GMTCopy the code

The reasons for this are summarized in the next section

Successfully returns

HTTP/1.1 200 X-Content-type-options: nosniffing X-xss-protection: 1; mode=block Cache-Control: no-cache, no-store, max-age=0, must-revalidate Pragma: no-cache Expires: 0 X-Frame-Options: DENY X-Application-Context: application Content-Type: text/plain; charset=UTF-8 Content-Length: 14 Date: Sun, 03 Dec 2017 06:39:24 GMT this is blog 1Copy the code

Error return

HTTP/1.1 401 X-Content-type-options: nosniffing X-xss-protection: 1; mode=block Cache-Control: no-cache, no-store, max-age=0, must-revalidate Pragma: no-cache Expires: 0 X-Frame-Options: DENY Cache-Control: no-store Pragma: no-cache WWW-Authenticate: Bearer realm="oauth2-resource", error="invalid_token", error_description="Invalid access token: 466ee845-2d08-461b-8f62-8204c47f652"Content-Type: application/json; charset=UTF-8 Transfer-Encoding: chunked Date: Sun, 03 Dec 2017 06:39:28 GMT {"error":"invalid_token"."error_description":"Invalid access token: 466ee845-2d08-461b-8f62-8204c47f652"}
Copy the code

WebSecurityConfigurerAdapter and ResourceServerConfigurerAdapter

Both have a configuration for HTTP Security, and their default configuration is as follows

WebSecurityConfigurerAdapter

Spring ws-security – config – RELEASE 4.2.3 – sources. The jar! /org/springframework/security/config/annotation/web/configuration/WebSecurityConfigurerAdapter.java

@Order(100)
public abstract class WebSecurityConfigurerAdapter implements
		WebSecurityConfigurer<WebSecurity> {
		//......
protected void configure(HttpSecurity http) throws Exception {
		logger.debug("Using default configure(HttpSecurity). If subclassed this will potentially override subclass configure(HttpSecurity)."); http .authorizeRequests() .anyRequest().authenticated() .and() .formLogin().and() .httpBasic(); } / /... }Copy the code

You can see WebSecurityConfigurerAdapter order is 100

ResourceServerConfigurerAdapter

Spring ws-security – oauth2-2.0.14. RELEASE – sources. The jar! /org/springframework/security/oauth2/config/annotation/web/configuration/ResourceServerConfigurerAdapter.java

public void configure(HttpSecurity http) throws Exception {
		http.authorizeRequests().anyRequest().authenticated();
	}
Copy the code

Spring. It is order SecurityProperties ACCESS_OVERRIDE_ORDER – 1 – the boot – autoconfigure – 1.5.5. RELEASE – sources. The jar! /org/springframework/boot/autoconfigure/security/oauth2/resource/ResourceServerProperties.java

/**
	 * The order of the filter chain used to authenticate tokens. Default puts it after
	 * the actuator endpoints and before the default HTTP basic filter chain (catchall).
	 */
	private int filterOrder = SecurityProperties.ACCESS_OVERRIDE_ORDER - 1;
Copy the code

Thus WebSecurityConfigurerAdapter interception should take precedence over ResourceServerConfigurerAdapter

The relationship between

  • WebSecurityConfigurerAdapter protects the request relevant endpoints, at the same time, the main effect on user login,form login.Basic auth)
  • ResourceServerConfigurerAdapter protects the request to open resource, at the same time, the main effects on the client side as well as the token authentication (Bearer auth)

So they work together

  • In WebSecurityConfigurerAdapter not intercept request to open resource
@Override
    public void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        http.requestMatchers().antMatchers("/oauth/**")
                .and()
                .authorizeRequests()
                .antMatchers("/oauth/**").authenticated();
    }
Copy the code
  • Resources in ResourceServerConfigurerAdapter configuration need a token validation
@Override
    public void configure(HttpSecurity http) throws Exception {
        http.requestMatchers().antMatchers("/api/**")
                .and()
                .authorizeRequests()
                .antMatchers("/api/**").authenticated();
    }
Copy the code

And you’re done

doc

  • Understand the 2.0(good)
  • Secure Spring REST API using OAuth2(good)
  • Handling error: UnsupportedGrantTypeException, Unsupported grant type: password #3
  • Spring Oauth2 : Authentication Object was not found in the SecurityContext
  • Spring Security OAuth2, which decides security?
  • Using WebSecurityConfigurerAdapter with Spring OAuth2 and user-info-uri
  • How to define order of spring security filter chain #1024
  • Relation between WebSecurityConfigurerAdapter and ResourceServerConfigurerAdapter
  • Spring Security OAuth2, which decides security?