I'm trying to access a web service which is protected by Spring Security using ResourceServerConfigurerAdapter
(with Oauth2 client_credentials
)
Following is the security configuration
//Micoservice 1
@Configuration
@EnableResourceServer
class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
@Autowired
private Environment env;
@Autowired
private DummyUserFilter dummyUserFilter;
@Override
public void configure(HttpSecurity http) throws Exception {
http.addFilterAfter(dummyUserFilter, LogoutFilter.class)
.formLogin().disable()
.httpBasic().disable()
.csrf().disable()
.antMatcher("/**")
.authorizeRequests()
.antMatchers("/js/**", "/webjars/**").permitAll()
.anyRequest()
.authenticated();
}
}
This application (Microservice 1) is to be accessed by another application (Microservice 2) with the Oauth2RestTemplate
. Following is the Oauth2RestTemplate
configuration.
//MicroService 2
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate() {
ClientCredentialsResourceDetails resourceDetails = new ClientCredentialsResourceDetails();
resourceDetails.setAccessTokenUri("https://<UAA>/oauth/token");
resourceDetails.setClientId("#####");
resourceDetails.setClientSecret("#####");
resourceDetails.setGrantType("client_credentials");
resourceDetails.setTokenName("access_token");
DefaultOAuth2ClientContext clientContext = new DefaultOAuth2ClientContext();
OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resourceDetails, clientContext);
return restTemplate;
}
}
Microservice 2
has various web services which use RestTemplate to access the protected web services of Microservice 1
.
This always results in following exception
Authentication is required to obtain an access token (anonymous not allowed)
I have searched for this error and found that it's thrown in AccessTokenProviderChain
Here's the link from github for the relevant code
https://github.com/spring-projects/spring-security-oauth/blob/master/spring-security-oauth2/src/main/java/org/springframework/security/oauth2/client/token/AccessTokenProviderChain.java#L89
if (auth instanceof AnonymousAuthenticationToken) {
if (!resource.isClientOnly()) {
throw new InsufficientAuthenticationException(
"Authentication is required to obtain an access token (anonymous not allowed)");
}
}
It seems that it doesn't allow anonymous user to get access to the Oauth2 token.
I have no intention of protecting the client application (Microservice 2) with Oauth2 and I must use client_credentials
for the Oauth2RestTemplate
, that's preconfigured.
How can I stop Spring from blocking anonymous user from accessing token ?
I have already tried to populate SecurityContextHolder
with dummy authentication in case of anonymouse user, with no success. Even if I do succeed in doing so, it seems like a hack.
The main goal of the OAuth2RestTemplate is to reduce the code needed to make OAuth2-based API calls. It basically meets two needs for our application: Handles the OAuth2 authentication flow. Extends Spring RestTemplate for making API calls.
OAuth2AuthorizedClientRepository: is a container class that holds and persists authorized clients between requests. The default implementation, InMemoryOAuth2AuthorizedClientService , simply stores the clients in memory.
The Client Credentials grant type is used by clients to obtain an access token outside of the context of a user. This is typically used by clients to access resources about themselves rather than to access a user's resources.
To use GitHub's OAuth 2.0 authentication system for login, you must first Add a new GitHub app. Select "New OAuth App" and then the "Register a new OAuth application" page is presented. Enter an app name and description. Then, enter your app's home page, which should be http://localhost:8080, in this case.
I had the same problem and concluded that the AccessTokenProvider
interface, which has multiple implementors is the culprit. By default, the OAuth2RestTemplate
instantiates the AccessTokenProviderChain
which tries to re-use the existing login context. However, if no such login exists, this is bound to fail. Try
restTemplate.setAccessTokenProvider(new ResourceOwnerPasswordAccessTokenProvider());
in your factory method. This uses a token provider which owns its credentials and doesn't reference the thread local SecurityContextHolder
in its implementation at all.
Try Enabling httpBasic() security in your 2nd microservice and login to it using default username ("user") and generated password by spring.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With