From 7237905ad8dadc1dd4d125719da526e53555b2bf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Apr 2026 06:55:59 +0000 Subject: [PATCH 1/9] Initial plan From 6ccc847d25617dd6467d4c8667411c85f9d42a86 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Apr 2026 07:39:01 +0000 Subject: [PATCH 2/9] Fix azure.scopes wrong value when cloud-type=azure_china or azure_us_government Agent-Logs-Url: https://github.com/Azure/azure-sdk-for-java/sessions/5f56cd61-af29-4585-a48b-d7bc109977a6 Co-authored-by: rujche <171773178+rujche@users.noreply.github.com> --- .../CHANGELOG.md | 2 + .../AzureJdbcPasswordlessProperties.java | 36 +++++++++++++++- .../JdbcPropertiesBeanPostProcessorTest.java | 30 +++++++++++++- .../MergeAzureCommonPropertiesTest.java | 41 +++++++++++++++++++ .../spring-cloud-azure-core/CHANGELOG.md | 2 + .../AzurePasswordlessPropertiesUtils.java | 4 +- 6 files changed, 112 insertions(+), 3 deletions(-) diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/CHANGELOG.md b/sdk/spring/spring-cloud-azure-autoconfigure/CHANGELOG.md index 68068a92722e..e766e36a38f1 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/CHANGELOG.md +++ b/sdk/spring/spring-cloud-azure-autoconfigure/CHANGELOG.md @@ -8,6 +8,8 @@ ### Bugs Fixed +- Fixed `azure.scopes` using wrong default value for Azure China and Azure US Government when `spring.cloud.azure.profile.cloud-type` is set to `azure_china` or `azure_us_government`. The scopes are now correctly derived from the merged cloud type. ([#44945](https://github.com/Azure/azure-sdk-for-java/issues/44945)) + ### Other Changes ## 7.1.0 (2026-03-11) diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/passwordless/properties/AzureJdbcPasswordlessProperties.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/passwordless/properties/AzureJdbcPasswordlessProperties.java index f9951793aad1..1297ffbe9f45 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/passwordless/properties/AzureJdbcPasswordlessProperties.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/passwordless/properties/AzureJdbcPasswordlessProperties.java @@ -3,12 +3,14 @@ package com.azure.spring.cloud.autoconfigure.implementation.passwordless.properties; +import com.azure.spring.cloud.core.implementation.properties.AzurePasswordlessPropertiesMapping; import com.azure.spring.cloud.core.properties.PasswordlessProperties; import com.azure.spring.cloud.core.properties.authentication.TokenCredentialProperties; import com.azure.spring.cloud.core.properties.profile.AzureProfileProperties; import java.util.HashMap; import java.util.Map; +import java.util.Properties; /** * Configuration properties for passwordless connections with Azure Database. @@ -43,11 +45,22 @@ public class AzureJdbcPasswordlessProperties implements PasswordlessProperties { /** * Get the scopes required for the access token. + * Returns null if scopes have not been explicitly set, so that the default + * scopes can be computed from the merged cloud type after property merging. * - * @return scopes required for the access token + * @return scopes required for the access token, or null if not explicitly set */ @Override public String getScopes() { + return this.scopes; + } + + /** + * Get the effective scopes, returning default cloud-specific scopes when not explicitly set. + * + * @return scopes required for the access token + */ + public String getEffectiveScopes() { return this.scopes == null ? getDefaultScopes() : this.scopes; } @@ -120,4 +133,25 @@ public TokenCredentialProperties getCredential() { public void setCredential(TokenCredentialProperties credential) { this.credential = credential; } + + /** + * Convert {@link AzureJdbcPasswordlessProperties} to {@link Properties}. + * Uses the effective scopes (cloud-type-aware) rather than the raw scopes value, + * ensuring the correct default scope is used when scopes have not been explicitly set. + * + * @return converted {@link Properties} instance + */ + @Override + public Properties toPasswordlessProperties() { + Properties properties = new Properties(); + for (AzurePasswordlessPropertiesMapping m : AzurePasswordlessPropertiesMapping.values()) { + String value = m == AzurePasswordlessPropertiesMapping.SCOPES + ? getEffectiveScopes() + : m.getGetter().apply(this); + if (value != null) { + m.getSetter().accept(properties, value); + } + } + return properties; + } } diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessorTest.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessorTest.java index f32493eba87a..385299aac131 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessorTest.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessorTest.java @@ -39,11 +39,14 @@ class JdbcPropertiesBeanPostProcessorTest { private static final String POSTGRESQL_CONNECTION_STRING = "jdbc:postgresql://host/database?enableSwitch1&property1=value1"; private static final String PASSWORD = "password"; private static final String US_AUTHORITY_HOST_STRING = AuthProperty.AUTHORITY_HOST.getPropertyKey() + "=" + "https://login.microsoftonline.us/"; + private static final String CHINA_AUTHORITY_HOST_STRING = AuthProperty.AUTHORITY_HOST.getPropertyKey() + "=" + "https://login.chinacloudapi.cn/"; public static final String PUBLIC_TOKEN_CREDENTIAL_BEAN_NAME_STRING = AuthProperty.TOKEN_CREDENTIAL_BEAN_NAME.getPropertyKey() + "="; private static final String POSTGRESQL_ASSUME_MIN_SERVER_VERSION = POSTGRESQL_PROPERTY_NAME_ASSUME_MIN_SERVER_VERSION + "=" + POSTGRESQL_PROPERTY_VALUE_ASSUME_MIN_SERVER_VERSION; protected static final String MANAGED_IDENTITY_ENABLED_DEFAULT = "azure.managedIdentityEnabled=false"; protected static final String SCOPES_DEFAULT = "azure.scopes=https://ossrdbms-aad.database.windows.net/.default"; + private static final String SCOPES_CHINA = "azure.scopes=https://ossrdbms-aad.database.chinacloudapi.cn/.default"; + private static final String SCOPES_US_GOVERNMENT = "azure.scopes=https://ossrdbms-aad.database.usgovcloudapi.net/.default"; private static final String DEFAULT_PASSWORDLESS_PROPERTIES_SUFFIX = ".spring.datasource.azure"; private MockEnvironment mockEnvironment; @@ -153,7 +156,7 @@ void shouldGetCloudTypeFromAzureUsGov() { DatabaseType.MYSQL, MYSQL_CONNECTION_STRING, MANAGED_IDENTITY_ENABLED_DEFAULT, - SCOPES_DEFAULT, + SCOPES_US_GOVERNMENT, MYSQL_USER_AGENT, US_AUTHORITY_HOST_STRING ); @@ -161,6 +164,31 @@ void shouldGetCloudTypeFromAzureUsGov() { assertEquals(expectedJdbcUrl, dataSourceProperties.getUrl()); } + @Test + void shouldGetCorrectScopeFromAzureChina() { + AzureProfileConfigurationProperties azureProfileConfigurationProperties = new AzureProfileConfigurationProperties(); + azureProfileConfigurationProperties.setCloudType(AzureProfileOptionsProvider.CloudType.AZURE_CHINA); + when(this.azureGlobalProperties.getProfile()).thenReturn(azureProfileConfigurationProperties); + + DataSourceProperties dataSourceProperties = new DataSourceProperties(); + dataSourceProperties.setUrl(POSTGRESQL_CONNECTION_STRING); + + this.mockEnvironment.setProperty("spring.datasource.azure.passwordless-enabled", "true"); + this.jdbcPropertiesBeanPostProcessor.postProcessBeforeInitialization(dataSourceProperties, "dataSourceProperties"); + + String expectedJdbcUrl = enhanceJdbcUrl( + DatabaseType.POSTGRESQL, + POSTGRESQL_CONNECTION_STRING, + MANAGED_IDENTITY_ENABLED_DEFAULT, + SCOPES_CHINA, + APPLICATION_NAME.getName() + "=" + AzureSpringIdentifier.AZURE_SPRING_POSTGRESQL_OAUTH, + POSTGRESQL_ASSUME_MIN_SERVER_VERSION, + CHINA_AUTHORITY_HOST_STRING + ); + + assertEquals(expectedJdbcUrl, dataSourceProperties.getUrl()); + } + @Test void mySqlUserAgentShouldConfigureIfConnectionAttributesIsEmpty() { DataSourceProperties dataSourceProperties = new DataSourceProperties(); diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/passwordless/MergeAzureCommonPropertiesTest.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/passwordless/MergeAzureCommonPropertiesTest.java index 56a9b5666059..edecabfbb183 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/passwordless/MergeAzureCommonPropertiesTest.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/passwordless/MergeAzureCommonPropertiesTest.java @@ -5,11 +5,13 @@ import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; import com.azure.spring.cloud.autoconfigure.implementation.jms.properties.AzureServiceBusJmsProperties; +import com.azure.spring.cloud.autoconfigure.implementation.passwordless.properties.AzureJdbcPasswordlessProperties; import com.azure.spring.cloud.core.implementation.util.AzurePasswordlessPropertiesUtils; import com.azure.spring.cloud.core.provider.AzureProfileOptionsProvider; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; class MergeAzureCommonPropertiesTest { @@ -116,4 +118,43 @@ void testGetPropertiesFromGlobalAndPasswordlessProperties() { assertEquals("sub", result.getProfile().getSubscriptionId()); assertEquals("global-tenant-id", result.getProfile().getTenantId()); } + + @Test + void testJdbcPropertiesGetCorrectScopeFromGlobalCloudType() { + AzureGlobalProperties globalProperties = new AzureGlobalProperties(); + globalProperties.getProfile().setCloudType(AzureProfileOptionsProvider.CloudType.AZURE_CHINA); + + AzureJdbcPasswordlessProperties jdbcProperties = new AzureJdbcPasswordlessProperties(); + // User has not explicitly set scopes + + AzureJdbcPasswordlessProperties result = new AzureJdbcPasswordlessProperties(); + AzurePasswordlessPropertiesUtils.mergeAzureCommonProperties(globalProperties, jdbcProperties, result); + + // scopes field should be null (not explicitly set) + assertNull(result.getScopes()); + // effective scopes should use the merged cloud type (AZURE_CHINA) + assertEquals("https://ossrdbms-aad.database.chinacloudapi.cn/.default", result.getEffectiveScopes()); + // toPasswordlessProperties should include the correct cloud-type-aware scope + assertEquals("https://ossrdbms-aad.database.chinacloudapi.cn/.default", + result.toPasswordlessProperties().getProperty("azure.scopes")); + assertEquals(AzureProfileOptionsProvider.CloudType.AZURE_CHINA, result.getProfile().getCloudType()); + } + + @Test + void testJdbcPropertiesExplicitScopesOverridesDefault() { + AzureGlobalProperties globalProperties = new AzureGlobalProperties(); + globalProperties.getProfile().setCloudType(AzureProfileOptionsProvider.CloudType.AZURE_CHINA); + + AzureJdbcPasswordlessProperties jdbcProperties = new AzureJdbcPasswordlessProperties(); + jdbcProperties.setScopes("https://custom-scope/.default"); + + AzureJdbcPasswordlessProperties result = new AzureJdbcPasswordlessProperties(); + AzurePasswordlessPropertiesUtils.mergeAzureCommonProperties(globalProperties, jdbcProperties, result); + + // Explicit scopes should be preserved + assertEquals("https://custom-scope/.default", result.getScopes()); + assertEquals("https://custom-scope/.default", result.getEffectiveScopes()); + assertEquals("https://custom-scope/.default", + result.toPasswordlessProperties().getProperty("azure.scopes")); + } } diff --git a/sdk/spring/spring-cloud-azure-core/CHANGELOG.md b/sdk/spring/spring-cloud-azure-core/CHANGELOG.md index 68068a92722e..8c79fe46f0d5 100644 --- a/sdk/spring/spring-cloud-azure-core/CHANGELOG.md +++ b/sdk/spring/spring-cloud-azure-core/CHANGELOG.md @@ -8,6 +8,8 @@ ### Bugs Fixed +- Fixed `copyAzureCommonPropertiesIgnoreNull` to respect "ignore null" semantics for `scopes` property, preventing incorrect scope overwriting during property merging. + ### Other Changes ## 7.1.0 (2026-03-11) diff --git a/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/util/AzurePasswordlessPropertiesUtils.java b/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/util/AzurePasswordlessPropertiesUtils.java index 6af576a029d8..43896433dbce 100644 --- a/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/util/AzurePasswordlessPropertiesUtils.java +++ b/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/util/AzurePasswordlessPropertiesUtils.java @@ -51,7 +51,9 @@ public static void copyAzureCommonPropertiesI copyPropertiesIgnoreNull(source.getProfile().getEnvironment(), target.getProfile().getEnvironment()); copyPropertiesIgnoreNull(source.getCredential(), target.getCredential()); - target.setScopes(source.getScopes()); + if (source.getScopes() != null) { + target.setScopes(source.getScopes()); + } target.setPasswordlessEnabled(source.isPasswordlessEnabled()); } From f56b6ba434f1af5a8cb83a191fe0afaa6ae040fc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Apr 2026 08:01:59 +0000 Subject: [PATCH 3/9] Fix issue number in CHANGELOG to #47096 Agent-Logs-Url: https://github.com/Azure/azure-sdk-for-java/sessions/2f82f4f9-ea2e-46a7-a2fc-062b403c19bd Co-authored-by: rujche <171773178+rujche@users.noreply.github.com> --- sdk/spring/spring-cloud-azure-autoconfigure/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/CHANGELOG.md b/sdk/spring/spring-cloud-azure-autoconfigure/CHANGELOG.md index e766e36a38f1..09f28728e3ea 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/CHANGELOG.md +++ b/sdk/spring/spring-cloud-azure-autoconfigure/CHANGELOG.md @@ -8,7 +8,7 @@ ### Bugs Fixed -- Fixed `azure.scopes` using wrong default value for Azure China and Azure US Government when `spring.cloud.azure.profile.cloud-type` is set to `azure_china` or `azure_us_government`. The scopes are now correctly derived from the merged cloud type. ([#44945](https://github.com/Azure/azure-sdk-for-java/issues/44945)) +- Fixed `azure.scopes` using wrong default value for Azure China and Azure US Government when `spring.cloud.azure.profile.cloud-type` is set to `azure_china` or `azure_us_government`. The scopes are now correctly derived from the merged cloud type. ([#47096](https://github.com/Azure/azure-sdk-for-java/issues/47096)) ### Other Changes From c49ccba218a7694b58c7aed2ff739d643f422947 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 22 Apr 2026 08:31:20 +0000 Subject: [PATCH 4/9] Move CHANGELOG entries to sdk/spring/CHANGELOG.md only per project convention Agent-Logs-Url: https://github.com/Azure/azure-sdk-for-java/sessions/177be99d-3645-4a73-a56c-753ad743f82b Co-authored-by: rujche <171773178+rujche@users.noreply.github.com> --- sdk/spring/CHANGELOG.md | 8 ++++++++ sdk/spring/spring-cloud-azure-autoconfigure/CHANGELOG.md | 2 -- sdk/spring/spring-cloud-azure-core/CHANGELOG.md | 2 -- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/sdk/spring/CHANGELOG.md b/sdk/spring/CHANGELOG.md index 0b4880086cf9..ce88047f5e2d 100644 --- a/sdk/spring/CHANGELOG.md +++ b/sdk/spring/CHANGELOG.md @@ -7,6 +7,14 @@ ### Bugs Fixed +### Spring Cloud Azure Autoconfigure + +This section includes changes in `spring-cloud-azure-autoconfigure` module. + +#### Bugs Fixed + +- Fixed `azure.scopes` using wrong default value for Azure China and Azure US Government when `spring.cloud.azure.profile.cloud-type` is set to `azure_china` or `azure_us_government`. The scopes are now correctly derived from the merged cloud type. ([#47096](https://github.com/Azure/azure-sdk-for-java/issues/47096)) + ### Other Changes ## 7.2.0 (2026-04-17) diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/CHANGELOG.md b/sdk/spring/spring-cloud-azure-autoconfigure/CHANGELOG.md index dd2bc0ba8816..a24aab13fece 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/CHANGELOG.md +++ b/sdk/spring/spring-cloud-azure-autoconfigure/CHANGELOG.md @@ -8,8 +8,6 @@ ### Bugs Fixed -- Fixed `azure.scopes` using wrong default value for Azure China and Azure US Government when `spring.cloud.azure.profile.cloud-type` is set to `azure_china` or `azure_us_government`. The scopes are now correctly derived from the merged cloud type. ([#47096](https://github.com/Azure/azure-sdk-for-java/issues/47096)) - ### Other Changes ## 7.2.0 (2026-04-17) diff --git a/sdk/spring/spring-cloud-azure-core/CHANGELOG.md b/sdk/spring/spring-cloud-azure-core/CHANGELOG.md index 67ddc58beeb5..a24aab13fece 100644 --- a/sdk/spring/spring-cloud-azure-core/CHANGELOG.md +++ b/sdk/spring/spring-cloud-azure-core/CHANGELOG.md @@ -8,8 +8,6 @@ ### Bugs Fixed -- Fixed `copyAzureCommonPropertiesIgnoreNull` to respect "ignore null" semantics for `scopes` property, preventing incorrect scope overwriting during property merging. - ### Other Changes ## 7.2.0 (2026-04-17) From cc3ef95d236f717cde80e290f5fee0937df640cf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 22 Apr 2026 08:38:28 +0000 Subject: [PATCH 5/9] Apply PR review suggestions: cache getScopes(), use AuthProperty constant, rename test method Agent-Logs-Url: https://github.com/Azure/azure-sdk-for-java/sessions/e12bfcb2-e753-484c-9f60-d4bd0aabc999 Co-authored-by: rujche <171773178+rujche@users.noreply.github.com> --- .../passwordless/MergeAzureCommonPropertiesTest.java | 7 ++++--- .../util/AzurePasswordlessPropertiesUtils.java | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/passwordless/MergeAzureCommonPropertiesTest.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/passwordless/MergeAzureCommonPropertiesTest.java index edecabfbb183..9759374eced5 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/passwordless/MergeAzureCommonPropertiesTest.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/passwordless/MergeAzureCommonPropertiesTest.java @@ -8,6 +8,7 @@ import com.azure.spring.cloud.autoconfigure.implementation.passwordless.properties.AzureJdbcPasswordlessProperties; import com.azure.spring.cloud.core.implementation.util.AzurePasswordlessPropertiesUtils; import com.azure.spring.cloud.core.provider.AzureProfileOptionsProvider; +import com.azure.identity.extensions.implementation.enums.AuthProperty; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -120,7 +121,7 @@ void testGetPropertiesFromGlobalAndPasswordlessProperties() { } @Test - void testJdbcPropertiesGetCorrectScopeFromGlobalCloudType() { + void testJdbcPropertiesGetCorrectScopeFromChinaCloudTypeInGlobalProperties() { AzureGlobalProperties globalProperties = new AzureGlobalProperties(); globalProperties.getProfile().setCloudType(AzureProfileOptionsProvider.CloudType.AZURE_CHINA); @@ -136,7 +137,7 @@ void testJdbcPropertiesGetCorrectScopeFromGlobalCloudType() { assertEquals("https://ossrdbms-aad.database.chinacloudapi.cn/.default", result.getEffectiveScopes()); // toPasswordlessProperties should include the correct cloud-type-aware scope assertEquals("https://ossrdbms-aad.database.chinacloudapi.cn/.default", - result.toPasswordlessProperties().getProperty("azure.scopes")); + result.toPasswordlessProperties().getProperty(AuthProperty.SCOPES.getPropertyKey())); assertEquals(AzureProfileOptionsProvider.CloudType.AZURE_CHINA, result.getProfile().getCloudType()); } @@ -155,6 +156,6 @@ void testJdbcPropertiesExplicitScopesOverridesDefault() { assertEquals("https://custom-scope/.default", result.getScopes()); assertEquals("https://custom-scope/.default", result.getEffectiveScopes()); assertEquals("https://custom-scope/.default", - result.toPasswordlessProperties().getProperty("azure.scopes")); + result.toPasswordlessProperties().getProperty(AuthProperty.SCOPES.getPropertyKey())); } } diff --git a/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/util/AzurePasswordlessPropertiesUtils.java b/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/util/AzurePasswordlessPropertiesUtils.java index 43896433dbce..be0ad39cfd8f 100644 --- a/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/util/AzurePasswordlessPropertiesUtils.java +++ b/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/util/AzurePasswordlessPropertiesUtils.java @@ -51,8 +51,9 @@ public static void copyAzureCommonPropertiesI copyPropertiesIgnoreNull(source.getProfile().getEnvironment(), target.getProfile().getEnvironment()); copyPropertiesIgnoreNull(source.getCredential(), target.getCredential()); - if (source.getScopes() != null) { - target.setScopes(source.getScopes()); + String[] scopes = source.getScopes(); + if (scopes != null) { + target.setScopes(scopes); } target.setPasswordlessEnabled(source.isPasswordlessEnabled()); } From 26c3b7737c3960675666e68820c42e164ea9c3ea Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 23 Apr 2026 02:42:53 +0000 Subject: [PATCH 6/9] =?UTF-8?q?Fix=20String[]=20=E2=86=92=20String=20type?= =?UTF-8?q?=20for=20scopes=20variable=20and=20use=20AuthProperty.SCOPES.ge?= =?UTF-8?q?tPropertyKey()=20in=20test=20constants?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Agent-Logs-Url: https://github.com/Azure/azure-sdk-for-java/sessions/12207d29-e188-4b4e-b9bf-f2360f7f01b4 Co-authored-by: rujche <171773178+rujche@users.noreply.github.com> --- .../jdbc/JdbcPropertiesBeanPostProcessorTest.java | 9 ++++++--- .../util/AzurePasswordlessPropertiesUtils.java | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessorTest.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessorTest.java index 385299aac131..a853868bdcbd 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessorTest.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessorTest.java @@ -44,9 +44,12 @@ class JdbcPropertiesBeanPostProcessorTest { private static final String POSTGRESQL_ASSUME_MIN_SERVER_VERSION = POSTGRESQL_PROPERTY_NAME_ASSUME_MIN_SERVER_VERSION + "=" + POSTGRESQL_PROPERTY_VALUE_ASSUME_MIN_SERVER_VERSION; protected static final String MANAGED_IDENTITY_ENABLED_DEFAULT = "azure.managedIdentityEnabled=false"; - protected static final String SCOPES_DEFAULT = "azure.scopes=https://ossrdbms-aad.database.windows.net/.default"; - private static final String SCOPES_CHINA = "azure.scopes=https://ossrdbms-aad.database.chinacloudapi.cn/.default"; - private static final String SCOPES_US_GOVERNMENT = "azure.scopes=https://ossrdbms-aad.database.usgovcloudapi.net/.default"; + protected static final String SCOPES_DEFAULT = AuthProperty.SCOPES.getPropertyKey() + "=" + + "https://ossrdbms-aad.database.windows.net/.default"; + private static final String SCOPES_CHINA = AuthProperty.SCOPES.getPropertyKey() + "=" + + "https://ossrdbms-aad.database.chinacloudapi.cn/.default"; + private static final String SCOPES_US_GOVERNMENT = AuthProperty.SCOPES.getPropertyKey() + "=" + + "https://ossrdbms-aad.database.usgovcloudapi.net/.default"; private static final String DEFAULT_PASSWORDLESS_PROPERTIES_SUFFIX = ".spring.datasource.azure"; private MockEnvironment mockEnvironment; diff --git a/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/util/AzurePasswordlessPropertiesUtils.java b/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/util/AzurePasswordlessPropertiesUtils.java index be0ad39cfd8f..ee14ea503ada 100644 --- a/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/util/AzurePasswordlessPropertiesUtils.java +++ b/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/util/AzurePasswordlessPropertiesUtils.java @@ -51,7 +51,7 @@ public static void copyAzureCommonPropertiesI copyPropertiesIgnoreNull(source.getProfile().getEnvironment(), target.getProfile().getEnvironment()); copyPropertiesIgnoreNull(source.getCredential(), target.getCredential()); - String[] scopes = source.getScopes(); + String scopes = source.getScopes(); if (scopes != null) { target.setScopes(scopes); } From 011a9325ca958ea4b60c0657f43c8760d812dfab Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 23 Apr 2026 03:03:28 +0000 Subject: [PATCH 7/9] Fix CHANGELOG structure: drop empty top-level sections, follow module-section pattern Agent-Logs-Url: https://github.com/Azure/azure-sdk-for-java/sessions/59374aea-7b8d-4f93-8ead-643620e36c89 Co-authored-by: rujche <171773178+rujche@users.noreply.github.com> --- sdk/spring/CHANGELOG.md | 8 -------- 1 file changed, 8 deletions(-) diff --git a/sdk/spring/CHANGELOG.md b/sdk/spring/CHANGELOG.md index ce88047f5e2d..fa40b7644e0b 100644 --- a/sdk/spring/CHANGELOG.md +++ b/sdk/spring/CHANGELOG.md @@ -1,12 +1,6 @@ # Release History ## 7.3.0-beta.1 (Unreleased) -### Features Added - -### Breaking Changes - -### Bugs Fixed - ### Spring Cloud Azure Autoconfigure This section includes changes in `spring-cloud-azure-autoconfigure` module. @@ -15,8 +9,6 @@ This section includes changes in `spring-cloud-azure-autoconfigure` module. - Fixed `azure.scopes` using wrong default value for Azure China and Azure US Government when `spring.cloud.azure.profile.cloud-type` is set to `azure_china` or `azure_us_government`. The scopes are now correctly derived from the merged cloud type. ([#47096](https://github.com/Azure/azure-sdk-for-java/issues/47096)) -### Other Changes - ## 7.2.0 (2026-04-17) - This release is compatible with Spring Boot 4.0.0-4.0.5. (Note: 4.0.x (x>5) should be supported, but they aren't tested with this release.) - This release is compatible with Spring Cloud 2025.1.0-2025.1.1. (Note: 2025.1.x (x>1) should be supported, but they aren't tested with this release.) From 29192351d1fedeba1f152bdd58b3340e3e5b8000 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 23 Apr 2026 06:01:53 +0000 Subject: [PATCH 8/9] Align AzureRedisPasswordlessProperties with JDBC raw/effective scopes pattern; clarify CHANGELOG entry Agent-Logs-Url: https://github.com/Azure/azure-sdk-for-java/sessions/bdd4ce6e-14e3-4a50-92e0-608069e8c44c Co-authored-by: rujche <171773178+rujche@users.noreply.github.com> --- sdk/spring/CHANGELOG.md | 2 +- .../AzureRedisPasswordlessProperties.java | 36 ++++++++++++++++++- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/sdk/spring/CHANGELOG.md b/sdk/spring/CHANGELOG.md index fa40b7644e0b..d6e4a7131362 100644 --- a/sdk/spring/CHANGELOG.md +++ b/sdk/spring/CHANGELOG.md @@ -7,7 +7,7 @@ This section includes changes in `spring-cloud-azure-autoconfigure` module. #### Bugs Fixed -- Fixed `azure.scopes` using wrong default value for Azure China and Azure US Government when `spring.cloud.azure.profile.cloud-type` is set to `azure_china` or `azure_us_government`. The scopes are now correctly derived from the merged cloud type. ([#47096](https://github.com/Azure/azure-sdk-for-java/issues/47096)) +- Fixed JDBC/Azure Database passwordless connection scope defaulting using the wrong `azure.scopes` value for Azure China and Azure US Government when `spring.cloud.azure.profile.cloud-type` is set to `azure_china` or `azure_us_government`. The scopes are now correctly derived from the merged cloud type. ([#47096](https://github.com/Azure/azure-sdk-for-java/issues/47096)) ## 7.2.0 (2026-04-17) - This release is compatible with Spring Boot 4.0.0-4.0.5. (Note: 4.0.x (x>5) should be supported, but they aren't tested with this release.) diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/passwordless/properties/AzureRedisPasswordlessProperties.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/passwordless/properties/AzureRedisPasswordlessProperties.java index 15a766263b48..4f60b66d938a 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/passwordless/properties/AzureRedisPasswordlessProperties.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/passwordless/properties/AzureRedisPasswordlessProperties.java @@ -3,6 +3,7 @@ package com.azure.spring.cloud.autoconfigure.implementation.passwordless.properties; +import com.azure.spring.cloud.core.implementation.properties.AzurePasswordlessPropertiesMapping; import com.azure.spring.cloud.core.properties.PasswordlessProperties; import com.azure.spring.cloud.core.properties.authentication.TokenCredentialProperties; import com.azure.spring.cloud.core.properties.profile.AzureProfileProperties; @@ -10,6 +11,7 @@ import java.util.HashMap; import java.util.Map; +import java.util.Properties; /** * Configuration properties for passwordless connections with Azure Redis. @@ -43,11 +45,22 @@ public class AzureRedisPasswordlessProperties implements PasswordlessProperties /** * Get the scopes required for the access token. + * Returns null if scopes have not been explicitly set, so that the default + * scopes can be computed from the merged cloud type after property merging. * - * @return scopes required for the access token + * @return scopes required for the access token, or null if not explicitly set */ @Override public String getScopes() { + return this.scopes; + } + + /** + * Get the effective scopes, returning default cloud-specific scopes when not explicitly set. + * + * @return scopes required for the access token + */ + public String getEffectiveScopes() { return this.scopes == null ? getDefaultScopes() : this.scopes; } @@ -121,4 +134,25 @@ public TokenCredentialProperties getCredential() { public void setCredential(TokenCredentialProperties credential) { this.credential = credential; } + + /** + * Convert {@link AzureRedisPasswordlessProperties} to {@link Properties}. + * Uses the effective scopes (cloud-type-aware) rather than the raw scopes value, + * ensuring the correct default scope is used when scopes have not been explicitly set. + * + * @return converted {@link Properties} instance + */ + @Override + public Properties toPasswordlessProperties() { + Properties properties = new Properties(); + for (AzurePasswordlessPropertiesMapping m : AzurePasswordlessPropertiesMapping.values()) { + String value = m == AzurePasswordlessPropertiesMapping.SCOPES + ? getEffectiveScopes() + : m.getGetter().apply(this); + if (value != null) { + m.getSetter().accept(properties, value); + } + } + return properties; + } } From 35a158add85ca6788fddc50be3968215e6717fa6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 24 Apr 2026 00:18:52 +0000 Subject: [PATCH 9/9] Update CHANGELOG to mention Redis; add Redis cloud-type scope tests Agent-Logs-Url: https://github.com/Azure/azure-sdk-for-java/sessions/40b2a63f-fac7-442b-a70a-f33b4e2a67a3 Co-authored-by: rujche <171773178+rujche@users.noreply.github.com> --- sdk/spring/CHANGELOG.md | 2 +- .../MergeAzureCommonPropertiesTest.java | 61 +++++++++++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/sdk/spring/CHANGELOG.md b/sdk/spring/CHANGELOG.md index d6e4a7131362..19b5398d7261 100644 --- a/sdk/spring/CHANGELOG.md +++ b/sdk/spring/CHANGELOG.md @@ -7,7 +7,7 @@ This section includes changes in `spring-cloud-azure-autoconfigure` module. #### Bugs Fixed -- Fixed JDBC/Azure Database passwordless connection scope defaulting using the wrong `azure.scopes` value for Azure China and Azure US Government when `spring.cloud.azure.profile.cloud-type` is set to `azure_china` or `azure_us_government`. The scopes are now correctly derived from the merged cloud type. ([#47096](https://github.com/Azure/azure-sdk-for-java/issues/47096)) +- Fixed JDBC/Azure Database and Redis passwordless connection scope defaulting using the wrong `azure.scopes` value for Azure China and Azure US Government when `spring.cloud.azure.profile.cloud-type` is set to `azure_china` or `azure_us_government`. The scopes are now correctly derived from the merged cloud type. ([#47096](https://github.com/Azure/azure-sdk-for-java/issues/47096)) ## 7.2.0 (2026-04-17) - This release is compatible with Spring Boot 4.0.0-4.0.5. (Note: 4.0.x (x>5) should be supported, but they aren't tested with this release.) diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/passwordless/MergeAzureCommonPropertiesTest.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/passwordless/MergeAzureCommonPropertiesTest.java index 9759374eced5..76a7754d6e82 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/passwordless/MergeAzureCommonPropertiesTest.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/passwordless/MergeAzureCommonPropertiesTest.java @@ -6,6 +6,7 @@ import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; import com.azure.spring.cloud.autoconfigure.implementation.jms.properties.AzureServiceBusJmsProperties; import com.azure.spring.cloud.autoconfigure.implementation.passwordless.properties.AzureJdbcPasswordlessProperties; +import com.azure.spring.cloud.autoconfigure.implementation.passwordless.properties.AzureRedisPasswordlessProperties; import com.azure.spring.cloud.core.implementation.util.AzurePasswordlessPropertiesUtils; import com.azure.spring.cloud.core.provider.AzureProfileOptionsProvider; import com.azure.identity.extensions.implementation.enums.AuthProperty; @@ -158,4 +159,64 @@ void testJdbcPropertiesExplicitScopesOverridesDefault() { assertEquals("https://custom-scope/.default", result.toPasswordlessProperties().getProperty(AuthProperty.SCOPES.getPropertyKey())); } + + @Test + void testRedisPropertiesGetCorrectScopeFromChinaCloudTypeInGlobalProperties() { + AzureGlobalProperties globalProperties = new AzureGlobalProperties(); + globalProperties.getProfile().setCloudType(AzureProfileOptionsProvider.CloudType.AZURE_CHINA); + + AzureRedisPasswordlessProperties redisProperties = new AzureRedisPasswordlessProperties(); + // User has not explicitly set scopes + + AzureRedisPasswordlessProperties result = new AzureRedisPasswordlessProperties(); + AzurePasswordlessPropertiesUtils.mergeAzureCommonProperties(globalProperties, redisProperties, result); + + // scopes field should be null (not explicitly set) + assertNull(result.getScopes()); + // effective scopes should use the merged cloud type (AZURE_CHINA) + assertEquals("https://*.cacheinfra.windows.net.china:10225/appid/.default", result.getEffectiveScopes()); + // toPasswordlessProperties should include the correct cloud-type-aware scope + assertEquals("https://*.cacheinfra.windows.net.china:10225/appid/.default", + result.toPasswordlessProperties().getProperty(AuthProperty.SCOPES.getPropertyKey())); + assertEquals(AzureProfileOptionsProvider.CloudType.AZURE_CHINA, result.getProfile().getCloudType()); + } + + @Test + void testRedisPropertiesGetCorrectScopeFromUsGovCloudTypeInGlobalProperties() { + AzureGlobalProperties globalProperties = new AzureGlobalProperties(); + globalProperties.getProfile().setCloudType(AzureProfileOptionsProvider.CloudType.AZURE_US_GOVERNMENT); + + AzureRedisPasswordlessProperties redisProperties = new AzureRedisPasswordlessProperties(); + // User has not explicitly set scopes + + AzureRedisPasswordlessProperties result = new AzureRedisPasswordlessProperties(); + AzurePasswordlessPropertiesUtils.mergeAzureCommonProperties(globalProperties, redisProperties, result); + + // scopes field should be null (not explicitly set) + assertNull(result.getScopes()); + // effective scopes should use the merged cloud type (AZURE_US_GOVERNMENT) + assertEquals("https://*.cacheinfra.windows.us.government.net:10225/appid/.default", result.getEffectiveScopes()); + // toPasswordlessProperties should include the correct cloud-type-aware scope + assertEquals("https://*.cacheinfra.windows.us.government.net:10225/appid/.default", + result.toPasswordlessProperties().getProperty(AuthProperty.SCOPES.getPropertyKey())); + assertEquals(AzureProfileOptionsProvider.CloudType.AZURE_US_GOVERNMENT, result.getProfile().getCloudType()); + } + + @Test + void testRedisPropertiesExplicitScopesOverridesDefault() { + AzureGlobalProperties globalProperties = new AzureGlobalProperties(); + globalProperties.getProfile().setCloudType(AzureProfileOptionsProvider.CloudType.AZURE_CHINA); + + AzureRedisPasswordlessProperties redisProperties = new AzureRedisPasswordlessProperties(); + redisProperties.setScopes("https://custom-redis-scope/.default"); + + AzureRedisPasswordlessProperties result = new AzureRedisPasswordlessProperties(); + AzurePasswordlessPropertiesUtils.mergeAzureCommonProperties(globalProperties, redisProperties, result); + + // Explicit scopes should be preserved + assertEquals("https://custom-redis-scope/.default", result.getScopes()); + assertEquals("https://custom-redis-scope/.default", result.getEffectiveScopes()); + assertEquals("https://custom-redis-scope/.default", + result.toPasswordlessProperties().getProperty(AuthProperty.SCOPES.getPropertyKey())); + } }