diff --git a/pom.xml b/pom.xml index f86382b13..9552cc9c0 100644 --- a/pom.xml +++ b/pom.xml @@ -44,19 +44,6 @@ HEAD - - spring-cloud-sleuth-dependencies - spring-cloud-sleuth-api - spring-cloud-sleuth-instrumentation - spring-cloud-sleuth-brave - spring-cloud-sleuth-autoconfigure - tests - spring-cloud-sleuth-zipkin - spring-cloud-starter-sleuth - spring-cloud-sleuth-samples - docs - - 1.8 1.8 @@ -75,9 +62,9 @@ 2.5.1 5.13.9 0.32.0 + 2.3.4.RELEASE 2.2.0.RELEASE - 5.6.0 false 4.9.0 4.8.0 @@ -103,6 +90,19 @@ 3.2.0 + + spring-cloud-sleuth-dependencies + spring-cloud-sleuth-api + spring-cloud-sleuth-instrumentation + spring-cloud-sleuth-brave + spring-cloud-sleuth-autoconfigure + tests + spring-cloud-sleuth-zipkin + spring-cloud-starter-sleuth + spring-cloud-sleuth-samples + docs + + @@ -270,13 +270,6 @@ import pom - - org.springframework.security - spring-security-bom - ${spring-security-version} - pom - import - org.springframework.security.oauth.boot spring-security-oauth2-autoconfigure diff --git a/spring-cloud-sleuth-autoconfigure/pom.xml b/spring-cloud-sleuth-autoconfigure/pom.xml index e9dbc5c48..4cd770321 100644 --- a/spring-cloud-sleuth-autoconfigure/pom.xml +++ b/spring-cloud-sleuth-autoconfigure/pom.xml @@ -192,6 +192,11 @@ spring-security-oauth2-autoconfigure true + + org.springframework.security + spring-security-oauth2-client + true + org.springframework.vault spring-vault-core diff --git a/spring-cloud-sleuth-autoconfigure/src/main/java/org/springframework/cloud/sleuth/autoconfig/instrument/web/client/TraceWebClientAutoConfiguration.java b/spring-cloud-sleuth-autoconfigure/src/main/java/org/springframework/cloud/sleuth/autoconfig/instrument/web/client/TraceWebClientAutoConfiguration.java index 507d87116..4a79a10a6 100644 --- a/spring-cloud-sleuth-autoconfigure/src/main/java/org/springframework/cloud/sleuth/autoconfig/instrument/web/client/TraceWebClientAutoConfiguration.java +++ b/spring-cloud-sleuth-autoconfigure/src/main/java/org/springframework/cloud/sleuth/autoconfig/instrument/web/client/TraceWebClientAutoConfiguration.java @@ -18,8 +18,10 @@ package org.springframework.cloud.sleuth.autoconfig.instrument.web.client; import reactor.netty.http.client.HttpClient; +import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.ListableBeanFactory; +import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; @@ -36,6 +38,7 @@ import org.springframework.cloud.sleuth.autoconfig.brave.BraveAutoConfiguration; import org.springframework.cloud.sleuth.http.HttpClientHandler; import org.springframework.cloud.sleuth.instrument.web.client.HttpClientBeanPostProcessor; import org.springframework.cloud.sleuth.instrument.web.client.LazyTraceClientHttpRequestInterceptor; +import org.springframework.cloud.sleuth.instrument.web.client.TraceDefaultOAuth2UserServiceCustomizer; import org.springframework.cloud.sleuth.instrument.web.client.TraceRequestHttpHeadersFilter; import org.springframework.cloud.sleuth.instrument.web.client.TraceResponseHttpHeadersFilter; import org.springframework.cloud.sleuth.instrument.web.client.TraceRestTemplateBeanPostProcessor; @@ -51,6 +54,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.security.oauth2.client.OAuth2RestTemplate; +import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService; import org.springframework.web.client.RestTemplate; import org.springframework.web.reactive.function.client.WebClient; @@ -167,6 +171,7 @@ class TraceWebClientAutoConfiguration { @Configuration(proxyBeanMethods = false) @ConditionalOnClass({ UserInfoRestTemplateCustomizer.class, OAuth2RestTemplate.class }) + @Deprecated // Use Spring-Security OAuth2 support protected static class TraceOAuthConfiguration { @Bean @@ -183,4 +188,24 @@ class TraceWebClientAutoConfiguration { } + @Configuration(proxyBeanMethods = false) + @ConditionalOnClass(DefaultOAuth2UserService.class) + protected static class TraceSpringSecurityOAuth2Configuration { + + @Bean + static BeanPostProcessor traceDefaultOAuth2UserServiceBeanPostProcessor(BeanFactory beanFactory) { + return new BeanPostProcessor() { + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { + if (bean instanceof DefaultOAuth2UserService) { + new TraceDefaultOAuth2UserServiceCustomizer(beanFactory) + .customize((DefaultOAuth2UserService) bean); + } + return bean; + } + }; + } + + } + } diff --git a/spring-cloud-sleuth-instrumentation/pom.xml b/spring-cloud-sleuth-instrumentation/pom.xml index cb6429c80..e30a07dbd 100644 --- a/spring-cloud-sleuth-instrumentation/pom.xml +++ b/spring-cloud-sleuth-instrumentation/pom.xml @@ -31,7 +31,7 @@ 3.1.4-SNAPSHOT .. - + @@ -220,6 +220,11 @@ spring-security-oauth2-autoconfigure true + + org.springframework.security + spring-security-oauth2-client + true + org.springframework.session spring-session-data-redis diff --git a/spring-cloud-sleuth-instrumentation/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/TraceDefaultOAuth2UserServiceCustomizer.java b/spring-cloud-sleuth-instrumentation/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/TraceDefaultOAuth2UserServiceCustomizer.java new file mode 100644 index 000000000..336dbbd06 --- /dev/null +++ b/spring-cloud-sleuth-instrumentation/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/TraceDefaultOAuth2UserServiceCustomizer.java @@ -0,0 +1,72 @@ +/* + * Copyright 2013-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.sleuth.instrument.web.client; + +import java.lang.reflect.Field; +import java.util.Objects; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.beans.factory.BeanFactory; +import org.springframework.cloud.sleuth.instrument.web.mvc.TracingClientHttpRequestInterceptor; +import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService; +import org.springframework.util.ReflectionUtils; +import org.springframework.web.client.RestOperations; +import org.springframework.web.client.RestTemplate; + +/** + * Customizes a {@link DefaultOAuth2UserService} by providing it with a trace interceptor. + * + * @author Marcin Grzejszczak + * @since 3.0.6 + */ +public class TraceDefaultOAuth2UserServiceCustomizer { + + private static final Log log = LogFactory.getLog(TraceDefaultOAuth2UserServiceCustomizer.class); + + private final BeanFactory beanFactory; + + private static final Field REST_OPERATIONS = ReflectionUtils.findField(DefaultOAuth2UserService.class, + "restOperations", RestOperations.class); + + public TraceDefaultOAuth2UserServiceCustomizer(BeanFactory beanFactory) { + this.beanFactory = beanFactory; + } + + public void customize(DefaultOAuth2UserService service) { + try { + ReflectionUtils.makeAccessible(Objects.requireNonNull(REST_OPERATIONS, + "restOperations field was not found in [DefaultOAuth2UserService] class")); + RestOperations restOperations = (RestOperations) REST_OPERATIONS.get(service); + if (!(restOperations instanceof RestTemplate)) { + log.warn( + "Won't instrument the restOperations field in [DefaultOAuth2UserService] class because it's not a RestTemplate object"); + return; + } + RestTemplate template = (RestTemplate) restOperations; + final TracingClientHttpRequestInterceptor interceptor = this.beanFactory + .getBean(TracingClientHttpRequestInterceptor.class); + new RestTemplateInterceptorInjector(interceptor).inject(template); + } + catch (Exception e) { + log.warn("Can't access the restOperations field - won't instrument the [DefaultOAuth2UserService] class", + e); + } + } + +} diff --git a/spring-cloud-sleuth-instrumentation/src/test/java/org/springframework/cloud/sleuth/instrument/web/client/TraceDefaultOAuth2UserServiceCustomizerTests.java b/spring-cloud-sleuth-instrumentation/src/test/java/org/springframework/cloud/sleuth/instrument/web/client/TraceDefaultOAuth2UserServiceCustomizerTests.java new file mode 100644 index 000000000..e5b020bdc --- /dev/null +++ b/spring-cloud-sleuth-instrumentation/src/test/java/org/springframework/cloud/sleuth/instrument/web/client/TraceDefaultOAuth2UserServiceCustomizerTests.java @@ -0,0 +1,56 @@ +/* + * Copyright 2013-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.sleuth.instrument.web.client; + +import org.assertj.core.api.BDDAssertions; +import org.junit.jupiter.api.Test; + +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.support.StaticListableBeanFactory; +import org.springframework.cloud.sleuth.instrument.web.mvc.TracingClientHttpRequestInterceptor; +import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService; +import org.springframework.util.ReflectionUtils; +import org.springframework.web.client.RestTemplate; + +class TraceDefaultOAuth2UserServiceCustomizerTests { + + @Test + void should_add_a_trace_interceptor_to_defaultoauth2userservice() { + DefaultOAuth2UserService service = new DefaultOAuth2UserService(); + BeanFactory beanFactory = beanFactory(); + TraceDefaultOAuth2UserServiceCustomizer serviceCustomizer = new TraceDefaultOAuth2UserServiceCustomizer( + beanFactory); + + serviceCustomizer.customize(service); + serviceCustomizer.customize(service); + + Object operations = ReflectionUtils + .getField(ReflectionUtils.findField(DefaultOAuth2UserService.class, "restOperations"), service); + BDDAssertions.then(operations).isInstanceOf(RestTemplate.class); + RestTemplate restTemplate = (RestTemplate) operations; + BDDAssertions.then(restTemplate.getInterceptors()).hasSize(1) + .hasOnlyElementsOfType(TracingClientHttpRequestInterceptor.class); + } + + private BeanFactory beanFactory() { + StaticListableBeanFactory beanFactory = new StaticListableBeanFactory(); + beanFactory.addBean("TracingClientHttpRequestInterceptor", + TracingClientHttpRequestInterceptor.create(null, null)); + return beanFactory; + } + +}