How to register a custom BasicAuthenticationFilter AuthenticationProvider in Spring Boot using Spring Security OAuth2

btiernay picture btiernay · Sep 4, 2014 · Viewed 12.5k times · Source

Context

I'm developing an application that allows an authenticated user to create OAuth2 bearer tokens for use with APIs published by the organization. The idea is to allow the user to self generate / revoke such tokens, similar to GitHub's Personal API tokens. The user can then use the issued tokens to gain programmatic access to protected resources. In this configuration, the OAuth "Client", "Authorization Server" and the "Resource Server" belong to the organization. For now, all of these services reside in the same process.

To this end, I'm trying support the Resource Owner Password Credentials Grant type. The implementation environment consists of following:

  • Spring Boot
  • Spring Security OAuth2

One constraint the implementation has is that is does not have access to the stored password. This processing is delegated to an internal web service which does the actual authentication.

Problem

Because of the constraint of not having access to the stored password, the default configured DaoAuthenticationProvider cannot be used since it requires access to the password provided by the UserDetails object returned by the provider's UserDetailsService.

My guess is that I will need to replace this AuthenticationProvider with a custom implementation. However, all attempts at doing so seem to not take effect.

The following seemed to register correctly in the parent reference of the AuthenticationManager, but is not delegated to at runtime (due the DaoAuthenticationProvider taking precedence):

@Configuration
public class SecurityConfig extends GlobalAuthenticationConfigurerAdapter {

  @Override
  public void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(new AuthenticationProvider() {

      @Override
      public boolean supports(Class<?> authentication) {
        // For testing this is easier, but should check for UsernamePasswordAuthentication.class
        return true;
      }

      @Override
      public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        // Perform custom logic...
        return authentication;
      }

    });
  }

}

It seems no matter what I try (see references below) I always get the following two providers in ProviderManager when the BasicAuthenticationFilter invokes Authentication authResult = authenticationManager.authenticate(authRequest) in its doFilter method:

[ org.springframework.security.authentication.AnonymousAuthenticationProvider@366815e4, org.springframework.security.authentication.dao.DaoAuthenticationProvider@5da3e311 ]

I believe this may be a consequence of the AuthorizationServerSecurityConfigurer's clientCredentialsTokenEndpointFilter method. However, this class is marked final and therefore cannot be customized.

Any suggestions or pointers would be greatly appreciated.

Resources

Things that I have tried / researched:

Answer

Dave Syer picture Dave Syer · Sep 15, 2014

If I understand correctly, you need a custom authentication manager for users in the password grant. There is a builder method for that: AuthorizationServerEndpointsConfigurer.authenticationManager(AuthenticationManager). And an example of using it:

@Configuration
@EnableAuthorizationServer
protected static class OAuth2Config extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;

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

    ...

(from https://github.com/spring-projects/spring-security-oauth/blob/master/tests/annotation/vanilla/src/main/java/demo/Application.java#L42).