Talk about the certification of several endpoint of spring security oauth2

  spring-security

Order

This article will talk about the certification of several endpoint of spring security oauth2.

endpoint

spring-security-oauth2-2.0.14.RELEASE-sources.jar! /org/springframework/security/oauth2/config/annotation/web/configuration/AuthorizationServerEndpointsConfiguration.java

@Configuration
@Import(TokenKeyEndpointRegistrar.class)
public class AuthorizationServerEndpointsConfiguration {

    private AuthorizationServerEndpointsConfigurer endpoints = new AuthorizationServerEndpointsConfigurer();

    @Autowired
    private ClientDetailsService clientDetailsService;

    @Autowired
    private List<AuthorizationServerConfigurer> configurers = Collections.emptyList();

    @PostConstruct
    public void init() {
        for (AuthorizationServerConfigurer configurer : configurers) {
            try {
                configurer.configure(endpoints);
            } catch (Exception e) {
                throw new IllegalStateException("Cannot configure enpdoints", e);
            }
        }
        endpoints.setClientDetailsService(clientDetailsService);
    }

    @Bean
    public AuthorizationEndpoint authorizationEndpoint() throws Exception {
        AuthorizationEndpoint authorizationEndpoint = new AuthorizationEndpoint();
        FrameworkEndpointHandlerMapping mapping = getEndpointsConfigurer().getFrameworkEndpointHandlerMapping();
        authorizationEndpoint.setUserApprovalPage(extractPath(mapping, "/oauth/confirm_access"));
        authorizationEndpoint.setProviderExceptionHandler(exceptionTranslator());
        authorizationEndpoint.setErrorPage(extractPath(mapping, "/oauth/error"));
        authorizationEndpoint.setTokenGranter(tokenGranter());
        authorizationEndpoint.setClientDetailsService(clientDetailsService);
        authorizationEndpoint.setAuthorizationCodeServices(authorizationCodeServices());
        authorizationEndpoint.setOAuth2RequestFactory(oauth2RequestFactory());
        authorizationEndpoint.setOAuth2RequestValidator(oauth2RequestValidator());
        authorizationEndpoint.setUserApprovalHandler(userApprovalHandler());
        return authorizationEndpoint;
    }

    @Bean
    public TokenEndpoint tokenEndpoint() throws Exception {
        TokenEndpoint tokenEndpoint = new TokenEndpoint();
        tokenEndpoint.setClientDetailsService(clientDetailsService);
        tokenEndpoint.setProviderExceptionHandler(exceptionTranslator());
        tokenEndpoint.setTokenGranter(tokenGranter());
        tokenEndpoint.setOAuth2RequestFactory(oauth2RequestFactory());
        tokenEndpoint.setOAuth2RequestValidator(oauth2RequestValidator());
        tokenEndpoint.setAllowedRequestMethods(allowedTokenEndpointRequestMethods());
        return tokenEndpoint;
    }

    @Bean
    public CheckTokenEndpoint checkTokenEndpoint() {
        CheckTokenEndpoint endpoint = new CheckTokenEndpoint(getEndpointsConfigurer().getResourceServerTokenServices());
        endpoint.setAccessTokenConverter(getEndpointsConfigurer().getAccessTokenConverter());
        endpoint.setExceptionTranslator(exceptionTranslator());
        return endpoint;
    }

    @Bean
    public WhitelabelApprovalEndpoint whitelabelApprovalEndpoint() {
        return new WhitelabelApprovalEndpoint();
    }

    @Bean
    public WhitelabelErrorEndpoint whitelabelErrorEndpoint() {
        return new WhitelabelErrorEndpoint();
    }

    //......
}

The following configurations are shown here

  • /oauth/authorize
  • /oauth/token
  • /oauth/check_token
  • /oauth/confirm_access
  • /oauth/error

Endpoint certification

/oauth/authorize

This need to protect the user account password authentication protection, otherwise it will be reported

curl -i http://localhost:8080/oauth/authorize\?response_type\=code\&client_id\=demoApp\&redirect_uri\=http://localhost:8081/callback
HTTP/1.1 500
X-Application-Context: application
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Sun, 10 Dec 2017 07:12:50 GMT
Connection: close

