Customize OAuth2 error response on client authenti

2020-07-10 05:55发布

问题:

While this seems to be an easy task, it turns out the opposite. I'm trying to customize the error handling for OAuth2 client authentication requests. The purpose of this is to remove the exception stacktrace/message from the response message.

Context

  • vanilla Oauth2 Spring Security implementation
  • Java Spring configuration

Steps taken to accomplish the task

  1. Create a custom implementation of OAuth2ExceptionRenderer
  2. Create a @Bean instance of OAuth2AuthenticationEntryPoint

    @Bean
    public OAuth2AuthenticationEntryPoint clientAuthEntryPoint()
    {
        OAuth2AuthenticationEntryPoint clientEntryPoint = new OAuth2AuthenticationEntryPoint();
        clientEntryPoint.setTypeName("Basic");
        clientEntryPoint.setRealmName("my-realm/client");
        clientEntryPoint.setExceptionRenderer(new CustomOAuth2ExceptionRenderer());
        return clientEntryPoint;
    }
    
  3. Create an access denied handler

    @Bean
    public OAuth2AccessDeniedHandler accessDeniedHandler()
    {
        OAuth2AccessDeniedHandler adh = new OAuth2AccessDeniedHandler();
        adh.setExceptionRenderer(new CustomOAuth2ExceptionRenderer());
        return adh;
    }
    
  4. Augment the AuthorizationServerSecurityConfigurer, among others, with these specialized implementations in AuthorizationServerConfiguration

    @Configuration
    @EnableAuthorizationServer
    protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter
    {
        @Override
        public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception
        {
            oauthServer.authenticationEntryPoint(clientAuthEntryPoint());
            oauthServer.accessDeniedHandler(accessDeniedHandler());
            oauthServer.realm("my-realm");
        }
    }
    

OAuth2 request

We use curl to initiate OAuth2 reuqests. Here is the command we use to test the client authenticaiton:

curl --insecure -H "Accept: application/json" -X POST -iu adfadsf:asdvadfgadf "https://localhost:8430/oauth/token?grant_type=password$username=john&pasword=johny"

Observed behavior

Since the client authentication is a Basic authentication, Spring Security will assign a BasicAuthenticationFilter to that step. If it happens to have an error in the backend related to this step (e.g. SQL exception), Spring Security will not pick up the OAuth2AuthenticationEntryPoint and will fall-back to a default entry point BasicAuthenticationEntryPoint.

Logs

o.s.s.authentication.ProviderManager     : Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider
o.s.s.w.a.www.BasicAuthenticationFilter  : Authentication request for failed: org.springframework.security.authentication.InternalAuthenticationServiceException: show me the money
s.w.a.DelegatingAuthenticationEntryPoint : Trying to match using RequestHeaderRequestMatcher [expectedHeaderName=X-Requested-With, expectedHeaderValue=XMLHttpRequest]
s.w.a.DelegatingAuthenticationEntryPoint : No match found. Using default entry point org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint@649f92da
s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed```

回答1:

You could try the solution posted by Roman Wozniak on your ticket #483. It worked pretty well for me :)

  • Code by Roman Wozniak:

    @Configuration
    @EnableAuthorizationServer
    protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
    
      //...
    
        @Override
        public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
            oauthServer
                        .realm(RESOURCE_ID + "/client")
                        .accessDeniedHandler(accessDeniedHandler)
                        .authenticationEntryPoint(entryPoint);
    
            // This allows you to replace default filter for Basic authentication and customize error responses
            oauthServer.addTokenEndpointAuthenticationFilter(
                    new BasicAuthenticationFilter(authenticationManager, entryPoint));
            }
    }