How to overwrite Spring Cloud OAuth2 client autoconfiguration? - spring

We want to setup a microservice which provides a REST API so it is configured as a OAuth2 resource server. This service should also act as a OAuth2 client with the client credential grant. Here is the configuration:
spring.oauth2.client.id=clientCredentialsResource
spring.oauth2.client.accessTokenUri=http://localhost:9003/oauth/token
spring.oauth2.client.userAuthorizationUri=http://localhost:9003/oauth/authorize
spring.oauth2.client.grantType=client_credentials
spring.oauth2.client.clientId=<service-id>
spring.oauth2.client.clientSecret=<service-pw>
The resource server part works fine. For the client part we want to use Feign, Ribbon and Eureka:
#FeignClient("user")
public interface UserClient
{
#RequestMapping( method = RequestMethod.GET, value = "/user/{uid}")
Map<String, String> getUser(#PathVariable("uid") String uid);
}
Based on the gist in issue https://github.com/spring-cloud/spring-cloud-security/issues/56 I created a feign request intercepter which sets the access token from the autowired OAuth2RestOperations template in the feign request header
#Autowired
private OAuth2RestOperations restTemplate;
template.header(headerName, String.format("%s %s", tokenTypeName, restTemplate.getAccessToken().toString()));
But this gives me the error on calling the user service:
error="access_denied", error_description="Unable to obtain a new access token for resource 'clientCredentialsResource'. The provider manager is not configured to support it.
As I can see the OAuth2ClientAutoConfiguration creates always an instance of AuthorizationCodeResourceDetails for an web application but not the required ClientCredentialsResourceDetails which is only used for non-web applications. In the end the no access token privider is responsible for the resource details and the call failed in
AccessTokenProviderChain.obtainNewAccessTokenInternal(AccessTokenProviderChain.java:146)
I tried to overwrite the auto configuration but failed. Can somebody please give me a hint how to do it?

To switch off this piece of autoconfiguration you can set spring.oauth2.client.clientId= (empty), (per the source code), otherwise you have to "exclude" it in the #EnableAutoConfiguration. If you do that you can just set up your own OAuth2RestTemplate and fill in the "real" client ID from your own configuration, e.g.
#Configuration
#EnableOAuth2Client
public class MyConfiguration {
#Value("myClientId")
String myClientId;
#Bean
#ConfigurationProperties("spring.oauth2.client")
#Primary
public ClientCredentialsResourceDetails oauth2RemoteResource() {
ClientCredentialsResourceDetails details = new ClientCredentialsResourceDetails();
details.setClientId(myClientId);
return details;
}
#Bean
public OAuth2ClientContext oauth2ClientContext() {
return new DefaultOAuth2ClientContext(new DefaultAccessTokenRequest());
}
#Bean
#Primary
public OAuth2RestTemplate oauth2RestTemplate(
OAuth2ClientContext oauth2ClientContext,
OAuth2ProtectedResourceDetails details) {
OAuth2RestTemplate template = new OAuth2RestTemplate(details,
oauth2ClientContext);
return template;
}
}

Related

Resolving OAuth2AuthorizedClient as a Spring bean

I have a controller that is autowired with many services. These services are HTTP restful calls that retrieve data from various data sources, but these services are protected with OAuth2.0.
I am trying to use Spring Security to implement a client-credentials flow that will allow these services to securely retrieve data from these protected data sources, but am having some difficulty in resolving the OAuth2AuthorizedClient data object at the service layer.
I've been trying to resolve the authorized client via the #RegisteredOAuth2AuthorizedClient annotation:
public void setAuthorizedClient(
#RegisteredOAuth2AuthorizedClient("azure") OAuth2AuthorizedClient authorizedClient) {
ClientRegistration clientRegistration =
this.clientRegistrationRepository.findByRegistrationId("azure");
System.out.println(clientRegistration);
OAuth2AccessToken accessToken = authorizedClient.getAccessToken();
jwtToken = accessToken.getTokenValue();
}
Is it possible to resolve the OAuth2AuthorizedClient as a Spring bean that can then be injected into another bean?
Or is there a better way of architecting such a system?
Thanks!
Bit of an old question but I just solved this for myself so here goes:
You can create a #Component that returns the OAuth2AuthorizedClient for you, and inject that where you need it. Here is an example approach:
Create a provider Component class
Inject the readily available OAuth2AuthorizedClientService bean to your class
Create a method that uses the service in order to return the OAuth2AuthorizedClient
Inject your provider class to your Controller
Example:
#Component
public class OAuth2AuthorizedClientProvider {
#Autowired
private OAuth2AuthorizedClientService clientService;
public OAuth2AuthorizedClient getClient() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
OAuth2AuthenticationToken oauthToken = (OAuth2AuthenticationToken) authentication;
return clientService.loadAuthorizedClient(oauthToken.getAuthorizedClientRegistrationId(), oauthToken.getName());
}
and then OAuth2AuthorizedClientProvider is used in a controller like so:
#RestController
public class Endpoint {
#Autowired
private final OAuth2AuthorizedClientProvider oauth2AuthorizedClientProvider;
#GetMapping("/mymethod")
public String mymethod() {
return oauth2AuthorizedClientProvider.getClient().getAccessToken();
}
}

Authentication is required to obtain an access token - when using 'password' grant and Spring's ResourceOwnerPasswordResourceDetails

I am new to Spring Security and I want to implement a client for a OAUTH2 secured service that only accepts password grant.
Obtaining the access_token from the auth server is done using data in the http body like this:
client_id={{clientId}}&client_secret={{client_secret}}&grant_type=password&username={{username}}&password={{password}}
Afterwards the access_token must be used in the header field Authorization to access the actual service. (e.g. Authorization=Bearer <access_token>)
My goal is to use the provided features from Spring Security OAuth2 to request an access_token from the auth service, and use it for accessing the service endpoints until token expiration. I also like to have that my access_token is automatically refreshed using the refresh_token value from the auth server. I want to achieve this while fully utilizing Spring's features.
I found that I can use OAuth2RestTemplate with ResourceOwnerPasswordResourceDetails for the grant_type password.
The StackOverflow post oAuth2 client with password grant in Spring Security was very helpful for me, but I have not got it to work.
I also found the post Authentication is required to obtain an access token (anonymous not allowed) where a user encountered the same exception, but uses client_credentials and AuthorizationCodeResourceDetails.
At the moment my code looks like this.
#Service
public class MyClient {
#Autowired
private OAuth2RestTemplate restTemplate;
#Value("${authServer.accessTokenUri}")
private String accessTokenUri;
#Value("${authServer.clientId}")
private String clientId;
#Value("${authServer.clientSecret}")
private String clientSecret;
#Value("${authServer.username}")
private String username;
#Value("${authServer.password}")
private String password;
#Value("${serviceUrl}")
private String serviceUrl;
#Bean
public OAuth2RestTemplate restTemplate(OAuth2ClientContext oauth2ClientContext) {
OAuth2RestTemplate template = new OAuth2RestTemplate(resource(), oauth2ClientContext);
template.setAccessTokenProvider(accessTokenProvider());
return template;
}
#Bean
public AccessTokenProvider accessTokenProvider() {
ResourceOwnerPasswordAccessTokenProvider tokenProvider = new ResourceOwnerPasswordAccessTokenProvider();
return new AccessTokenProviderChain(
Arrays.<AccessTokenProvider>asList(tokenProvider)
);
}
#Bean
protected OAuth2ProtectedResourceDetails resource() {
ResourceOwnerPasswordResourceDetails resource = new ResourceOwnerPasswordResourceDetails();
resource.setId(clientId);
resource.setAccessTokenUri(accessTokenUri);
resource.setClientId(clientId);
resource.setClientSecret(clientSecret);
resource.setGrantType("password");
resource.setClientAuthenticationScheme(AuthenticationScheme.form); // fetch access_token by sending authentication data in HTTP Body
resource.setAuthenticationScheme(AuthenticationScheme.header); // send access_token via HTTP Header 'Bearer' field when accessing actual service
resource.setUsername(username);
resource.setPassword(password);
return resource;
}
public void getDataFromService() {
String response = restTemplate.getForObject(serviceUrl, String.class);
}
}
An exception is thrown in AccessTokenProviderChain, because of this block.
if (auth instanceof AnonymousAuthenticationToken) {
if (!resource.isClientOnly()) {
throw new InsufficientAuthenticationException("Authentication is required to obtain an access token (anonymous not allowed)");
}
}
Here is the exception stack trace.
org.springframework.security.authentication.InsufficientAuthenticationException: Authentication is required to obtain an access token (anonymous not allowed)
at org.springframework.security.oauth2.client.token.AccessTokenProviderChain.obtainAccessToken(AccessTokenProviderChain.java:91) ~[spring-security-oauth2-2.3.4.RELEASE.jar:na]
at org.springframework.security.oauth2.client.OAuth2RestTemplate.acquireAccessToken(OAuth2RestTemplate.java:221) ~[spring-security-oauth2-2.3.4.RELEASE.jar:na]
at org.springframework.security.oauth2.client.OAuth2RestTemplate.getAccessToken(OAuth2RestTemplate.java:173) ~[spring-security-oauth2-2.3.4.RELEASE.jar:na]
at org.springframework.security.oauth2.client.OAuth2RestTemplate.createRequest(OAuth2RestTemplate.java:105) ~[spring-security-oauth2-2.3.4.RELEASE.jar:na]
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:731) ~[spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.security.oauth2.client.OAuth2RestTemplate.doExecute(OAuth2RestTemplate.java:128) ~[spring-security-oauth2-2.3.4.RELEASE.jar:na]
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:670) ~[spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:311) ~[spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
As you can see I cannot request an access_token. I do not understand why I get this exception, because if I directly request an access_token from the auth server using the curl command, I am able to authenticate using only the provided data as stated.
I manually obtained an access_token successfully like this, when adding the following code before invoking restTemplate.getForObject(...).
ResourceOwnerPasswordAccessTokenProvider accessTokenProvider = new ResourceOwnerPasswordAccessTokenProvider();
OAuth2AccessToken token = accessTokenProvider.obtainAccessToken(resource(), new DefaultAccessTokenRequest());
restTemplate.getOAuth2ClientContext().setAccessToken(token);
String token = restTemplate.getAccessToken();
But, manually obtaining the access_token is not that what I want. Is there something I am missing? Is it possible to automatically obtain an access_token and refresh it using Spring Security with password grant?
Although checking code multiple hours on Github, StackOverflow etc. ... I have not been able to get my code to work.
UPDATE:
I found that my ResourceOwnerPasswordResourceDetails instance inside my OAuth2RestTemplate instance is not initialized, when I want to make use of it inside getDataFromService(). (i.e. the fields like username are null). After clarification and help from #JoeGrandja, my question now does not really target Spring Security, but rather Spring.
What can I do to make use of the #Value annotations inside a #Bean annotated method. At the moment, when the restTemplate is constructed using the #Bean annotated method resource(), the values from the application.yml are obviously not available yet.
I found a solution with the help and support of #JoeGrandja. Thank you very much! :)
If anyone else has problems, here is my working solution. I also recommend reading the comments from #JoeGrandja above.
#Configuration
#ConfigurationProperties(prefix = "authserver")
public class AuthServerConfigProperties {
private String accessTokenUri;
private String clientId;
private String grantType;
private String clientSecret;
private String username;
private String password;
// Getter & Setter for all properties ...
}
#Configuration
public class CommConfig {
#Autowired
AuthServerConfigProperties configProperties;
#Bean
public OAuth2RestOperations restTemplate(OAuth2ClientContext oauth2ClientContext) {
OAuth2RestTemplate oAuth2RestTemplate = new OAuth2RestTemplate(resource(), oauth2ClientContext);
oAuth2RestTemplate.setAccessTokenProvider(new ResourceOwnerPasswordAccessTokenProvider());
return oAuth2RestTemplate;
}
#Bean
protected OAuth2ProtectedResourceDetails resource() {
ResourceOwnerPasswordResourceDetails resource = new ResourceOwnerPasswordResourceDetails();
resource.setId(configProperties.getClientId()); // not necessary
resource.setAccessTokenUri(configProperties.getAccessTokenUri());
resource.setClientId(configProperties.getClientId());
resource.setClientSecret(configProperties.getClientSecret());
resource.setGrantType(configProperties.getGrantType());
resource.setClientAuthenticationScheme(AuthenticationScheme.form); // fetch access_token by sending authentication data in HTTP Body
resource.setAuthenticationScheme(AuthenticationScheme.header); // send access_token via HTTP Header 'Bearer' field when accessing actual service
resource.setUsername(configProperties.getUsername());
resource.setPassword(configProperties.getPassword());
return resource;
}
}
#RestController
public class MyController {
#Autowired
private OAuth2RestOperations restTemplate;
#Value("${serviceUrl}")
private String serviceUrl;
#RequestMapping(value = "/getData", method = RequestMethod.GET)
#ResponseBody
public ResponseEntity<String> getData() {
String response = restTemplate.getForObject(serviceUrl, String.class);
return new ResponseEntity(response, HttpStatus.OK);
}
}
I had a similar problem: rest request was anonymous, but internal processing required oauth2 authorization, resolved with a simple extend:
public class CustomResourceOwnerPasswordResourceDetails extends ResourceOwnerPasswordResourceDetails {
#Override
public boolean isClientOnly() {
return true;
}
}

Unable to use #LoadBalanced with OAuth2RestTemplate configured on ClientCredentials

I want to use OAuth2 ClientCredentials flow for inter service communication between two Resource Servers. Everything works fine except that i am not able to use service name (Ribbon Load Balancer feature) instead of hostname in my OAuth2RestTemplate calls to remote resource server.
One of my Resource Server (that calls another Resource Server) has below configuration:
Spring Boot 1.5.13
Spring Cloud Edgware.SR3
build.gradle contains entries for eureka and ribbon
compile('org.springframework.cloud:spring-cloud-starter-ribbon')
compile('org.springframework.cloud:spring-cloud-starter-eureka')
#Configuration
class RestTemplateConfig {
#Bean
#ConfigurationProperties("security.oauth2.client")
public ClientCredentialsResourceDetails oauth2ClientCredentialsResourceDetails() {
return new ClientCredentialsResourceDetails();
}
#LoadBalanced
#Bean(name = "oauthRestTemplate")
public OAuth2RestOperations oAuthRestTemplate(ClientCredentialsResourceDetails oauth2ClientCredentialsResourceDetails) {
return new OAuth2RestTemplate(oauth2ClientCredentialsResourceDetails);
}
}
Service Consuming this OAuth2RestTemplate
#Service
class TestService {
#Autowired
#Qualifier("oauthRestTemplate")
private OAuth2RestOperations oAuth2RestOperations;
public void notifyOrderStatus(long orderId, OrderStatus newStatus) {
oAuth2RestOperations.exchange("http://notification-service/api/order/{id}/status/{status}", HttpMethod.POST, null, Void.class, orderId, newStatus.name());
}
}
Exception appears while invoking remote service using service name i.e. http://notification-service instead of actual hostname and port of remote resource server. If I use actual hostname + port, then everything works fine but I don't want my one resource to know host/post of another resource server.
Exception:
Caused by: java.net.UnknownHostException: notification-service
I have few questions:
If my RestTemplate is annotated with #LoadBalanced, then everything works fine. Does OAuth2RestTemplate support this annotation and can we use service name instead of hostname? If yes, any reference or documentation would be appreciated.
Is it a good idea to use oauth2 client credentials for inter service security between two resource servers? I do not see any samples for the same in documentation?
#LoadBalanced RestTemplate works when we use RestTemplateCustomizer to customize the newly created OAuth2RestTemplate, as shown in the below code:
#Bean(name = "MyOAuthRestTemplate")
#LoadBalanced
public OAuth2RestOperations restTemplate(RestTemplateCustomizer customizer, ClientCredentialsResourceDetails oauth2ClientCredentialsResourceDetails) {
OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(oauth2ClientCredentialsResourceDetails);
customizer.customize(restTemplate);
return restTemplate;
}
Using service name instead of actual host name works fine using this RestTemplate.

Spring #FeignClient with OAuth2FeignRequestInterceptor not working

I'm trying to set FeignClient with OAuth2 to implement "Relay Token". I just want FeignClient to relay / propagate the OAuth2 Token that comes from ZuulProxy (SSO Enabled).
I use Spring 1.3.1-RELEASE and Spring Cloud Brixton.M4.
I have added an interceptor in a custom #FeignClient configuration:
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.security.oauth2.client.feign.OAuth2FeignRequestInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.client.OAuth2ClientContext;
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails;
import feign.RequestInterceptor;
#Configuration
public class FeignClientConfiguration {
#Value("${security.oauth2.client.userAuthorizationUri}")
private String authorizeUrl;
#Value("${security.oauth2.client.accessTokenUri}")
private String tokenUrl;
#Value("${security.oauth2.client.client-id}")
private String clientId;
// See https://github.com/spring-cloud/spring-cloud-netflix/issues/675
#Bean
public RequestInterceptor oauth2FeignRequestInterceptor(OAuth2ClientContext oauth2ClientContext){
return new OAuth2FeignRequestInterceptor(oauth2ClientContext, resource());
}
#Bean
protected OAuth2ProtectedResourceDetails resource() {
AuthorizationCodeResourceDetails resource = new AuthorizationCodeResourceDetails();
resource.setAccessTokenUri(tokenUrl);
resource.setUserAuthorizationUri(authorizeUrl);
resource.setClientId(clientId);
// TODO: Remove this harcode
resource.setClientSecret("secret");
return resource;
}
}
And I add the configuration to my #FeignClient like that:
#FeignClient(name = "car-service", configuration = FeignClientConfiguration.class)
interface CarClient {
#RequestMapping(value = "car-service/api/car", method = GET)
List<CarVO> getAllCars();
}
The application starts but when I use the Feign Client from my service I get:
2016-01-08 13:14:29.757 ERROR 3308 --- [nio-9081-exec-1] o.a.c.c.C.[.[.[. [dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in
context with path [/user-service] threw exception [Request processing failed; nested exception is com.netflix.hystrix.exception.HystrixRuntimeException: getAllCars failed and no fallback available.] with root cause
java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.web.context.request.AbstractRequestAttributesScope.get(AbstractRequestAttributesScope.java:41) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:340) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
I want my application / microservice (the one that uses the #FeingClient to call the other application / microservice) to be STATELESS. However, I have tried both, with security.sessions=STATELESS (SpringBoot default) and security.sessions=ALWAYS (just to try).
In both cases I got the same exception.
Having a look at the code I have seen that the OAuth2ClientContext is saved in Session (Session scoped bean). How does it work when you want to implement a STATELESS OAuth2 enabled application / microservice? Precisely this is one of the big advantages of using OAuth2 in my current scenario. However, as I said, the result was the same enabling sessions.
Can someone help with this, please?
Thanks so much! :-)
I have found out that the problem is that Hystrix forces code execution in another thread and so you have no access to request / session scoped beans.
I was using #FeignClient with Hystrix enabled. When I disable Hystrix using feign.hystrix.enabled: false
the call from Microservice A to Microservice B relaying the token (using OAuth2FeignRequestInterceptor) works fine.
However, it would be desirable to be able to keep Hystrix enabled.
I have seen there is a new module that improves Hystrix - Feign (feign-hystrix module) in this regard in this post:
Does Spring Cloud Feign client call execute inside hystrix command?
However, I don't see how to properly do the setup using feign-hystrix and I was not able to find an example. Please, could you help with this or provide an example using feign-hystrix?
Thanks so much!
I am not exactly sure if I understood you correctly but the following worked for me.
See https://jfconavarrete.wordpress.com/2014/09/15/make-spring-security-context-available-inside-a-hystrix-command/
Basically the tutorial shows how to setup / augment hystrix with an additional "plugin" so the security context is made available inside hystrix wrapped calls via a threadlocal variable
With this setup all you need to do is define a feign request interceptor like so:
#Bean
public RequestInterceptor requestTokenBearerInterceptor() {
return new RequestInterceptor() {
#Override
public void apply(RequestTemplate requestTemplate) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) authentication.getDetails();
requestTemplate.header("Authorization", "Bearer " + details.getTokenValue());
}
};
}
With this setup the token contained in the request is made available to the feign request interceptor so you can set the Authorization header on the feign request with the token from your authenticated user.
Also note that with this approach you can keep your SessionManagementStrategy "STATELESS" as no data has to be "stored" on the server side
USE THIS CODE AND COMMENT RESTEMPLATE config when you are using as ribbon client instead of that here we will use oauth2restTemplate
#EnableOAuth2Client
#Configuration
public class OAuthClientConfig {
#Value("${config.oauth2.accessTokenUri}")
private String tokenUri;
#Value("${app.client.id}")
private String clientId;
#Value("${app.client.secret}")
private String clientSecret;
#Bean
protected OAuth2ProtectedResourceDetails resource() {
ResourceOwnerPasswordResourceDetails resource;
resource = new ResourceOwnerPasswordResourceDetails();
List<String> scopes = new ArrayList<String>(2);
scopes.add("write");
scopes.add("read");
resource.setAccessTokenUri(tokenUri);
resource.setClientId(clientId);
resource.setClientSecret(clientSecret);
resource.setGrantType("password");
resource.setScope(scopes);
return resource;
}
#Bean
public OAuth2ClientContext oauth2ClientContext() {
DefaultOAuth2ClientContext defaultOAuth2ClientContext = new DefaultOAuth2ClientContext();
return defaultOAuth2ClientContext;
}
#Bean
#Primary
#LoadBalanced
public OAuth2RestTemplate oAuth2RestTemplate(OAuth2ProtectedResourceDetails oAuth2ProtectedResourceDetails,
OAuth2ClientContext oauth2ClientContext) {
OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(oAuth2ProtectedResourceDetails, oauth2ClientContext);
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
restTemplate.setRequestFactory(factory);
return restTemplate;
}
#Bean
public OAuth2FeignRequestInterceptor aauthRequestInterceptor(OAuth2ProtectedResourceDetails oAuth2ProtectedResourceDetails,
OAuth2ClientContext oauth2ClientContext)
{
OAuth2FeignRequestInterceptor auth2FeignRequestInterceptor=new OAuth2FeignRequestInterceptor(oauth2ClientContext, oAuth2ProtectedResourceDetails);
return auth2FeignRequestInterceptor;
}

Consume an OAuth-secured REST webservice using Spring oauth2

I want to consume a REST webservice from a server which protects his resources using oauth2.
I use Spring boot (JHipster).
To do this i have in SecurityConfiguration class this :
#Value("${oauth.resource:http://sercverUsingOAuth2}")
private String baseUrl;
#Value("${oauth.authorize:http://sercverUsingOAuth2/rest/oauth/token}")
private String authorizeUrl;
#Value("${oauth.token:http://sercverUsingOAuth2/rest/oauth/token}")
private String tokenUrl;
#Bean
public OAuth2RestOperations oauth2RestTemplate() {
AccessTokenRequest atr = new DefaultAccessTokenRequest();
return new OAuth2RestTemplate(resource(),
new DefaultOAuth2ClientContext(atr));
}
#Bean
protected OAuth2ProtectedResourceDetails resource() {
AuthorizationCodeResourceDetails resource = new AuthorizationCodeResourceDetails();
resource.setAccessTokenUri(tokenUrl);
resource.setUserAuthorizationUri(authorizeUrl);
resource.setClientId("client_id");
resource.setClientSecret("client_secret");
resource.setGrantType("grant_type");
return resource;
}
This class (SecurityConfiguration) is annoted using :
#Configuration
#EnableWebSecurity
#EnableOAuth2Client
And this is my controller (Spring MVC) :
#RestController
#RequestMapping("/consume")
public class MyContrtoller {
#Inject
private OAuth2RestOperations oauth2RestTemplate;
#RequestMapping(value = "/oauth2", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public List<DataModel> getProducts() {
ResponseEntity<MyModel> forEntity = oauth2RestTemplate
.getForEntity("http://sercverUsingOAuth2/rest/resourceToConsume",
MyModel.class);
return forEntity.getBody().getData();
}
}
However when i want to consume my webservice (http://myHost/consume/oauth2) i get this Exception :
org.springframework.security.oauth2.client.resource.OAuth2AccessDeniedException:
Unable to obtain a new access token for resource 'null'. The provider manager
is not configured to support it.
I have googled and i found this :
github
stackoverflow
But it doesn't help me.
Thanks.
You are using the same URL for the authorization url and the token url. That was my first clue, then I saw your comments.
Even though you are changing the grant type, you are still using "AuthorizationCodeResourceDetails" when you should be using "ClientCredentialsResourceDetails" instead. This type of ResourceDetails is meant to be used for the case you are explaining.
ClientCredentialsResourceDetails resource = new ClientCredentialsResourceDetails();
resource.setAccessTokenUri(TOKEN_URL);
resource.setClientId(CLIENT_ID);
resource.setClientSecret(CLIENT_SECRET);
resource.setClientAuthenticationScheme(AuthenticationScheme.form); //This line isn't always needed
return resource;

Resources