简体   繁体   中英

Spring Security OAuth2 InvalidGrantException

I have successfully create a web-service using the spring-boot framework. Now I want to secure my web-service with OAuth2 (using spring) and have a few questions regarding that:

According to my research, spring provides some kind of default-url to request an access token ( baseURL/oauth/token ). I have tested the URL using postman, and a valid access token was returned (using client_credentials grant type), but no refresh token. However this method does not work with grant_type=password and results in the following error response:

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

My spring application logs InvalidGrantException .

The curl I used to test grant_type=password is the following:

curl -v -X POST -H "Content-Type: application/json" -H "Authorization: Basic base64encodedclientidandsecret" 'http://localhost:8888/oauth/token?grant_type=password&username=user&password=1234'

I did not test using postman because it does not support grant_type=password .

How can I get spring to return both accessToken and refreshToken using grant_type=password ?

Is there anything wrong with my configuration?

My spring application (configuration) looks as follows:

@Configuration
@ComponentScan
@EnableAutoConfiguration(exclude = { MongoAutoConfiguration.class, MongoDataAutoConfiguration.class })
@SpringBootApplication
public class CsWebServerApplication {

    public static final String RESOURCE_ID = "myresource";

    public static final String CLIENT_ID = "myapplication";
    public static final String CLIENT_SECRET = "application_secret";

    public static void main(String[] args) {

        SpringApplication.run(MyWebServerApplication.class, args);
    }

    @Configuration
    @EnableAuthorizationServer
    protected static class OAuth2Config extends AuthorizationServerConfigurerAdapter {

        @Inject
        private AuthenticationManager authenticationManager;

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

        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {

            clients.inMemory().withClient(CLIENT_ID)
            .authorizedGrantTypes("client_credentials", "password", "refresh_token")
            .authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT")
            .scopes("read", "write", "trust")
            .secret(CLIENT_SECRET);
        }

        @Override
        public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
            super.configure(oauthServer);
        }
    }

    @Configuration
    @EnableResourceServer
    protected static class ResourceConfig extends ResourceServerConfigurerAdapter {

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

            http.requestMatchers().antMatchers("/*", "/admin/beans").and().authorizeRequests().anyRequest()
                .access("#oauth2.hasScope('read')"); 
        }

        @Override
        public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
            resources.resourceId(RESOURCE_ID);
        }
    }

    @Configuration
    @EnableWebSecurity
    protected static class WebConfigurer extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            super.configure(http);
        }

        @Override
        public void configure(WebSecurity webSecurity) throws Exception {
            webSecurity.ignoring()
                    // All of Spring Security will ignore the requests
                    .antMatchers("/accessibleservices/**")
        }
    }

}

" 4.3.2. Access Token Request " in RFC 6749 (The OAuth 2.0 Authorization Framework) says as follows.

The client makes a request to the token endpoint by adding the following parameters using the "application/x-www-form-urlencoded" format per Appendix B with a character encoding of UTF-8 in the HTTP request entity-body:

So, -H "Content-Type: application/json" is wrong. In addition, your curl command line is wrong. Use -d option to specify a form parameter for POST.

About supporting of refresh tokens. By default spring oauth using DefaultTokenServices class and support of refresh tokens disabled by default. You should override its initialization in your OAuth2Config.class.

Example:

    @Bean
    @Primary
    public DefaultTokenServices tokenServices() {
        DefaultTokenServices tokenServices = new DefaultTokenServices();
        tokenServices.setSupportRefreshToken(true);
        return tokenServices;
    } 

DefaultTokenServices.class

not set TokenStore

OAuth2RefreshToken refreshToken = tokenStore.readRefreshToken(refreshTokenValue);
    if (refreshToken == null) {
        throw new InvalidGrantException("Invalid refresh token: " + refreshTokenValue);
    }

pom.xml add

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

add config

@Configuration
public class RedisTokenStoreConfig {

    @Autowired
    private RedisConnectionFactory redisConnectionFactory;

    @Bean
    public TokenStore redisTokenStore (){
        return new RedisTokenStore(redisConnectionFactory);
    }
}

in your OAuth2Config

@Autowired
@Qualifier("redisTokenStore")
private TokenStore tokenStore;

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
    endpoints.authenticationManager(authenticationManager)
            .userDetailsService(userService)
            .tokenStore(tokenStore);//set tokenStore
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM