Spring fetch public key from authentication service via Eureka - spring

I'm implementing a Spring Security Resource Server that validating JWT tokens with a public key.
I'm trying to fetch the public key from the Authentication Service I've built, via Eureka service.
The fetching occurring on service startup, before the service registers on Eureka.
So when it's calling the authentication service, an UnknownHostException is thrown.
Can I modify the order and set the key just after Eureka registration finished?
#EnableResourceServer
public class MyResourceServerConfig extends
AuthorizationServerConfigurerAdapter {
#Bean
#Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
return defaultTokenServices;
}
#Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
#Bean
public JwtAccessTokenConverter accessTokenConverter() {
final JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
HttpEntity<Void> request = new HttpEntity<Void>(new HttpHeaders());
ResponseEntity<Map> responseEntity = restTemplate.exchange(AUTH_URI, HttpMethod.GET, request, Map.class);
String publicKey = (String) responseEntity.getBody().get("value");
converter.setVerifierKey(publicKey);
return converter;
}
}

#DependsOn annotation can help.
From docs:
... Used infrequently in cases where a bean does not explicitly depend on another through properties or constructor arguments, but rather depends on the side effects of another bean's initialization. ...
You can try adding #Depends("discoveryClient") to the class implementing auth-service client.
Note: I haven't tested if the bean name should be discoveryClient. Please see debug logs to see correct bean name if this doesn't work.

Related

Spring session jdbc - How to add multiple HttpSessionIdResolver for a single application

I have a problem in injecting multiple HttpSessionIdResolver for a single spring application.
For normal web application I would like to use CookieHttpSessionIdResolver
For Rest API I would go for HeaderHttpSessionIdResolver and Rest API url will be like "/api/**"
Internally spring sets a bean and uses that bean for all request(In this case HeaderHttpSessionIdResolver
and my web stopped working because i dont set X-Auth-Token header for every request) but i would like to override it.
Could any one please help me.
Thank you.
#EnableJdbcHttpSession(maxInactiveIntervalInSeconds = 3600)
public class SessionConfig extends AbstractHttpSessionApplicationInitializer{
#Autowired
#Qualifier("userDatabase")
private DataSource dataSource;
#Bean
public DataSource dataSource() {
return dataSource;
}
#Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
#Bean(value = "httpSessionIdResolver")
public HttpSessionIdResolver httpSessionIdResolver() {
return HeaderHttpSessionIdResolver.xAuthToken();
}
#Bean(value = "cookieHttpSessionIdResolver")
public HttpSessionIdResolver cookieHttpSessionIdResolver() {
return new CookieHttpSessionIdResolver();
}
}
I overridden spring session to enable both cookie and header based session.
Now it's working fine.
Currently I'm checking for URL that contains /api/* and if it contains i'm using header based other wise cookie based session.

How to Create or configure Rest Template using #Bean in Spring Boot

