From f15ca5fca98bfccde2a51040dbfb0fffced713a3 Mon Sep 17 00:00:00 2001 From: kvmw Date: Mon, 9 Nov 2026 13:16:43 +0100 Subject: [PATCH] feat(scs): also set the Spring Cloud Config 5.1 OAuth2 properties Spring Cloud Config 5.1 reads its OAuth2 settings from spring.cloud.config.oauth2.* and a Spring Security client registration, not from spring.cloud.config.client.oauth2.*. When its OAuth2 support is on the classpath, set these as well from the config-server binding. Keep the old properties for backward compatibility. Signed-off-by: kvmw --- .../boot/scs/CfConfigClientProcessor.java | 40 +++++++++++++++++++ .../CfConfigClientProcessorTest.java | 34 ++++++++++++++++ .../oauth2/ConfigClientOAuth2Properties.java | 25 ++++++++++++ 3 files changed, 99 insertions(+) create mode 100644 java-cfenv-boot-pivotal-scs/src/test/java/org/springframework/cloud/config/client/oauth2/ConfigClientOAuth2Properties.java diff --git a/java-cfenv-boot-pivotal-scs/src/main/java/io/pivotal/cfenv/boot/scs/CfConfigClientProcessor.java b/java-cfenv-boot-pivotal-scs/src/main/java/io/pivotal/cfenv/boot/scs/CfConfigClientProcessor.java index 77898c14..fa743e4c 100644 --- a/java-cfenv-boot-pivotal-scs/src/main/java/io/pivotal/cfenv/boot/scs/CfConfigClientProcessor.java +++ b/java-cfenv-boot-pivotal-scs/src/main/java/io/pivotal/cfenv/boot/scs/CfConfigClientProcessor.java @@ -17,6 +17,8 @@ import java.util.Map; +import org.springframework.util.ClassUtils; + import io.pivotal.cfenv.core.CfCredentials; import io.pivotal.cfenv.core.CfService; import io.pivotal.cfenv.spring.boot.CfEnvProcessor; @@ -25,9 +27,37 @@ /** * Sets config-client properties with values found in service bindings of a * spring-cloud-services config-server service instance. + *

+ * The {@code spring.cloud.config.client.oauth2.*} properties are always set. When the + * OAuth2 support of Spring Cloud Config 5.1 or later is on the classpath, the properties + * it reads ({@code spring.cloud.config.oauth2.*} and + * {@code spring.security.oauth2.client.*}) are set as well. */ public class CfConfigClientProcessor implements CfEnvProcessor { + static final String CONFIG_OAUTH2_CLASS = "org.springframework.cloud.config.client.oauth2.ConfigClientOAuth2Properties"; + + static final String REGISTRATION_ID = "config-server"; + + private static final String REGISTRATION_PREFIX = "spring.security.oauth2.client.registration." + REGISTRATION_ID; + + private static final String PROVIDER_PREFIX = "spring.security.oauth2.client.provider." + REGISTRATION_ID; + + private final ClassLoader classLoader; + + public CfConfigClientProcessor() { + this(null); + } + + /** + * Create a processor that looks for Spring Cloud Config OAuth2 support in the given + * class loader. + * @param classLoader the class loader to check, or {@code null} for the default one + */ + public CfConfigClientProcessor(ClassLoader classLoader) { + this.classLoader = classLoader; + } + @Override public boolean accept(CfService service) { return service.existsByTagIgnoreCase("configuration"); @@ -41,6 +71,16 @@ public void process(CfCredentials cfCredentials, Map properties) properties.put("spring.cloud.config.client.oauth2.access-token-uri", cfCredentials.getString("access_token_uri")); properties.put("spring.cloud.config.client.oauth2.scope", ""); + if (ClassUtils.isPresent(CONFIG_OAUTH2_CLASS, this.classLoader)) { + properties.put("spring.cloud.config.oauth2.enabled", "true"); + properties.put("spring.cloud.config.oauth2.client-registration-id", REGISTRATION_ID); + properties.put(REGISTRATION_PREFIX + ".client-id", cfCredentials.getString("client_id")); + properties.put(REGISTRATION_PREFIX + ".client-secret", cfCredentials.getString("client_secret")); + properties.put(REGISTRATION_PREFIX + ".authorization-grant-type", "client_credentials"); + properties.put(REGISTRATION_PREFIX + ".provider", REGISTRATION_ID); + properties.put(PROVIDER_PREFIX + ".token-uri", cfCredentials.getString("access_token_uri")); + } + properties.put("spring.cloud.refresh.additional-property-sources-to-retain", this.getClass().getSimpleName()); } diff --git a/java-cfenv-boot-pivotal-scs/src/test/java/io/pivotal/cfenv/boot/scs/serviceregistry/CfConfigClientProcessorTest.java b/java-cfenv-boot-pivotal-scs/src/test/java/io/pivotal/cfenv/boot/scs/serviceregistry/CfConfigClientProcessorTest.java index 4a23151d..0199bc4a 100644 --- a/java-cfenv-boot-pivotal-scs/src/test/java/io/pivotal/cfenv/boot/scs/serviceregistry/CfConfigClientProcessorTest.java +++ b/java-cfenv-boot-pivotal-scs/src/test/java/io/pivotal/cfenv/boot/scs/serviceregistry/CfConfigClientProcessorTest.java @@ -27,6 +27,8 @@ import org.mockito.junit.jupiter.MockitoSettings; import org.mockito.quality.Strictness; +import org.springframework.boot.test.context.FilteredClassLoader; + import io.pivotal.cfenv.boot.scs.CfConfigClientProcessor; import io.pivotal.cfenv.core.CfCredentials; import io.pivotal.cfenv.core.CfService; @@ -98,4 +100,36 @@ public void shouldRetainThePropertiesDuringRefresh() { assertThat(properties.get("spring.cloud.refresh.additional-property-sources-to-retain")) .isEqualTo("CfConfigClientProcessor"); } + + @Test + public void shouldSetTheConfigOAuth2PropertiesWhenSupported() { + Map properties = new HashMap<>(); + + new CfConfigClientProcessor(getClass().getClassLoader()).process(cfCredentials, properties); + + assertThat(properties.get("spring.cloud.config.oauth2.enabled")).isEqualTo("true"); + assertThat(properties.get("spring.cloud.config.oauth2.client-registration-id")).isEqualTo("config-server"); + assertThat(properties.get("spring.security.oauth2.client.registration.config-server.client-id")) + .isEqualTo(CLIENT_ID); + assertThat(properties.get("spring.security.oauth2.client.registration.config-server.client-secret")) + .isEqualTo(CLIENT_SECRET); + assertThat(properties.get("spring.security.oauth2.client.registration.config-server.authorization-grant-type")) + .isEqualTo("client_credentials"); + assertThat(properties.get("spring.security.oauth2.client.provider.config-server.token-uri")) + .isEqualTo(ACCESS_TOKEN_URI); + assertThat(properties.get("spring.cloud.config.client.oauth2.client-id")).isEqualTo(CLIENT_ID); + } + + @Test + public void shouldNotSetTheConfigOAuth2PropertiesWithoutSupport() { + Map properties = new HashMap<>(); + ClassLoader withoutConfigOAuth2 = new FilteredClassLoader("org.springframework.cloud.config.client"); + + new CfConfigClientProcessor(withoutConfigOAuth2).process(cfCredentials, properties); + + assertThat(properties.keySet()).noneMatch(key -> key.startsWith("spring.cloud.config.oauth2.") + || key.startsWith("spring.security.oauth2.client.")); + assertThat(properties.get("spring.cloud.config.client.oauth2.client-id")).isEqualTo(CLIENT_ID); + assertThat(properties.get("spring.cloud.config.uri")).isEqualTo(URI); + } } diff --git a/java-cfenv-boot-pivotal-scs/src/test/java/org/springframework/cloud/config/client/oauth2/ConfigClientOAuth2Properties.java b/java-cfenv-boot-pivotal-scs/src/test/java/org/springframework/cloud/config/client/oauth2/ConfigClientOAuth2Properties.java new file mode 100644 index 00000000..fbc10ae6 --- /dev/null +++ b/java-cfenv-boot-pivotal-scs/src/test/java/org/springframework/cloud/config/client/oauth2/ConfigClientOAuth2Properties.java @@ -0,0 +1,25 @@ +/* + * Copyright 2026 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.config.client.oauth2; + +/** + * Stand-in for the class of Spring Cloud Config 5.1 that + * {@code CfConfigClientProcessor} looks for, so the tests do not need Spring Cloud + * Config on the classpath. + */ +public class ConfigClientOAuth2Properties { + +}