Search code examples
javaspring-bootspring-cloudspring-security-oauth2spring-cloud-netflix

Zuul as OAuth2 AuthServer and ResourceServer: share AuthenticationManager


I'd like to have the Zuul Proxy as SSO @EnableOAuth2Ssoand as Resource Server @EnableResourceServer at the same time.

After some research I found a lot of similar question here on stackoverflow and this lovely uaa-behind-zuul-sample project on github.

  1. I removed the user and password property from application.yml of the uaa-service
  2. I added more users for authentication and disabled the parentAuthenticationManager

like this

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth
      .inMemoryAuthentication()
      .withUser("user").password("password").roles("USER")
      .and()
      .withUser("admin").password("admin").roles("ADMIN");
      // Disables this line below:
      //  auth.parentAuthenticationManager(authenticationManager);
}
  1. It works fine in the browser with admin and user credentials. So authorization is fine there.

But a call from another client like curl --insecure -H "Authorization: Basic $(echo -n 'acme:acmesecret' | base64)" http://localhost:8765/uaa/oauth/token -d grant_type=password -d username=admin -d password=admin -v

results in {"error":"invalid_grant","error_description":"Bad credentials"}

With the log message: o.s.s.a.dao.DaoAuthenticationProvider : User 'admin' not found. The same happens with user and password. And I works if I leave the user defined in the application.yml.

Question: Is it possible to share the authentication manager of the WebSecurityAdapter with the AuthorizationServerConfigurerAdapter? So that they are configured the same way?

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {           
  endpoints
  // TODO here: use the authenticationManager from the other class 
    .authenticationManager(authenticationManager)
    .accessTokenConverter(jwtAccessTokenConverter());
}

I forked the project mentioned above with a separate branch https://github.com/mavogel/uaa-behind-zuul-sample/tree/integration-resource-server which can be easily setup by running ./build_run.sh


Solution

  • The solution was

    1. Exposing the AuthenticationManager from LoginConfiguration

      @Override @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); }

    2. Injecting it in the AuthorizationServerConfiguration

    like this

    @Autowired
    @Qualifier("authenticationManagerBean")
    private AuthenticationManager authenticationManager;
    
    1. I also added a protected resource only accessible for the ROLE_ADMIN in the DummyServiceApplication which gets an ACCESS_DENIED for the user:

    like this

    @PreAuthorize("#oauth2.hasScope('openid') and hasRole('ROLE_ADMIN')")
    @RequestMapping(value = "secret", method = RequestMethod.GET)
    @ResponseBody
    public String helloSecret(Principal principal) {
        return principal == null ? "Hello anonymous" : "S3CR3T  - Hello " + principal.getName();
    }
    

    Props to the PiggyMetrics project who brought me up to the solution