I want to define RestTemplate as an application bean using #Bean annotation in my configuration class in a spring boot application.
I am calling 4 rest services in different places in my application flow. Currently I am creating RestTemplate every time every request. Is there a way I can define that as application bean using #Bean and inject that using #Autowired?
Main reason for this question is I can able to define RestTemplate using #Bean but when I inject it with #Autowired I am loosing all defined interceptors (Interceptors are not getting called.)
Configuration Class
#Bean(name = "appRestClient")
public RestTemplate getRestClient() {
RestTemplate restClient = new RestTemplate(
new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory()));
List<ClientHttpRequestInterceptor> interceptors = new ArrayList<ClientHttpRequestInterceptor>();
interceptors.add(new RestServiceLoggingInterceptor());
restClient.setInterceptors(interceptors);
return restClient;
}
Service Class
public class MyServiceClass {
#Autowired
private RestTemplate appRestClient;
public String callRestService() {
// create uri, method response objects
String restResp = appRestClient.getForObject(uri, method, response);
// do something with the restResp
// return String
}
}
It seems my Interceptors are not getting called at all with this configuration. But RestTemplate is able to make a call to the REST service and get a response.
Answer for Spring boot 2.*.* version.
I am using Spring boot 2.1.2.RELEASE and I also added RestTemplate in my project in a class where mail method exists.
#Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.setConnectTimeout(Duration.ofMillis(300000))
.setReadTimeout(Duration.ofMillis(300000)).build();
}
and Used in my service or other classes like this
#Autowired
RestTemplate res;
and in methods
HttpEntity<String> entity = new HttpEntity<>(str, headers);
return res.exchange(url, HttpMethod.POST, entity, Object.class);
Judging form the name of the interceptor, I'm guessing you're doing some logging in it? You could of missed logging level configuration. I created a small application to check weather your configuration works, using 1.3.6.RELEASE version.
In this class I define the RestTemplate bean and the interceptor with logging.
package com.example;
// imports...
#SpringBootApplication
public class TestApplication {
private static final Logger LOGGER = LoggerFactory.getLogger(TestApplication.class);
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
#Bean(name = "appRestClient")
public RestTemplate getRestClient() {
RestTemplate restClient = new RestTemplate(
new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory()));
// Add one interceptor like in your example, except using anonymous class.
restClient.setInterceptors(Collections.singletonList((request, body, execution) -> {
LOGGER.debug("Intercepting...");
return execution.execute(request, body);
}));
return restClient;
}
}
For logging to work, I also have to set the correct debug level in application.properties.
logging.level.com.example=DEBUG
Then I create a service where I inject this RestTemplate.
#Service
public class SomeService {
private final RestTemplate appRestClient;
#Autowired
public SomeService(#Qualifier("appRestClient") RestTemplate appRestClient) {
this.appRestClient = appRestClient;
}
public String callRestService() {
return appRestClient.getForObject("http://localhost:8080", String.class);
}
}
And also an endpoint to test this out.
#RestController
public class SomeController {
private final SomeService service;
#Autowired
public SomeController(SomeService service) {
this.service = service;
}
#RequestMapping(value = "/", method = RequestMethod.GET)
public String testEndpoint() {
return "hello!";
}
#RequestMapping(value = "/test", method = RequestMethod.GET)
public String test() {
return service.callRestService();
}
}
By performing a GET request to http://localhost:8080/test I should expect to get the String hello! getting printed (the service makes a call to http://localhost:8080 which returns hello! and sends this back to me). The interceptor with logger also prints out Intercepting... in the console.
Edd's solution won't work if you're using Spring Boot 1.4.0 or later. You will have to use RestTemplateBuilder to get this working. Here is the example
#Bean(name="simpleRestTemplate")
#Primary
public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder){
RestTemplate template = restTemplateBuilder.requestFactory(new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory()))
.interceptors(logRestRequestInterceptor) //This is your custom interceptor bean
.messageConverters(new MappingJackson2HttpMessageConverter())
.build();
return template;
}
Now you can autowire the bean into your service class
#Autowired
#Qualifier("simpleRestTemplate")
private RestTemplate simpleRestTemplate;
Hope this helps

Spring Cloud Security Resource Server and JSON Vulnerability Protection

According to JSON Vulnerability Protection I prefix JSON responses:
#Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setJsonPrefix(")]}',\n");
return converter;
}
It works fine with AngularJS, but not with #EnableOAuth2Resource-App, because Jackson can't parse response from Authorization Server. Firthermore, I can't override
#Bean
public TokenStore jwtTokenStore() {
return new JwtTokenStore(jwtTokenEnhancer());
}
definition from org.springframework.cloud.security.oauth2.resource.ResourceServerTokenServicesConfiguration.JwtTokenServicesConfiguration to configure ObjectMapper/RestTemplate because of autoconfiguration ordering and SPR-13980.
Maybe I'm missing a solution?

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;

How to overwrite Spring Cloud OAuth2 client autoconfiguration?

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;
}
}

Resources