Refresh token call fails using spring security an oauth2 with error: UserDetailsService is required

被刻印的时光 ゝ 提交于 2019-12-23 10:15:15

问题


I am using Spring Security OAuth2 for authorizations. When trying to refresh the token I get an error: UserDetailsService is required (interestingly I get this error only on unix machines and not on windows). I am using Spring OAuth2 version 2.0.7.

For some reason the AuthenticationManager in the DefaultTokenService is not empty and it tries to authenticate the user to check if he still exists. I think it gets initialized because of some spring security vs. spring oauth2 configuration problems.

I am not using any custom UserDetailsService, hence it should not authenticate the users at this point. However, when I debug it I see that it tries to use one from the WebSecurityConfigurerAdapter and gets to this error. Even if I provide my custom dummy UserDetailsService, it is not using that one, but tries to use the other one, which is null. Am I missing here something? I can not find out why is this happening?

Here is my Oauth2 configuration

@Configuration
@EnableAuthorizationServer
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private MySpringTokenStore tokenStore;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private MyClientDetailsServiceImpl clientDetailsService;

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

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.withClientDetails(clientDetailsService);
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.allowFormAuthenticationForClients();
    }

    @Bean
    public TokenStore tokenStore() {
        return new InMemoryTokenStore();
    }
}

Here is my Spring security configuration

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // @formatter:off
        http
        .authorizeRequests()
            .antMatchers("/myRest/events/**", "/events/**", "/events", "/myRest/events").permitAll() 
            .antMatchers("/login.jsp", "/login").permitAll() 
        .and()
            .csrf().requireCsrfProtectionMatcher(new AntPathRequestMatcher("/oauth/authorize")).disable()
            .csrf().requireCsrfProtectionMatcher(new AntPathRequestMatcher("/myRest/events")).disable()
        .sessionManagement().sessionFixation().none();
        // @formatter:on
    }


    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/index*", "/myRest/events/**", "/events/**", "/myRest/events", "/events", "/swagger/**", "/kibana/**",
            "/elastic/**", "/version/**", "/api-docs/**", "/js/**", "/oauth/uncache_approvals", "/oauth/cache_approvals");
    }
}

回答1:


Authorization server endpoint needs UserDetailsService. In your OAuth2Config class configure user details service like the following:

@Autowired
private UserDetailsService userDetailsService;

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

You can also configure it in WebSecurityConfigurerAdapter:

@Autowired
private AuthorizationServerEndpointsConfiguration endpoints;

@Override
protected void configure(HttpSecurity http) throws Exception {

    if (!endpoints.getEndpointsConfigurer().isUserDetailsServiceOverride()) {
        UserDetailsService userDetailsService = http.getSharedObject(UserDetailsService.class);
        endpoints.getEndpointsConfigurer().userDetailsService(userDetailsService);
    }

    // @formatter:off
    http
    .authorizeRequests()
        .antMatchers("/myRest/events/**", "/events/**", "/events", "/myRest/events").permitAll() 
        .antMatchers("/login.jsp", "/login").permitAll() 
    .and()
        .csrf().requireCsrfProtectionMatcher(new AntPathRequestMatcher("/oauth/authorize")).disable()
        .csrf().requireCsrfProtectionMatcher(new AntPathRequestMatcher("/myRest/events")).disable()
    .sessionManagement().sessionFixation().none();
    // @formatter:on
}



回答2:


If implementing custom DefaultTokenServices, we don't need UserDetailsService.

@Configuration
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
    @Override
    public void configure(final AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
            // ...
            .tokenServices(tokenServices(endpoints));
    }

    public AuthorizationServerTokenServices tokenServices(final AuthorizationServerEndpointsConfigurer endpoints) {
        final DefaultTokenServices tokenServices = new DefaultTokenServices();
        tokenServices.setTokenStore(endpoints.getTokenStore());
        tokenServices.setClientDetailsService(endpoints.getClientDetailsService());
        tokenServices.setTokenEnhancer(endpoints.getTokenEnhancer());
        // ...
        tokenServices.setAuthenticationManager(
            new ProviderManager(List.of(new MyCustomAuthProvider())));
        return tokenServices;
    }
}

The commit message says:

Add AuthenticationManager to default token services

So that it can be used to check user account changes in a refresh token grant. If a global UserDetailsService is available it will be used as a default (e.g. if user has a GlobalAuthenticationConfigurer). It works by constructing a PreAuthenticationAuthenticationProvider and using that the authenticate the user in DefaultTokenServices. To customize that process, users can create their own DefaultTokenServices and inject an AuthenticationManager.

Fixes gh-401



来源:https://stackoverflow.com/questions/43842659/refresh-token-call-fails-using-spring-security-an-oauth2-with-error-userdetails

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!