Out of the box, the X-B3-TraceId and X-B3-SpanId headers are not set on requests made with the OAuth2RestTemplate. The workaround for this is to add the TraceRestTemplateInterceptor to the list of OAuth2RestTemplate interceptors. Until out-of-the-box support for OAuth2RestTemplate is provided, the Spring Cloud Sleuth documentation should note that the TraceRestTemplateInterceptor must be added to the OAuth2RestTemplate.
That's actually interesting that this is not working out of the box. We already add interceptors to all RestTemplates - https://github.com/spring-cloud/spring-cloud-sleuth/blob/master/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/TraceWebClientAutoConfiguration.java#L61-L81
Do you think you could push a sample to Github of how you set up a project with the @OAuth2RestTemplate in such a way that things don't work? That way it will be easier for me to analyze what's wrong
Hi Marcin,
Sorry for the delayed response -- was out of the office. Let me see what I can get together.
Thanks!
Ping @mhuisking ?
Closing due to inactivity
@marcingrzejszczak, @mhuisking
I've faced with this issue too.
I've solved with next code:
@Bean
public UserInfoRestTemplateCustomizer userInfoRestTemplateCustomizer(
TraceRestTemplateInterceptor traceRestTemplateInterceptor) {
return restTemplate -> {
List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>(
restTemplate.getInterceptors());
interceptors.add(traceRestTemplateInterceptor);
restTemplate.setInterceptors(interceptors);
};
}
So you're saying that for some reason the TraceRestTemplateInterceptor doesn't get injected into the OAuth2RestTemplate ? That's super strange. @rwinch, @dsyer - are OAuth2RestTemplate's interceptors somehow separated from the "traditional" RestTemplate interceptors? In other words, do I have to do sth special for my custom RestTemplate interceptor to get registered in my OAuth2RestTemplate
@marcingrzejszczak,
TraceRestTemplateInterceptor works good with OAuth2RestTemplate using my solution.
So now my requests for instance client->user-service [solution added here]->auth-service to security.oauth2.resource.user-info-uri has the same X-B3-TraceId, without config only client and user-service has the same X-B3-TraceId, but auth-service different.
Yeah using your solution it works fine, but the idea was that that TraceRestTemplateInterceptor gets injected automatically - https://github.com/spring-cloud/spring-cloud-sleuth/blob/master/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/TraceWebClientAutoConfiguration.java#L63-L83 . In theory all rest templates should have it injected. For some reason it seems that the OAuth2RestTemplate is not in that collection. BTW @Triggerself could you put a breakpoint here - https://github.com/spring-cloud/spring-cloud-sleuth/blob/master/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/TraceWebClientAutoConfiguration.java#L78 and see if your OAuth2RestTemplate is there?
@marcingrzejszczak,
I see only my RestTemplate, which was configured this way:
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.build();
}
There is no OAuth2RestTemplate there.
P.S
OAuth2RestTemplate class extends RestTemplate and implements OAuth2RestOperations
That's what I suspected... Meh. @rwinch @dsyer any ideas? Maybe that OAuth2RestTemplate is created later than this interceptor injection gets executed?
@Triggerself Have you created the OAuth2RestTemplate as a bean?
@marcingrzejszczak,
No, it's created in backgroud here:
ResourceServerTokenServicesConfiguration:RemoteTokenServicesConfiguration:UserInfoTokenServicesConfiguration[constructor with constructor autowired UserInfoRestTemplateFactory restTemplateFactory] by calling restTemplateFactory.getUserInfoRestTemplate()
That's why it's not working out of the box. @dsyer suggested that, in Sleuth, we could
just provide a customizer (That's the supported extension point in Spring Boot).
UserInfoRestTemplateCustomizerworks for this precise instance (that isn't a bean)
So, at the end the issue will be solved by providing UserInfoRestTemplateCustomizer as I suggested?
Not necessarilly UserInfoRestTemplateCustomizer but some customizer. I don't know yet how to do it exactly, but that's good that you've provided a workaround for this
As far as I researched UserInfoRestTemplateCustomizer using for customizing OAuth2RestTemplate, because list of UserInfoRestTemplateCustomizer is used in DefaultUserInfoRestTemplateFactory:getUserInfoRestTemplate().
@Override
public OAuth2RestTemplate getUserInfoRestTemplate() {
if (this.oauth2RestTemplate == null) {
this.oauth2RestTemplate = createOAuth2RestTemplate(
this.details == null ? DEFAULT_RESOURCE_DETAILS : this.details);
this.oauth2RestTemplate.getInterceptors()
.add(new AcceptJsonRequestInterceptor());
AuthorizationCodeAccessTokenProvider accessTokenProvider = new AuthorizationCodeAccessTokenProvider();
accessTokenProvider.setTokenRequestEnhancer(new AcceptJsonRequestEnhancer());
this.oauth2RestTemplate.setAccessTokenProvider(accessTokenProvider);
if (!CollectionUtils.isEmpty(this.customizers)) {
AnnotationAwareOrderComparator.sort(this.customizers);
for (UserInfoRestTemplateCustomizer customizer : this.customizers) {
customizer.customize(this.oauth2RestTemplate);
}
}
}
return this.oauth2RestTemplate;
}
Most helpful comment
As far as I researched
UserInfoRestTemplateCustomizerusing for customizingOAuth2RestTemplate, because list ofUserInfoRestTemplateCustomizeris used inDefaultUserInfoRestTemplateFactory:getUserInfoRestTemplate().