{"timestamp":1512889970484,"status":500,"error":"Internal Server Error","exception":"org.springframework.security.authentication.InsufficientAuthenticationException","message":"User must be authenticated with Spring Security before authorization can be completed.","path":"/oauth/authorize"}

/oauth/token

  • If the configuration supports allowformationforclients, and the url has client_id and client_secret, clientcredentialstokendpointfilter will be used to protect it.
  • If there is no support for AllowFormationForClients or if there is support but there is no client_id and client_secret in the url, go to basic authentication protection.

/oauth/check_token

This is protected by basic authentication.

/oauth/confirm_access

This requires authentication protection, otherwise report 500

curl -i http://localhost:8080/oauth/confirm_access

HTTP/1.1 500
X-Application-Context: application
Cache-Control: no-store
Content-Type: application/json;charset=UTF-8
Content-Language: zh-CN
Transfer-Encoding: chunked
Date: Sun, 10 Dec 2017 07:13:55 GMT
Connection: close

{"timestamp":1512890035907,"status":500,"error":"Internal Server Error","exception":"org.springframework.expression.spel.SpelEvaluationException","message":"EL1008E: Property or field 'authorizationRequest' cannot be found on object of type 'java.util.HashMap' - maybe not public?","path":"/oauth/confirm_access"}

/oauth/error

This can be protected without authentication

Basic Certified Source Code for Protection

spring-security-oauth2-2.0.14.RELEASE-sources.jar! /org/springframework/security/oauth2/config/annotation/web/configuration/AuthorizationServerSecurityConfiguration.java

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        AuthorizationServerSecurityConfigurer configurer = new AuthorizationServerSecurityConfigurer();
        FrameworkEndpointHandlerMapping handlerMapping = endpoints.oauth2EndpointHandlerMapping();
        http.setSharedObject(FrameworkEndpointHandlerMapping.class, handlerMapping);
        configure(configurer);
        http.apply(configurer);
        String tokenEndpointPath = handlerMapping.getServletPath("/oauth/token");
        String tokenKeyPath = handlerMapping.getServletPath("/oauth/token_key");
        String checkTokenPath = handlerMapping.getServletPath("/oauth/check_token");
        if (!endpoints.getEndpointsConfigurer().isUserDetailsServiceOverride()) {
            UserDetailsService userDetailsService = http.getSharedObject(UserDetailsService.class);
            endpoints.getEndpointsConfigurer().userDetailsService(userDetailsService);
        }
        // @formatter:off
        http
            .authorizeRequests()
                .antMatchers(tokenEndpointPath).fullyAuthenticated()
                .antMatchers(tokenKeyPath).access(configurer.getTokenKeyAccess())
                .antMatchers(checkTokenPath).access(configurer.getCheckTokenAccess())
        .and()
            .requestMatchers()
                .antMatchers(tokenEndpointPath, tokenKeyPath, checkTokenPath)
        .and()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER);
        // @formatter:on
        http.setSharedObject(ClientDetailsService.class, clientDetailsService);
    }

Among them, you can specify the authentication level of check_token yourself, while /oauth/token requires fullyAuthenticated

Token_key This is unique to jwt and is ignored here.

The difference between isAuthenticated () and isFullyAuthenticated

One is authenticated and the other is fullyAuthenticated. The former excludes anonymous, while the latter excludes anonymous and remember-me-Me

  • isAuthenticated()

Returns true if the user is not anonymous

  • isFullyAuthenticated()

Returns true if the user is not an anonymous or a remember-me user

Summary

To sum up, it is necessary to protect the two endpoints of /oauth/authorize and /oauth/confirm_access, and of course the main endpoint is /oauth/authorize.

Since the authentication priority of the other authentication endpoint configurations starting with /oauth/, is higher than the default WebSecurityConfigurerAdapter configuration (order=100), the default configuration can be this way

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        http
                .requestMatchers().antMatchers("/oauth/**","/login/**","/logout/**")
                .and()
                .authorizeRequests()
                .antMatchers("/oauth/**").authenticated()
                .and()
                .formLogin().permitAll(); //新增login form支持用户登录及授权
    }
}

Protect the whole /oauth/** in

doc