'Spring OAuth2: Always returning invalid token
I am trying to implement an OAuth2-Server with one Resource Server using Spring Boot. I am able to request tokens but if I use them to request resources from the Resource server the result is always 'invalid token'.
This is the authorization server configuration:
@Configuration
@EnableAuthorizationServer
public class AuthserverConfiguration extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authorizationCodeServices(authorizationCodeServices())
// injects the Spring Security authentication manager (set up in WebSecurityConfiguration )
.authenticationManager(authenticationManager)
.tokenStore(tokenStore());
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
// configure security for /oauth/check_token and /oauth/token_key endpoint
security.tokenKeyAccess("permitAll()")
.checkTokenAccess("permitAll()"); // should be isAuthenticated()
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("clientId").secret("{noop}clientsecret")
.authorizedGrantTypes("authorization_code", "refresh_token", "password")
.scopes("read");
}
@Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
@Bean
protected AuthorizationCodeServices authorizationCodeServices() {
// creates authorization codes, stores the codes in memory.
return new InMemoryAuthorizationCodeServices();
}
}
WebSecurityConfiguration is:
@EnableWebSecurity
@Configuration
@Order(SecurityProperties.BASIC_AUTH_ORDER - 20)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user").password("{noop}password").roles("USER");
/* for now testing with inMemoryAuthentication, later I want to use:
* auth.userDetailsService(userDetailsService); */
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers().antMatchers("/login", "/oauth/authorize", "/oauth/confirm_access")
.and()
.formLogin().loginPage("/login").permitAll().failureUrl("/login?error")
.and()
.authorizeRequests().anyRequest().authenticated();
}
@Bean(name = BeanIds.AUTHENTICATION_MANAGER)
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
And the UserInfoController:
@RestController
public class UserInfoController {
@RequestMapping(value = "/user")
public Principal userInfo(@AuthenticationPrincipal Principal user) {
return user;
}
}
pom.xml contains the following dependencies:+
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.0.5.RELEASE</version>
</dependency>
</dependencies>
The Resource server on the other hand is a standard Spring Boot project with tomcat, listening to GET /products
(returning a list in JSON format) on port 8081.
The servers main class is annotated with @EnableResourceServer
and its configuration contains:
security:
oauth2:
resource:
user-info-uri: http://localhost:8090/user
where 8090 is the port of above mentioned authentication server.
Testing with curl:
> curl clientId:clientsecret@localhost:8090/oauth/token -d grant_type=password -d username=user -d password=password -d scope=read`
{"access_token":"1cdd6dc2-42fe-4b55-b16d-78d189a88cc4","token_type":"bearer","refresh_token":"d59d78b5-43c8-4d12-b4ee-007da8548744","expires_in":43199,"scope":"read"}
> curl -H 'Authorization: Bearer 1cdd6dc2-42fe-4b55-b16d-78d189a88cc4' 'localhost:8090/oauth/check_token?token=1cdd6dc2-42fe-4b55-b16d-78d189a88cc4'
{"exp":1561956415,"user_name":"user","authorities":["ROLE_USER"],"client_id":"clientId","scope":["read"]}+ set +o xtrace
The token seems to be valid and recognized (if I tamper with the token I get a different error: "unrecognized token").
But if I try to request data from the Resource Server using the token:
> curl -H 'Authorization: Bearer 1cdd6dc2-42fe-4b55-b16d-78d189a88cc4' localhost:8081/products
{"error":"invalid_token","error_description":"Invalid access token: 1cdd6dc2-42fe-4b55-b16d-78d189a88cc4"}
This error is very consistent, I tried a lot of different changes to the configuration and even adding custom implementations of TokenServices, UserDetailsService, etc.
In the debug logs I find the following line in the output of the resource server everytime I do the request via curl:
Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@2b139cc0: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS
This is confusing to me because the Principal should not be anonymousUser in my understanding.
How can I solve this problem and request the data from my resource server? Any help highly appreciated.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|