From c0de5df556e993a7e0df5ad49e3982915b18d543 Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Fri, 27 Sep 2024 10:47:21 +0800 Subject: [PATCH 01/23] Fix primitive type copy issue --- .../MergeAzureCommonPropertiesTest.java | 14 +++-- .../AzurePasswordlessPropertiesUtils.java | 44 ++-------------- .../util/AzurePropertiesUtils.java | 29 +++++++---- .../core/implementation/util/ClassUtils.java | 51 +++++++++++++++++++ .../AzurePasswordlessPropertiesUtilsTest.java | 8 +++ .../core/util/AzurePropertiesUtilsTests.java | 5 ++ 6 files changed, 99 insertions(+), 52 deletions(-) create mode 100644 sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/util/ClassUtils.java 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 9b4db99190af..56a9b5666059 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 @@ -10,6 +10,7 @@ import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; class MergeAzureCommonPropertiesTest { @@ -21,6 +22,7 @@ void testGetPropertiesFromGlobalProperties() { globalProperties.getCredential().setPassword("global-password"); globalProperties.getCredential().setUsername("global-user-name"); globalProperties.getCredential().setManagedIdentityEnabled(true); + globalProperties.getCredential().setTokenCredentialBeanName("my-token-credential"); globalProperties.getProfile().setCloudType(AzureProfileOptionsProvider.CloudType.AZURE_CHINA); globalProperties.getProfile().setSubscriptionId("global-sub"); globalProperties.getProfile().setTenantId("global-tenant-id"); @@ -35,7 +37,8 @@ void testGetPropertiesFromGlobalProperties() { assertEquals("global-client-secret", result.getCredential().getClientSecret()); assertEquals("global-password", result.getCredential().getPassword()); assertEquals("global-user-name", result.getCredential().getUsername()); - assertEquals(false, result.getCredential().isManagedIdentityEnabled()); + assertTrue(result.getCredential().isManagedIdentityEnabled()); + assertEquals("my-token-credential", result.getCredential().getTokenCredentialBeanName()); assertEquals(AzureProfileOptionsProvider.CloudType.AZURE_CHINA, result.getProfile().getCloudType()); assertEquals("global-sub", result.getProfile().getSubscriptionId()); assertEquals("global-tenant-id", result.getProfile().getTenantId()); @@ -52,6 +55,7 @@ void testGetPropertiesFromAzurePasswordlessProperties() { passwordlessProperties.getCredential().setPassword("password"); passwordlessProperties.getCredential().setUsername("user-name"); passwordlessProperties.getCredential().setManagedIdentityEnabled(true); + passwordlessProperties.getCredential().setTokenCredentialBeanName("my-token-credential"); passwordlessProperties.getProfile().setCloudType(AzureProfileOptionsProvider.CloudType.AZURE_US_GOVERNMENT); passwordlessProperties.getProfile().setSubscriptionId("sub"); passwordlessProperties.getProfile().setTenantId("tenant-id"); @@ -64,7 +68,8 @@ void testGetPropertiesFromAzurePasswordlessProperties() { assertEquals("client-secret", result.getCredential().getClientSecret()); assertEquals("password", result.getCredential().getPassword()); assertEquals("user-name", result.getCredential().getUsername()); - assertEquals(true, result.getCredential().isManagedIdentityEnabled()); + assertTrue(result.getCredential().isManagedIdentityEnabled()); + assertEquals("my-token-credential", result.getCredential().getTokenCredentialBeanName()); assertEquals(AzureProfileOptionsProvider.CloudType.AZURE_US_GOVERNMENT, result.getProfile().getCloudType()); assertEquals("sub", result.getProfile().getSubscriptionId()); assertEquals("tenant-id", result.getProfile().getTenantId()); @@ -93,7 +98,7 @@ void testGetPropertiesFromGlobalAndPasswordlessProperties() { passwordlessProperties.setScopes("scope"); passwordlessProperties.getCredential().setClientSecret("client-secret"); passwordlessProperties.getCredential().setPassword("password"); - passwordlessProperties.getCredential().setManagedIdentityEnabled(true); + passwordlessProperties.getCredential().setTokenCredentialBeanName("my-token-credential"); passwordlessProperties.getProfile().setCloudType(AzureProfileOptionsProvider.CloudType.AZURE_US_GOVERNMENT); passwordlessProperties.getProfile().setSubscriptionId("sub"); @@ -105,7 +110,8 @@ void testGetPropertiesFromGlobalAndPasswordlessProperties() { assertEquals("client-secret", result.getCredential().getClientSecret()); assertEquals("password", result.getCredential().getPassword()); assertEquals("global-user-name", result.getCredential().getUsername()); - assertEquals(true, result.getCredential().isManagedIdentityEnabled()); + assertTrue(result.getCredential().isManagedIdentityEnabled()); + assertEquals("my-token-credential", result.getCredential().getTokenCredentialBeanName()); assertEquals(AzureProfileOptionsProvider.CloudType.AZURE_US_GOVERNMENT, result.getProfile().getCloudType()); assertEquals("sub", result.getProfile().getSubscriptionId()); assertEquals("global-tenant-id", result.getProfile().getTenantId()); 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 54df0ceecbe7..6af576a029d8 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 @@ -6,14 +6,8 @@ import com.azure.spring.cloud.core.properties.AzureProperties; import com.azure.spring.cloud.core.properties.PasswordlessProperties; import org.springframework.beans.BeanUtils; -import org.springframework.beans.BeanWrapper; -import org.springframework.beans.BeanWrapperImpl; -import java.beans.PropertyDescriptor; -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; -import java.util.function.Predicate; +import static com.azure.spring.cloud.core.implementation.util.AzurePropertiesUtils.copyPropertiesIgnoreNull; /** * Util class for AzurePasswordlessProperties. @@ -42,8 +36,10 @@ public static void copyAzureCommonProperties( } /** - * Copy common properties from source {@link PasswordlessProperties} object to target {@link T extends PasswordlessProperties} object. Ignore the source - * value if it is null. + * Copy common properties from source {@link PasswordlessProperties} object to target {@link T extends PasswordlessProperties} object. + * Ignore the source value: + * 1. if it is null. + * 2. if it's a primitive type and value is the default value. * * @param source The source {@link PasswordlessProperties} object. * @param target The target object. @@ -74,34 +70,4 @@ public static void mergeAzureCommonProperties copyAzureCommonProperties(defaultProperties, target); copyAzureCommonPropertiesIgnoreNull(properties, target); } - - /** - * Copy common properties from source object to target object. Ignore the source value if it is null. - * - * @param source The source object. - * @param target The target object. - */ - public static void copyPropertiesIgnoreNull(Object source, Object target) { - BeanUtils.copyProperties(source, target, findNullPropertyNames(source)); - } - - private static String[] findPropertyNames(Object source, Predicate predicate) { - final Set emptyNames = new HashSet<>(); - - final BeanWrapper beanWrapper = new BeanWrapperImpl(source); - PropertyDescriptor[] pds = beanWrapper.getPropertyDescriptors(); - - for (PropertyDescriptor pd : pds) { - Object srcValue = beanWrapper.getPropertyValue(pd.getName()); - if (predicate.test(srcValue)) { - emptyNames.add(pd.getName()); - } - } - return emptyNames.toArray(new String[0]); - } - - private static String[] findNullPropertyNames(Object source) { - return findPropertyNames(source, Objects::isNull); - } - } diff --git a/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/util/AzurePropertiesUtils.java b/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/util/AzurePropertiesUtils.java index 2ba0581a5fcf..c5574e20a0ae 100644 --- a/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/util/AzurePropertiesUtils.java +++ b/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/util/AzurePropertiesUtils.java @@ -14,7 +14,10 @@ import java.util.HashSet; import java.util.Objects; import java.util.Set; -import java.util.function.Predicate; +import java.util.function.BiFunction; + +import static com.azure.spring.cloud.core.implementation.util.ClassUtils.isPrimitiveDefaultValue; +import static com.azure.spring.cloud.core.implementation.util.ClassUtils.isPrimitiveNonDefaultValue; /** * @@ -96,7 +99,10 @@ public static void mergeAzureCommonProperties(AzureP } /** - * Copy common properties from source object to target object. Ignore the source value if it is null. + * Copy common properties from source object to target object. + * Ignore the source value: + * 1. if it is null. + * 2. if it's a primitive type and value is the default value. * * @param source The source object. * @param target The target object. @@ -106,7 +112,10 @@ public static void copyPropertiesIgnoreNull(Object source, Object target) { } /** - * Copy common properties from source object to target object. Ignore the target value if it is nonnull. + * Copy common properties from source object to target object. + * Ignore the target value: + * 1. if it is nonnull. + * 2. it's a primitive type and value is not the default value. * * @param source The source object. * @param target The target object. @@ -134,7 +143,7 @@ private static void copyHttpClientProperties(AzurePr } } - private static String[] findPropertyNames(Object source, Predicate predicate) { + private static String[] findPropertyNames(Object source, BiFunction, Object, Boolean> function) { final Set emptyNames = new HashSet<>(); final BeanWrapper beanWrapper = new BeanWrapperImpl(source); @@ -142,18 +151,20 @@ private static String[] findPropertyNames(Object source, Predicate predi for (PropertyDescriptor pd : pds) { Object srcValue = beanWrapper.getPropertyValue(pd.getName()); - if (predicate.test(srcValue)) { + if (function.apply(pd.getPropertyType(), srcValue)) { emptyNames.add(pd.getName()); } } return emptyNames.toArray(new String[0]); } - private static String[] findNullPropertyNames(Object source) { - return findPropertyNames(source, Objects::isNull); + static String[] findNullPropertyNames(Object source) { + return findPropertyNames(source, (propertyType, srcValue) -> + Objects.isNull(srcValue) || isPrimitiveDefaultValue(propertyType, srcValue)); } - private static String[] findNonNullPropertyNames(Object source) { - return findPropertyNames(source, Objects::nonNull); + static String[] findNonNullPropertyNames(Object source) { + return findPropertyNames(source, (propertyType, srcValue) -> + Objects.nonNull(srcValue) && isPrimitiveNonDefaultValue(propertyType, srcValue)); } } diff --git a/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/util/ClassUtils.java b/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/util/ClassUtils.java new file mode 100644 index 000000000000..51bf5b4da180 --- /dev/null +++ b/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/util/ClassUtils.java @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.spring.cloud.core.implementation.util; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; + +public class ClassUtils { + + private ClassUtils() { + + } + + private static final Map, Function> PRIMITIVE_DEFAULT_VALUE_CHECKER; + static { + PRIMITIVE_DEFAULT_VALUE_CHECKER = new HashMap<>(8); + PRIMITIVE_DEFAULT_VALUE_CHECKER.put(boolean.class, (v) -> !((Boolean) v)); + PRIMITIVE_DEFAULT_VALUE_CHECKER.put(byte.class, (v) -> (Byte) v == 0); + PRIMITIVE_DEFAULT_VALUE_CHECKER.put(char.class, (v) -> (Character) v == '\u0000'); + PRIMITIVE_DEFAULT_VALUE_CHECKER.put(short.class, (v) -> (Short) v == 0); + PRIMITIVE_DEFAULT_VALUE_CHECKER.put(int.class, (v) -> (Integer) v == 0); + PRIMITIVE_DEFAULT_VALUE_CHECKER.put(long.class, (v) -> (Long) v == 0); + PRIMITIVE_DEFAULT_VALUE_CHECKER.put(double.class, (v) -> (Double) v == 0d); + PRIMITIVE_DEFAULT_VALUE_CHECKER.put(float.class, (v) -> (Float) v == 0.0f); + } + + /** + * Check if it's a primitive type property with default init value. + * @param type Type class to be checked. + * @param value Value to be checked. + * @return True if it's a primitive type property with default init value. + */ + public static boolean isPrimitiveDefaultValue(Class type, Object value) { + return PRIMITIVE_DEFAULT_VALUE_CHECKER.containsKey(type) + && PRIMITIVE_DEFAULT_VALUE_CHECKER.get(type).apply(value); + } + + /** + * Check if it's a primitive type property and has a non default value. + * @param type Type class to be checked. + * @param value Value to be checked. + * @return True if it's a primitive type property and has a non default value. + */ + public static boolean isPrimitiveNonDefaultValue(Class type, Object value) { + return PRIMITIVE_DEFAULT_VALUE_CHECKER.containsKey(type) + && !PRIMITIVE_DEFAULT_VALUE_CHECKER.get(type).apply(value); + } + +} diff --git a/sdk/spring/spring-cloud-azure-core/src/test/java/com/azure/spring/cloud/core/implementation/util/AzurePasswordlessPropertiesUtilsTest.java b/sdk/spring/spring-cloud-azure-core/src/test/java/com/azure/spring/cloud/core/implementation/util/AzurePasswordlessPropertiesUtilsTest.java index dc552df767f7..b3e969dcbc5d 100644 --- a/sdk/spring/spring-cloud-azure-core/src/test/java/com/azure/spring/cloud/core/implementation/util/AzurePasswordlessPropertiesUtilsTest.java +++ b/sdk/spring/spring-cloud-azure-core/src/test/java/com/azure/spring/cloud/core/implementation/util/AzurePasswordlessPropertiesUtilsTest.java @@ -53,6 +53,7 @@ void testCopyPropertiesToNewObjectShouldEqual() { source.credential.setUsername("credential-username-A"); source.credential.setPassword("credential-password-A"); source.credential.setManagedIdentityEnabled(true); + source.credential.setTokenCredentialBeanName("my-token-credential"); final PasswordlessPropertiesB target = new PasswordlessPropertiesB(); AzurePasswordlessPropertiesUtils.copyAzureCommonProperties(source, target); @@ -68,6 +69,8 @@ void testCopyPropertiesToNewObjectShouldEqual() { assertEquals("credential-client-cert-password-A", target.credential.getClientCertificatePassword()); assertEquals("credential-username-A", target.credential.getUsername()); assertEquals("credential-password-A", target.credential.getPassword()); + assertTrue(target.credential.isManagedIdentityEnabled()); + assertEquals("my-token-credential", target.credential.getTokenCredentialBeanName()); } @@ -98,6 +101,7 @@ void testCopyPropertiesToObjectWithSameFieldsSetShouldOverrideWithNull() { assertEquals("credential-client-cert-password-B", target.credential.getClientCertificatePassword()); assertEquals("credential-username-B", target.credential.getUsername()); assertEquals("credential-password-B", target.credential.getPassword()); + assertTrue(target.credential.isManagedIdentityEnabled()); AzurePropertiesA source = new AzurePropertiesA(); source.client.setApplicationId("client-application-id-A"); @@ -107,6 +111,7 @@ void testCopyPropertiesToObjectWithSameFieldsSetShouldOverrideWithNull() { source.retry.getExponential().setMaxRetries(13); source.retry.getExponential().setMaxDelay(Duration.ofSeconds(14)); source.credential.setClientId("credential-client-id-A"); + source.credential.setTokenCredentialBeanName("my-token-credential"); AzurePasswordlessPropertiesUtils.copyAzureCommonProperties(source, target); @@ -117,6 +122,8 @@ void testCopyPropertiesToObjectWithSameFieldsSetShouldOverrideWithNull() { assertEquals(AzureEnvironment.AZURE_CHINA.getActiveDirectoryEndpoint(), target.profile.getEnvironment().getActiveDirectoryEndpoint()); assertEquals(AzureEnvironment.AZURE_CHINA.getActiveDirectoryGraphApiVersion(), target.profile.getEnvironment().getActiveDirectoryGraphApiVersion()); assertEquals("credential-client-id-A", target.credential.getClientId()); + assertEquals("my-token-credential", target.credential.getTokenCredentialBeanName()); +// assertTrue(target.credential.isManagedIdentityEnabled()); assertNull(target.credential.getClientSecret()); assertNull(target.credential.getClientCertificatePath()); assertNull(target.credential.getClientCertificatePassword()); @@ -174,6 +181,7 @@ void testCopyPropertiesIgnoresNullToObjectWithSameFieldsSetShouldOverrideWithout assertEquals("credential-client-cert-password-B", target.credential.getClientCertificatePassword()); assertEquals("credential-username-B", target.credential.getUsername()); assertEquals("credential-password-B", target.credential.getPassword()); + assertTrue(target.credential.isManagedIdentityEnabled()); assertTrue(target.isPasswordlessEnabled()); assertEquals("fake-scopes", target.getScopes()); diff --git a/sdk/spring/spring-cloud-azure-core/src/test/java/com/azure/spring/cloud/core/util/AzurePropertiesUtilsTests.java b/sdk/spring/spring-cloud-azure-core/src/test/java/com/azure/spring/cloud/core/util/AzurePropertiesUtilsTests.java index 07a17e1464a7..b14a69f9e7dd 100644 --- a/sdk/spring/spring-cloud-azure-core/src/test/java/com/azure/spring/cloud/core/util/AzurePropertiesUtilsTests.java +++ b/sdk/spring/spring-cloud-azure-core/src/test/java/com/azure/spring/cloud/core/util/AzurePropertiesUtilsTests.java @@ -31,6 +31,7 @@ import static com.azure.spring.cloud.core.provider.RetryOptionsProvider.RetryMode.FIXED; 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 AzurePropertiesUtilsTests { @@ -404,6 +405,8 @@ void testCopyPropertiesIgnoreNullToObjectWithDifferentFieldsSetShouldMerge() { void testCopyPropertiesSourceNotChanged() { AzurePropertiesA source = new AzurePropertiesA(); source.credential.setClientId("client-id-A"); + source.credential.setManagedIdentityEnabled(true); + source.credential.setTokenCredentialBeanName("my-token-credential"); source.getProfile().setCloudType(AZURE); AzurePropertiesB target = new AzurePropertiesB(); @@ -411,6 +414,8 @@ void testCopyPropertiesSourceNotChanged() { AzurePropertiesUtils.copyAzureCommonProperties(source, target); assertEquals("client-id-A", target.credential.getClientId()); + assertEquals("my-token-credential", target.credential.getTokenCredentialBeanName()); + assertTrue(target.credential.isManagedIdentityEnabled()); // Update target will not affect source target.retry.getExponential().setBaseDelay(Duration.ofSeconds(2)); From acc1255e7c14554b1954b464936871eb4c42f417 Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Mon, 21 Oct 2024 11:05:27 +0800 Subject: [PATCH 02/23] Support enhance multiple datasource properties --- .../jdbc/JdbcPropertiesBeanPostProcessor.java | 58 ++++++++++++------- ...okenCredentialConfigurationProperties.java | 14 +++++ .../JdbcPropertiesBeanPostProcessorTest.java | 16 ++--- ...essorWithApplicationContextRunnerTest.java | 2 +- .../MySqlAzureJdbcAutoConfigurationTest.java | 4 +- ...tgreSqlAzureJdbcAutoConfigurationTest.java | 4 +- .../descriptor/AuthenticationDescriptor.java | 2 +- .../TokenCredentialProperties.java | 18 ++++++ .../TokenCredentialOptionsProvider.java | 5 ++ 9 files changed, 88 insertions(+), 35 deletions(-) diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessor.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessor.java index 9af7ed53bad8..2a13b556df94 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessor.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessor.java @@ -7,15 +7,17 @@ import com.azure.identity.extensions.implementation.credential.provider.TokenCredentialProvider; import com.azure.identity.extensions.implementation.enums.AuthProperty; import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; +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.implementation.util.AzureSpringIdentifier; import com.azure.spring.cloud.service.implementation.identity.credential.provider.SpringTokenCredentialProvider; -import com.azure.spring.cloud.autoconfigure.implementation.passwordless.properties.AzureJdbcPasswordlessProperties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; +import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.bind.Binder; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; @@ -24,6 +26,7 @@ import org.springframework.core.Ordered; import org.springframework.core.PriorityOrdered; import org.springframework.core.env.Environment; +import org.springframework.core.type.AnnotatedTypeMetadata; import org.springframework.util.StringUtils; import java.util.HashMap; @@ -46,8 +49,6 @@ class JdbcPropertiesBeanPostProcessor implements BeanPostProcessor, EnvironmentA private static final Logger LOGGER = LoggerFactory.getLogger(JdbcPropertiesBeanPostProcessor.class); private static final String SPRING_TOKEN_CREDENTIAL_PROVIDER_CLASS_NAME = SpringTokenCredentialProvider.class.getName(); - private static final String SPRING_CLOUD_AZURE_DATASOURCE_PREFIX = "spring.datasource.azure"; - private GenericApplicationContext applicationContext; private Environment environment; @@ -61,16 +62,25 @@ public int getOrder() { public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof DataSourceProperties) { DataSourceProperties dataSourceProperties = (DataSourceProperties) bean; - AzureJdbcPasswordlessProperties properties = buildAzureProperties(); - + BeanDefinition bd = applicationContext.getBeanDefinition(beanName); + String datasourcePropertiesPrefix = "spring.datasource"; + if(bd != null && bd.getSource() instanceof AnnotatedTypeMetadata metadata) { + Map annotationAttributes = metadata.getAnnotationAttributes(ConfigurationProperties.class.getName()); + if (annotationAttributes != null) { + datasourcePropertiesPrefix = (String) annotationAttributes.get("prefix"); + } + } + String passwordlessPropertiesPrefix = datasourcePropertiesPrefix + ".azure"; + AzureJdbcPasswordlessProperties properties = buildAzureProperties(passwordlessPropertiesPrefix); if (!properties.isPasswordlessEnabled()) { - LOGGER.debug("Feature passwordless authentication is not enabled, skip enhancing jdbc url."); + LOGGER.debug("Feature passwordless authentication is not enabled(bean name is {} and {}.passwordless-enabled=false), " + + "skip enhancing jdbc url.", beanName, passwordlessPropertiesPrefix); return bean; } String url = dataSourceProperties.getUrl(); if (!StringUtils.hasText(url)) { - LOGGER.debug("No 'spring.datasource.url' provided, skip enhancing jdbc url."); + LOGGER.debug("No '{}.url' provided, skip enhancing jdbc url.", datasourcePropertiesPrefix); return bean; } @@ -84,24 +94,25 @@ public Object postProcessBeforeInitialization(Object bean, String beanName) thro if (isPasswordProvided) { LOGGER.debug( "If you are using Azure hosted services," - + "it is encouraged to use the passwordless feature. " - + "Please refer to https://aka.ms/passwordless-connections."); + + "it is encouraged to use the passwordless feature ({}). " + + "Please refer to https://aka.ms/passwordless-connections.", datasourcePropertiesPrefix); return bean; } DatabaseType databaseType = connectionString.getDatabaseType(); if (!databaseType.isDatabasePluginAvailable()) { - LOGGER.debug("The jdbc plugin with provided jdbc schema is not on the classpath, skip enhancing jdbc url."); + LOGGER.debug("The jdbc plugin with provided jdbc schema is not on the classpath, " + + "skip enhancing jdbc url ({}).", datasourcePropertiesPrefix); return bean; } try { JdbcConnectionStringEnhancer enhancer = new JdbcConnectionStringEnhancer(connectionString); - enhancer.enhanceProperties(buildEnhancedProperties(databaseType, properties), true); + enhancer.enhanceProperties(buildEnhancedProperties(passwordlessPropertiesPrefix, databaseType, properties), true); enhanceUserAgent(databaseType, enhancer); ((DataSourceProperties) bean).setUrl(enhancer.getJdbcUrl()); } catch (IllegalArgumentException e) { - LOGGER.error("Inconsistent properties detected, skip enhancing jdbc url.", e); + LOGGER.error("Inconsistent properties detected, skip enhancing jdbc url ({}).", datasourcePropertiesPrefix, e); } } return bean; @@ -134,13 +145,19 @@ private void enhanceUserAgent(DatabaseType databaseType, JdbcConnectionStringEnh } } - private Map buildEnhancedProperties(DatabaseType databaseType, AzureJdbcPasswordlessProperties properties) { + private Map buildEnhancedProperties(String passwordlessPropertiesPrefix, DatabaseType databaseType, AzureJdbcPasswordlessProperties properties) { Map result = new HashMap<>(); - TokenCredentialProvider tokenCredentialProvider = TokenCredentialProvider.createDefault(new TokenCredentialProviderOptions(properties.toPasswordlessProperties())); - TokenCredential tokenCredential = tokenCredentialProvider.get(); - - AuthProperty.TOKEN_CREDENTIAL_BEAN_NAME.setProperty(result, PASSWORDLESS_TOKEN_CREDENTIAL_BEAN_NAME); - applicationContext.registerBean(PASSWORDLESS_TOKEN_CREDENTIAL_BEAN_NAME, TokenCredential.class, () -> tokenCredential); + String tokenCredentialBeanName = properties.getCredential().getTokenCredentialBeanName(); + if (StringUtils.hasText(tokenCredentialBeanName)) { + AuthProperty.TOKEN_CREDENTIAL_BEAN_NAME.setProperty(result, tokenCredentialBeanName); + } else { + TokenCredentialProvider tokenCredentialProvider = TokenCredentialProvider.createDefault(new TokenCredentialProviderOptions(properties.toPasswordlessProperties())); + TokenCredential tokenCredential = tokenCredentialProvider.get(); + + tokenCredentialBeanName = PASSWORDLESS_TOKEN_CREDENTIAL_BEAN_NAME + "." + passwordlessPropertiesPrefix; + AuthProperty.TOKEN_CREDENTIAL_BEAN_NAME.setProperty(result, tokenCredentialBeanName); + applicationContext.registerBean(tokenCredentialBeanName, TokenCredential.class, () -> tokenCredential); + } LOGGER.debug("Add SpringTokenCredentialProvider as the default token credential provider."); AuthProperty.TOKEN_CREDENTIAL_PROVIDER_CLASS_NAME.setProperty(result, SPRING_TOKEN_CREDENTIAL_PROVIDER_CLASS_NAME); @@ -161,14 +178,13 @@ public void setApplicationContext(ApplicationContext applicationContext) throws this.applicationContext = (GenericApplicationContext) applicationContext; } - private AzureJdbcPasswordlessProperties buildAzureProperties() { + private AzureJdbcPasswordlessProperties buildAzureProperties(String azureDatasourcePrefix) { AzureGlobalProperties azureGlobalProperties = applicationContext.getBean(AzureGlobalProperties.class); AzureJdbcPasswordlessProperties azurePasswordlessProperties = Binder.get(environment) - .bindOrCreate(SPRING_CLOUD_AZURE_DATASOURCE_PREFIX, AzureJdbcPasswordlessProperties.class); + .bindOrCreate(azureDatasourcePrefix, AzureJdbcPasswordlessProperties.class); AzureJdbcPasswordlessProperties mergedProperties = new AzureJdbcPasswordlessProperties(); AzurePasswordlessPropertiesUtils.mergeAzureCommonProperties(azureGlobalProperties, azurePasswordlessProperties, mergedProperties); return mergedProperties; - } } diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/properties/core/authentication/TokenCredentialConfigurationProperties.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/properties/core/authentication/TokenCredentialConfigurationProperties.java index b2e6f6062f51..98000130686c 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/properties/core/authentication/TokenCredentialConfigurationProperties.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/properties/core/authentication/TokenCredentialConfigurationProperties.java @@ -47,6 +47,11 @@ public class TokenCredentialConfigurationProperties implements TokenCredentialOp */ private boolean managedIdentityEnabled = false; + /** + * Custom Get the custom {@link com.azure.core.credential.TokenCredential} bean name, it's used for Service builder factory or passwordless authentication. + */ + private String tokenCredentialBeanName; + @Override public String getClientId() { return clientId; @@ -106,6 +111,15 @@ public boolean isManagedIdentityEnabled() { return managedIdentityEnabled; } + @Override + public String getTokenCredentialBeanName() { + return tokenCredentialBeanName; + } + + public void setTokenCredentialBeanName(String tokenCredentialBeanName) { + this.tokenCredentialBeanName = tokenCredentialBeanName; + } + public void setManagedIdentityEnabled(boolean managedIdentityEnabled) { this.managedIdentityEnabled = managedIdentityEnabled; } 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 643cd0df1cb1..52cb9c3b2a67 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 @@ -42,7 +42,7 @@ class JdbcPropertiesBeanPostProcessorTest { public static final String PUBLIC_TOKEN_CREDENTIAL_BEAN_NAME_STRING = AuthProperty.TOKEN_CREDENTIAL_BEAN_NAME.getPropertyKey() + "=" + "passwordlessTokenCredential"; private static final String POSTGRESQL_ASSUME_MIN_SERVER_VERSION = POSTGRESQL_PROPERTY_NAME_ASSUME_MIN_SERVER_VERSION + "=" + POSTGRESQL_PROPERTY_VALUE_ASSUME_MIN_SERVER_VERSION; - + private static final String DEFAULT_PASSWORDLESS_PROPERTIES_SUFFIX = ".spring.datasource.azure"; private MockEnvironment mockEnvironment; private ApplicationContext applicationContext; @@ -103,7 +103,7 @@ void shouldPostprocessWhenSwitchOn() { String expectedJdbcUrl = enhanceJdbcUrl( DatabaseType.MYSQL, MYSQL_CONNECTION_STRING, - PUBLIC_TOKEN_CREDENTIAL_BEAN_NAME_STRING, + PUBLIC_TOKEN_CREDENTIAL_BEAN_NAME_STRING + DEFAULT_PASSWORDLESS_PROPERTIES_SUFFIX, MYSQL_USER_AGENT, AuthProperty.TOKEN_CREDENTIAL_PROVIDER_CLASS_NAME.getPropertyKey() + "=" + SpringTokenCredentialProvider.class.getName() ); @@ -153,7 +153,7 @@ void shouldGetCloudTypeFromAzureUsGov() { MYSQL_USER_AGENT, AuthProperty.TOKEN_CREDENTIAL_PROVIDER_CLASS_NAME.getPropertyKey() + "=" + SpringTokenCredentialProvider.class.getName(), US_AUTHORITY_HOST_STRING, - PUBLIC_TOKEN_CREDENTIAL_BEAN_NAME_STRING + PUBLIC_TOKEN_CREDENTIAL_BEAN_NAME_STRING + DEFAULT_PASSWORDLESS_PROPERTIES_SUFFIX ); assertEquals(expectedJdbcUrl, dataSourceProperties.getUrl()); @@ -170,7 +170,7 @@ void mySqlUserAgentShouldConfigureIfConnectionAttributesIsEmpty() { String expectedJdbcUrl = enhanceJdbcUrl( DatabaseType.MYSQL, MYSQL_CONNECTION_STRING, - PUBLIC_TOKEN_CREDENTIAL_BEAN_NAME_STRING, + PUBLIC_TOKEN_CREDENTIAL_BEAN_NAME_STRING + DEFAULT_PASSWORDLESS_PROPERTIES_SUFFIX, MYSQL_USER_AGENT, AuthProperty.TOKEN_CREDENTIAL_PROVIDER_CLASS_NAME.getPropertyKey() + "=" + SpringTokenCredentialProvider.class.getName() ); @@ -193,7 +193,7 @@ void mySqlUserAgentShouldConfigureIfConnectionAttributesIsNotEmpty() { DatabaseType.MYSQL, baseUrl + ",_extension_version:" + AzureSpringIdentifier.AZURE_SPRING_MYSQL_OAUTH, AuthProperty.TOKEN_CREDENTIAL_PROVIDER_CLASS_NAME.getPropertyKey() + "=" + SpringTokenCredentialProvider.class.getName(), - PUBLIC_TOKEN_CREDENTIAL_BEAN_NAME_STRING + PUBLIC_TOKEN_CREDENTIAL_BEAN_NAME_STRING + DEFAULT_PASSWORDLESS_PROPERTIES_SUFFIX ); assertEquals(expectedJdbcUrl, dataSourceProperties.getUrl()); @@ -214,7 +214,7 @@ void mySqlUserAgentShouldConfigureIfConnectionAttributes() { DatabaseType.MYSQL, baseUrl + ",_extension_version:" + AzureSpringIdentifier.AZURE_SPRING_MYSQL_OAUTH, AuthProperty.TOKEN_CREDENTIAL_PROVIDER_CLASS_NAME.getPropertyKey() + "=" + SpringTokenCredentialProvider.class.getName(), - PUBLIC_TOKEN_CREDENTIAL_BEAN_NAME_STRING + PUBLIC_TOKEN_CREDENTIAL_BEAN_NAME_STRING + DEFAULT_PASSWORDLESS_PROPERTIES_SUFFIX ); assertEquals(expectedJdbcUrl, dataSourceProperties.getUrl()); } @@ -233,7 +233,7 @@ void postgreSqlUserAgentShouldConfigureIfNonApplicationNameProvided() { baseUrl, AuthProperty.TOKEN_CREDENTIAL_PROVIDER_CLASS_NAME.getPropertyKey() + "=" + SpringTokenCredentialProvider.class.getName(), APPLICATION_NAME.getName() + "=" + AzureSpringIdentifier.AZURE_SPRING_POSTGRESQL_OAUTH, - PUBLIC_TOKEN_CREDENTIAL_BEAN_NAME_STRING, + PUBLIC_TOKEN_CREDENTIAL_BEAN_NAME_STRING + DEFAULT_PASSWORDLESS_PROPERTIES_SUFFIX, POSTGRESQL_ASSUME_MIN_SERVER_VERSION ); @@ -255,7 +255,7 @@ void postgreSqlUserAgentShouldNotConfigureIfApplicationNameExists() { DatabaseType.POSTGRESQL, baseUrl, AuthProperty.TOKEN_CREDENTIAL_PROVIDER_CLASS_NAME.getPropertyKey() + "=" + SpringTokenCredentialProvider.class.getName(), - PUBLIC_TOKEN_CREDENTIAL_BEAN_NAME_STRING, + PUBLIC_TOKEN_CREDENTIAL_BEAN_NAME_STRING + DEFAULT_PASSWORDLESS_PROPERTIES_SUFFIX, POSTGRESQL_ASSUME_MIN_SERVER_VERSION ); diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessorWithApplicationContextRunnerTest.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessorWithApplicationContextRunnerTest.java index 34badc584b5f..eca3c3cc12d5 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessorWithApplicationContextRunnerTest.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessorWithApplicationContextRunnerTest.java @@ -73,7 +73,7 @@ void mySqlAuthPluginOnClassPath() { String expectedJdbcUrl = enhanceJdbcUrl( DatabaseType.MYSQL, MYSQL_CONNECTION_STRING, - PUBLIC_TOKEN_CREDENTIAL_BEAN_NAME_STRING, + PUBLIC_TOKEN_CREDENTIAL_BEAN_NAME_STRING + ".spring.datasource.azure", PUBLIC_AUTHORITY_HOST_STRING, MYSQL_USER_AGENT, AuthProperty.TOKEN_CREDENTIAL_PROVIDER_CLASS_NAME.getPropertyKey() + "=" + SpringTokenCredentialProvider.class.getName() diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/MySqlAzureJdbcAutoConfigurationTest.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/MySqlAzureJdbcAutoConfigurationTest.java index a743dd418be7..bda3308f5999 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/MySqlAzureJdbcAutoConfigurationTest.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/MySqlAzureJdbcAutoConfigurationTest.java @@ -82,7 +82,7 @@ void enhanceUrlWithDefaultCredential() { DatabaseType.MYSQL, false, connectionString, - PUBLIC_TOKEN_CREDENTIAL_BEAN_NAME_STRING, + PUBLIC_TOKEN_CREDENTIAL_BEAN_NAME_STRING + ".spring.datasource.azure", PUBLIC_AUTHORITY_HOST_STRING, AUTHPROPERTY_TOKENCREDENTIALPROVIDERCLASSNAME_PROPERTY, MYSQL_USER_AGENT @@ -109,7 +109,7 @@ void enhanceUrlWithCustomCredential() { false, connectionString, PUBLIC_AUTHORITY_HOST_STRING, - AUTHPROPERTY_CREDENTIAL_BEAN_NAME, + AUTHPROPERTY_CREDENTIAL_BEAN_NAME + ".spring.datasource.azure", AUTHPROPERTY_TOKENCREDENTIALPROVIDERCLASSNAME_PROPERTY, MYSQL_USER_AGENT ); diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/PostgreSqlAzureJdbcAutoConfigurationTest.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/PostgreSqlAzureJdbcAutoConfigurationTest.java index 301faa2d8902..66be23a6c7df 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/PostgreSqlAzureJdbcAutoConfigurationTest.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/PostgreSqlAzureJdbcAutoConfigurationTest.java @@ -70,7 +70,7 @@ void enhanceUrlWithDefaultCredential() { DatabaseType.POSTGRESQL, false, connectionString, - PUBLIC_TOKEN_CREDENTIAL_BEAN_NAME_STRING, + PUBLIC_TOKEN_CREDENTIAL_BEAN_NAME_STRING + ".spring.datasource.azure", PUBLIC_AUTHORITY_HOST_STRING, POSTGRESQL_USER_AGENT, AUTHPROPERTY_TOKENCREDENTIALPROVIDERCLASSNAME_PROPERTY, @@ -96,7 +96,7 @@ void enhanceUrlWithCustomCredential() { false, connectionString, PUBLIC_AUTHORITY_HOST_STRING, - AUTHPROPERTY_CREDENTIAL_BEAN_NAME, + AUTHPROPERTY_CREDENTIAL_BEAN_NAME + ".spring.datasource.azure", AUTHPROPERTY_TOKENCREDENTIALPROVIDERCLASSNAME_PROPERTY, POSTGRESQL_USER_AGENT, POSTGRESQL_ASSUME_MIN_SERVER_VERSION diff --git a/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/credential/descriptor/AuthenticationDescriptor.java b/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/credential/descriptor/AuthenticationDescriptor.java index 9cdaf3ff686f..8e63dfee180d 100644 --- a/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/credential/descriptor/AuthenticationDescriptor.java +++ b/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/credential/descriptor/AuthenticationDescriptor.java @@ -27,7 +27,7 @@ public interface AuthenticationDescriptor { /** * Get the consumer function for credential. - * @return the cunsumer function. + * @return the consumer function. */ Consumer getConsumer(); } diff --git a/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/properties/authentication/TokenCredentialProperties.java b/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/properties/authentication/TokenCredentialProperties.java index 929108547cb2..e76b759b489d 100644 --- a/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/properties/authentication/TokenCredentialProperties.java +++ b/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/properties/authentication/TokenCredentialProperties.java @@ -53,6 +53,11 @@ public TokenCredentialProperties() { */ private boolean managedIdentityEnabled; + /** + * Custom Get the custom {@link com.azure.core.credential.TokenCredential} bean name, it's used for Service builder factory or passwordless authentication. + */ + private String tokenCredentialBeanName; + @Override public String getClientId() { return clientId; @@ -143,4 +148,17 @@ public boolean isManagedIdentityEnabled() { public void setManagedIdentityEnabled(boolean managedIdentityEnabled) { this.managedIdentityEnabled = managedIdentityEnabled; } + + @Override + public String getTokenCredentialBeanName() { + return tokenCredentialBeanName; + } + + /** + * Set the token credential bean name. + * @param tokenCredentialBeanName the bean name. + */ + public void setTokenCredentialBeanName(String tokenCredentialBeanName) { + this.tokenCredentialBeanName = tokenCredentialBeanName; + } } diff --git a/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/provider/authentication/TokenCredentialOptionsProvider.java b/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/provider/authentication/TokenCredentialOptionsProvider.java index e2e2624b4629..451b2c04e582 100644 --- a/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/provider/authentication/TokenCredentialOptionsProvider.java +++ b/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/provider/authentication/TokenCredentialOptionsProvider.java @@ -62,6 +62,11 @@ interface TokenCredentialOptions { */ boolean isManagedIdentityEnabled(); + /** + * Get the custom {@link com.azure.core.credential.TokenCredential} bean name. + * @return the token credential bean name. + */ + String getTokenCredentialBeanName(); } } From 3cad5ad49a884b675b7bfd73d9ebe213c2bcee8d Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Mon, 21 Oct 2024 11:07:02 +0800 Subject: [PATCH 03/23] Avoid configuring conn string if credential has been configured. --- .../factory/AbstractAzureServiceClientBuilderFactory.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/factory/AbstractAzureServiceClientBuilderFactory.java b/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/factory/AbstractAzureServiceClientBuilderFactory.java index a2e8c565d8f2..531ebc015415 100644 --- a/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/factory/AbstractAzureServiceClientBuilderFactory.java +++ b/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/factory/AbstractAzureServiceClientBuilderFactory.java @@ -207,7 +207,7 @@ protected void configureCredential(T builder) { } /** - * Configure the connection string to the builder. It will try to resolve a connection string from the + * Configure the connection string to the builder if the credential is not yet configured. It will try to resolve a connection string from the * {@link AzureProperties}, if it is a {@link ConnectionStringProvider} instance. If no connection string found from * the {@link AzureProperties}, it will check if any {@link ServiceConnectionStringProvider} is provided and get the * connection string from the provider if set. If a connection string is resolved successfully, the @@ -216,6 +216,10 @@ protected void configureCredential(T builder) { * @param builder The service client builder. */ protected void configureConnectionString(T builder) { + if (credentialConfigured) { + return; + } + AzureProperties azureProperties = getAzureProperties(); // connection string set to properties will advantage the one from connection string provider From fa32e5a1d700654c7d0a02662e455f32cf48dde2 Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Mon, 21 Oct 2024 11:08:51 +0800 Subject: [PATCH 04/23] Avoid overriding service bus client credential and make the resource manager uses the correct token credential bean --- ...tHubsResourceManagerAutoConfiguration.java | 7 +++- ...AzureResourceManagerAutoConfiguration.java | 14 ++++++- ...ceBusResourceManagerAutoConfiguration.java | 7 +++- ...QueueResourceManagerAutoConfiguration.java | 8 +++- ...ResourceManagerAutoConfigurationTests.java | 24 ++++++++++++ ...ResourceManagerAutoConfigurationTests.java | 24 ++++++++++++ ...ResourceManagerAutoConfigurationTests.java | 24 ++++++++++++ ...ractServiceBusSubClientBuilderFactory.java | 5 +++ .../config/ServiceBusBinderConfiguration.java | 10 +++++ .../ServiceBusBinderConfigurationTests.java | 38 +++++++++---------- 10 files changed, 136 insertions(+), 25 deletions(-) diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureEventHubsResourceManagerAutoConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureEventHubsResourceManagerAutoConfiguration.java index d5d9b741941c..32b71fd7594a 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureEventHubsResourceManagerAutoConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureEventHubsResourceManagerAutoConfiguration.java @@ -5,6 +5,7 @@ import com.azure.resourcemanager.AzureResourceManager; import com.azure.spring.cloud.autoconfigure.implementation.condition.ConditionalOnMissingProperty; +import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; import com.azure.spring.cloud.autoconfigure.implementation.eventhubs.properties.AzureEventHubsProperties; import com.azure.spring.cloud.resourcemanager.implementation.connectionstring.EventHubsArmConnectionStringProvider; import com.azure.spring.cloud.resourcemanager.implementation.provisioning.DefaultEventHubsProvisioner; @@ -42,7 +43,11 @@ public class AzureEventHubsResourceManagerAutoConfiguration extends AzureService @Bean @ConditionalOnMissingBean @ConditionalOnProperty(prefix = AzureEventHubsProperties.PREFIX, value = "namespace") - @ConditionalOnMissingProperty(prefix = AzureEventHubsProperties.PREFIX, value = "connection-string") + @ConditionalOnMissingProperty({ + AzureEventHubsProperties.PREFIX + ".connection-string", + AzureGlobalProperties.PREFIX + ".credential.token-credential-bean-name", + AzureEventHubsProperties.PREFIX + ".credential.token-credential-bean-name" + }) @Order EventHubsArmConnectionStringProvider eventHubsArmConnectionStringProvider() { diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureResourceManagerAutoConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureResourceManagerAutoConfiguration.java index c2ee35deaa07..aa565da8994c 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureResourceManagerAutoConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureResourceManagerAutoConfiguration.java @@ -7,13 +7,18 @@ import com.azure.core.management.profile.AzureProfile; import com.azure.resourcemanager.AzureResourceManager; import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.util.StringUtils; + +import static com.azure.spring.cloud.autoconfigure.implementation.context.AzureContextUtils.DEFAULT_TOKEN_CREDENTIAL_BEAN_NAME; /** @@ -35,9 +40,16 @@ public class AzureResourceManagerAutoConfiguration { @Bean @ConditionalOnMissingBean - AzureResourceManager azureResourceManager(TokenCredential tokenCredential, AzureProfile azureProfile) { + AzureResourceManager azureResourceManager(ApplicationContext applicationContext, + @Qualifier(DEFAULT_TOKEN_CREDENTIAL_BEAN_NAME) TokenCredential defaultTokenCredential, + AzureProfile azureProfile) { // TODO (xiada) Do we need to pass our User-Agent to with the management sdk? // TODO (xiada) configure the http client of arm client + TokenCredential tokenCredential = defaultTokenCredential; + String tokenCredentialBeanName = this.globalProperties.getCredential().getTokenCredentialBeanName(); + if (StringUtils.hasText(tokenCredentialBeanName)) { + tokenCredential = (TokenCredential) applicationContext.getBean(tokenCredentialBeanName); + } return AzureResourceManager.configure().authenticate(tokenCredential, azureProfile).withDefaultSubscription(); } diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureServiceBusResourceManagerAutoConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureServiceBusResourceManagerAutoConfiguration.java index ce7c1aaba138..3a15266e567b 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureServiceBusResourceManagerAutoConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureServiceBusResourceManagerAutoConfiguration.java @@ -5,6 +5,7 @@ import com.azure.resourcemanager.AzureResourceManager; import com.azure.spring.cloud.autoconfigure.implementation.condition.ConditionalOnMissingProperty; +import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; import com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties.AzureServiceBusProperties; import com.azure.spring.cloud.resourcemanager.implementation.connectionstring.ServiceBusArmConnectionStringProvider; import com.azure.spring.cloud.resourcemanager.implementation.provisioning.DefaultServiceBusProvisioner; @@ -48,7 +49,11 @@ ServiceBusProvisioner serviceBusProvisioner() { @Bean @ConditionalOnMissingBean @ConditionalOnProperty(prefix = AzureServiceBusProperties.PREFIX, value = "namespace") - @ConditionalOnMissingProperty(prefix = AzureServiceBusProperties.PREFIX, value = "connection-string") + @ConditionalOnMissingProperty({ + AzureServiceBusProperties.PREFIX + ".connection-string", + AzureGlobalProperties.PREFIX + ".credential.token-credential-bean-name", + AzureServiceBusProperties.PREFIX + ".credential.token-credential-bean-name" + }) @Order ServiceBusArmConnectionStringProvider serviceBusArmConnectionStringProvider() { return new ServiceBusArmConnectionStringProvider(this.azureResourceManager, diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureStorageQueueResourceManagerAutoConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureStorageQueueResourceManagerAutoConfiguration.java index 132723ca57d5..79efb410c9a4 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureStorageQueueResourceManagerAutoConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureStorageQueueResourceManagerAutoConfiguration.java @@ -4,6 +4,8 @@ package com.azure.spring.cloud.autoconfigure.implementation.resourcemanager; import com.azure.resourcemanager.AzureResourceManager; +import com.azure.spring.cloud.autoconfigure.implementation.condition.ConditionalOnMissingProperty; +import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; import com.azure.spring.cloud.autoconfigure.implementation.storage.queue.properties.AzureStorageQueueProperties; import com.azure.spring.cloud.resourcemanager.implementation.connectionstring.StorageQueueArmConnectionStringProvider; import org.springframework.boot.autoconfigure.AutoConfigureAfter; @@ -38,7 +40,11 @@ public class AzureStorageQueueResourceManagerAutoConfiguration extends AzureServ @Bean @ConditionalOnMissingBean - @ConditionalOnProperty(prefix = AzureStorageQueueProperties.PREFIX, value = "account-name") + @ConditionalOnMissingProperty({ + AzureStorageQueueProperties.PREFIX + ".connection-string", + AzureGlobalProperties.PREFIX + ".credential.token-credential-bean-name", + AzureStorageQueueProperties.PREFIX + ".credential.token-credential-bean-name" + }) @Order StorageQueueArmConnectionStringProvider storageQueueArmConnectionStringProvider() { return new StorageQueueArmConnectionStringProvider(this.azureResourceManager, diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureEventHubsResourceManagerAutoConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureEventHubsResourceManagerAutoConfigurationTests.java index bef554db47ac..154fe88c2d2f 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureEventHubsResourceManagerAutoConfigurationTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureEventHubsResourceManagerAutoConfigurationTests.java @@ -5,11 +5,14 @@ import com.azure.messaging.eventhubs.EventHubClientBuilder; import com.azure.resourcemanager.AzureResourceManager; +import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; import com.azure.spring.cloud.autoconfigure.implementation.eventhubs.properties.AzureEventHubsProperties; import com.azure.spring.cloud.resourcemanager.implementation.connectionstring.EventHubsArmConnectionStringProvider; import com.azure.spring.cloud.resourcemanager.implementation.provisioning.EventHubsProvisioner; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.runner.ApplicationContextRunner; @@ -84,4 +87,25 @@ void testAzureEventHubsResourceManagerAutoConfigurationBeans() { .withBean(AzureEventHubsProperties.class, AzureEventHubsProperties::new) .run(context -> assertThat(context).hasSingleBean(EventHubsProvisioner.class)); } + + @ParameterizedTest + @ValueSource(strings = { + "spring.cloud.azure.eventhubs.connection-string=Endpoint=sb://eventhub-test-1.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=ByyyxxxUw=", + "spring.cloud.azure.credential.token-credential-bean-name=my-token-credential", + "spring.cloud.azure.eventhubs.token-credential-bean-name=my-token-credential" + }) + void testNotCreateProviderBeanWhenMissingPropertiesConfigured(String missingProperty) { + this.contextRunner + .withUserConfiguration(AzureGlobalPropertiesAutoConfiguration.class) + .withBean(AzureResourceManager.class, () -> mock(AzureResourceManager.class)) + .withPropertyValues( + "spring.cloud.azure.profile.tenant-id=test-tenant", + "spring.cloud.azure.profile.subscription-id=test-subscription-id", + missingProperty + ) + .run(context -> { + assertThat(context).hasSingleBean(AzureResourceManager.class); + assertThat(context).doesNotHaveBean(EventHubsArmConnectionStringProvider.class); + }); + } } diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureServiceBusResourceManagerAutoConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureServiceBusResourceManagerAutoConfigurationTests.java index 05669cafdb3a..5ce6001da09e 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureServiceBusResourceManagerAutoConfigurationTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureServiceBusResourceManagerAutoConfigurationTests.java @@ -5,11 +5,14 @@ import com.azure.messaging.servicebus.ServiceBusClientBuilder; import com.azure.resourcemanager.AzureResourceManager; +import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; import com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties.AzureServiceBusProperties; import com.azure.spring.cloud.resourcemanager.implementation.connectionstring.ServiceBusArmConnectionStringProvider; import com.azure.spring.cloud.resourcemanager.implementation.provisioning.ServiceBusProvisioner; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.runner.ApplicationContextRunner; @@ -71,4 +74,25 @@ void testAzureServiceBusResourceManagerAutoConfigurationBeans() { assertThat(context).hasSingleBean(ServiceBusProvisioner.class); }); } + + @ParameterizedTest + @ValueSource(strings = { + "spring.cloud.azure.eventhubs.connection-string=Endpoint=sb://test.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=key", + "spring.cloud.azure.credential.token-credential-bean-name=my-token-credential", + "spring.cloud.azure.servicebus.credential.token-credential-bean-name=my-token-credential" + }) + void testNotCreateProviderBeanWhenMissingPropertiesConfigured(String missingProperty) { + this.contextRunner + .withUserConfiguration(AzureGlobalPropertiesAutoConfiguration.class) + .withBean(AzureResourceManager.class, () -> mock(AzureResourceManager.class)) + .withPropertyValues( + "spring.cloud.azure.profile.tenant-id=test-tenant", + "spring.cloud.azure.profile.subscription-id=test-subscription-id", + missingProperty + ) + .run(context -> { + assertThat(context).hasSingleBean(AzureResourceManager.class); + assertThat(context).doesNotHaveBean(ServiceBusArmConnectionStringProvider.class); + }); + } } diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureStorageQueueResourceManagerAutoConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureStorageQueueResourceManagerAutoConfigurationTests.java index 31dfa2aed298..a9daa8dddd28 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureStorageQueueResourceManagerAutoConfigurationTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureStorageQueueResourceManagerAutoConfigurationTests.java @@ -4,11 +4,14 @@ package com.azure.spring.cloud.autoconfigure.implementation.resourcemanager; import com.azure.resourcemanager.AzureResourceManager; +import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; import com.azure.spring.cloud.autoconfigure.implementation.storage.queue.properties.AzureStorageQueueProperties; import com.azure.spring.cloud.resourcemanager.implementation.connectionstring.StorageQueueArmConnectionStringProvider; import com.azure.storage.queue.QueueServiceClientBuilder; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.runner.ApplicationContextRunner; @@ -57,4 +60,25 @@ void testStorageQueueResourceManagerWithoutArmConnectionStringProviderClass() { .withBean(AzureResourceManager.class, () -> mock(AzureResourceManager.class)) .run(context -> assertThat(context).doesNotHaveBean(AzureStorageQueueResourceManagerAutoConfiguration.class)); } + + @ParameterizedTest + @ValueSource(strings = { + "spring.cloud.azure.storage.queue.connection-string=DefaultEndpointsProtocol=https;AccountName=test;AccountKey=key;EndpointSuffix=core.windows.net", + "spring.cloud.azure.credential.token-credential-bean-name=my-token-credential", + "spring.cloud.azure.storage.queue.credential.token-credential-bean-name=my-token-credential" + }) + void testNotCreateProviderBeanWhenMissingPropertiesConfigured(String missingProperty) { + this.contextRunner + .withUserConfiguration(AzureGlobalPropertiesAutoConfiguration.class) + .withBean(AzureResourceManager.class, () -> mock(AzureResourceManager.class)) + .withPropertyValues( + "spring.cloud.azure.profile.tenant-id=test-tenant", + "spring.cloud.azure.profile.subscription-id=test-subscription-id", + missingProperty + ) + .run(context -> { + assertThat(context).hasSingleBean(AzureResourceManager.class); + assertThat(context).doesNotHaveBean(StorageQueueArmConnectionStringProvider.class); + }); + } } diff --git a/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java b/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java index baca3060b5a2..95db3f81d498 100644 --- a/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java +++ b/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java @@ -76,6 +76,11 @@ protected AbstractServiceBusSubClientBuilderFactory(ServiceBusClientBuilder serv } } + @Override + protected void configureCore(T builder) { + // skip to avoid overriding the parent builder's credentials. + } + protected boolean isShareServiceBusClientBuilder() { return shareServiceBusClientBuilder; } diff --git a/sdk/spring/spring-cloud-azure-stream-binder-servicebus/src/main/java/com/azure/spring/cloud/stream/binder/servicebus/implementation/config/ServiceBusBinderConfiguration.java b/sdk/spring/spring-cloud-azure-stream-binder-servicebus/src/main/java/com/azure/spring/cloud/stream/binder/servicebus/implementation/config/ServiceBusBinderConfiguration.java index 4a22c91216ac..4e26622665ae 100644 --- a/sdk/spring/spring-cloud-azure-stream-binder-servicebus/src/main/java/com/azure/spring/cloud/stream/binder/servicebus/implementation/config/ServiceBusBinderConfiguration.java +++ b/sdk/spring/spring-cloud-azure-stream-binder-servicebus/src/main/java/com/azure/spring/cloud/stream/binder/servicebus/implementation/config/ServiceBusBinderConfiguration.java @@ -121,9 +121,11 @@ ServiceBusMessageChannelBinder serviceBusBinder(ServiceBusChannelProvisioner cha ServiceBusProducerFactoryCustomizer defaultServiceBusProducerFactoryCustomizer( AzureTokenCredentialResolver azureTokenCredentialResolver, @Qualifier(DEFAULT_TOKEN_CREDENTIAL_BEAN_NAME) TokenCredential defaultAzureCredential, + ObjectProvider> clientBuilderCustomizers, ObjectProvider> senderClientBuilderCustomizers) { return new DefaultProducerFactoryCustomizer(defaultAzureCredential, azureTokenCredentialResolver, + clientBuilderCustomizers, senderClientBuilderCustomizers); } @@ -149,13 +151,16 @@ static class DefaultProducerFactoryCustomizer implements ServiceBusProducerFacto private final TokenCredential defaultCredential; private final AzureTokenCredentialResolver tokenCredentialResolver; + private final ObjectProvider> clientBuilderCustomizers; private final ObjectProvider> senderClientBuilderCustomizers; DefaultProducerFactoryCustomizer(TokenCredential defaultCredential, AzureTokenCredentialResolver azureTokenCredentialResolver, + ObjectProvider> clientBuilderCustomizers, ObjectProvider> senderClientBuilderCustomizers) { this.defaultCredential = defaultCredential; this.tokenCredentialResolver = azureTokenCredentialResolver; + this.clientBuilderCustomizers = clientBuilderCustomizers; this.senderClientBuilderCustomizers = senderClientBuilderCustomizers; } @@ -167,10 +172,15 @@ public void customize(ServiceBusProducerFactory factory) { defaultFactory.setDefaultCredential(defaultCredential); defaultFactory.setTokenCredentialResolver(tokenCredentialResolver); + clientBuilderCustomizers.orderedStream().forEach(defaultFactory::addServiceBusClientBuilderCustomizer); senderClientBuilderCustomizers.orderedStream().forEach(defaultFactory::addBuilderCustomizer); } } + ObjectProvider> getClientBuilderCustomizers() { + return clientBuilderCustomizers; + } + ObjectProvider> getSenderClientBuilderCustomizers() { return senderClientBuilderCustomizers; } diff --git a/sdk/spring/spring-cloud-azure-stream-binder-servicebus/src/test/java/com/azure/spring/cloud/stream/binder/servicebus/implementation/config/ServiceBusBinderConfigurationTests.java b/sdk/spring/spring-cloud-azure-stream-binder-servicebus/src/test/java/com/azure/spring/cloud/stream/binder/servicebus/implementation/config/ServiceBusBinderConfigurationTests.java index 337342aac1b0..1611bf16157a 100644 --- a/sdk/spring/spring-cloud-azure-stream-binder-servicebus/src/test/java/com/azure/spring/cloud/stream/binder/servicebus/implementation/config/ServiceBusBinderConfigurationTests.java +++ b/sdk/spring/spring-cloud-azure-stream-binder-servicebus/src/test/java/com/azure/spring/cloud/stream/binder/servicebus/implementation/config/ServiceBusBinderConfigurationTests.java @@ -173,39 +173,21 @@ void processorFactoryCustomizerShouldBeConfigured() { @Test void producerBuilderCustomizerShouldBeConfiguredToProducerFactoryCustomizer() { - this.contextRunner - .withBean(ServiceBusProvisioner.class, () -> mock(ServiceBusProvisioner.class)) - .withPropertyValues("spring.cloud.azure.servicebus.namespace=fake-namespace") - .withBean("producer-customizer1", ServiceBusSenderClientBuilderCustomizer.class, ServiceBusSenderClientBuilderCustomizer::new) - .withBean("processor-customizer1", ServiceBusProcessorClientBuilderCustomizer.class, ServiceBusProcessorClientBuilderCustomizer::new) - .withBean("processor-customizer2", ServiceBusProcessorClientBuilderCustomizer.class, ServiceBusProcessorClientBuilderCustomizer::new) - .withBean("session-processor-customizer1", ServiceBusSessionProcessorClientBuilderCustomizer.class, ServiceBusSessionProcessorClientBuilderCustomizer::new) - .withBean("session-processor-customizer2", ServiceBusSessionProcessorClientBuilderCustomizer.class, ServiceBusSessionProcessorClientBuilderCustomizer::new) - .withBean("session-processor-customizer3", ServiceBusSessionProcessorClientBuilderCustomizer.class, ServiceBusSessionProcessorClientBuilderCustomizer::new) - .withBean("other-customizer1", OtherBuilderCustomizer.class, OtherBuilderCustomizer::new) + getCustomizedApplicationContextRunner() .run(context -> { assertThat(context).hasSingleBean(ServiceBusProducerFactoryCustomizer.class); ServiceBusProducerFactoryCustomizer clientFactoryCustomizer = context.getBean(ServiceBusProducerFactoryCustomizer.class); ServiceBusBinderConfiguration.DefaultProducerFactoryCustomizer defaultFactoryCustomizer = (ServiceBusBinderConfiguration.DefaultProducerFactoryCustomizer) clientFactoryCustomizer; + assertEquals(1, (int) defaultFactoryCustomizer.getClientBuilderCustomizers().stream().count()); assertEquals(1, (int) defaultFactoryCustomizer.getSenderClientBuilderCustomizers().stream().count()); }); } @Test void processorBuilderCustomizerShouldBeConfiguredToProcessorFactoryCustomizer() { - this.contextRunner - .withBean(ServiceBusProvisioner.class, () -> mock(ServiceBusProvisioner.class)) - .withPropertyValues("spring.cloud.azure.servicebus.namespace=fake-namespace") - .withBean("client-customizer1", ServiceBusClientBuilderCustomizer.class, ServiceBusClientBuilderCustomizer::new) - .withBean("producer-customizer1", ServiceBusSenderClientBuilderCustomizer.class, ServiceBusSenderClientBuilderCustomizer::new) - .withBean("processor-customizer1", ServiceBusProcessorClientBuilderCustomizer.class, ServiceBusProcessorClientBuilderCustomizer::new) - .withBean("processor-customizer2", ServiceBusProcessorClientBuilderCustomizer.class, ServiceBusProcessorClientBuilderCustomizer::new) - .withBean("session-processor-customizer1", ServiceBusSessionProcessorClientBuilderCustomizer.class, ServiceBusSessionProcessorClientBuilderCustomizer::new) - .withBean("session-processor-customizer2", ServiceBusSessionProcessorClientBuilderCustomizer.class, ServiceBusSessionProcessorClientBuilderCustomizer::new) - .withBean("session-processor-customizer3", ServiceBusSessionProcessorClientBuilderCustomizer.class, ServiceBusSessionProcessorClientBuilderCustomizer::new) - .withBean("other-customizer1", OtherBuilderCustomizer.class, OtherBuilderCustomizer::new) + getCustomizedApplicationContextRunner() .run(context -> { assertThat(context).hasSingleBean(ServiceBusProcessorFactoryCustomizer.class); ServiceBusProcessorFactoryCustomizer clientFactoryCustomizer = context.getBean(ServiceBusProcessorFactoryCustomizer.class); @@ -218,6 +200,20 @@ void processorBuilderCustomizerShouldBeConfiguredToProcessorFactoryCustomizer() }); } + private ApplicationContextRunner getCustomizedApplicationContextRunner() { + return this.contextRunner + .withBean(ServiceBusProvisioner.class, () -> mock(ServiceBusProvisioner.class)) + .withPropertyValues("spring.cloud.azure.servicebus.namespace=fake-namespace") + .withBean("client-customizer1", ServiceBusClientBuilderCustomizer.class, ServiceBusClientBuilderCustomizer::new) + .withBean("producer-customizer1", ServiceBusSenderClientBuilderCustomizer.class, ServiceBusSenderClientBuilderCustomizer::new) + .withBean("processor-customizer1", ServiceBusProcessorClientBuilderCustomizer.class, ServiceBusProcessorClientBuilderCustomizer::new) + .withBean("processor-customizer2", ServiceBusProcessorClientBuilderCustomizer.class, ServiceBusProcessorClientBuilderCustomizer::new) + .withBean("session-processor-customizer1", ServiceBusSessionProcessorClientBuilderCustomizer.class, ServiceBusSessionProcessorClientBuilderCustomizer::new) + .withBean("session-processor-customizer2", ServiceBusSessionProcessorClientBuilderCustomizer.class, ServiceBusSessionProcessorClientBuilderCustomizer::new) + .withBean("session-processor-customizer3", ServiceBusSessionProcessorClientBuilderCustomizer.class, ServiceBusSessionProcessorClientBuilderCustomizer::new) + .withBean("other-customizer1", OtherBuilderCustomizer.class, OtherBuilderCustomizer::new); + } + private static class ServiceBusClientBuilderCustomizer implements AzureServiceClientBuilderCustomizer { @Override From 433f08218b53500d63cab8d07af2af82c7a6ff11 Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Mon, 21 Oct 2024 11:11:34 +0800 Subject: [PATCH 05/23] Support customizing the credential for Service Bus sPRING Integration scenario --- ...eServiceBusMessagingAutoConfiguration.java | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/AzureServiceBusMessagingAutoConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/AzureServiceBusMessagingAutoConfiguration.java index 9f49827d8859..afae3241c1b0 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/AzureServiceBusMessagingAutoConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/AzureServiceBusMessagingAutoConfiguration.java @@ -3,8 +3,12 @@ package com.azure.spring.cloud.autoconfigure.implementation.servicebus; +import com.azure.core.credential.TokenCredential; +import com.azure.messaging.servicebus.ServiceBusClientBuilder; import com.azure.spring.cloud.autoconfigure.implementation.condition.ConditionalOnAnyProperty; import com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties.AzureServiceBusProperties; +import com.azure.spring.cloud.core.customizer.AzureServiceClientBuilderCustomizer; +import com.azure.spring.cloud.core.implementation.credential.resolver.AzureTokenCredentialResolver; import com.azure.spring.cloud.core.provider.connectionstring.ServiceConnectionStringProvider; import com.azure.spring.cloud.core.service.AzureServiceType; import com.azure.spring.messaging.ConsumerIdentifier; @@ -24,6 +28,7 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.ObjectProvider; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; @@ -34,6 +39,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import static com.azure.spring.cloud.autoconfigure.implementation.context.AzureContextUtils.DEFAULT_TOKEN_CREDENTIAL_BEAN_NAME; import static com.azure.spring.cloud.core.implementation.util.AzurePropertiesUtils.copyAzureCommonProperties; @@ -80,8 +86,19 @@ static class ProcessorContainerConfiguration { @ConditionalOnMissingBean ServiceBusProcessorFactory defaultServiceBusNamespaceProcessorFactory( NamespaceProperties properties, - ObjectProvider> suppliers) { - return new DefaultServiceBusNamespaceProcessorFactory(properties, suppliers.getIfAvailable()); + ObjectProvider> suppliers, + ObjectProvider tokenCredentialResolvers, + ObjectProvider defaultTokenCredentials, + ObjectProvider> clientBuilderCustomizers, + ObjectProvider> processorClientBuilderCustomizers, + ObjectProvider> sessionProcessorClientBuilderCustomizers) { + DefaultServiceBusNamespaceProcessorFactory factory = new DefaultServiceBusNamespaceProcessorFactory(properties, suppliers.getIfAvailable()); + factory.setDefaultCredential(defaultTokenCredentials.getIfAvailable()); + factory.setTokenCredentialResolver(tokenCredentialResolvers.getIfAvailable()); + clientBuilderCustomizers.orderedStream().forEach(factory::addServiceBusClientBuilderCustomizer); + processorClientBuilderCustomizers.orderedStream().forEach(factory::addBuilderCustomizer); + sessionProcessorClientBuilderCustomizers.orderedStream().forEach(factory::addSessionBuilderCustomizer); + return factory; } } @@ -92,8 +109,17 @@ static class ServiceBusTemplateConfiguration { @ConditionalOnMissingBean ServiceBusProducerFactory defaultServiceBusNamespaceProducerFactory( NamespaceProperties properties, - ObjectProvider> suppliers) { - return new DefaultServiceBusNamespaceProducerFactory(properties, suppliers.getIfAvailable()); + ObjectProvider> suppliers, + ObjectProvider tokenCredentialResolvers, + ObjectProvider defaultTokenCredentials, + ObjectProvider> clientBuilderCustomizers, + ObjectProvider> senderClientBuilderCustomizers) { + DefaultServiceBusNamespaceProducerFactory factory = new DefaultServiceBusNamespaceProducerFactory(properties, suppliers.getIfAvailable()); + factory.setDefaultCredential(defaultTokenCredentials.getIfAvailable()); + factory.setTokenCredentialResolver(tokenCredentialResolvers.getIfAvailable()); + clientBuilderCustomizers.orderedStream().forEach(factory::addServiceBusClientBuilderCustomizer); + senderClientBuilderCustomizers.orderedStream().forEach(factory::addBuilderCustomizer); + return factory; } @Bean From 28ac8cdfa49bac86f827cd60ede623b94190d72e Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Mon, 21 Oct 2024 13:02:02 +0800 Subject: [PATCH 06/23] Support customizing the credential for Service Bus sPRING Integration scenario --- ...AzureTokenCredentialAutoConfiguration.java | 10 ++++ ...kenCredentialProviderContextCondition.java | 31 ++++++++++ .../jdbc/AzureJdbcAutoConfiguration.java | 7 --- ...eBusJmsConnectionFactoryConfiguration.java | 60 +++++++++++++++++-- ...ServiceBusJmsConnectionFactoryFactory.java | 23 ++++++- .../AzureServiceBusJmsProperties.java | 2 +- 6 files changed, 117 insertions(+), 16 deletions(-) create mode 100644 sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/condition/SpringTokenCredentialProviderContextCondition.java diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/AzureTokenCredentialAutoConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/AzureTokenCredentialAutoConfiguration.java index c6a9ee8e2760..63f8a4b7915f 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/AzureTokenCredentialAutoConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/AzureTokenCredentialAutoConfiguration.java @@ -10,7 +10,9 @@ import com.azure.identity.ManagedIdentityCredentialBuilder; import com.azure.identity.UsernamePasswordCredentialBuilder; import com.azure.spring.cloud.autoconfigure.implementation.AzureServiceConfigurationBase; +import com.azure.spring.cloud.autoconfigure.implementation.context.condition.SpringTokenCredentialProviderContextCondition; import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; +import com.azure.spring.cloud.autoconfigure.implementation.jdbc.SpringTokenCredentialProviderContextProvider; import com.azure.spring.cloud.autoconfigure.implementation.properties.core.AbstractAzureHttpConfigurationProperties; import com.azure.spring.cloud.core.customizer.AzureServiceClientBuilderCustomizer; import com.azure.spring.cloud.core.implementation.credential.resolver.AzureTokenCredentialResolver; @@ -36,6 +38,7 @@ import org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration; import org.springframework.boot.task.TaskExecutorBuilder; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; @@ -225,6 +228,13 @@ ThreadPoolTaskExecutor credentialTaskExecutor() { .build(); } + @Bean + @ConditionalOnMissingBean + @Conditional(SpringTokenCredentialProviderContextCondition.class) + SpringTokenCredentialProviderContextProvider springTokenCredentialProviderContextProvider() { + return new SpringTokenCredentialProviderContextProvider(); + } + static class AzureServiceClientBuilderFactoryPostProcessor implements BeanPostProcessor, BeanFactoryAware { private BeanFactory beanFactory; diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/condition/SpringTokenCredentialProviderContextCondition.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/condition/SpringTokenCredentialProviderContextCondition.java new file mode 100644 index 000000000000..b7159ef34273 --- /dev/null +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/condition/SpringTokenCredentialProviderContextCondition.java @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.spring.cloud.autoconfigure.implementation.context.condition; + +import com.azure.spring.cloud.autoconfigure.implementation.condition.ConditionalOnMissingProperty; +import org.springframework.boot.autoconfigure.condition.AnyNestedCondition; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; +import org.springframework.context.annotation.ConfigurationCondition; + +public class SpringTokenCredentialProviderContextCondition extends AnyNestedCondition { + + SpringTokenCredentialProviderContextCondition() { + super(ConfigurationCondition.ConfigurationPhase.REGISTER_BEAN); + } + + @ConditionalOnBean(DataSourceProperties.class) + @ConditionalOnClass(name = "com.azure.identity.extensions.implementation.template.AzureAuthenticationTemplate") + static class JdbcPasswordlessCondition { + + } + + @ConditionalOnProperty(value = "spring.jms.servicebus.passwordless-enabled", havingValue = "true") + @ConditionalOnMissingProperty(prefix = "spring.jms.servicebus", name = "connection-string") + static class ServiceBusJmsPasswordlessCondition { + + } +} diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/AzureJdbcAutoConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/AzureJdbcAutoConfiguration.java index 2b52462cbdcf..75a2a3a6d012 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/AzureJdbcAutoConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/AzureJdbcAutoConfiguration.java @@ -33,11 +33,4 @@ public class AzureJdbcAutoConfiguration { JdbcPropertiesBeanPostProcessor jdbcConfigurationPropertiesBeanPostProcessor() { return new JdbcPropertiesBeanPostProcessor(); } - - @Bean - @ConditionalOnMissingBean - SpringTokenCredentialProviderContextProvider springTokenCredentialProviderContextProvider() { - return new SpringTokenCredentialProviderContextProvider(); - } - } diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java index 4851cfeddd6f..7baa446e0923 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java @@ -3,10 +3,17 @@ package com.azure.spring.cloud.autoconfigure.implementation.jms; +import com.azure.core.credential.TokenCredential; +import com.azure.identity.extensions.implementation.credential.TokenCredentialProviderOptions; +import com.azure.identity.extensions.implementation.credential.provider.TokenCredentialProvider; +import com.azure.identity.extensions.implementation.enums.AuthProperty; import com.azure.servicebus.jms.ServiceBusJmsConnectionFactory; import com.azure.spring.cloud.autoconfigure.implementation.jms.properties.AzureServiceBusJmsProperties; import com.azure.spring.cloud.autoconfigure.jms.AzureServiceBusJmsConnectionFactoryCustomizer; +import com.azure.spring.cloud.service.implementation.identity.credential.provider.SpringTokenCredentialProvider; import jakarta.jms.ConnectionFactory; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.apache.commons.pool2.PooledObject; import org.messaginghub.pooled.jms.JmsPoolConnectionFactory; import org.springframework.beans.factory.ObjectProvider; @@ -17,28 +24,69 @@ import org.springframework.boot.autoconfigure.jms.JmsProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.DependsOn; +import org.springframework.context.support.GenericApplicationContext; import org.springframework.jms.connection.CachingConnectionFactory; +import org.springframework.util.StringUtils; +import java.util.Properties; import java.util.stream.Collectors; +import static com.azure.spring.cloud.service.implementation.identity.credential.provider.SpringTokenCredentialProvider.PASSWORDLESS_TOKEN_CREDENTIAL_BEAN_NAME; + @Configuration(proxyBeanMethods = false) @ConditionalOnMissingBean(ConnectionFactory.class) class ServiceBusJmsConnectionFactoryConfiguration { - private static ServiceBusJmsConnectionFactory createJmsConnectionFactory(AzureServiceBusJmsProperties properties, + private static final Log logger = LogFactory.getLog(ServiceBusJmsConnectionFactoryConfiguration.class); + private final GenericApplicationContext applicationContext; + + ServiceBusJmsConnectionFactoryConfiguration(GenericApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + private ServiceBusJmsConnectionFactory createJmsConnectionFactory(AzureServiceBusJmsProperties jmsProperties, ObjectProvider factoryCustomizers) { - return new ServiceBusJmsConnectionFactoryFactory(properties, + TokenCredentialProvider tokenCredentialProvider = getPasswordlessTokenCredentialProvider(jmsProperties); + return new ServiceBusJmsConnectionFactoryFactory(tokenCredentialProvider, jmsProperties, factoryCustomizers.orderedStream().collect(Collectors.toList())) .createConnectionFactory(ServiceBusJmsConnectionFactory.class); } + private TokenCredentialProvider getPasswordlessTokenCredentialProvider(AzureServiceBusJmsProperties serviceBusJmsProperties) { + if (!serviceBusJmsProperties.isPasswordlessEnabled()) { + logger.debug("Feature passwordless authentication is not enabled(" + AzureServiceBusJmsProperties.PREFIX + ".passwordless-enabled=false), " + + "skip enhancing Service Bus JMS properties."); + return null; + } + + Properties properties = serviceBusJmsProperties.toPasswordlessProperties(); + String tokenCredentialBeanName = serviceBusJmsProperties.getCredential().getTokenCredentialBeanName(); + if (StringUtils.hasText(tokenCredentialBeanName)) { + AuthProperty.TOKEN_CREDENTIAL_BEAN_NAME.setProperty(properties, tokenCredentialBeanName); + } else { + TokenCredentialProvider tokenCredentialProvider = TokenCredentialProvider.createDefault(new TokenCredentialProviderOptions(properties)); + TokenCredential tokenCredential = tokenCredentialProvider.get(); + + tokenCredentialBeanName = PASSWORDLESS_TOKEN_CREDENTIAL_BEAN_NAME + "." + AzureServiceBusJmsProperties.PREFIX; + AuthProperty.TOKEN_CREDENTIAL_BEAN_NAME.setProperty(properties, tokenCredentialBeanName); + applicationContext.registerBean(tokenCredentialBeanName, TokenCredential.class, () -> tokenCredential); + } + + AuthProperty.TOKEN_CREDENTIAL_PROVIDER_CLASS_NAME.setProperty(properties, SpringTokenCredentialProvider.class.getName()); + AuthProperty.AUTHORITY_HOST.setProperty(properties, serviceBusJmsProperties.getProfile().getEnvironment().getActiveDirectoryEndpoint()); + + return TokenCredentialProvider.createDefault(new TokenCredentialProviderOptions(properties)); + } + @Configuration(proxyBeanMethods = false) @ConditionalOnProperty(prefix = "spring.jms.servicebus.pool", name = "enabled", havingValue = "false", matchIfMissing = true) - static class SimpleConnectionFactoryConfiguration { + class SimpleConnectionFactoryConfiguration { @Bean @ConditionalOnProperty(prefix = "spring.jms.cache", name = "enabled", havingValue = "false") + @DependsOn("springTokenCredentialProviderContextProvider") ServiceBusJmsConnectionFactory jmsConnectionFactory(AzureServiceBusJmsProperties properties, ObjectProvider factoryCustomizers) { return createJmsConnectionFactory(properties, factoryCustomizers); @@ -48,9 +96,10 @@ ServiceBusJmsConnectionFactory jmsConnectionFactory(AzureServiceBusJmsProperties @ConditionalOnClass(CachingConnectionFactory.class) @ConditionalOnProperty(prefix = "spring.jms.cache", name = "enabled", havingValue = "true", matchIfMissing = true) - static class CachingConnectionFactoryConfiguration { + class CachingConnectionFactoryConfiguration { @Bean + @DependsOn("springTokenCredentialProviderContextProvider") CachingConnectionFactory jmsConnectionFactory(JmsProperties jmsProperties, AzureServiceBusJmsProperties properties, ObjectProvider factoryCustomizers) { @@ -68,10 +117,11 @@ CachingConnectionFactory jmsConnectionFactory(JmsProperties jmsProperties, @Configuration(proxyBeanMethods = false) @ConditionalOnClass({ JmsPoolConnectionFactory.class, PooledObject.class }) - static class PooledConnectionFactoryConfiguration { + class PooledConnectionFactoryConfiguration { @Bean(destroyMethod = "stop") @ConditionalOnProperty(prefix = "spring.jms.servicebus.pool", name = "enabled", havingValue = "true") + @DependsOn("springTokenCredentialProviderContextProvider") JmsPoolConnectionFactory jmsPoolConnectionFactory(AzureServiceBusJmsProperties properties, ObjectProvider factoryCustomizers) { ServiceBusJmsConnectionFactory factory = createJmsConnectionFactory(properties, factoryCustomizers); diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryFactory.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryFactory.java index e3222c6f1930..721d58667016 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryFactory.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryFactory.java @@ -21,12 +21,31 @@ class ServiceBusJmsConnectionFactoryFactory { private final AzureServiceBusJmsProperties properties; private final List factoryCustomizers; + private final TokenCredentialProvider tokenCredentialProvider; + ServiceBusJmsConnectionFactoryFactory(AzureServiceBusJmsProperties properties, List factoryCustomizers) { + this(null, properties, factoryCustomizers); + + } + + ServiceBusJmsConnectionFactoryFactory(TokenCredentialProvider tokenCredentialProvider, + AzureServiceBusJmsProperties properties, + List factoryCustomizers) { + if (properties.isPasswordlessEnabled()) { + if (tokenCredentialProvider == null) { + this.tokenCredentialProvider = TokenCredentialProvider.createDefault( + new TokenCredentialProviderOptions(properties.toPasswordlessProperties())); + } else { + this.tokenCredentialProvider = tokenCredentialProvider; + } + } else { + this.tokenCredentialProvider = null; + } + Assert.notNull(properties, "Properties must not be null"); this.properties = properties; this.factoryCustomizers = (factoryCustomizers != null) ? factoryCustomizers : Collections.emptyList(); - } T createConnectionFactory(Class factoryClass) { @@ -61,8 +80,6 @@ private T createConnectionFactoryInst if (properties.isPasswordlessEnabled()) { String hostName = properties.getNamespace() + "." + properties.getProfile().getEnvironment().getServiceBusDomainName(); - TokenCredentialProvider tokenCredentialProvider = - TokenCredentialProvider.createDefault(new TokenCredentialProviderOptions(properties.toPasswordlessProperties())); TokenCredential tokenCredential = tokenCredentialProvider.get(); factory = factoryClass.getConstructor(TokenCredential.class, String.class, ServiceBusJmsConnectionFactorySettings.class) diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/properties/AzureServiceBusJmsProperties.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/properties/AzureServiceBusJmsProperties.java index 427309429027..807abd3f67ba 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/properties/AzureServiceBusJmsProperties.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/properties/AzureServiceBusJmsProperties.java @@ -194,7 +194,7 @@ public void afterPropertiesSet() throws Exception { } } else { if (!StringUtils.hasText(connectionString)) { - throw new IllegalArgumentException("'spring.jms.servicebus.connection-string' should be provided."); + throw new IllegalArgumentException("'spring.jms.servicebus.connection-string' should be provided, otherwise you should provide a bean 'StaticConnectionStringProvider'."); } } From f3abae4ad6979b74edd077d9ea35abb22d5672ac Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Mon, 21 Oct 2024 14:48:41 +0800 Subject: [PATCH 07/23] Support customizing the credential for Redis passwordless scenario --- ...AzureTokenCredentialAutoConfiguration.java | 10 --- ...viderContextProviderAutoConfiguration.java | 28 +++++++++ ...kenCredentialProviderContextCondition.java | 31 ---------- ...eLettucePasswordlessAutoConfiguration.java | 11 +++- .../redis/lettuce/AzureRedisCredentials.java | 62 ++++++++++++++++++- ...eBusJmsConnectionFactoryConfiguration.java | 3 +- ...ot.autoconfigure.AutoConfiguration.imports | 1 + 7 files changed, 102 insertions(+), 44 deletions(-) create mode 100644 sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/SpringTokenCredentialProviderContextProviderAutoConfiguration.java delete mode 100644 sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/condition/SpringTokenCredentialProviderContextCondition.java diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/AzureTokenCredentialAutoConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/AzureTokenCredentialAutoConfiguration.java index 63f8a4b7915f..c6a9ee8e2760 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/AzureTokenCredentialAutoConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/AzureTokenCredentialAutoConfiguration.java @@ -10,9 +10,7 @@ import com.azure.identity.ManagedIdentityCredentialBuilder; import com.azure.identity.UsernamePasswordCredentialBuilder; import com.azure.spring.cloud.autoconfigure.implementation.AzureServiceConfigurationBase; -import com.azure.spring.cloud.autoconfigure.implementation.context.condition.SpringTokenCredentialProviderContextCondition; import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; -import com.azure.spring.cloud.autoconfigure.implementation.jdbc.SpringTokenCredentialProviderContextProvider; import com.azure.spring.cloud.autoconfigure.implementation.properties.core.AbstractAzureHttpConfigurationProperties; import com.azure.spring.cloud.core.customizer.AzureServiceClientBuilderCustomizer; import com.azure.spring.cloud.core.implementation.credential.resolver.AzureTokenCredentialResolver; @@ -38,7 +36,6 @@ import org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration; import org.springframework.boot.task.TaskExecutorBuilder; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; @@ -228,13 +225,6 @@ ThreadPoolTaskExecutor credentialTaskExecutor() { .build(); } - @Bean - @ConditionalOnMissingBean - @Conditional(SpringTokenCredentialProviderContextCondition.class) - SpringTokenCredentialProviderContextProvider springTokenCredentialProviderContextProvider() { - return new SpringTokenCredentialProviderContextProvider(); - } - static class AzureServiceClientBuilderFactoryPostProcessor implements BeanPostProcessor, BeanFactoryAware { private BeanFactory beanFactory; diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/SpringTokenCredentialProviderContextProviderAutoConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/SpringTokenCredentialProviderContextProviderAutoConfiguration.java new file mode 100644 index 000000000000..f7b7996f37bb --- /dev/null +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/SpringTokenCredentialProviderContextProviderAutoConfiguration.java @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.spring.cloud.autoconfigure.implementation.context; + +import com.azure.identity.extensions.implementation.template.AzureAuthenticationTemplate; +import com.azure.spring.cloud.autoconfigure.implementation.jdbc.SpringTokenCredentialProviderContextProvider; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for Spring Cloud Azure {@link SpringTokenCredentialProviderContextProvider}. + * + * @since 5.17.0 + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnClass(AzureAuthenticationTemplate.class) +class SpringTokenCredentialProviderContextProviderAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + static SpringTokenCredentialProviderContextProvider springTokenCredentialProviderContextProvider() { + return new SpringTokenCredentialProviderContextProvider(); + } +} diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/condition/SpringTokenCredentialProviderContextCondition.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/condition/SpringTokenCredentialProviderContextCondition.java deleted file mode 100644 index b7159ef34273..000000000000 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/condition/SpringTokenCredentialProviderContextCondition.java +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.spring.cloud.autoconfigure.implementation.context.condition; - -import com.azure.spring.cloud.autoconfigure.implementation.condition.ConditionalOnMissingProperty; -import org.springframework.boot.autoconfigure.condition.AnyNestedCondition; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; -import org.springframework.context.annotation.ConfigurationCondition; - -public class SpringTokenCredentialProviderContextCondition extends AnyNestedCondition { - - SpringTokenCredentialProviderContextCondition() { - super(ConfigurationCondition.ConfigurationPhase.REGISTER_BEAN); - } - - @ConditionalOnBean(DataSourceProperties.class) - @ConditionalOnClass(name = "com.azure.identity.extensions.implementation.template.AzureAuthenticationTemplate") - static class JdbcPasswordlessCondition { - - } - - @ConditionalOnProperty(value = "spring.jms.servicebus.passwordless-enabled", havingValue = "true") - @ConditionalOnMissingProperty(prefix = "spring.jms.servicebus", name = "connection-string") - static class ServiceBusJmsPasswordlessCondition { - - } -} diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/AzureLettucePasswordlessAutoConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/AzureLettucePasswordlessAutoConfiguration.java index 07ca86c1308a..7d9a86e2a3d6 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/AzureLettucePasswordlessAutoConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/AzureLettucePasswordlessAutoConfiguration.java @@ -23,6 +23,8 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.DependsOn; +import org.springframework.context.support.GenericApplicationContext; import org.springframework.data.redis.connection.RedisConfiguration; import org.springframework.data.redis.connection.RedisSentinelConfiguration; import org.springframework.data.redis.connection.lettuce.LettuceConnection; @@ -43,6 +45,12 @@ @EnableConfigurationProperties(RedisProperties.class) public class AzureLettucePasswordlessAutoConfiguration { + private final GenericApplicationContext applicationContext; + + AzureLettucePasswordlessAutoConfiguration(GenericApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + @Bean @ConfigurationProperties(prefix = "spring.data.redis.azure") AzureRedisPasswordlessProperties redisPasswordlessProperties() { @@ -51,10 +59,11 @@ AzureRedisPasswordlessProperties redisPasswordlessProperties() { @Bean(name = "azureRedisCredentials") @ConditionalOnMissingBean + @DependsOn("springTokenCredentialProviderContextProvider") AzureRedisCredentials azureRedisCredentials(RedisProperties redisProperties, AzureRedisPasswordlessProperties azureRedisPasswordlessProperties, AzureGlobalProperties azureGlobalProperties) { - return new AzureRedisCredentials(redisProperties.getUsername(), + return new AzureRedisCredentials(applicationContext, redisProperties.getUsername(), mergeAzureProperties(azureGlobalProperties, azureRedisPasswordlessProperties)); } diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/lettuce/AzureRedisCredentials.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/lettuce/AzureRedisCredentials.java index 6640fcd3b1a4..833a4676e2ee 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/lettuce/AzureRedisCredentials.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/lettuce/AzureRedisCredentials.java @@ -4,30 +4,65 @@ package com.azure.spring.cloud.autoconfigure.implementation.data.redis.lettuce; import com.azure.core.credential.TokenCredential; +import com.azure.identity.extensions.implementation.credential.TokenCredentialProviderOptions; +import com.azure.identity.extensions.implementation.credential.provider.TokenCredentialProvider; +import com.azure.identity.extensions.implementation.enums.AuthProperty; import com.azure.identity.extensions.implementation.template.AzureAuthenticationTemplate; import com.azure.spring.cloud.core.properties.PasswordlessProperties; +import com.azure.spring.cloud.service.implementation.identity.credential.provider.SpringTokenCredentialProvider; import com.nimbusds.jwt.JWT; import com.nimbusds.jwt.JWTParser; import io.lettuce.core.RedisCredentials; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.context.support.GenericApplicationContext; import org.springframework.util.StringUtils; import java.util.Objects; +import java.util.Properties; + +import static com.azure.spring.cloud.service.implementation.identity.credential.provider.SpringTokenCredentialProvider.PASSWORDLESS_TOKEN_CREDENTIAL_BEAN_NAME; public class AzureRedisCredentials implements RedisCredentials { public static final Logger LOGGER = LoggerFactory.getLogger(AzureRedisCredentials.class); private final AzureAuthenticationTemplate azureAuthenticationTemplate; private final String username; + private static final String SPRING_CLOUD_AZURE_REDIS_PREFIX = "spring.data.redis.azure"; + private String passwordlessPropertiesPrefix = SPRING_CLOUD_AZURE_REDIS_PREFIX; + private GenericApplicationContext applicationContext; /** * Create instance of Azure Redis Credentials */ public AzureRedisCredentials(String username, PasswordlessProperties passwordlessProperties) { + this(null, null, username, passwordlessProperties); + } + + public AzureRedisCredentials(GenericApplicationContext applicationContext, + String username, + PasswordlessProperties passwordlessProperties) { + this( null, applicationContext, username, passwordlessProperties); + } + + public AzureRedisCredentials(String passwordlessPropertiesPrefix, + GenericApplicationContext applicationContext, + String username, + PasswordlessProperties passwordlessProperties) { Objects.requireNonNull(passwordlessProperties, "PasswordlessProperties is required"); + this.applicationContext = applicationContext; azureAuthenticationTemplate = new AzureAuthenticationTemplate(); - azureAuthenticationTemplate.init(passwordlessProperties.toPasswordlessProperties()); + Properties properties = passwordlessProperties.toPasswordlessProperties(); + if (applicationContext == null) { + LOGGER.debug("The applicationContext is not available, unable to obtain the Redis passwordless " + + "token credential bean, will use default credential."); + } else { + enhancePasswordlessProperties(properties, passwordlessProperties); + } + if (StringUtils.hasText(passwordlessPropertiesPrefix)) { + this.passwordlessPropertiesPrefix = passwordlessPropertiesPrefix; + } + azureAuthenticationTemplate.init(properties); this.username = resolveUsername(azureAuthenticationTemplate, username); } @@ -55,6 +90,31 @@ private static String resolveUsername(AzureAuthenticationTemplate authentication } } + private void enhancePasswordlessProperties(Properties properties, PasswordlessProperties passwordlessProperties) { + if (!passwordlessProperties.isPasswordlessEnabled()) { + if (!passwordlessProperties.isPasswordlessEnabled()) { + LOGGER.debug("Feature passwordless authentication is not enabled({}.passwordless-enabled=false), " + + "skip enhancing Redis properties.", passwordlessPropertiesPrefix); + return; + } + } + + String tokenCredentialBeanName = passwordlessProperties.getCredential().getTokenCredentialBeanName(); + if (StringUtils.hasText(tokenCredentialBeanName)) { + AuthProperty.TOKEN_CREDENTIAL_BEAN_NAME.setProperty(properties, tokenCredentialBeanName); + } else { + TokenCredentialProvider tokenCredentialProvider = TokenCredentialProvider.createDefault(new TokenCredentialProviderOptions(properties)); + TokenCredential tokenCredential = tokenCredentialProvider.get(); + + tokenCredentialBeanName = PASSWORDLESS_TOKEN_CREDENTIAL_BEAN_NAME + "." + passwordlessPropertiesPrefix; + AuthProperty.TOKEN_CREDENTIAL_BEAN_NAME.setProperty(properties, tokenCredentialBeanName); + applicationContext.registerBean(tokenCredentialBeanName, TokenCredential.class, () -> tokenCredential); + } + + AuthProperty.TOKEN_CREDENTIAL_PROVIDER_CLASS_NAME.setProperty(properties, SpringTokenCredentialProvider.class.getName()); + AuthProperty.AUTHORITY_HOST.setProperty(properties, passwordlessProperties.getProfile().getEnvironment().getActiveDirectoryEndpoint()); + } + @Override public String getUsername() { return username; diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java index 7baa446e0923..274ba96ba9d6 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java @@ -36,7 +36,7 @@ @Configuration(proxyBeanMethods = false) @ConditionalOnMissingBean(ConnectionFactory.class) -class ServiceBusJmsConnectionFactoryConfiguration { +class ServiceBusJmsConnectionFactoryConfiguration { private static final Log logger = LogFactory.getLog(ServiceBusJmsConnectionFactoryConfiguration.class); private final GenericApplicationContext applicationContext; @@ -84,6 +84,7 @@ private TokenCredentialProvider getPasswordlessTokenCredentialProvider(AzureServ matchIfMissing = true) class SimpleConnectionFactoryConfiguration { + @Bean @ConditionalOnProperty(prefix = "spring.jms.cache", name = "enabled", havingValue = "false") @DependsOn("springTokenCredentialProviderContextProvider") diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index c23b97895fc2..12741d703d32 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -5,6 +5,7 @@ com.azure.spring.cloud.autoconfigure.implementation.aadb2c.configuration.AadB2cR com.azure.spring.cloud.autoconfigure.implementation.redis.AzureRedisAutoConfiguration com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration com.azure.spring.cloud.autoconfigure.implementation.context.AzureTokenCredentialAutoConfiguration +com.azure.spring.cloud.autoconfigure.implementation.context.SpringTokenCredentialProviderContextProviderAutoConfiguration com.azure.spring.cloud.autoconfigure.implementation.appconfiguration.AzureAppConfigurationAutoConfiguration com.azure.spring.cloud.autoconfigure.implementation.cosmos.AzureCosmosAutoConfiguration com.azure.spring.cloud.autoconfigure.implementation.eventhubs.AzureEventHubsAutoConfiguration From 052537a4d3c3ce08244aab4dda814b67e79f2f1f Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Mon, 21 Oct 2024 14:55:46 +0800 Subject: [PATCH 08/23] Fix ut failures: duplicate global properties beans, new dependency for Spring credential provider --- ...tialProviderContextProviderAutoConfiguration.java | 2 +- ...zureLettucePasswordlessAutoConfigurationTest.java | 4 +++- .../jdbc/AbstractAzureJdbcAutoConfigurationTest.java | 4 +++- ...ostProcessorWithApplicationContextRunnerTest.java | 4 +++- .../jms/ServiceBusJmsAutoConfigurationTests.java | 6 +++++- .../AzureServiceBusJmsPropertiesTests.java | 3 ++- .../environment/KeyVaultPropertySourceTests.java | 2 +- .../blob/AzureStorageBlobAutoConfigurationTests.java | 4 ++-- .../AzureStorageQueueAutoConfigurationTests.java | 4 ++-- .../AbstractServiceBusSubClientBuilderFactory.java | 12 +++++++++++- 10 files changed, 33 insertions(+), 12 deletions(-) diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/SpringTokenCredentialProviderContextProviderAutoConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/SpringTokenCredentialProviderContextProviderAutoConfiguration.java index f7b7996f37bb..683535c863a6 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/SpringTokenCredentialProviderContextProviderAutoConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/SpringTokenCredentialProviderContextProviderAutoConfiguration.java @@ -18,7 +18,7 @@ */ @Configuration(proxyBeanMethods = false) @ConditionalOnClass(AzureAuthenticationTemplate.class) -class SpringTokenCredentialProviderContextProviderAutoConfiguration { +public class SpringTokenCredentialProviderContextProviderAutoConfiguration { @Bean @ConditionalOnMissingBean diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/AzureLettucePasswordlessAutoConfigurationTest.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/AzureLettucePasswordlessAutoConfigurationTest.java index a0dc607e282c..e31868ca8491 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/AzureLettucePasswordlessAutoConfigurationTest.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/AzureLettucePasswordlessAutoConfigurationTest.java @@ -3,6 +3,7 @@ package com.azure.spring.cloud.autoconfigure.implementation.data.redis; +import com.azure.spring.cloud.autoconfigure.implementation.context.SpringTokenCredentialProviderContextProviderAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; import com.azure.spring.cloud.autoconfigure.implementation.data.redis.lettuce.AzureRedisCredentials; import io.lettuce.core.RedisCredentials; @@ -18,7 +19,8 @@ class AzureLettucePasswordlessAutoConfigurationTest { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withBean(AzureGlobalProperties.class, () -> new AzureGlobalProperties()) - .withConfiguration(AutoConfigurations.of(AzureLettucePasswordlessAutoConfiguration.class)); + .withConfiguration(AutoConfigurations.of(AzureLettucePasswordlessAutoConfiguration.class, + SpringTokenCredentialProviderContextProviderAutoConfiguration.class)); @Test void configureWithoutSpringDataLettuceConnection() { diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/AbstractAzureJdbcAutoConfigurationTest.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/AbstractAzureJdbcAutoConfigurationTest.java index 761fd6e19289..47d427e1edff 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/AbstractAzureJdbcAutoConfigurationTest.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/AbstractAzureJdbcAutoConfigurationTest.java @@ -7,6 +7,7 @@ import com.azure.identity.extensions.implementation.template.AzureAuthenticationTemplate; import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.context.AzureTokenCredentialAutoConfiguration; +import com.azure.spring.cloud.autoconfigure.implementation.context.SpringTokenCredentialProviderContextProviderAutoConfiguration; import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; @@ -30,7 +31,8 @@ abstract class AbstractAzureJdbcAutoConfigurationTest { .withConfiguration(AutoConfigurations.of(AzureJdbcAutoConfiguration.class, AzureTokenCredentialAutoConfiguration.class, AzureGlobalPropertiesAutoConfiguration.class, - DataSourceAutoConfiguration.class)); + DataSourceAutoConfiguration.class, + SpringTokenCredentialProviderContextProviderAutoConfiguration.class)); @Test void testEnhanceUrlDefaultCredential() { diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessorWithApplicationContextRunnerTest.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessorWithApplicationContextRunnerTest.java index eca3c3cc12d5..cebcec4ed08b 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessorWithApplicationContextRunnerTest.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessorWithApplicationContextRunnerTest.java @@ -7,6 +7,7 @@ import com.azure.identity.extensions.jdbc.mysql.AzureMysqlAuthenticationPlugin; import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.context.AzureTokenCredentialAutoConfiguration; +import com.azure.spring.cloud.autoconfigure.implementation.context.SpringTokenCredentialProviderContextProviderAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; import com.azure.spring.cloud.service.implementation.identity.credential.provider.SpringTokenCredentialProvider; import com.azure.spring.cloud.autoconfigure.implementation.passwordless.properties.AzureJdbcPasswordlessProperties; @@ -35,7 +36,8 @@ class JdbcPropertiesBeanPostProcessorWithApplicationContextRunnerTest { DataSourceProperties.class, AzureJdbcPasswordlessProperties.class, AzureGlobalPropertiesAutoConfiguration.class, - AzureTokenCredentialAutoConfiguration.class)); + AzureTokenCredentialAutoConfiguration.class, + SpringTokenCredentialProviderContextProviderAutoConfiguration.class)); @Test void mySqlAuthPluginNotOnClassPath() { diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsAutoConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsAutoConfigurationTests.java index 3f5dc92485db..c323888ee58a 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsAutoConfigurationTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsAutoConfigurationTests.java @@ -3,6 +3,7 @@ package com.azure.spring.cloud.autoconfigure.implementation.jms; +import com.azure.spring.cloud.autoconfigure.implementation.context.SpringTokenCredentialProviderContextProviderAutoConfiguration; 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.core.provider.connectionstring.StaticConnectionStringProvider; @@ -45,7 +46,10 @@ class ServiceBusJmsAutoConfigurationTests { new AzureServiceBusJmsPropertiesEnvironmentPostProcessor(); private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withBean(AzureGlobalProperties.class, AzureGlobalProperties::new) - .withConfiguration(AutoConfigurations.of(JmsAutoConfiguration.class, ServiceBusJmsAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of( + SpringTokenCredentialProviderContextProviderAutoConfiguration.class, + JmsAutoConfiguration.class, + ServiceBusJmsAutoConfiguration.class)) .withInitializer(context -> processor.postProcessEnvironment(context.getEnvironment(), null)); private void testQueueJmsListenerContainerFactoryWithCustomSettings(AssertableApplicationContext loaded) { diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jms/properties/AzureServiceBusJmsPropertiesTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jms/properties/AzureServiceBusJmsPropertiesTests.java index 334323482132..313e5e4fa505 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jms/properties/AzureServiceBusJmsPropertiesTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jms/properties/AzureServiceBusJmsPropertiesTests.java @@ -32,7 +32,8 @@ void connectionStringNotValid() { Exception ex = assertThrows(IllegalArgumentException.class, prop::afterPropertiesSet); - String expectedMessage = "'spring.jms.servicebus.connection-string' should be provided."; + String expectedMessage = "'spring.jms.servicebus.connection-string' should be provided, " + + "otherwise you should provide a bean 'StaticConnectionStringProvider'."; String actualMessage = ex.getMessage(); LOGGER.log(LogLevel.VERBOSE, () -> "message:" + actualMessage); assertTrue(actualMessage.contains(expectedMessage)); diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/keyvault/environment/KeyVaultPropertySourceTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/keyvault/environment/KeyVaultPropertySourceTests.java index 14b6f2504431..1747c0cfe468 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/keyvault/environment/KeyVaultPropertySourceTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/keyvault/environment/KeyVaultPropertySourceTests.java @@ -114,7 +114,7 @@ public void setTestSpringRelaxedBindingNames() { } @Test - @Timeout(5) + @Timeout(6) public void refreshTwoKeyVaultsPropertySources() throws InterruptedException { CountDownLatch latchForRefreshing = new CountDownLatch(2); new SecretRefreshing(latchForRefreshing, "KeyVault1", "test1", diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/storage/blob/AzureStorageBlobAutoConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/storage/blob/AzureStorageBlobAutoConfigurationTests.java index 0c2d29c4677a..6c80d08b170e 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/storage/blob/AzureStorageBlobAutoConfigurationTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/storage/blob/AzureStorageBlobAutoConfigurationTests.java @@ -6,6 +6,7 @@ import com.azure.data.appconfiguration.ConfigurationClientBuilder; import com.azure.spring.cloud.autoconfigure.implementation.AbstractAzureServiceConfigurationTests; import com.azure.spring.cloud.autoconfigure.implementation.TestBuilderCustomizer; +import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; import com.azure.spring.cloud.autoconfigure.implementation.storage.blob.properties.AzureStorageBlobConnectionDetails; import com.azure.spring.cloud.autoconfigure.implementation.storage.blob.properties.AzureStorageBlobProperties; @@ -34,8 +35,7 @@ class AzureStorageBlobAutoConfigurationTests extends AbstractAzureServiceConfigu private static final String STORAGE_CONNECTION_STRING_PATTERN = "DefaultEndpointsProtocol=https;AccountName=%s;AccountKey=%s;EndpointSuffix=core.windows.net"; private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withBean(AzureGlobalProperties.class, AzureGlobalProperties::new) - .withConfiguration(AutoConfigurations.of(AzureStorageBlobAutoConfiguration.class)); + .withConfiguration(AutoConfigurations.of(AzureGlobalPropertiesAutoConfiguration.class, AzureStorageBlobAutoConfiguration.class)); @Override protected ApplicationContextRunner getMinimalContextRunner() { diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/storage/queue/AzureStorageQueueAutoConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/storage/queue/AzureStorageQueueAutoConfigurationTests.java index e172d0fb9b89..b1d819b0b356 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/storage/queue/AzureStorageQueueAutoConfigurationTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/storage/queue/AzureStorageQueueAutoConfigurationTests.java @@ -6,6 +6,7 @@ import com.azure.data.appconfiguration.ConfigurationClientBuilder; import com.azure.spring.cloud.autoconfigure.implementation.AbstractAzureServiceConfigurationTests; import com.azure.spring.cloud.autoconfigure.implementation.TestBuilderCustomizer; +import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; import com.azure.spring.cloud.autoconfigure.implementation.storage.queue.properties.AzureStorageQueueConnectionDetails; import com.azure.spring.cloud.autoconfigure.implementation.storage.queue.properties.AzureStorageQueueProperties; @@ -32,8 +33,7 @@ class AzureStorageQueueAutoConfigurationTests extends AbstractAzureServiceConfig private static final String STORAGE_CONNECTION_STRING_PATTERN = "DefaultEndpointsProtocol=https;AccountName=%s;AccountKey=%s;EndpointSuffix=core.windows.net"; private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withBean(AzureGlobalProperties.class, AzureGlobalProperties::new) - .withConfiguration(AutoConfigurations.of(AzureStorageQueueAutoConfiguration.class)); + .withConfiguration(AutoConfigurations.of(AzureGlobalPropertiesAutoConfiguration.class, AzureStorageQueueAutoConfiguration.class)); @Override protected ApplicationContextRunner getMinimalContextRunner() { diff --git a/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java b/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java index 95db3f81d498..e8177a24cdb2 100644 --- a/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java +++ b/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/servicebus/factory/AbstractServiceBusSubClientBuilderFactory.java @@ -77,7 +77,17 @@ protected AbstractServiceBusSubClientBuilderFactory(ServiceBusClientBuilder serv } @Override - protected void configureCore(T builder) { + protected void configureCredential(T builder) { + // skip to avoid overriding the parent builder's credentials. + } + + @Override + protected void configureConnectionString(T builder) { + // skip to avoid overriding the parent builder's credentials. + } + + @Override + protected void configureDefaultCredential(T builder) { // skip to avoid overriding the parent builder's credentials. } From 52263a77e22c4ce9729fe43bbcbf1e0e2fd16597 Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Mon, 21 Oct 2024 15:11:03 +0800 Subject: [PATCH 09/23] Update change log --- sdk/spring/CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sdk/spring/CHANGELOG.md b/sdk/spring/CHANGELOG.md index cf42dd46fb97..cb176866282a 100644 --- a/sdk/spring/CHANGELOG.md +++ b/sdk/spring/CHANGELOG.md @@ -5,6 +5,13 @@ ### Spring Cloud Azure Autoconfigure This section includes changes in `spring-cloud-azure-autoconfigure` module. +#### Features Added +- Support to configure token credential bean name. [#41977](https://github.com/Azure/azure-sdk-for-java/issues/41977). + +#### Bugs Fixed +- Fix primitive type prop (isManagedIdentityEnabled) copy issue. [#41977](https://github.com/Azure/azure-sdk-for-java/issues/41977). +- Fix to support multiple JDBC datasource prop passwordless. [#41977](https://github.com/Azure/azure-sdk-for-java/issues/41977). + #### Breaking Changes - Change the default Service Bus JMS connection factory to `JmsPoolConnectionFactory` from `CachingConnectionFactory`. Set `spring.jms.cache.enabled=true` to continue using `CachingConnectionFactory` [#42306](https://github.com/Azure/azure-sdk-for-java/pull/42306). From ba4f2f9ef95d4487ecfaeb8a872760a2b5abc227 Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Mon, 21 Oct 2024 15:32:38 +0800 Subject: [PATCH 10/23] Fix code smells --- .../data/redis/lettuce/AzureRedisCredentials.java | 6 +++--- .../jdbc/JdbcPropertiesBeanPostProcessor.java | 10 +++++----- .../ServiceBusJmsConnectionFactoryConfiguration.java | 6 +++--- .../AzureServiceBusMessagingAutoConfiguration.java | 2 -- .../blob/AzureStorageBlobAutoConfigurationTests.java | 1 - .../queue/AzureStorageQueueAutoConfigurationTests.java | 1 - .../cloud/core/implementation/util/ClassUtils.java | 2 +- 7 files changed, 12 insertions(+), 16 deletions(-) diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/lettuce/AzureRedisCredentials.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/lettuce/AzureRedisCredentials.java index 833a4676e2ee..235bbac944d6 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/lettuce/AzureRedisCredentials.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/lettuce/AzureRedisCredentials.java @@ -42,7 +42,7 @@ public AzureRedisCredentials(String username, PasswordlessProperties passwordles public AzureRedisCredentials(GenericApplicationContext applicationContext, String username, PasswordlessProperties passwordlessProperties) { - this( null, applicationContext, username, passwordlessProperties); + this(null, applicationContext, username, passwordlessProperties); } public AzureRedisCredentials(String passwordlessPropertiesPrefix, @@ -93,8 +93,8 @@ private static String resolveUsername(AzureAuthenticationTemplate authentication private void enhancePasswordlessProperties(Properties properties, PasswordlessProperties passwordlessProperties) { if (!passwordlessProperties.isPasswordlessEnabled()) { if (!passwordlessProperties.isPasswordlessEnabled()) { - LOGGER.debug("Feature passwordless authentication is not enabled({}.passwordless-enabled=false), " + - "skip enhancing Redis properties.", passwordlessPropertiesPrefix); + LOGGER.debug("Feature passwordless authentication is not enabled({}.passwordless-enabled=false), " + + "skip enhancing Redis properties.", passwordlessPropertiesPrefix); return; } } diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessor.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessor.java index 2a13b556df94..05479d771870 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessor.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessor.java @@ -64,7 +64,7 @@ public Object postProcessBeforeInitialization(Object bean, String beanName) thro DataSourceProperties dataSourceProperties = (DataSourceProperties) bean; BeanDefinition bd = applicationContext.getBeanDefinition(beanName); String datasourcePropertiesPrefix = "spring.datasource"; - if(bd != null && bd.getSource() instanceof AnnotatedTypeMetadata metadata) { + if (bd != null && bd.getSource() instanceof AnnotatedTypeMetadata metadata) { Map annotationAttributes = metadata.getAnnotationAttributes(ConfigurationProperties.class.getName()); if (annotationAttributes != null) { datasourcePropertiesPrefix = (String) annotationAttributes.get("prefix"); @@ -73,8 +73,8 @@ public Object postProcessBeforeInitialization(Object bean, String beanName) thro String passwordlessPropertiesPrefix = datasourcePropertiesPrefix + ".azure"; AzureJdbcPasswordlessProperties properties = buildAzureProperties(passwordlessPropertiesPrefix); if (!properties.isPasswordlessEnabled()) { - LOGGER.debug("Feature passwordless authentication is not enabled(bean name is {} and {}.passwordless-enabled=false), " + - "skip enhancing jdbc url.", beanName, passwordlessPropertiesPrefix); + LOGGER.debug("Feature passwordless authentication is not enabled(bean name is {} and {}.passwordless-enabled=false), " + + "skip enhancing jdbc url.", beanName, passwordlessPropertiesPrefix); return bean; } @@ -101,8 +101,8 @@ public Object postProcessBeforeInitialization(Object bean, String beanName) thro DatabaseType databaseType = connectionString.getDatabaseType(); if (!databaseType.isDatabasePluginAvailable()) { - LOGGER.debug("The jdbc plugin with provided jdbc schema is not on the classpath, " + - "skip enhancing jdbc url ({}).", datasourcePropertiesPrefix); + LOGGER.debug("The jdbc plugin with provided jdbc schema is not on the classpath, " + + "skip enhancing jdbc url ({}).", datasourcePropertiesPrefix); return bean; } diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java index 274ba96ba9d6..d4fd9bd61111 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java @@ -38,7 +38,7 @@ @ConditionalOnMissingBean(ConnectionFactory.class) class ServiceBusJmsConnectionFactoryConfiguration { - private static final Log logger = LogFactory.getLog(ServiceBusJmsConnectionFactoryConfiguration.class); + private static final Log LOGGER = LogFactory.getLog(ServiceBusJmsConnectionFactoryConfiguration.class); private final GenericApplicationContext applicationContext; ServiceBusJmsConnectionFactoryConfiguration(GenericApplicationContext applicationContext) { @@ -55,8 +55,8 @@ private ServiceBusJmsConnectionFactory createJmsConnectionFactory(AzureServiceBu private TokenCredentialProvider getPasswordlessTokenCredentialProvider(AzureServiceBusJmsProperties serviceBusJmsProperties) { if (!serviceBusJmsProperties.isPasswordlessEnabled()) { - logger.debug("Feature passwordless authentication is not enabled(" + AzureServiceBusJmsProperties.PREFIX + ".passwordless-enabled=false), " + - "skip enhancing Service Bus JMS properties."); + LOGGER.debug("Feature passwordless authentication is not enabled(" + AzureServiceBusJmsProperties.PREFIX + ".passwordless-enabled=false), " + + "skip enhancing Service Bus JMS properties."); return null; } diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/AzureServiceBusMessagingAutoConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/AzureServiceBusMessagingAutoConfiguration.java index afae3241c1b0..43c1be1b0ac2 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/AzureServiceBusMessagingAutoConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/AzureServiceBusMessagingAutoConfiguration.java @@ -28,7 +28,6 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.ObjectProvider; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; @@ -39,7 +38,6 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; -import static com.azure.spring.cloud.autoconfigure.implementation.context.AzureContextUtils.DEFAULT_TOKEN_CREDENTIAL_BEAN_NAME; import static com.azure.spring.cloud.core.implementation.util.AzurePropertiesUtils.copyAzureCommonProperties; diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/storage/blob/AzureStorageBlobAutoConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/storage/blob/AzureStorageBlobAutoConfigurationTests.java index 6c80d08b170e..c43d2aba4dff 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/storage/blob/AzureStorageBlobAutoConfigurationTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/storage/blob/AzureStorageBlobAutoConfigurationTests.java @@ -7,7 +7,6 @@ import com.azure.spring.cloud.autoconfigure.implementation.AbstractAzureServiceConfigurationTests; import com.azure.spring.cloud.autoconfigure.implementation.TestBuilderCustomizer; import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration; -import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; import com.azure.spring.cloud.autoconfigure.implementation.storage.blob.properties.AzureStorageBlobConnectionDetails; import com.azure.spring.cloud.autoconfigure.implementation.storage.blob.properties.AzureStorageBlobProperties; import com.azure.spring.cloud.service.implementation.storage.blob.BlobServiceClientBuilderFactory; diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/storage/queue/AzureStorageQueueAutoConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/storage/queue/AzureStorageQueueAutoConfigurationTests.java index b1d819b0b356..ce5076f1c018 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/storage/queue/AzureStorageQueueAutoConfigurationTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/storage/queue/AzureStorageQueueAutoConfigurationTests.java @@ -7,7 +7,6 @@ import com.azure.spring.cloud.autoconfigure.implementation.AbstractAzureServiceConfigurationTests; import com.azure.spring.cloud.autoconfigure.implementation.TestBuilderCustomizer; import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration; -import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; import com.azure.spring.cloud.autoconfigure.implementation.storage.queue.properties.AzureStorageQueueConnectionDetails; import com.azure.spring.cloud.autoconfigure.implementation.storage.queue.properties.AzureStorageQueueProperties; import com.azure.spring.cloud.service.implementation.storage.queue.QueueServiceClientBuilderFactory; diff --git a/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/util/ClassUtils.java b/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/util/ClassUtils.java index 51bf5b4da180..5c18926e2da0 100644 --- a/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/util/ClassUtils.java +++ b/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/util/ClassUtils.java @@ -7,7 +7,7 @@ import java.util.Map; import java.util.function.Function; -public class ClassUtils { +public final class ClassUtils { private ClassUtils() { From 5591decb78253dccbefab2d1b3d18ce2a9996262 Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Mon, 21 Oct 2024 16:26:34 +0800 Subject: [PATCH 11/23] Update revapi: addedToInterface --- .../src/main/resources/revapi/revapi.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/eng/code-quality-reports/src/main/resources/revapi/revapi.json b/eng/code-quality-reports/src/main/resources/revapi/revapi.json index 41e22b303156..fce21882f76b 100644 --- a/eng/code-quality-reports/src/main/resources/revapi/revapi.json +++ b/eng/code-quality-reports/src/main/resources/revapi/revapi.json @@ -405,6 +405,11 @@ "new": "method void com.mysql.cj.protocol.ServerSession::setOldStatusFlags(int)", "justification": "Method was added to an interface." }, + { + "code": "java.method.addedToInterface", + "new": "method java.lang.String com.azure.spring.cloud.core.provider.authentication.TokenCredentialOptionsProvider.TokenCredentialOptions::getTokenCredentialBeanName()", + "justification": "Support to configure token credential bean name." + }, { "code": "java.annotation.added", "old": "method com.azure.cosmos.CosmosDiagnosticsContext com.azure.cosmos.CosmosDiagnostics::getDiagnosticsContext()", From 0a68acba4cd95dc5e17d3a40975493bf2099f422 Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Tue, 22 Oct 2024 16:31:10 +0800 Subject: [PATCH 12/23] Decouple application context for AzureRedisCredentials --- ...eLettucePasswordlessAutoConfiguration.java | 45 +++++++++++++- .../redis/lettuce/AzureRedisCredentials.java | 62 +++---------------- 2 files changed, 51 insertions(+), 56 deletions(-) diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/AzureLettucePasswordlessAutoConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/AzureLettucePasswordlessAutoConfiguration.java index 7d9a86e2a3d6..92aa673bf28e 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/AzureLettucePasswordlessAutoConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/AzureLettucePasswordlessAutoConfiguration.java @@ -3,14 +3,23 @@ package com.azure.spring.cloud.autoconfigure.implementation.data.redis; +import com.azure.core.credential.TokenCredential; +import com.azure.identity.extensions.implementation.credential.TokenCredentialProviderOptions; +import com.azure.identity.extensions.implementation.credential.provider.TokenCredentialProvider; +import com.azure.identity.extensions.implementation.credential.provider.TokenCredentialProviders; +import com.azure.identity.extensions.implementation.enums.AuthProperty; import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; import com.azure.spring.cloud.autoconfigure.implementation.passwordless.properties.AzureRedisPasswordlessProperties; import com.azure.spring.cloud.autoconfigure.implementation.data.redis.lettuce.AzureRedisCredentials; import com.azure.spring.cloud.core.implementation.util.AzurePasswordlessPropertiesUtils; +import com.azure.spring.cloud.core.properties.PasswordlessProperties; +import com.azure.spring.cloud.service.implementation.identity.credential.provider.SpringTokenCredentialProvider; import io.lettuce.core.ClientOptions; import io.lettuce.core.RedisCredentials; import io.lettuce.core.RedisCredentialsProvider; import io.lettuce.core.protocol.ProtocolVersion; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; @@ -29,8 +38,13 @@ import org.springframework.data.redis.connection.RedisSentinelConfiguration; import org.springframework.data.redis.connection.lettuce.LettuceConnection; import org.springframework.data.redis.connection.lettuce.RedisCredentialsProviderFactory; +import org.springframework.util.StringUtils; import reactor.core.publisher.Mono; +import java.util.Properties; + +import static com.azure.spring.cloud.service.implementation.identity.credential.provider.SpringTokenCredentialProvider.PASSWORDLESS_TOKEN_CREDENTIAL_BEAN_NAME; + /** * Azure Redis passwordless connection configuration using Lettuce. @@ -45,6 +59,8 @@ @EnableConfigurationProperties(RedisProperties.class) public class AzureLettucePasswordlessAutoConfiguration { + private static final Log LOGGER = LogFactory.getLog(AzureLettucePasswordlessAutoConfiguration.class); + private final GenericApplicationContext applicationContext; AzureLettucePasswordlessAutoConfiguration(GenericApplicationContext applicationContext) { @@ -63,7 +79,10 @@ AzureRedisPasswordlessProperties redisPasswordlessProperties() { AzureRedisCredentials azureRedisCredentials(RedisProperties redisProperties, AzureRedisPasswordlessProperties azureRedisPasswordlessProperties, AzureGlobalProperties azureGlobalProperties) { - return new AzureRedisCredentials(applicationContext, redisProperties.getUsername(), + Properties properties = azureRedisPasswordlessProperties.toPasswordlessProperties(); + enhancePasswordlessProperties(properties, azureRedisPasswordlessProperties); + TokenCredentialProvider provider = TokenCredentialProviders.createInstance(new TokenCredentialProviderOptions(properties)); + return new AzureRedisCredentials(redisProperties.getUsername(), provider, mergeAzureProperties(azureGlobalProperties, azureRedisPasswordlessProperties)); } @@ -91,4 +110,28 @@ private AzureRedisPasswordlessProperties mergeAzureProperties(AzureGlobalPropert return mergedProperties; } + private void enhancePasswordlessProperties(Properties properties, PasswordlessProperties passwordlessProperties) { + if (!passwordlessProperties.isPasswordlessEnabled()) { + if (!passwordlessProperties.isPasswordlessEnabled()) { + LOGGER.debug("Feature passwordless authentication is not enabled(spring.data.redis.azure.passwordless-enabled=false), " + + "skip enhancing Redis properties."); + return; + } + } + + String tokenCredentialBeanName = passwordlessProperties.getCredential().getTokenCredentialBeanName(); + if (StringUtils.hasText(tokenCredentialBeanName)) { + AuthProperty.TOKEN_CREDENTIAL_BEAN_NAME.setProperty(properties, tokenCredentialBeanName); + } else { + TokenCredentialProvider tokenCredentialProvider = TokenCredentialProvider.createDefault(new TokenCredentialProviderOptions(properties)); + TokenCredential tokenCredential = tokenCredentialProvider.get(); + + tokenCredentialBeanName = PASSWORDLESS_TOKEN_CREDENTIAL_BEAN_NAME + ".spring.data.redis.azure"; + AuthProperty.TOKEN_CREDENTIAL_BEAN_NAME.setProperty(properties, tokenCredentialBeanName); + applicationContext.registerBean(tokenCredentialBeanName, TokenCredential.class, () -> tokenCredential); + } + + AuthProperty.TOKEN_CREDENTIAL_PROVIDER_CLASS_NAME.setProperty(properties, SpringTokenCredentialProvider.class.getName()); + AuthProperty.AUTHORITY_HOST.setProperty(properties, passwordlessProperties.getProfile().getEnvironment().getActiveDirectoryEndpoint()); + } } diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/lettuce/AzureRedisCredentials.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/lettuce/AzureRedisCredentials.java index 235bbac944d6..df5f33e2483e 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/lettuce/AzureRedisCredentials.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/lettuce/AzureRedisCredentials.java @@ -4,64 +4,41 @@ package com.azure.spring.cloud.autoconfigure.implementation.data.redis.lettuce; import com.azure.core.credential.TokenCredential; -import com.azure.identity.extensions.implementation.credential.TokenCredentialProviderOptions; import com.azure.identity.extensions.implementation.credential.provider.TokenCredentialProvider; -import com.azure.identity.extensions.implementation.enums.AuthProperty; import com.azure.identity.extensions.implementation.template.AzureAuthenticationTemplate; import com.azure.spring.cloud.core.properties.PasswordlessProperties; -import com.azure.spring.cloud.service.implementation.identity.credential.provider.SpringTokenCredentialProvider; import com.nimbusds.jwt.JWT; import com.nimbusds.jwt.JWTParser; import io.lettuce.core.RedisCredentials; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.context.support.GenericApplicationContext; import org.springframework.util.StringUtils; import java.util.Objects; import java.util.Properties; -import static com.azure.spring.cloud.service.implementation.identity.credential.provider.SpringTokenCredentialProvider.PASSWORDLESS_TOKEN_CREDENTIAL_BEAN_NAME; - public class AzureRedisCredentials implements RedisCredentials { public static final Logger LOGGER = LoggerFactory.getLogger(AzureRedisCredentials.class); private final AzureAuthenticationTemplate azureAuthenticationTemplate; private final String username; - private static final String SPRING_CLOUD_AZURE_REDIS_PREFIX = "spring.data.redis.azure"; - private String passwordlessPropertiesPrefix = SPRING_CLOUD_AZURE_REDIS_PREFIX; - private GenericApplicationContext applicationContext; /** * Create instance of Azure Redis Credentials */ public AzureRedisCredentials(String username, PasswordlessProperties passwordlessProperties) { - this(null, null, username, passwordlessProperties); - } - - public AzureRedisCredentials(GenericApplicationContext applicationContext, - String username, - PasswordlessProperties passwordlessProperties) { - this(null, applicationContext, username, passwordlessProperties); + Objects.requireNonNull(passwordlessProperties, "PasswordlessProperties is required"); + azureAuthenticationTemplate = new AzureAuthenticationTemplate(); + azureAuthenticationTemplate.init(passwordlessProperties.toPasswordlessProperties()); + this.username = resolveUsername(azureAuthenticationTemplate, username); } - public AzureRedisCredentials(String passwordlessPropertiesPrefix, - GenericApplicationContext applicationContext, - String username, + public AzureRedisCredentials(String username, + TokenCredentialProvider tokenCredentialProvider, PasswordlessProperties passwordlessProperties) { Objects.requireNonNull(passwordlessProperties, "PasswordlessProperties is required"); - this.applicationContext = applicationContext; - azureAuthenticationTemplate = new AzureAuthenticationTemplate(); + azureAuthenticationTemplate = new AzureAuthenticationTemplate(tokenCredentialProvider, null); Properties properties = passwordlessProperties.toPasswordlessProperties(); - if (applicationContext == null) { - LOGGER.debug("The applicationContext is not available, unable to obtain the Redis passwordless " - + "token credential bean, will use default credential."); - } else { - enhancePasswordlessProperties(properties, passwordlessProperties); - } - if (StringUtils.hasText(passwordlessPropertiesPrefix)) { - this.passwordlessPropertiesPrefix = passwordlessPropertiesPrefix; - } azureAuthenticationTemplate.init(properties); this.username = resolveUsername(azureAuthenticationTemplate, username); } @@ -90,31 +67,6 @@ private static String resolveUsername(AzureAuthenticationTemplate authentication } } - private void enhancePasswordlessProperties(Properties properties, PasswordlessProperties passwordlessProperties) { - if (!passwordlessProperties.isPasswordlessEnabled()) { - if (!passwordlessProperties.isPasswordlessEnabled()) { - LOGGER.debug("Feature passwordless authentication is not enabled({}.passwordless-enabled=false), " - + "skip enhancing Redis properties.", passwordlessPropertiesPrefix); - return; - } - } - - String tokenCredentialBeanName = passwordlessProperties.getCredential().getTokenCredentialBeanName(); - if (StringUtils.hasText(tokenCredentialBeanName)) { - AuthProperty.TOKEN_CREDENTIAL_BEAN_NAME.setProperty(properties, tokenCredentialBeanName); - } else { - TokenCredentialProvider tokenCredentialProvider = TokenCredentialProvider.createDefault(new TokenCredentialProviderOptions(properties)); - TokenCredential tokenCredential = tokenCredentialProvider.get(); - - tokenCredentialBeanName = PASSWORDLESS_TOKEN_CREDENTIAL_BEAN_NAME + "." + passwordlessPropertiesPrefix; - AuthProperty.TOKEN_CREDENTIAL_BEAN_NAME.setProperty(properties, tokenCredentialBeanName); - applicationContext.registerBean(tokenCredentialBeanName, TokenCredential.class, () -> tokenCredential); - } - - AuthProperty.TOKEN_CREDENTIAL_PROVIDER_CLASS_NAME.setProperty(properties, SpringTokenCredentialProvider.class.getName()); - AuthProperty.AUTHORITY_HOST.setProperty(properties, passwordlessProperties.getProfile().getEnvironment().getActiveDirectoryEndpoint()); - } - @Override public String getUsername() { return username; From 641fde31e20ba48dbc60069950ea349a645fd3e1 Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Wed, 23 Oct 2024 09:24:42 +0800 Subject: [PATCH 13/23] Remove public access modifier and static keyword --- ...viderContextProviderAutoConfiguration.java | 4 ++-- ...tucePasswordlessAutoConfigurationTest.java | 7 ++++--- ...bstractAzureJdbcAutoConfigurationTest.java | 19 +++++++++++++++++-- ...essorWithApplicationContextRunnerTest.java | 6 +++--- .../ServiceBusJmsAutoConfigurationTests.java | 5 +++-- 5 files changed, 29 insertions(+), 12 deletions(-) diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/SpringTokenCredentialProviderContextProviderAutoConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/SpringTokenCredentialProviderContextProviderAutoConfiguration.java index 683535c863a6..e1c2c0d3cf4c 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/SpringTokenCredentialProviderContextProviderAutoConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/SpringTokenCredentialProviderContextProviderAutoConfiguration.java @@ -18,11 +18,11 @@ */ @Configuration(proxyBeanMethods = false) @ConditionalOnClass(AzureAuthenticationTemplate.class) -public class SpringTokenCredentialProviderContextProviderAutoConfiguration { +class SpringTokenCredentialProviderContextProviderAutoConfiguration { @Bean @ConditionalOnMissingBean - static SpringTokenCredentialProviderContextProvider springTokenCredentialProviderContextProvider() { + SpringTokenCredentialProviderContextProvider springTokenCredentialProviderContextProvider() { return new SpringTokenCredentialProviderContextProvider(); } } diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/AzureLettucePasswordlessAutoConfigurationTest.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/AzureLettucePasswordlessAutoConfigurationTest.java index e31868ca8491..d38784899ccf 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/AzureLettucePasswordlessAutoConfigurationTest.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/AzureLettucePasswordlessAutoConfigurationTest.java @@ -3,9 +3,9 @@ package com.azure.spring.cloud.autoconfigure.implementation.data.redis; -import com.azure.spring.cloud.autoconfigure.implementation.context.SpringTokenCredentialProviderContextProviderAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; import com.azure.spring.cloud.autoconfigure.implementation.data.redis.lettuce.AzureRedisCredentials; +import com.azure.spring.cloud.autoconfigure.implementation.jdbc.SpringTokenCredentialProviderContextProvider; import io.lettuce.core.RedisCredentials; import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; @@ -19,8 +19,9 @@ class AzureLettucePasswordlessAutoConfigurationTest { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withBean(AzureGlobalProperties.class, () -> new AzureGlobalProperties()) - .withConfiguration(AutoConfigurations.of(AzureLettucePasswordlessAutoConfiguration.class, - SpringTokenCredentialProviderContextProviderAutoConfiguration.class)); + .withBean("springTokenCredentialProviderContextProvider", SpringTokenCredentialProviderContextProvider.class, + SpringTokenCredentialProviderContextProvider::new) + .withConfiguration(AutoConfigurations.of(AzureLettucePasswordlessAutoConfiguration.class)); @Test void configureWithoutSpringDataLettuceConnection() { diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/AbstractAzureJdbcAutoConfigurationTest.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/AbstractAzureJdbcAutoConfigurationTest.java index 47d427e1edff..3b6e3c6db6c1 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/AbstractAzureJdbcAutoConfigurationTest.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/AbstractAzureJdbcAutoConfigurationTest.java @@ -7,13 +7,16 @@ import com.azure.identity.extensions.implementation.template.AzureAuthenticationTemplate; import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.context.AzureTokenCredentialAutoConfiguration; -import com.azure.spring.cloud.autoconfigure.implementation.context.SpringTokenCredentialProviderContextProviderAutoConfiguration; import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -32,7 +35,19 @@ abstract class AbstractAzureJdbcAutoConfigurationTest { AzureTokenCredentialAutoConfiguration.class, AzureGlobalPropertiesAutoConfiguration.class, DataSourceAutoConfiguration.class, - SpringTokenCredentialProviderContextProviderAutoConfiguration.class)); + TestSpringTokenCredentialProviderContextProviderAutoConfiguration.class)); + + @Configuration(proxyBeanMethods = false) + @ConditionalOnClass(AzureAuthenticationTemplate.class) + static + class TestSpringTokenCredentialProviderContextProviderAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + SpringTokenCredentialProviderContextProvider springTokenCredentialProviderContextProvider() { + return new SpringTokenCredentialProviderContextProvider(); + } + } @Test void testEnhanceUrlDefaultCredential() { diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessorWithApplicationContextRunnerTest.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessorWithApplicationContextRunnerTest.java index cebcec4ed08b..a63f8ec1b9aa 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessorWithApplicationContextRunnerTest.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessorWithApplicationContextRunnerTest.java @@ -7,7 +7,6 @@ import com.azure.identity.extensions.jdbc.mysql.AzureMysqlAuthenticationPlugin; import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.context.AzureTokenCredentialAutoConfiguration; -import com.azure.spring.cloud.autoconfigure.implementation.context.SpringTokenCredentialProviderContextProviderAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; import com.azure.spring.cloud.service.implementation.identity.credential.provider.SpringTokenCredentialProvider; import com.azure.spring.cloud.autoconfigure.implementation.passwordless.properties.AzureJdbcPasswordlessProperties; @@ -32,12 +31,13 @@ class JdbcPropertiesBeanPostProcessorWithApplicationContextRunnerTest { public static final String PUBLIC_TOKEN_CREDENTIAL_BEAN_NAME_STRING = AuthProperty.TOKEN_CREDENTIAL_BEAN_NAME.getPropertyKey() + "=" + "passwordlessTokenCredential"; private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withBean("springTokenCredentialProviderContextProvider", SpringTokenCredentialProviderContextProvider.class, + SpringTokenCredentialProviderContextProvider::new) .withConfiguration(AutoConfigurations.of(AzureJdbcAutoConfiguration.class, DataSourceProperties.class, AzureJdbcPasswordlessProperties.class, AzureGlobalPropertiesAutoConfiguration.class, - AzureTokenCredentialAutoConfiguration.class, - SpringTokenCredentialProviderContextProviderAutoConfiguration.class)); + AzureTokenCredentialAutoConfiguration.class)); @Test void mySqlAuthPluginNotOnClassPath() { diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsAutoConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsAutoConfigurationTests.java index c323888ee58a..b4992251b0aa 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsAutoConfigurationTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsAutoConfigurationTests.java @@ -3,8 +3,8 @@ package com.azure.spring.cloud.autoconfigure.implementation.jms; -import com.azure.spring.cloud.autoconfigure.implementation.context.SpringTokenCredentialProviderContextProviderAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; +import com.azure.spring.cloud.autoconfigure.implementation.jdbc.SpringTokenCredentialProviderContextProvider; import com.azure.spring.cloud.autoconfigure.implementation.jms.properties.AzureServiceBusJmsProperties; import com.azure.spring.cloud.core.provider.connectionstring.StaticConnectionStringProvider; import com.azure.spring.cloud.core.service.AzureServiceType; @@ -46,8 +46,9 @@ class ServiceBusJmsAutoConfigurationTests { new AzureServiceBusJmsPropertiesEnvironmentPostProcessor(); private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withBean(AzureGlobalProperties.class, AzureGlobalProperties::new) + .withBean("springTokenCredentialProviderContextProvider", SpringTokenCredentialProviderContextProvider.class, + SpringTokenCredentialProviderContextProvider::new) .withConfiguration(AutoConfigurations.of( - SpringTokenCredentialProviderContextProviderAutoConfiguration.class, JmsAutoConfiguration.class, ServiceBusJmsAutoConfiguration.class)) .withInitializer(context -> processor.postProcessEnvironment(context.getEnvironment(), null)); From de2b137603f924aefa71f91653bee9fb578db0d7 Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Mon, 28 Oct 2024 17:21:54 +0800 Subject: [PATCH 14/23] Resolve comments --- .../context/AzureContextUtils.java | 6 ++ ...zureGlobalPropertiesAutoConfiguration.java | 20 +++-- ...AzureTokenCredentialAutoConfiguration.java | 10 ++- ...viderContextProviderAutoConfiguration.java | 4 +- ...eLettucePasswordlessAutoConfiguration.java | 41 ++------- .../redis/lettuce/AzureRedisCredentials.java | 9 +- .../jdbc/AzureJdbcAutoConfiguration.java | 2 - .../jdbc/JdbcPropertiesBeanPostProcessor.java | 26 +----- ...eBusJmsConnectionFactoryConfiguration.java | 45 ++-------- ...tHubsResourceManagerAutoConfiguration.java | 7 +- ...ceBusResourceManagerAutoConfiguration.java | 7 +- ...QueueResourceManagerAutoConfiguration.java | 8 +- .../SpringPasswordlessPropertiesUtils.java | 85 +++++++++++++++++++ ...bstractAzureServiceConfigurationTests.java | 4 + .../aad/WebApplicationContextRunnerUtils.java | 6 +- .../AadResourceServerConfigurationTests.java | 5 +- .../AadWebApplicationConfigurationTests.java | 4 +- ...adAuthenticationFilterPropertiesTests.java | 4 +- .../aad/filter/ResourceRetrieverTests.java | 10 ++- .../AadB2cAutoConfigurationTests.java | 34 ++++---- ...cResourceServerAutoConfigurationTests.java | 6 +- ...dB2cAuthorizationRequestResolverTests.java | 2 + ...ppConfigurationAutoConfigurationTests.java | 4 +- ...lobalPropertiesAutoConfigurationTests.java | 3 +- ...viderContextProviderAutoConfiguration.java | 22 +++++ .../AzureCosmosAutoConfigurationTests.java | 2 + .../CosmosDataAutoConfigurationTests.java | 2 + .../AzureEventGridAutoConfigurationTests.java | 2 + .../AzureEventHubsAutoConfigurationTests.java | 4 +- ...AzureEventHubsKafkaConfigurationTests.java | 6 +- ...bstractAzureJdbcAutoConfigurationTest.java | 21 +---- ...reKafkaOAuth2BinderConfigurationTests.java | 2 + ...zureKafkaOAuth2BootConfigurationTests.java | 2 + .../AzureKeyVaultAutoConfigurationTests.java | 3 + ...aultCertificateAutoConfigurationTests.java | 2 + ...eKeyVaultSecretAutoConfigurationTests.java | 2 + ...ResourceManagerAutoConfigurationTests.java | 3 +- ...ResourceManagerAutoConfigurationTests.java | 7 +- ...ResourceManagerAutoConfigurationTests.java | 4 +- ...ResourceManagerAutoConfigurationTests.java | 4 +- ...AzureServiceBusAutoConfigurationTests.java | 4 +- ...zureStorageBlobAutoConfigurationTests.java | 4 +- ...ureStorageQueueAutoConfigurationTests.java | 4 +- .../http/IdentityUserAgentTests.java | 2 + ...tractAzureServiceClientBuilderFactory.java | 27 +++++- 45 files changed, 289 insertions(+), 192 deletions(-) create mode 100644 sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/util/SpringPasswordlessPropertiesUtils.java create mode 100644 sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/context/TestSpringTokenCredentialProviderContextProviderAutoConfiguration.java diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/AzureContextUtils.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/AzureContextUtils.java index 381b8cf6de90..a5816594b636 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/AzureContextUtils.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/AzureContextUtils.java @@ -93,4 +93,10 @@ private AzureContextUtils() { */ public static final String PASSWORDLESS_KAFKA_PROPERTIES_BEAN_POST_PROCESSOR_BEAN_NAME = "azurePasswordlessKafkaPropertiesBeanPostProcessor"; + + /** + * Bean name of the SpringTokenCredentialProviderContextProvider for the passwordless token credential acquisition. + */ + public static final String SPRING_TOKEN_CREDENTIAL_PROVIDER_CONTEXT_BEAN_NAME = + "springTokenCredentialProviderContextProvider"; } diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/AzureGlobalPropertiesAutoConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/AzureGlobalPropertiesAutoConfiguration.java index c169fbb1c6c4..f7fd5315011e 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/AzureGlobalPropertiesAutoConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/AzureGlobalPropertiesAutoConfiguration.java @@ -5,6 +5,7 @@ import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; import org.springframework.beans.factory.aot.BeanRegistrationExcludeFilter; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.RegisteredBean; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -14,8 +15,10 @@ import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.env.Environment; import org.springframework.core.type.AnnotationMetadata; +import org.springframework.util.ClassUtils; import static com.azure.spring.cloud.autoconfigure.implementation.context.AzureContextUtils.AZURE_GLOBAL_PROPERTY_BEAN_NAME; +import static com.azure.spring.cloud.autoconfigure.implementation.context.AzureContextUtils.SPRING_TOKEN_CREDENTIAL_PROVIDER_CONTEXT_BEAN_NAME; import static org.springframework.beans.factory.support.BeanDefinitionBuilder.genericBeanDefinition; /** @@ -29,6 +32,9 @@ public class AzureGlobalPropertiesAutoConfiguration { static class Registrar implements EnvironmentAware, ImportBeanDefinitionRegistrar { private Environment environment; + private static final String AZURE_AUTHENTICATION_TEMPLATE_CLASS_NAME = + "com.azure.identity.extensions.implementation.template.AzureAuthenticationTemplate"; + @Override public void setEnvironment(Environment environment) { this.environment = environment; @@ -38,12 +44,14 @@ public void setEnvironment(Environment environment) { public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { if (!registry.containsBeanDefinition(AZURE_GLOBAL_PROPERTY_BEAN_NAME)) { - registry.registerBeanDefinition(AZURE_GLOBAL_PROPERTY_BEAN_NAME, - genericBeanDefinition(AzureGlobalProperties.class, - () -> Binder.get(this.environment) - .bindOrCreate(AzureGlobalProperties.PREFIX, - AzureGlobalProperties.class)) - .getBeanDefinition()); + BeanDefinitionBuilder definitionBuilder = genericBeanDefinition(AzureGlobalProperties.class, + () -> Binder.get(this.environment) + .bindOrCreate(AzureGlobalProperties.PREFIX, + AzureGlobalProperties.class)); + if (ClassUtils.isPresent(AZURE_AUTHENTICATION_TEMPLATE_CLASS_NAME, ClassUtils.getDefaultClassLoader())) { + definitionBuilder.addDependsOn(SPRING_TOKEN_CREDENTIAL_PROVIDER_CONTEXT_BEAN_NAME); + } + registry.registerBeanDefinition(AZURE_GLOBAL_PROPERTY_BEAN_NAME, definitionBuilder.getBeanDefinition()); } } diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/AzureTokenCredentialAutoConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/AzureTokenCredentialAutoConfiguration.java index c6a9ee8e2760..6367bd2056be 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/AzureTokenCredentialAutoConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/AzureTokenCredentialAutoConfiguration.java @@ -37,6 +37,7 @@ import org.springframework.boot.task.TaskExecutorBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.support.GenericApplicationContext; import org.springframework.core.annotation.Order; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.util.StringUtils; @@ -55,10 +56,12 @@ public class AzureTokenCredentialAutoConfiguration extends AzureServiceConfigurationBase { private static final Logger LOGGER = LoggerFactory.getLogger(AzureTokenCredentialAutoConfiguration.class); + private final GenericApplicationContext applicationContext; private final IdentityClientProperties identityClientProperties; - AzureTokenCredentialAutoConfiguration(AzureGlobalProperties azureGlobalProperties) { + AzureTokenCredentialAutoConfiguration(GenericApplicationContext applicationContext, AzureGlobalProperties azureGlobalProperties) { super(azureGlobalProperties); + this.applicationContext = applicationContext; this.identityClientProperties = loadProperties(azureGlobalProperties, new IdentityClientProperties()); } @@ -101,6 +104,11 @@ AzureTokenCredentialResolver azureTokenCredentialResolver( return null; } + String tokenCredentialBeanName = azureProperties.getCredential().getTokenCredentialBeanName(); + if (StringUtils.hasText(tokenCredentialBeanName)) { + return this.applicationContext.getBean(tokenCredentialBeanName, TokenCredential.class); + } + final TokenCredentialOptionsProvider.TokenCredentialOptions properties = azureProperties.getCredential(); final String tenantId = azureProperties.getProfile().getTenantId(); final String clientId = properties.getClientId(); diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/SpringTokenCredentialProviderContextProviderAutoConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/SpringTokenCredentialProviderContextProviderAutoConfiguration.java index e1c2c0d3cf4c..32abeee6edd2 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/SpringTokenCredentialProviderContextProviderAutoConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/SpringTokenCredentialProviderContextProviderAutoConfiguration.java @@ -11,6 +11,8 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import static com.azure.spring.cloud.autoconfigure.implementation.context.AzureContextUtils.SPRING_TOKEN_CREDENTIAL_PROVIDER_CONTEXT_BEAN_NAME; + /** * {@link EnableAutoConfiguration Auto-configuration} for Spring Cloud Azure {@link SpringTokenCredentialProviderContextProvider}. * @@ -20,7 +22,7 @@ @ConditionalOnClass(AzureAuthenticationTemplate.class) class SpringTokenCredentialProviderContextProviderAutoConfiguration { - @Bean + @Bean(name = SPRING_TOKEN_CREDENTIAL_PROVIDER_CONTEXT_BEAN_NAME) @ConditionalOnMissingBean SpringTokenCredentialProviderContextProvider springTokenCredentialProviderContextProvider() { return new SpringTokenCredentialProviderContextProvider(); diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/AzureLettucePasswordlessAutoConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/AzureLettucePasswordlessAutoConfiguration.java index 92aa673bf28e..d24cbbcfa647 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/AzureLettucePasswordlessAutoConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/AzureLettucePasswordlessAutoConfiguration.java @@ -3,17 +3,13 @@ package com.azure.spring.cloud.autoconfigure.implementation.data.redis; -import com.azure.core.credential.TokenCredential; import com.azure.identity.extensions.implementation.credential.TokenCredentialProviderOptions; import com.azure.identity.extensions.implementation.credential.provider.TokenCredentialProvider; import com.azure.identity.extensions.implementation.credential.provider.TokenCredentialProviders; -import com.azure.identity.extensions.implementation.enums.AuthProperty; import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; import com.azure.spring.cloud.autoconfigure.implementation.passwordless.properties.AzureRedisPasswordlessProperties; import com.azure.spring.cloud.autoconfigure.implementation.data.redis.lettuce.AzureRedisCredentials; import com.azure.spring.cloud.core.implementation.util.AzurePasswordlessPropertiesUtils; -import com.azure.spring.cloud.core.properties.PasswordlessProperties; -import com.azure.spring.cloud.service.implementation.identity.credential.provider.SpringTokenCredentialProvider; import io.lettuce.core.ClientOptions; import io.lettuce.core.RedisCredentials; import io.lettuce.core.RedisCredentialsProvider; @@ -32,18 +28,16 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.DependsOn; import org.springframework.context.support.GenericApplicationContext; import org.springframework.data.redis.connection.RedisConfiguration; import org.springframework.data.redis.connection.RedisSentinelConfiguration; import org.springframework.data.redis.connection.lettuce.LettuceConnection; import org.springframework.data.redis.connection.lettuce.RedisCredentialsProviderFactory; -import org.springframework.util.StringUtils; import reactor.core.publisher.Mono; import java.util.Properties; -import static com.azure.spring.cloud.service.implementation.identity.credential.provider.SpringTokenCredentialProvider.PASSWORDLESS_TOKEN_CREDENTIAL_BEAN_NAME; +import static com.azure.spring.cloud.autoconfigure.implementation.util.SpringPasswordlessPropertiesUtils.enhancePasswordlessProperties; /** @@ -75,15 +69,15 @@ AzureRedisPasswordlessProperties redisPasswordlessProperties() { @Bean(name = "azureRedisCredentials") @ConditionalOnMissingBean - @DependsOn("springTokenCredentialProviderContextProvider") AzureRedisCredentials azureRedisCredentials(RedisProperties redisProperties, AzureRedisPasswordlessProperties azureRedisPasswordlessProperties, AzureGlobalProperties azureGlobalProperties) { Properties properties = azureRedisPasswordlessProperties.toPasswordlessProperties(); - enhancePasswordlessProperties(properties, azureRedisPasswordlessProperties); + enhancePasswordlessProperties(applicationContext, "spring.data.redis.azure", + azureRedisPasswordlessProperties, properties); TokenCredentialProvider provider = TokenCredentialProviders.createInstance(new TokenCredentialProviderOptions(properties)); - return new AzureRedisCredentials(redisProperties.getUsername(), provider, - mergeAzureProperties(azureGlobalProperties, azureRedisPasswordlessProperties)); + return new AzureRedisCredentials(redisProperties.getUsername(), + mergeAzureProperties(azureGlobalProperties, azureRedisPasswordlessProperties), provider); } @Bean(name = "azureLettuceClientConfigurationBuilderCustomizer") @@ -109,29 +103,4 @@ private AzureRedisPasswordlessProperties mergeAzureProperties(AzureGlobalPropert AzurePasswordlessPropertiesUtils.mergeAzureCommonProperties(azureGlobalProperties, azurePasswordlessProperties, mergedProperties); return mergedProperties; } - - private void enhancePasswordlessProperties(Properties properties, PasswordlessProperties passwordlessProperties) { - if (!passwordlessProperties.isPasswordlessEnabled()) { - if (!passwordlessProperties.isPasswordlessEnabled()) { - LOGGER.debug("Feature passwordless authentication is not enabled(spring.data.redis.azure.passwordless-enabled=false), " - + "skip enhancing Redis properties."); - return; - } - } - - String tokenCredentialBeanName = passwordlessProperties.getCredential().getTokenCredentialBeanName(); - if (StringUtils.hasText(tokenCredentialBeanName)) { - AuthProperty.TOKEN_CREDENTIAL_BEAN_NAME.setProperty(properties, tokenCredentialBeanName); - } else { - TokenCredentialProvider tokenCredentialProvider = TokenCredentialProvider.createDefault(new TokenCredentialProviderOptions(properties)); - TokenCredential tokenCredential = tokenCredentialProvider.get(); - - tokenCredentialBeanName = PASSWORDLESS_TOKEN_CREDENTIAL_BEAN_NAME + ".spring.data.redis.azure"; - AuthProperty.TOKEN_CREDENTIAL_BEAN_NAME.setProperty(properties, tokenCredentialBeanName); - applicationContext.registerBean(tokenCredentialBeanName, TokenCredential.class, () -> tokenCredential); - } - - AuthProperty.TOKEN_CREDENTIAL_PROVIDER_CLASS_NAME.setProperty(properties, SpringTokenCredentialProvider.class.getName()); - AuthProperty.AUTHORITY_HOST.setProperty(properties, passwordlessProperties.getProfile().getEnvironment().getActiveDirectoryEndpoint()); - } } diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/lettuce/AzureRedisCredentials.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/lettuce/AzureRedisCredentials.java index df5f33e2483e..feb476e56309 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/lettuce/AzureRedisCredentials.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/lettuce/AzureRedisCredentials.java @@ -27,15 +27,12 @@ public class AzureRedisCredentials implements RedisCredentials { * Create instance of Azure Redis Credentials */ public AzureRedisCredentials(String username, PasswordlessProperties passwordlessProperties) { - Objects.requireNonNull(passwordlessProperties, "PasswordlessProperties is required"); - azureAuthenticationTemplate = new AzureAuthenticationTemplate(); - azureAuthenticationTemplate.init(passwordlessProperties.toPasswordlessProperties()); - this.username = resolveUsername(azureAuthenticationTemplate, username); + this(username, passwordlessProperties, (TokenCredentialProvider) null); } public AzureRedisCredentials(String username, - TokenCredentialProvider tokenCredentialProvider, - PasswordlessProperties passwordlessProperties) { + PasswordlessProperties passwordlessProperties, + TokenCredentialProvider tokenCredentialProvider) { Objects.requireNonNull(passwordlessProperties, "PasswordlessProperties is required"); azureAuthenticationTemplate = new AzureAuthenticationTemplate(tokenCredentialProvider, null); Properties properties = passwordlessProperties.toPasswordlessProperties(); diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/AzureJdbcAutoConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/AzureJdbcAutoConfiguration.java index 75a2a3a6d012..9cb55b4266ea 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/AzureJdbcAutoConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/AzureJdbcAutoConfiguration.java @@ -12,7 +12,6 @@ import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.DependsOn; /** @@ -29,7 +28,6 @@ public class AzureJdbcAutoConfiguration { @Bean @ConditionalOnMissingBean - @DependsOn("springTokenCredentialProviderContextProvider") JdbcPropertiesBeanPostProcessor jdbcConfigurationPropertiesBeanPostProcessor() { return new JdbcPropertiesBeanPostProcessor(); } diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessor.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessor.java index 05479d771870..1d9e177c4606 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessor.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessor.java @@ -2,15 +2,10 @@ // Licensed under the MIT License. package com.azure.spring.cloud.autoconfigure.implementation.jdbc; -import com.azure.core.credential.TokenCredential; -import com.azure.identity.extensions.implementation.credential.TokenCredentialProviderOptions; -import com.azure.identity.extensions.implementation.credential.provider.TokenCredentialProvider; -import com.azure.identity.extensions.implementation.enums.AuthProperty; import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; 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.implementation.util.AzureSpringIdentifier; -import com.azure.spring.cloud.service.implementation.identity.credential.provider.SpringTokenCredentialProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; @@ -39,7 +34,7 @@ import static com.azure.spring.cloud.autoconfigure.implementation.jdbc.JdbcPropertyConstants.POSTGRESQL_PROPERTY_NAME_APPLICATION_NAME; import static com.azure.spring.cloud.autoconfigure.implementation.jdbc.JdbcPropertyConstants.POSTGRESQL_PROPERTY_NAME_ASSUME_MIN_SERVER_VERSION; import static com.azure.spring.cloud.autoconfigure.implementation.jdbc.JdbcPropertyConstants.POSTGRESQL_PROPERTY_VALUE_ASSUME_MIN_SERVER_VERSION; -import static com.azure.spring.cloud.service.implementation.identity.credential.provider.SpringTokenCredentialProvider.PASSWORDLESS_TOKEN_CREDENTIAL_BEAN_NAME; +import static com.azure.spring.cloud.autoconfigure.implementation.util.SpringPasswordlessPropertiesUtils.enhancePasswordlessProperties; /** @@ -48,7 +43,6 @@ class JdbcPropertiesBeanPostProcessor implements BeanPostProcessor, EnvironmentAware, ApplicationContextAware, PriorityOrdered { private static final Logger LOGGER = LoggerFactory.getLogger(JdbcPropertiesBeanPostProcessor.class); - private static final String SPRING_TOKEN_CREDENTIAL_PROVIDER_CLASS_NAME = SpringTokenCredentialProvider.class.getName(); private GenericApplicationContext applicationContext; private Environment environment; @@ -147,24 +141,8 @@ private void enhanceUserAgent(DatabaseType databaseType, JdbcConnectionStringEnh private Map buildEnhancedProperties(String passwordlessPropertiesPrefix, DatabaseType databaseType, AzureJdbcPasswordlessProperties properties) { Map result = new HashMap<>(); - String tokenCredentialBeanName = properties.getCredential().getTokenCredentialBeanName(); - if (StringUtils.hasText(tokenCredentialBeanName)) { - AuthProperty.TOKEN_CREDENTIAL_BEAN_NAME.setProperty(result, tokenCredentialBeanName); - } else { - TokenCredentialProvider tokenCredentialProvider = TokenCredentialProvider.createDefault(new TokenCredentialProviderOptions(properties.toPasswordlessProperties())); - TokenCredential tokenCredential = tokenCredentialProvider.get(); - - tokenCredentialBeanName = PASSWORDLESS_TOKEN_CREDENTIAL_BEAN_NAME + "." + passwordlessPropertiesPrefix; - AuthProperty.TOKEN_CREDENTIAL_BEAN_NAME.setProperty(result, tokenCredentialBeanName); - applicationContext.registerBean(tokenCredentialBeanName, TokenCredential.class, () -> tokenCredential); - } - - LOGGER.debug("Add SpringTokenCredentialProvider as the default token credential provider."); - AuthProperty.TOKEN_CREDENTIAL_PROVIDER_CLASS_NAME.setProperty(result, SPRING_TOKEN_CREDENTIAL_PROVIDER_CLASS_NAME); - AuthProperty.AUTHORITY_HOST.setProperty(result, properties.getProfile().getEnvironment().getActiveDirectoryEndpoint()); - + enhancePasswordlessProperties(applicationContext, passwordlessPropertiesPrefix, properties, result); databaseType.setDefaultEnhancedProperties(result); - return result; } diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java index d4fd9bd61111..a7fd8a597416 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java @@ -3,17 +3,12 @@ package com.azure.spring.cloud.autoconfigure.implementation.jms; -import com.azure.core.credential.TokenCredential; import com.azure.identity.extensions.implementation.credential.TokenCredentialProviderOptions; import com.azure.identity.extensions.implementation.credential.provider.TokenCredentialProvider; -import com.azure.identity.extensions.implementation.enums.AuthProperty; import com.azure.servicebus.jms.ServiceBusJmsConnectionFactory; import com.azure.spring.cloud.autoconfigure.implementation.jms.properties.AzureServiceBusJmsProperties; import com.azure.spring.cloud.autoconfigure.jms.AzureServiceBusJmsConnectionFactoryCustomizer; -import com.azure.spring.cloud.service.implementation.identity.credential.provider.SpringTokenCredentialProvider; import jakarta.jms.ConnectionFactory; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.apache.commons.pool2.PooledObject; import org.messaginghub.pooled.jms.JmsPoolConnectionFactory; import org.springframework.beans.factory.ObjectProvider; @@ -24,21 +19,18 @@ import org.springframework.boot.autoconfigure.jms.JmsProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.DependsOn; import org.springframework.context.support.GenericApplicationContext; import org.springframework.jms.connection.CachingConnectionFactory; -import org.springframework.util.StringUtils; import java.util.Properties; import java.util.stream.Collectors; -import static com.azure.spring.cloud.service.implementation.identity.credential.provider.SpringTokenCredentialProvider.PASSWORDLESS_TOKEN_CREDENTIAL_BEAN_NAME; +import static com.azure.spring.cloud.autoconfigure.implementation.util.SpringPasswordlessPropertiesUtils.enhancePasswordlessProperties; @Configuration(proxyBeanMethods = false) @ConditionalOnMissingBean(ConnectionFactory.class) -class ServiceBusJmsConnectionFactoryConfiguration { +public class ServiceBusJmsConnectionFactoryConfiguration { - private static final Log LOGGER = LogFactory.getLog(ServiceBusJmsConnectionFactoryConfiguration.class); private final GenericApplicationContext applicationContext; ServiceBusJmsConnectionFactoryConfiguration(GenericApplicationContext applicationContext) { @@ -47,38 +39,14 @@ class ServiceBusJmsConnectionFactoryConfiguration { private ServiceBusJmsConnectionFactory createJmsConnectionFactory(AzureServiceBusJmsProperties jmsProperties, ObjectProvider factoryCustomizers) { - TokenCredentialProvider tokenCredentialProvider = getPasswordlessTokenCredentialProvider(jmsProperties); + Properties properties = jmsProperties.toPasswordlessProperties(); + enhancePasswordlessProperties(applicationContext, AzureServiceBusJmsProperties.PREFIX, jmsProperties, properties); + TokenCredentialProvider tokenCredentialProvider = TokenCredentialProvider.createDefault(new TokenCredentialProviderOptions(properties)); return new ServiceBusJmsConnectionFactoryFactory(tokenCredentialProvider, jmsProperties, factoryCustomizers.orderedStream().collect(Collectors.toList())) .createConnectionFactory(ServiceBusJmsConnectionFactory.class); } - private TokenCredentialProvider getPasswordlessTokenCredentialProvider(AzureServiceBusJmsProperties serviceBusJmsProperties) { - if (!serviceBusJmsProperties.isPasswordlessEnabled()) { - LOGGER.debug("Feature passwordless authentication is not enabled(" + AzureServiceBusJmsProperties.PREFIX + ".passwordless-enabled=false), " - + "skip enhancing Service Bus JMS properties."); - return null; - } - - Properties properties = serviceBusJmsProperties.toPasswordlessProperties(); - String tokenCredentialBeanName = serviceBusJmsProperties.getCredential().getTokenCredentialBeanName(); - if (StringUtils.hasText(tokenCredentialBeanName)) { - AuthProperty.TOKEN_CREDENTIAL_BEAN_NAME.setProperty(properties, tokenCredentialBeanName); - } else { - TokenCredentialProvider tokenCredentialProvider = TokenCredentialProvider.createDefault(new TokenCredentialProviderOptions(properties)); - TokenCredential tokenCredential = tokenCredentialProvider.get(); - - tokenCredentialBeanName = PASSWORDLESS_TOKEN_CREDENTIAL_BEAN_NAME + "." + AzureServiceBusJmsProperties.PREFIX; - AuthProperty.TOKEN_CREDENTIAL_BEAN_NAME.setProperty(properties, tokenCredentialBeanName); - applicationContext.registerBean(tokenCredentialBeanName, TokenCredential.class, () -> tokenCredential); - } - - AuthProperty.TOKEN_CREDENTIAL_PROVIDER_CLASS_NAME.setProperty(properties, SpringTokenCredentialProvider.class.getName()); - AuthProperty.AUTHORITY_HOST.setProperty(properties, serviceBusJmsProperties.getProfile().getEnvironment().getActiveDirectoryEndpoint()); - - return TokenCredentialProvider.createDefault(new TokenCredentialProviderOptions(properties)); - } - @Configuration(proxyBeanMethods = false) @ConditionalOnProperty(prefix = "spring.jms.servicebus.pool", name = "enabled", havingValue = "false", matchIfMissing = true) @@ -87,7 +55,6 @@ class SimpleConnectionFactoryConfiguration { @Bean @ConditionalOnProperty(prefix = "spring.jms.cache", name = "enabled", havingValue = "false") - @DependsOn("springTokenCredentialProviderContextProvider") ServiceBusJmsConnectionFactory jmsConnectionFactory(AzureServiceBusJmsProperties properties, ObjectProvider factoryCustomizers) { return createJmsConnectionFactory(properties, factoryCustomizers); @@ -100,7 +67,6 @@ ServiceBusJmsConnectionFactory jmsConnectionFactory(AzureServiceBusJmsProperties class CachingConnectionFactoryConfiguration { @Bean - @DependsOn("springTokenCredentialProviderContextProvider") CachingConnectionFactory jmsConnectionFactory(JmsProperties jmsProperties, AzureServiceBusJmsProperties properties, ObjectProvider factoryCustomizers) { @@ -122,7 +88,6 @@ class PooledConnectionFactoryConfiguration { @Bean(destroyMethod = "stop") @ConditionalOnProperty(prefix = "spring.jms.servicebus.pool", name = "enabled", havingValue = "true") - @DependsOn("springTokenCredentialProviderContextProvider") JmsPoolConnectionFactory jmsPoolConnectionFactory(AzureServiceBusJmsProperties properties, ObjectProvider factoryCustomizers) { ServiceBusJmsConnectionFactory factory = createJmsConnectionFactory(properties, factoryCustomizers); diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureEventHubsResourceManagerAutoConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureEventHubsResourceManagerAutoConfiguration.java index 32b71fd7594a..d5d9b741941c 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureEventHubsResourceManagerAutoConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureEventHubsResourceManagerAutoConfiguration.java @@ -5,7 +5,6 @@ import com.azure.resourcemanager.AzureResourceManager; import com.azure.spring.cloud.autoconfigure.implementation.condition.ConditionalOnMissingProperty; -import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; import com.azure.spring.cloud.autoconfigure.implementation.eventhubs.properties.AzureEventHubsProperties; import com.azure.spring.cloud.resourcemanager.implementation.connectionstring.EventHubsArmConnectionStringProvider; import com.azure.spring.cloud.resourcemanager.implementation.provisioning.DefaultEventHubsProvisioner; @@ -43,11 +42,7 @@ public class AzureEventHubsResourceManagerAutoConfiguration extends AzureService @Bean @ConditionalOnMissingBean @ConditionalOnProperty(prefix = AzureEventHubsProperties.PREFIX, value = "namespace") - @ConditionalOnMissingProperty({ - AzureEventHubsProperties.PREFIX + ".connection-string", - AzureGlobalProperties.PREFIX + ".credential.token-credential-bean-name", - AzureEventHubsProperties.PREFIX + ".credential.token-credential-bean-name" - }) + @ConditionalOnMissingProperty(prefix = AzureEventHubsProperties.PREFIX, value = "connection-string") @Order EventHubsArmConnectionStringProvider eventHubsArmConnectionStringProvider() { diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureServiceBusResourceManagerAutoConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureServiceBusResourceManagerAutoConfiguration.java index 3a15266e567b..ce7c1aaba138 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureServiceBusResourceManagerAutoConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureServiceBusResourceManagerAutoConfiguration.java @@ -5,7 +5,6 @@ import com.azure.resourcemanager.AzureResourceManager; import com.azure.spring.cloud.autoconfigure.implementation.condition.ConditionalOnMissingProperty; -import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; import com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties.AzureServiceBusProperties; import com.azure.spring.cloud.resourcemanager.implementation.connectionstring.ServiceBusArmConnectionStringProvider; import com.azure.spring.cloud.resourcemanager.implementation.provisioning.DefaultServiceBusProvisioner; @@ -49,11 +48,7 @@ ServiceBusProvisioner serviceBusProvisioner() { @Bean @ConditionalOnMissingBean @ConditionalOnProperty(prefix = AzureServiceBusProperties.PREFIX, value = "namespace") - @ConditionalOnMissingProperty({ - AzureServiceBusProperties.PREFIX + ".connection-string", - AzureGlobalProperties.PREFIX + ".credential.token-credential-bean-name", - AzureServiceBusProperties.PREFIX + ".credential.token-credential-bean-name" - }) + @ConditionalOnMissingProperty(prefix = AzureServiceBusProperties.PREFIX, value = "connection-string") @Order ServiceBusArmConnectionStringProvider serviceBusArmConnectionStringProvider() { return new ServiceBusArmConnectionStringProvider(this.azureResourceManager, diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureStorageQueueResourceManagerAutoConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureStorageQueueResourceManagerAutoConfiguration.java index 79efb410c9a4..132723ca57d5 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureStorageQueueResourceManagerAutoConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureStorageQueueResourceManagerAutoConfiguration.java @@ -4,8 +4,6 @@ package com.azure.spring.cloud.autoconfigure.implementation.resourcemanager; import com.azure.resourcemanager.AzureResourceManager; -import com.azure.spring.cloud.autoconfigure.implementation.condition.ConditionalOnMissingProperty; -import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; import com.azure.spring.cloud.autoconfigure.implementation.storage.queue.properties.AzureStorageQueueProperties; import com.azure.spring.cloud.resourcemanager.implementation.connectionstring.StorageQueueArmConnectionStringProvider; import org.springframework.boot.autoconfigure.AutoConfigureAfter; @@ -40,11 +38,7 @@ public class AzureStorageQueueResourceManagerAutoConfiguration extends AzureServ @Bean @ConditionalOnMissingBean - @ConditionalOnMissingProperty({ - AzureStorageQueueProperties.PREFIX + ".connection-string", - AzureGlobalProperties.PREFIX + ".credential.token-credential-bean-name", - AzureStorageQueueProperties.PREFIX + ".credential.token-credential-bean-name" - }) + @ConditionalOnProperty(prefix = AzureStorageQueueProperties.PREFIX, value = "account-name") @Order StorageQueueArmConnectionStringProvider storageQueueArmConnectionStringProvider() { return new StorageQueueArmConnectionStringProvider(this.azureResourceManager, diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/util/SpringPasswordlessPropertiesUtils.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/util/SpringPasswordlessPropertiesUtils.java new file mode 100644 index 000000000000..ae37cd3b0d9b --- /dev/null +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/util/SpringPasswordlessPropertiesUtils.java @@ -0,0 +1,85 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.spring.cloud.autoconfigure.implementation.util; + +import com.azure.core.credential.TokenCredential; +import com.azure.identity.extensions.implementation.credential.TokenCredentialProviderOptions; +import com.azure.identity.extensions.implementation.credential.provider.TokenCredentialProvider; +import com.azure.identity.extensions.implementation.enums.AuthProperty; +import com.azure.spring.cloud.core.properties.PasswordlessProperties; +import com.azure.spring.cloud.service.implementation.identity.credential.provider.SpringTokenCredentialProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.support.GenericApplicationContext; +import org.springframework.util.StringUtils; + +import java.util.Map; +import java.util.Properties; + +import static com.azure.spring.cloud.service.implementation.identity.credential.provider.SpringTokenCredentialProvider.PASSWORDLESS_TOKEN_CREDENTIAL_BEAN_NAME; + +/** + * Util class for passwordless properties enhancement. + */ +public final class SpringPasswordlessPropertiesUtils { + + private static final Logger LOGGER = LoggerFactory.getLogger(SpringPasswordlessPropertiesUtils.class); + + private SpringPasswordlessPropertiesUtils() { + + } + + /** + * Enhance the {@link PasswordlessProperties} implementation into the {@link Properties}. + * @param applicationContext the application context. + * @param passwordlessPropertiesPrefix the prefix for the {@link PasswordlessProperties}. + * @param passwordlessProperties the {@link PasswordlessProperties} implementation. + * @param properties the {@link Properties} {@link Properties}. + */ + public static void enhancePasswordlessProperties(GenericApplicationContext applicationContext, + String passwordlessPropertiesPrefix, + PasswordlessProperties passwordlessProperties, + Properties properties) { + if (!passwordlessProperties.isPasswordlessEnabled()) { + if (!passwordlessProperties.isPasswordlessEnabled()) { + LOGGER.debug("Feature passwordless authentication is not enabled({}.passwordless-enabled=false), " + + "skip enhancing properties.", passwordlessPropertiesPrefix); + return; + } + } + + String tokenCredentialBeanName = passwordlessProperties.getCredential().getTokenCredentialBeanName(); + if (StringUtils.hasText(tokenCredentialBeanName)) { + AuthProperty.TOKEN_CREDENTIAL_BEAN_NAME.setProperty(properties, tokenCredentialBeanName); + } else { + TokenCredentialProvider tokenCredentialProvider = TokenCredentialProvider.createDefault(new TokenCredentialProviderOptions(properties)); + TokenCredential tokenCredential = tokenCredentialProvider.get(); + + tokenCredentialBeanName = PASSWORDLESS_TOKEN_CREDENTIAL_BEAN_NAME + "." + passwordlessPropertiesPrefix; + AuthProperty.TOKEN_CREDENTIAL_BEAN_NAME.setProperty(properties, tokenCredentialBeanName); + applicationContext.registerBean(tokenCredentialBeanName, TokenCredential.class, () -> tokenCredential); + } + + AuthProperty.TOKEN_CREDENTIAL_PROVIDER_CLASS_NAME.setProperty(properties, SpringTokenCredentialProvider.class.getName()); + AuthProperty.AUTHORITY_HOST.setProperty(properties, passwordlessProperties.getProfile().getEnvironment().getActiveDirectoryEndpoint()); + + } + + /** + * Enhance the {@link PasswordlessProperties} implementation into the Map. + * @param applicationContext the application context. + * @param passwordlessPropertiesPrefix the prefix for the {@link PasswordlessProperties}. + * @param passwordlessProperties the {@link PasswordlessProperties} implementation. + * @param result the Map. + */ + public static void enhancePasswordlessProperties(GenericApplicationContext applicationContext, + String passwordlessPropertiesPrefix, + PasswordlessProperties passwordlessProperties, + Map result) { + Properties properties = new Properties(); + result.forEach(properties::setProperty); + enhancePasswordlessProperties(applicationContext, passwordlessPropertiesPrefix, passwordlessProperties, properties); + properties.forEach((key, value) -> result.put((String) key, (String) value)); + } +} diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/AbstractAzureServiceConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/AbstractAzureServiceConfigurationTests.java index 9285faecaf06..0a986f307174 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/AbstractAzureServiceConfigurationTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/AbstractAzureServiceConfigurationTests.java @@ -11,6 +11,7 @@ import com.azure.identity.implementation.IdentityClient; import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.context.AzureTokenCredentialAutoConfiguration; +import com.azure.spring.cloud.autoconfigure.implementation.context.TestSpringTokenCredentialProviderContextProviderAutoConfiguration; import com.azure.spring.cloud.core.implementation.credential.resolver.AzureTokenCredentialResolver; import com.azure.spring.cloud.core.implementation.factory.AbstractAzureServiceClientBuilderFactory; import com.azure.spring.cloud.core.properties.AzureProperties; @@ -44,6 +45,7 @@ protected void usGovCloudShouldWorkWithClientSecretCredential() { getPropertyPrefix() + ".credential.client-secret=fake-client-secret" ) .withConfiguration(AutoConfigurations.of( + TestSpringTokenCredentialProviderContextProviderAutoConfiguration.class, AzureTokenCredentialAutoConfiguration.class, AzureGlobalPropertiesAutoConfiguration.class )) @@ -62,6 +64,7 @@ protected void usGovCloudShouldWorkWithClientCertificateCredential() { getPropertyPrefix() + ".credential.client-certificate-path=fake-client-cert-path" ) .withConfiguration(AutoConfigurations.of( + TestSpringTokenCredentialProviderContextProviderAutoConfiguration.class, AzureTokenCredentialAutoConfiguration.class, AzureGlobalPropertiesAutoConfiguration.class )) @@ -81,6 +84,7 @@ protected void usGovCloudShouldWorkWithUsernamePasswordCredential() { ) .withConfiguration(AutoConfigurations.of( AzureTokenCredentialAutoConfiguration.class, + TestSpringTokenCredentialProviderContextProviderAutoConfiguration.class, AzureGlobalPropertiesAutoConfiguration.class )) .run(context -> { diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/aad/WebApplicationContextRunnerUtils.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/aad/WebApplicationContextRunnerUtils.java index a619816dc9e1..89dbb10767a6 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/aad/WebApplicationContextRunnerUtils.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/aad/WebApplicationContextRunnerUtils.java @@ -5,6 +5,7 @@ import com.azure.spring.cloud.autoconfigure.implementation.aad.configuration.AadAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration; +import com.azure.spring.cloud.autoconfigure.implementation.context.TestSpringTokenCredentialProviderContextProviderAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration; import org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener; @@ -26,7 +27,10 @@ public static WebApplicationContextRunner oauthClientAndResourceServerRunner() { .withConfiguration(AutoConfigurations.of( HttpMessageConvertersAutoConfiguration.class, RestTemplateAutoConfiguration.class)) - .withUserConfiguration(AzureGlobalPropertiesAutoConfiguration.class, AadAutoConfiguration.class) + .withUserConfiguration( + TestSpringTokenCredentialProviderContextProviderAutoConfiguration.class, + AzureGlobalPropertiesAutoConfiguration.class, + AadAutoConfiguration.class) .withInitializer(new ConditionEvaluationReportLoggingListener()); } diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/aad/configuration/AadResourceServerConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/aad/configuration/AadResourceServerConfigurationTests.java index dd38d11eb2a6..ad29f3055201 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/aad/configuration/AadResourceServerConfigurationTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/aad/configuration/AadResourceServerConfigurationTests.java @@ -2,6 +2,7 @@ // Licensed under the MIT License. package com.azure.spring.cloud.autoconfigure.implementation.aad.configuration; +import com.azure.identity.extensions.implementation.template.AzureAuthenticationTemplate; import com.azure.spring.cloud.autoconfigure.implementation.aad.configuration.properties.AadAuthenticationProperties; import com.azure.spring.cloud.autoconfigure.implementation.aad.security.AadResourceServerHttpSecurityConfigurer; import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration; @@ -120,7 +121,7 @@ void useCustomJwtGrantedAuthoritiesConverter() { TestAadResourceServerConfiguration.class, AadAutoConfiguration.class) .withPropertyValues(withResourceServerPropertyValues()) - .withClassLoader(new FilteredClassLoader(ClientRegistration.class)) + .withClassLoader(new FilteredClassLoader(AzureAuthenticationTemplate.class, ClientRegistration.class)) .run(context -> { SecurityFilterChain filterChain = context.getBean(SecurityFilterChain.class); assertThat(filterChain).isNotNull(); @@ -170,7 +171,7 @@ void useCustomSecurityFilterChain() { TestAadResourceServerConfiguration.class, AadAutoConfiguration.class) .withInitializer(ConditionEvaluationReportLoggingListener.forLogLevel(LogLevel.INFO)) - .withClassLoader(new FilteredClassLoader(ClientRegistration.class)) + .withClassLoader(new FilteredClassLoader(AzureAuthenticationTemplate.class, ClientRegistration.class)) .withPropertyValues("spring.cloud.azure.active-directory.enabled=true", "spring.cloud.azure.active-directory.credential.client-id=fake-client-id" ) diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/aad/configuration/AadWebApplicationConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/aad/configuration/AadWebApplicationConfigurationTests.java index 014ee8d96b6b..9bc6f51883cb 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/aad/configuration/AadWebApplicationConfigurationTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/aad/configuration/AadWebApplicationConfigurationTests.java @@ -4,6 +4,7 @@ package com.azure.spring.cloud.autoconfigure.implementation.aad.configuration; import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration; +import com.azure.spring.cloud.autoconfigure.implementation.context.TestSpringTokenCredentialProviderContextProviderAutoConfiguration; import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration; @@ -39,7 +40,8 @@ void useCustomSecurityFilterChain() { .withConfiguration(AutoConfigurations.of( HttpMessageConvertersAutoConfiguration.class, RestTemplateAutoConfiguration.class)) - .withUserConfiguration(AzureGlobalPropertiesAutoConfiguration.class, + .withUserConfiguration(TestSpringTokenCredentialProviderContextProviderAutoConfiguration.class, + AzureGlobalPropertiesAutoConfiguration.class, TestSecurityFilterChain.class, AadAutoConfiguration.class) .withInitializer(ConditionEvaluationReportLoggingListener.forLogLevel(LogLevel.INFO)) diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/aad/filter/AadAuthenticationFilterPropertiesTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/aad/filter/AadAuthenticationFilterPropertiesTests.java index cd8143d15a16..0f569fa6b33f 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/aad/filter/AadAuthenticationFilterPropertiesTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/aad/filter/AadAuthenticationFilterPropertiesTests.java @@ -5,6 +5,7 @@ import com.azure.spring.cloud.autoconfigure.implementation.aad.configuration.AzureAuthenticationFilterTestConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.aad.configuration.properties.AadAuthenticationProperties; +import com.azure.spring.cloud.autoconfigure.implementation.context.TestSpringTokenCredentialProviderContextProviderAutoConfiguration; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; @@ -30,7 +31,8 @@ public class AadAuthenticationFilterPropertiesTests { public void canSetProperties() { try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) { configureAllRequiredProperties(context); - context.register(AzureAuthenticationFilterTestConfiguration.class); + context.register(TestSpringTokenCredentialProviderContextProviderAutoConfiguration.class, + AzureAuthenticationFilterTestConfiguration.class); context.refresh(); final AadAuthenticationProperties properties = context.getBean(AadAuthenticationProperties.class); diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/aad/filter/ResourceRetrieverTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/aad/filter/ResourceRetrieverTests.java index 520e56128bb1..0f6f0d4bf1b4 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/aad/filter/ResourceRetrieverTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/aad/filter/ResourceRetrieverTests.java @@ -6,6 +6,7 @@ import com.azure.spring.cloud.autoconfigure.implementation.aad.configuration.AadAuthenticationFilterAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.aad.security.jose.RestOperationsResourceRetriever; import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration; +import com.azure.spring.cloud.autoconfigure.implementation.context.TestSpringTokenCredentialProviderContextProviderAutoConfiguration; import com.nimbusds.jose.util.ResourceRetriever; import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; @@ -20,10 +21,11 @@ class ResourceRetrieverTests { private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() .withConfiguration(AutoConfigurations.of( - AzureGlobalPropertiesAutoConfiguration.class, - AadAuthenticationFilterAutoConfiguration.class, - HttpMessageConvertersAutoConfiguration.class, - RestTemplateAutoConfiguration.class)) + TestSpringTokenCredentialProviderContextProviderAutoConfiguration.class, + AzureGlobalPropertiesAutoConfiguration.class, + AadAuthenticationFilterAutoConfiguration.class, + HttpMessageConvertersAutoConfiguration.class, + RestTemplateAutoConfiguration.class)) .withClassLoader(new FilteredClassLoader(BearerTokenAuthenticationToken.class)) .withPropertyValues( "spring.cloud.azure.active-directory.enabled=true", diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/aadb2c/configuration/AadB2cAutoConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/aadb2c/configuration/AadB2cAutoConfigurationTests.java index 563c0295ff00..10d4249480c4 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/aadb2c/configuration/AadB2cAutoConfigurationTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/aadb2c/configuration/AadB2cAutoConfigurationTests.java @@ -12,6 +12,7 @@ import com.azure.spring.cloud.autoconfigure.implementation.aadb2c.security.AadB2cLogoutSuccessHandler; import com.azure.spring.cloud.autoconfigure.implementation.aadb2c.security.AadB2cOidcLoginConfigurer; import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration; +import com.azure.spring.cloud.autoconfigure.implementation.context.TestSpringTokenCredentialProviderContextProviderAutoConfiguration; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.mockito.MockedStatic; @@ -78,11 +79,12 @@ void mapPropertiesSetting() { WebApplicationContextRunner getDefaultContextRunner() { return new WebApplicationContextRunner() .withConfiguration(AutoConfigurations.of( - AzureGlobalPropertiesAutoConfiguration.class, - WebOAuth2ClientTestApp.class, - AadB2cAutoConfiguration.class, - HttpMessageConvertersAutoConfiguration.class, - RestTemplateAutoConfiguration.class)) + TestSpringTokenCredentialProviderContextProviderAutoConfiguration.class, + AzureGlobalPropertiesAutoConfiguration.class, + WebOAuth2ClientTestApp.class, + AadB2cAutoConfiguration.class, + HttpMessageConvertersAutoConfiguration.class, + RestTemplateAutoConfiguration.class)) .withClassLoader(new FilteredClassLoader(BearerTokenAuthenticationToken.class)) .withPropertyValues(getWebappCommonPropertyValuesWithOutGlobalConfigurableItems()) .withPropertyValues(getGlobalConfigurableItems()); @@ -165,11 +167,12 @@ void testPropertiesBean() { void setDefaultValueFromAzureGlobalPropertiesTest() { new WebApplicationContextRunner() .withConfiguration(AutoConfigurations.of( - AzureGlobalPropertiesAutoConfiguration.class, - WebOAuth2ClientTestApp.class, - AadB2cAutoConfiguration.class, - HttpMessageConvertersAutoConfiguration.class, - RestTemplateAutoConfiguration.class)) + TestSpringTokenCredentialProviderContextProviderAutoConfiguration.class, + AzureGlobalPropertiesAutoConfiguration.class, + WebOAuth2ClientTestApp.class, + AadB2cAutoConfiguration.class, + HttpMessageConvertersAutoConfiguration.class, + RestTemplateAutoConfiguration.class)) .withClassLoader(new FilteredClassLoader(BearerTokenAuthenticationToken.class)) .withPropertyValues(getWebappCommonPropertyValuesWithOutGlobalConfigurableItems()) .withPropertyValues( @@ -189,11 +192,12 @@ void setDefaultValueFromAzureGlobalPropertiesTest() { }); new WebApplicationContextRunner() .withConfiguration(AutoConfigurations.of( - AzureGlobalPropertiesAutoConfiguration.class, - WebOAuth2ClientTestApp.class, - AadB2cAutoConfiguration.class, - HttpMessageConvertersAutoConfiguration.class, - RestTemplateAutoConfiguration.class)) + TestSpringTokenCredentialProviderContextProviderAutoConfiguration.class, + AzureGlobalPropertiesAutoConfiguration.class, + WebOAuth2ClientTestApp.class, + AadB2cAutoConfiguration.class, + HttpMessageConvertersAutoConfiguration.class, + RestTemplateAutoConfiguration.class)) .withClassLoader(new FilteredClassLoader(BearerTokenAuthenticationToken.class)) .withPropertyValues(getWebappCommonPropertyValuesWithOutGlobalConfigurableItems()) .withPropertyValues( diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/aadb2c/configuration/AadB2cResourceServerAutoConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/aadb2c/configuration/AadB2cResourceServerAutoConfigurationTests.java index c5374bf2133c..4479495ec055 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/aadb2c/configuration/AadB2cResourceServerAutoConfigurationTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/aadb2c/configuration/AadB2cResourceServerAutoConfigurationTests.java @@ -2,6 +2,7 @@ // Licensed under the MIT License. package com.azure.spring.cloud.autoconfigure.implementation.aadb2c.configuration; +import com.azure.identity.extensions.implementation.template.AzureAuthenticationTemplate; import com.azure.spring.cloud.autoconfigure.implementation.aadb2c.AadB2cConstants; import com.azure.spring.cloud.autoconfigure.implementation.aad.security.jwt.AadIssuerJwsKeySelector; import com.azure.spring.cloud.autoconfigure.implementation.aad.security.jwt.AadTrustedIssuerRepository; @@ -9,6 +10,7 @@ import com.azure.spring.cloud.autoconfigure.implementation.aadb2c.configuration.properties.AadB2cProperties; import com.azure.spring.cloud.autoconfigure.implementation.aadb2c.security.jwt.AadB2cTrustedIssuerRepository; import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration; +import com.azure.spring.cloud.autoconfigure.implementation.context.TestSpringTokenCredentialProviderContextProviderAutoConfiguration; import com.nimbusds.jose.proc.SecurityContext; import com.nimbusds.jwt.proc.DefaultJWTProcessor; import com.nimbusds.jwt.proc.JWTClaimsSetAwareJWSKeySelector; @@ -42,7 +44,8 @@ class AadB2cResourceServerAutoConfigurationTests extends AbstractAadB2cOAuth2Cli private WebApplicationContextRunner getResourceServerContextRunner() { return new WebApplicationContextRunner() - .withClassLoader(new FilteredClassLoader(OAuth2LoginAuthenticationFilter.class)) + .withClassLoader(new FilteredClassLoader(AzureAuthenticationTemplate.class, + OAuth2LoginAuthenticationFilter.class)) .withConfiguration(AutoConfigurations.of( AzureGlobalPropertiesAutoConfiguration.class, WebResourceServerTestApp.class, @@ -57,6 +60,7 @@ WebApplicationContextRunner getDefaultContextRunner() { return new WebApplicationContextRunner() .withConfiguration(AutoConfigurations.of( WebOAuth2ClientTestApp.class, + TestSpringTokenCredentialProviderContextProviderAutoConfiguration.class, AzureGlobalPropertiesAutoConfiguration.class, AadB2cResourceServerAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class, diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/aadb2c/security/AadB2cAuthorizationRequestResolverTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/aadb2c/security/AadB2cAuthorizationRequestResolverTests.java index 7f026ec54a90..1ce7ecc0c8f4 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/aadb2c/security/AadB2cAuthorizationRequestResolverTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/aadb2c/security/AadB2cAuthorizationRequestResolverTests.java @@ -6,6 +6,7 @@ import com.azure.spring.cloud.autoconfigure.implementation.aadb2c.configuration.AadB2cAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.aadb2c.configuration.WebOAuth2ClientTestApp; import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration; +import com.azure.spring.cloud.autoconfigure.implementation.context.TestSpringTokenCredentialProviderContextProviderAutoConfiguration; import jakarta.servlet.http.HttpServletRequest; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -28,6 +29,7 @@ private WebApplicationContextRunner getContextRunner() { return new WebApplicationContextRunner() .withClassLoader(new FilteredClassLoader(BearerTokenAuthenticationToken.class)) .withConfiguration(AutoConfigurations.of( + TestSpringTokenCredentialProviderContextProviderAutoConfiguration.class, AzureGlobalPropertiesAutoConfiguration.class, WebOAuth2ClientTestApp.class, AadB2cAutoConfiguration.class, diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/appconfiguration/AzureAppConfigurationAutoConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/appconfiguration/AzureAppConfigurationAutoConfigurationTests.java index b8b2852678a9..e412191e27ce 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/appconfiguration/AzureAppConfigurationAutoConfigurationTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/appconfiguration/AzureAppConfigurationAutoConfigurationTests.java @@ -9,6 +9,7 @@ import com.azure.messaging.eventhubs.EventHubClientBuilder; import com.azure.spring.cloud.autoconfigure.implementation.AbstractAzureServiceConfigurationTests; import com.azure.spring.cloud.autoconfigure.implementation.TestBuilderCustomizer; +import com.azure.spring.cloud.autoconfigure.implementation.context.TestSpringTokenCredentialProviderContextProviderAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; import com.azure.spring.cloud.autoconfigure.implementation.keyvault.secrets.AzureKeyVaultSecretAutoConfiguration; import com.azure.spring.cloud.service.implementation.appconfiguration.ConfigurationClientBuilderFactory; @@ -28,7 +29,8 @@ class AzureAppConfigurationAutoConfigurationTests extends AbstractAzureServiceCo private static final String ENDPOINT = "https://%s.azconfig.io"; private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(AzureAppConfigurationAutoConfiguration.class)); + .withConfiguration(AutoConfigurations.of(TestSpringTokenCredentialProviderContextProviderAutoConfiguration.class, + AzureAppConfigurationAutoConfiguration.class)); @Override protected ApplicationContextRunner getMinimalContextRunner() { diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/context/AzureGlobalPropertiesAutoConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/context/AzureGlobalPropertiesAutoConfigurationTests.java index 91671ef38db7..c9ff6181e7e6 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/context/AzureGlobalPropertiesAutoConfigurationTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/context/AzureGlobalPropertiesAutoConfigurationTests.java @@ -30,7 +30,8 @@ class AzureGlobalPropertiesAutoConfigurationTests { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(AzureGlobalPropertiesAutoConfiguration.class)); + .withConfiguration(AutoConfigurations.of(TestSpringTokenCredentialProviderContextProviderAutoConfiguration.class, + AzureGlobalPropertiesAutoConfiguration.class)); @Test void testAutoConfiguration() { diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/context/TestSpringTokenCredentialProviderContextProviderAutoConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/context/TestSpringTokenCredentialProviderContextProviderAutoConfiguration.java new file mode 100644 index 000000000000..9724083b8510 --- /dev/null +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/context/TestSpringTokenCredentialProviderContextProviderAutoConfiguration.java @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.spring.cloud.autoconfigure.implementation.context; + +import com.azure.identity.extensions.implementation.template.AzureAuthenticationTemplate; +import com.azure.spring.cloud.autoconfigure.implementation.jdbc.SpringTokenCredentialProviderContextProvider; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration(proxyBeanMethods = false) +@ConditionalOnClass(AzureAuthenticationTemplate.class) +public class TestSpringTokenCredentialProviderContextProviderAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + SpringTokenCredentialProviderContextProvider springTokenCredentialProviderContextProvider() { + return new SpringTokenCredentialProviderContextProvider(); + } +} diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/cosmos/AzureCosmosAutoConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/cosmos/AzureCosmosAutoConfigurationTests.java index 52a9872241d7..2a7ec15e2b65 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/cosmos/AzureCosmosAutoConfigurationTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/cosmos/AzureCosmosAutoConfigurationTests.java @@ -12,6 +12,7 @@ import com.azure.spring.cloud.autoconfigure.implementation.AbstractAzureServiceConfigurationTests; import com.azure.spring.cloud.autoconfigure.implementation.TestBuilderCustomizer; import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration; +import com.azure.spring.cloud.autoconfigure.implementation.context.TestSpringTokenCredentialProviderContextProviderAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.cosmos.properties.AzureCosmosConnectionDetails; import com.azure.spring.cloud.autoconfigure.implementation.cosmos.properties.AzureCosmosProperties; import com.azure.spring.cloud.service.implementation.cosmos.CosmosClientBuilderFactory; @@ -35,6 +36,7 @@ class AzureCosmosAutoConfigurationTests extends AbstractAzureServiceConfiguratio static final String TEST_ENDPOINT_HTTPS = "https://test.https.documents.azure.com:443/"; private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of(AzureCosmosAutoConfiguration.class, + TestSpringTokenCredentialProviderContextProviderAutoConfiguration.class, AzureGlobalPropertiesAutoConfiguration.class)); @Override diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/data/cosmos/CosmosDataAutoConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/data/cosmos/CosmosDataAutoConfigurationTests.java index edb2cc9f9e21..09723946128d 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/data/cosmos/CosmosDataAutoConfigurationTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/data/cosmos/CosmosDataAutoConfigurationTests.java @@ -6,6 +6,7 @@ import com.azure.cosmos.ConnectionMode; import com.azure.cosmos.CosmosClientBuilder; import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration; +import com.azure.spring.cloud.autoconfigure.implementation.context.TestSpringTokenCredentialProviderContextProviderAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.cosmos.properties.AzureCosmosConnectionDetails; import com.azure.spring.data.cosmos.CosmosFactory; import com.azure.spring.data.cosmos.config.CosmosConfig; @@ -31,6 +32,7 @@ class CosmosDataAutoConfigurationTests { private static final String ENDPOINT = "https://test.documents.azure.com:443/"; private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of(CosmosDataAutoConfiguration.class, + TestSpringTokenCredentialProviderContextProviderAutoConfiguration.class, AzureGlobalPropertiesAutoConfiguration.class)); @Test diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/eventgrid/AzureEventGridAutoConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/eventgrid/AzureEventGridAutoConfigurationTests.java index b70200bc177c..0ffb405541e8 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/eventgrid/AzureEventGridAutoConfigurationTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/eventgrid/AzureEventGridAutoConfigurationTests.java @@ -13,6 +13,7 @@ import com.azure.spring.cloud.autoconfigure.implementation.AbstractAzureServiceConfigurationTests; import com.azure.spring.cloud.autoconfigure.implementation.TestBuilderCustomizer; import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration; +import com.azure.spring.cloud.autoconfigure.implementation.context.TestSpringTokenCredentialProviderContextProviderAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.eventgrid.properties.AzureEventGridProperties; import com.azure.spring.cloud.service.implementation.eventgrid.factory.EventGridPublisherClientBuilderFactory; import org.junit.jupiter.api.Test; @@ -30,6 +31,7 @@ class AzureEventGridAutoConfigurationTests extends AbstractAzureServiceConfigura private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of( + TestSpringTokenCredentialProviderContextProviderAutoConfiguration.class, AzureGlobalPropertiesAutoConfiguration.class, AzureEventGridAutoConfiguration.class)); diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsAutoConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsAutoConfigurationTests.java index 09dacc93710c..e5cd907bcef5 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsAutoConfigurationTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/AzureEventHubsAutoConfigurationTests.java @@ -5,6 +5,7 @@ import com.azure.messaging.eventhubs.EventHubClientBuilder; import com.azure.spring.cloud.autoconfigure.implementation.AbstractAzureServiceConfigurationTests; +import com.azure.spring.cloud.autoconfigure.implementation.context.TestSpringTokenCredentialProviderContextProviderAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; import com.azure.spring.cloud.autoconfigure.implementation.eventhubs.properties.AzureEventHubsProperties; import com.azure.spring.cloud.core.properties.profile.AzureEnvironmentProperties; @@ -31,7 +32,8 @@ class AzureEventHubsAutoConfigurationTests extends AbstractAzureServiceConfigura EventHubClientBuilderFactory, AzureEventHubsProperties> { private static final String CONNECTION_STRING = String.format(CONNECTION_STRING_FORMAT, "test-namespace"); private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(AzureEventHubsAutoConfiguration.class)); + .withConfiguration(AutoConfigurations.of(TestSpringTokenCredentialProviderContextProviderAutoConfiguration.class, + AzureEventHubsAutoConfiguration.class)); @Override protected ApplicationContextRunner getMinimalContextRunner() { diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/kafka/AzureEventHubsKafkaConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/kafka/AzureEventHubsKafkaConfigurationTests.java index fdc30c5da879..49cb97b41304 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/kafka/AzureEventHubsKafkaConfigurationTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/eventhubs/kafka/AzureEventHubsKafkaConfigurationTests.java @@ -4,6 +4,7 @@ import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.context.AzureTokenCredentialAutoConfiguration; +import com.azure.spring.cloud.autoconfigure.implementation.context.TestSpringTokenCredentialProviderContextProviderAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; import com.azure.spring.cloud.autoconfigure.implementation.kafka.AzureEventHubsKafkaOAuth2AutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.kafka.AzureKafkaSpringCloudStreamConfiguration; @@ -34,8 +35,9 @@ class AzureEventHubsKafkaConfigurationTests { @SuppressWarnings("deprecation") private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of(AzureEventHubsKafkaOAuth2AutoConfiguration.class, AzureEventHubsKafkaAutoConfiguration.class, - AzureGlobalPropertiesAutoConfiguration.class, AzureTokenCredentialAutoConfiguration.class, - KafkaAutoConfiguration.class, AzureKafkaSpringCloudStreamConfiguration.class, KafkaBinderConfiguration.class)); + AzureGlobalPropertiesAutoConfiguration.class, TestSpringTokenCredentialProviderContextProviderAutoConfiguration.class, + AzureTokenCredentialAutoConfiguration.class, + KafkaAutoConfiguration.class, AzureKafkaSpringCloudStreamConfiguration.class, KafkaBinderConfiguration.class)); @SuppressWarnings("removal") diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/AbstractAzureJdbcAutoConfigurationTest.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/AbstractAzureJdbcAutoConfigurationTest.java index 3b6e3c6db6c1..ba5a605cebd5 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/AbstractAzureJdbcAutoConfigurationTest.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/AbstractAzureJdbcAutoConfigurationTest.java @@ -7,16 +7,13 @@ import com.azure.identity.extensions.implementation.template.AzureAuthenticationTemplate; import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.context.AzureTokenCredentialAutoConfiguration; +import com.azure.spring.cloud.autoconfigure.implementation.context.TestSpringTokenCredentialProviderContextProviderAutoConfiguration; import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.runner.ApplicationContextRunner; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -33,21 +30,9 @@ abstract class AbstractAzureJdbcAutoConfigurationTest { protected final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of(AzureJdbcAutoConfiguration.class, AzureTokenCredentialAutoConfiguration.class, + TestSpringTokenCredentialProviderContextProviderAutoConfiguration.class, AzureGlobalPropertiesAutoConfiguration.class, - DataSourceAutoConfiguration.class, - TestSpringTokenCredentialProviderContextProviderAutoConfiguration.class)); - - @Configuration(proxyBeanMethods = false) - @ConditionalOnClass(AzureAuthenticationTemplate.class) - static - class TestSpringTokenCredentialProviderContextProviderAutoConfiguration { - - @Bean - @ConditionalOnMissingBean - SpringTokenCredentialProviderContextProvider springTokenCredentialProviderContextProvider() { - return new SpringTokenCredentialProviderContextProvider(); - } - } + DataSourceAutoConfiguration.class)); @Test void testEnhanceUrlDefaultCredential() { diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/kafka/AzureKafkaOAuth2BinderConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/kafka/AzureKafkaOAuth2BinderConfigurationTests.java index 929a0d82bdf4..645cbd7f4158 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/kafka/AzureKafkaOAuth2BinderConfigurationTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/kafka/AzureKafkaOAuth2BinderConfigurationTests.java @@ -7,6 +7,7 @@ import com.azure.identity.ManagedIdentityCredential; import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.context.AzureTokenCredentialAutoConfiguration; +import com.azure.spring.cloud.autoconfigure.implementation.context.TestSpringTokenCredentialProviderContextProviderAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; import com.azure.spring.cloud.core.credential.AzureCredentialResolver; import com.azure.spring.cloud.service.implementation.kafka.KafkaOAuth2AuthenticateCallbackHandler; @@ -44,6 +45,7 @@ class AzureKafkaOAuth2BinderConfigurationTests extends AbstractAzureKafkaOAuth2A private final ApplicationContextRunner contextRunnerWithoutEventHubsURL = new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of(AzureEventHubsKafkaOAuth2AutoConfiguration.class, + TestSpringTokenCredentialProviderContextProviderAutoConfiguration.class, AzureGlobalPropertiesAutoConfiguration.class, AzureTokenCredentialAutoConfiguration.class, KafkaAutoConfiguration.class, AzureKafkaSpringCloudStreamConfiguration.class, KafkaBinderConfiguration.class)); diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/kafka/AzureKafkaOAuth2BootConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/kafka/AzureKafkaOAuth2BootConfigurationTests.java index 0f018403653f..17e8189087ba 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/kafka/AzureKafkaOAuth2BootConfigurationTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/kafka/AzureKafkaOAuth2BootConfigurationTests.java @@ -8,6 +8,7 @@ import com.azure.identity.ManagedIdentityCredential; import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.context.AzureTokenCredentialAutoConfiguration; +import com.azure.spring.cloud.autoconfigure.implementation.context.TestSpringTokenCredentialProviderContextProviderAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; import com.azure.spring.cloud.core.credential.AzureCredentialResolver; import com.azure.spring.cloud.service.implementation.kafka.KafkaOAuth2AuthenticateCallbackHandler; @@ -41,6 +42,7 @@ class AzureKafkaOAuth2BootConfigurationTests extends AbstractAzureKafkaOAuth2Aut private final ApplicationContextRunner contextRunnerWithoutEventHubsURL = new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of(AzureEventHubsKafkaOAuth2AutoConfiguration.class, + TestSpringTokenCredentialProviderContextProviderAutoConfiguration.class, AzureGlobalPropertiesAutoConfiguration.class, AzureTokenCredentialAutoConfiguration.class, KafkaAutoConfiguration.class)); diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/keyvault/AzureKeyVaultAutoConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/keyvault/AzureKeyVaultAutoConfigurationTests.java index 06cd1c40f2dc..1bb847fd016e 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/keyvault/AzureKeyVaultAutoConfigurationTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/keyvault/AzureKeyVaultAutoConfigurationTests.java @@ -3,6 +3,7 @@ package com.azure.spring.cloud.autoconfigure.implementation.keyvault; +import com.azure.identity.extensions.implementation.template.AzureAuthenticationTemplate; import com.azure.security.keyvault.certificates.CertificateAsyncClient; import com.azure.security.keyvault.certificates.CertificateClient; import com.azure.security.keyvault.certificates.CertificateClientBuilder; @@ -18,6 +19,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import static org.assertj.core.api.Assertions.assertThat; @@ -30,6 +32,7 @@ class AzureKeyVaultAutoConfigurationTests { private static final String ENDPOINT = "https:/%s.vault.azure.net/"; private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withClassLoader(new FilteredClassLoader(AzureAuthenticationTemplate.class)) .withBean(AzureGlobalProperties.class, AzureGlobalProperties::new) .withConfiguration(AutoConfigurations.of(AzureKeyVaultCertificateAutoConfiguration.class)) .withConfiguration(AutoConfigurations.of(AzureKeyVaultSecretAutoConfiguration.class)); diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/keyvault/certificates/AzureKeyVaultCertificateAutoConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/keyvault/certificates/AzureKeyVaultCertificateAutoConfigurationTests.java index 33543a634e2d..a3c1f3b40f84 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/keyvault/certificates/AzureKeyVaultCertificateAutoConfigurationTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/keyvault/certificates/AzureKeyVaultCertificateAutoConfigurationTests.java @@ -11,6 +11,7 @@ import com.azure.spring.cloud.autoconfigure.implementation.AbstractAzureServiceConfigurationTests; import com.azure.spring.cloud.autoconfigure.implementation.TestBuilderCustomizer; import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration; +import com.azure.spring.cloud.autoconfigure.implementation.context.TestSpringTokenCredentialProviderContextProviderAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.keyvault.certificates.properties.AzureKeyVaultCertificateProperties; import com.azure.spring.cloud.service.implementation.keyvault.certificates.CertificateClientBuilderFactory; import org.junit.jupiter.api.Test; @@ -30,6 +31,7 @@ class AzureKeyVaultCertificateAutoConfigurationTests extends AbstractAzureServic private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of(AzureKeyVaultCertificateAutoConfiguration.class, + TestSpringTokenCredentialProviderContextProviderAutoConfiguration.class, AzureGlobalPropertiesAutoConfiguration.class)); @Override diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/keyvault/secrets/AzureKeyVaultSecretAutoConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/keyvault/secrets/AzureKeyVaultSecretAutoConfigurationTests.java index b53ba7442e2b..d3767e76603c 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/keyvault/secrets/AzureKeyVaultSecretAutoConfigurationTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/keyvault/secrets/AzureKeyVaultSecretAutoConfigurationTests.java @@ -11,6 +11,7 @@ import com.azure.spring.cloud.autoconfigure.implementation.AbstractAzureServiceConfigurationTests; import com.azure.spring.cloud.autoconfigure.implementation.TestBuilderCustomizer; import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration; +import com.azure.spring.cloud.autoconfigure.implementation.context.TestSpringTokenCredentialProviderContextProviderAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.keyvault.secrets.properties.AzureKeyVaultPropertySourceProperties; import com.azure.spring.cloud.autoconfigure.implementation.keyvault.secrets.properties.AzureKeyVaultSecretProperties; import com.azure.spring.cloud.service.implementation.keyvault.secrets.SecretClientBuilderFactory; @@ -35,6 +36,7 @@ class AzureKeyVaultSecretAutoConfigurationTests extends AbstractAzureServiceConf private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of( + TestSpringTokenCredentialProviderContextProviderAutoConfiguration.class, AzureGlobalPropertiesAutoConfiguration.class, AzureKeyVaultSecretAutoConfiguration.class)); diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureEventHubsResourceManagerAutoConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureEventHubsResourceManagerAutoConfigurationTests.java index 154fe88c2d2f..0600371159f8 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureEventHubsResourceManagerAutoConfigurationTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureEventHubsResourceManagerAutoConfigurationTests.java @@ -6,6 +6,7 @@ import com.azure.messaging.eventhubs.EventHubClientBuilder; import com.azure.resourcemanager.AzureResourceManager; import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration; +import com.azure.spring.cloud.autoconfigure.implementation.context.TestSpringTokenCredentialProviderContextProviderAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; import com.azure.spring.cloud.autoconfigure.implementation.eventhubs.properties.AzureEventHubsProperties; import com.azure.spring.cloud.resourcemanager.implementation.connectionstring.EventHubsArmConnectionStringProvider; @@ -96,7 +97,7 @@ void testAzureEventHubsResourceManagerAutoConfigurationBeans() { }) void testNotCreateProviderBeanWhenMissingPropertiesConfigured(String missingProperty) { this.contextRunner - .withUserConfiguration(AzureGlobalPropertiesAutoConfiguration.class) + .withUserConfiguration(TestSpringTokenCredentialProviderContextProviderAutoConfiguration.class, AzureGlobalPropertiesAutoConfiguration.class) .withBean(AzureResourceManager.class, () -> mock(AzureResourceManager.class)) .withPropertyValues( "spring.cloud.azure.profile.tenant-id=test-tenant", diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureResourceManagerAutoConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureResourceManagerAutoConfigurationTests.java index 45c5f96a996f..0a23489ffbd3 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureResourceManagerAutoConfigurationTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureResourceManagerAutoConfigurationTests.java @@ -6,6 +6,7 @@ import com.azure.core.management.profile.AzureProfile; import com.azure.resourcemanager.AzureResourceManager; import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration; +import com.azure.spring.cloud.autoconfigure.implementation.context.TestSpringTokenCredentialProviderContextProviderAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; import com.azure.spring.cloud.core.properties.resource.AzureResourceMetadata; import org.junit.jupiter.api.Test; @@ -84,7 +85,8 @@ void testWithoutAzureResourceMetadataClass() { @Test void testAzureProfileWithAzureDefault() { this.contextRunner - .withUserConfiguration(AzureGlobalPropertiesAutoConfiguration.class) + .withUserConfiguration(TestSpringTokenCredentialProviderContextProviderAutoConfiguration.class, + AzureGlobalPropertiesAutoConfiguration.class) .withBean(AzureResourceManager.class, () -> mock(AzureResourceManager.class)) .withPropertyValues( "spring.cloud.azure.profile.tenant-id=test-tenant-id", @@ -103,7 +105,8 @@ void testAzureProfileWithAzureDefault() { @Test void testAzureProfileWithAzureChina() { this.contextRunner - .withUserConfiguration(AzureGlobalPropertiesAutoConfiguration.class) + .withUserConfiguration(TestSpringTokenCredentialProviderContextProviderAutoConfiguration.class, + AzureGlobalPropertiesAutoConfiguration.class) .withBean(AzureResourceManager.class, () -> mock(AzureResourceManager.class)) .withPropertyValues( "spring.cloud.azure.profile.tenant-id=test-tenant-id", diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureServiceBusResourceManagerAutoConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureServiceBusResourceManagerAutoConfigurationTests.java index 5ce6001da09e..51c41efa3d68 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureServiceBusResourceManagerAutoConfigurationTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureServiceBusResourceManagerAutoConfigurationTests.java @@ -6,6 +6,7 @@ import com.azure.messaging.servicebus.ServiceBusClientBuilder; import com.azure.resourcemanager.AzureResourceManager; import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration; +import com.azure.spring.cloud.autoconfigure.implementation.context.TestSpringTokenCredentialProviderContextProviderAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; import com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties.AzureServiceBusProperties; import com.azure.spring.cloud.resourcemanager.implementation.connectionstring.ServiceBusArmConnectionStringProvider; @@ -83,7 +84,8 @@ void testAzureServiceBusResourceManagerAutoConfigurationBeans() { }) void testNotCreateProviderBeanWhenMissingPropertiesConfigured(String missingProperty) { this.contextRunner - .withUserConfiguration(AzureGlobalPropertiesAutoConfiguration.class) + .withUserConfiguration(TestSpringTokenCredentialProviderContextProviderAutoConfiguration.class, + AzureGlobalPropertiesAutoConfiguration.class) .withBean(AzureResourceManager.class, () -> mock(AzureResourceManager.class)) .withPropertyValues( "spring.cloud.azure.profile.tenant-id=test-tenant", diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureStorageQueueResourceManagerAutoConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureStorageQueueResourceManagerAutoConfigurationTests.java index a9daa8dddd28..93425aa9a545 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureStorageQueueResourceManagerAutoConfigurationTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/resourcemanager/AzureStorageQueueResourceManagerAutoConfigurationTests.java @@ -5,6 +5,7 @@ import com.azure.resourcemanager.AzureResourceManager; import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration; +import com.azure.spring.cloud.autoconfigure.implementation.context.TestSpringTokenCredentialProviderContextProviderAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; import com.azure.spring.cloud.autoconfigure.implementation.storage.queue.properties.AzureStorageQueueProperties; import com.azure.spring.cloud.resourcemanager.implementation.connectionstring.StorageQueueArmConnectionStringProvider; @@ -69,7 +70,8 @@ void testStorageQueueResourceManagerWithoutArmConnectionStringProviderClass() { }) void testNotCreateProviderBeanWhenMissingPropertiesConfigured(String missingProperty) { this.contextRunner - .withUserConfiguration(AzureGlobalPropertiesAutoConfiguration.class) + .withUserConfiguration(TestSpringTokenCredentialProviderContextProviderAutoConfiguration.class, + AzureGlobalPropertiesAutoConfiguration.class) .withBean(AzureResourceManager.class, () -> mock(AzureResourceManager.class)) .withPropertyValues( "spring.cloud.azure.profile.tenant-id=test-tenant", diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/AzureServiceBusAutoConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/AzureServiceBusAutoConfigurationTests.java index 92b4aff290d7..c4b66847fc11 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/AzureServiceBusAutoConfigurationTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/servicebus/AzureServiceBusAutoConfigurationTests.java @@ -7,6 +7,7 @@ import com.azure.messaging.servicebus.ServiceBusClientBuilder; import com.azure.messaging.servicebus.models.ServiceBusReceiveMode; import com.azure.spring.cloud.autoconfigure.implementation.AbstractAzureServiceConfigurationTests; +import com.azure.spring.cloud.autoconfigure.implementation.context.TestSpringTokenCredentialProviderContextProviderAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; import com.azure.spring.cloud.autoconfigure.implementation.servicebus.properties.AzureServiceBusProperties; import com.azure.spring.cloud.core.properties.profile.AzureEnvironmentProperties; @@ -34,7 +35,8 @@ class AzureServiceBusAutoConfigurationTests extends AbstractAzureServiceConfigur ServiceBusClientBuilderFactory, AzureServiceBusProperties> { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(AzureServiceBusAutoConfiguration.class)); + .withConfiguration(AutoConfigurations.of(TestSpringTokenCredentialProviderContextProviderAutoConfiguration.class, + AzureServiceBusAutoConfiguration.class)); @Override protected ApplicationContextRunner getMinimalContextRunner() { diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/storage/blob/AzureStorageBlobAutoConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/storage/blob/AzureStorageBlobAutoConfigurationTests.java index c43d2aba4dff..4d5ab81ea8a9 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/storage/blob/AzureStorageBlobAutoConfigurationTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/storage/blob/AzureStorageBlobAutoConfigurationTests.java @@ -7,6 +7,7 @@ import com.azure.spring.cloud.autoconfigure.implementation.AbstractAzureServiceConfigurationTests; import com.azure.spring.cloud.autoconfigure.implementation.TestBuilderCustomizer; import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration; +import com.azure.spring.cloud.autoconfigure.implementation.context.TestSpringTokenCredentialProviderContextProviderAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.storage.blob.properties.AzureStorageBlobConnectionDetails; import com.azure.spring.cloud.autoconfigure.implementation.storage.blob.properties.AzureStorageBlobProperties; import com.azure.spring.cloud.service.implementation.storage.blob.BlobServiceClientBuilderFactory; @@ -34,7 +35,8 @@ class AzureStorageBlobAutoConfigurationTests extends AbstractAzureServiceConfigu private static final String STORAGE_CONNECTION_STRING_PATTERN = "DefaultEndpointsProtocol=https;AccountName=%s;AccountKey=%s;EndpointSuffix=core.windows.net"; private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(AzureGlobalPropertiesAutoConfiguration.class, AzureStorageBlobAutoConfiguration.class)); + .withConfiguration(AutoConfigurations.of(TestSpringTokenCredentialProviderContextProviderAutoConfiguration.class, + AzureGlobalPropertiesAutoConfiguration.class, AzureStorageBlobAutoConfiguration.class)); @Override protected ApplicationContextRunner getMinimalContextRunner() { diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/storage/queue/AzureStorageQueueAutoConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/storage/queue/AzureStorageQueueAutoConfigurationTests.java index ce5076f1c018..f44c7fcb8844 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/storage/queue/AzureStorageQueueAutoConfigurationTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/storage/queue/AzureStorageQueueAutoConfigurationTests.java @@ -7,6 +7,7 @@ import com.azure.spring.cloud.autoconfigure.implementation.AbstractAzureServiceConfigurationTests; import com.azure.spring.cloud.autoconfigure.implementation.TestBuilderCustomizer; import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration; +import com.azure.spring.cloud.autoconfigure.implementation.context.TestSpringTokenCredentialProviderContextProviderAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.storage.queue.properties.AzureStorageQueueConnectionDetails; import com.azure.spring.cloud.autoconfigure.implementation.storage.queue.properties.AzureStorageQueueProperties; import com.azure.spring.cloud.service.implementation.storage.queue.QueueServiceClientBuilderFactory; @@ -32,7 +33,8 @@ class AzureStorageQueueAutoConfigurationTests extends AbstractAzureServiceConfig private static final String STORAGE_CONNECTION_STRING_PATTERN = "DefaultEndpointsProtocol=https;AccountName=%s;AccountKey=%s;EndpointSuffix=core.windows.net"; private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(AzureGlobalPropertiesAutoConfiguration.class, AzureStorageQueueAutoConfiguration.class)); + .withConfiguration(AutoConfigurations.of(TestSpringTokenCredentialProviderContextProviderAutoConfiguration.class, + AzureGlobalPropertiesAutoConfiguration.class, AzureStorageQueueAutoConfiguration.class)); @Override protected ApplicationContextRunner getMinimalContextRunner() { diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/useragent/http/IdentityUserAgentTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/useragent/http/IdentityUserAgentTests.java index 4843af5a875a..a7c078a7fa52 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/useragent/http/IdentityUserAgentTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/useragent/http/IdentityUserAgentTests.java @@ -11,6 +11,7 @@ import com.azure.identity.ClientSecretCredentialBuilder; import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.context.AzureTokenCredentialAutoConfiguration; +import com.azure.spring.cloud.autoconfigure.implementation.context.TestSpringTokenCredentialProviderContextProviderAutoConfiguration; import com.azure.spring.cloud.core.customizer.AzureServiceClientBuilderCustomizer; import com.azure.spring.cloud.core.implementation.util.AzureSpringIdentifier; import org.junit.jupiter.api.Test; @@ -38,6 +39,7 @@ class IdentityUserAgentTests { void userAgentTest(CapturedOutput output) { new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of( + TestSpringTokenCredentialProviderContextProviderAutoConfiguration.class, AzureTokenCredentialAutoConfiguration.class, AzureGlobalPropertiesAutoConfiguration.class )) diff --git a/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/factory/AbstractAzureServiceClientBuilderFactory.java b/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/factory/AbstractAzureServiceClientBuilderFactory.java index 531ebc015415..c2c01ae4e882 100644 --- a/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/factory/AbstractAzureServiceClientBuilderFactory.java +++ b/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/factory/AbstractAzureServiceClientBuilderFactory.java @@ -19,6 +19,9 @@ import com.azure.spring.cloud.core.provider.connectionstring.ServiceConnectionStringProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; import org.springframework.util.StringUtils; import java.util.ArrayList; @@ -34,12 +37,14 @@ * * @param Type of the service client builder */ -public abstract class AbstractAzureServiceClientBuilderFactory implements AzureServiceClientBuilderFactory { +public abstract class AbstractAzureServiceClientBuilderFactory implements AzureServiceClientBuilderFactory, ApplicationContextAware { private static final Logger LOGGER = LoggerFactory.getLogger(AbstractAzureServiceClientBuilderFactory.class); private static final TokenCredential DEFAULT_DEFAULT_TOKEN_CREDENTIAL = new DefaultAzureCredentialBuilder().build(); private static final AzureTokenCredentialResolver DEFAULT_TOKEN_CREDENTIAL_RESOLVER = new AzureTokenCredentialResolver(); + private ApplicationContext applicationContext; + /** * Create an instance of Azure sdk client builder. * @return The service client builder. @@ -185,6 +190,21 @@ protected void configureConfiguration(T builder) { @SuppressWarnings({ "rawtypes", "unchecked" }) protected void configureCredential(T builder) { List> descriptors = getAuthenticationDescriptors(builder); + String tokenCredentialBeanName = getAzureProperties().getCredential().getTokenCredentialBeanName(); + if (applicationContext != null && StringUtils.hasText(tokenCredentialBeanName)) { + Optional> tokenCredentialDescriptor = descriptors.stream() + .filter(auth -> TokenCredential.class == auth.getAzureCredentialType()) + .findFirst(); + if (tokenCredentialDescriptor.isPresent()) { + LOGGER.debug("Will configure the custom token credential bean ({}) for {}.", + tokenCredentialBeanName, builder.getClass().getSimpleName()); + TokenCredential customTokenCredential = applicationContext.getBean(tokenCredentialBeanName, TokenCredential.class); + ((AuthenticationDescriptor)tokenCredentialDescriptor.get()).getConsumer().accept(customTokenCredential); + credentialConfigured = true; + return; + } + } + Object azureCredential = resolveAzureCredential(getAzureProperties(), descriptors); if (azureCredential == null) { LOGGER.debug("No authentication credential configured for class {}.", builder.getClass().getSimpleName()); @@ -347,4 +367,9 @@ public void setTokenCredentialResolver(AzureCredentialResolver LOGGER.debug("Will ignore the 'null' token credential resolver."); } } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } } From cf4df22db9bd421a723758fe9cb161f82d5c99f4 Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Tue, 29 Oct 2024 08:27:41 +0800 Subject: [PATCH 15/23] Fix code smells --- .../factory/AbstractAzureServiceClientBuilderFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/factory/AbstractAzureServiceClientBuilderFactory.java b/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/factory/AbstractAzureServiceClientBuilderFactory.java index c2c01ae4e882..04f997fa5940 100644 --- a/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/factory/AbstractAzureServiceClientBuilderFactory.java +++ b/sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/factory/AbstractAzureServiceClientBuilderFactory.java @@ -199,7 +199,7 @@ protected void configureCredential(T builder) { LOGGER.debug("Will configure the custom token credential bean ({}) for {}.", tokenCredentialBeanName, builder.getClass().getSimpleName()); TokenCredential customTokenCredential = applicationContext.getBean(tokenCredentialBeanName, TokenCredential.class); - ((AuthenticationDescriptor)tokenCredentialDescriptor.get()).getConsumer().accept(customTokenCredential); + ((AuthenticationDescriptor) tokenCredentialDescriptor.get()).getConsumer().accept(customTokenCredential); credentialConfigured = true; return; } From e34a91347eb48fbf76449b26719d9f6747da127b Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Tue, 29 Oct 2024 09:40:19 +0800 Subject: [PATCH 16/23] Use the fixed class loader --- .../context/AzureGlobalPropertiesAutoConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/AzureGlobalPropertiesAutoConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/AzureGlobalPropertiesAutoConfiguration.java index f7fd5315011e..d248a8d32b66 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/AzureGlobalPropertiesAutoConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/AzureGlobalPropertiesAutoConfiguration.java @@ -48,7 +48,7 @@ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, () -> Binder.get(this.environment) .bindOrCreate(AzureGlobalProperties.PREFIX, AzureGlobalProperties.class)); - if (ClassUtils.isPresent(AZURE_AUTHENTICATION_TEMPLATE_CLASS_NAME, ClassUtils.getDefaultClassLoader())) { + if (ClassUtils.isPresent(AZURE_AUTHENTICATION_TEMPLATE_CLASS_NAME, AzureGlobalPropertiesAutoConfiguration.class.getClassLoader())) { definitionBuilder.addDependsOn(SPRING_TOKEN_CREDENTIAL_PROVIDER_CONTEXT_BEAN_NAME); } registry.registerBeanDefinition(AZURE_GLOBAL_PROPERTY_BEAN_NAME, definitionBuilder.getBeanDefinition()); From e4f22a7b9b139716a0236775e22325849873617d Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Tue, 29 Oct 2024 10:09:28 +0800 Subject: [PATCH 17/23] Use null class loader --- .../context/AzureGlobalPropertiesAutoConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/AzureGlobalPropertiesAutoConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/AzureGlobalPropertiesAutoConfiguration.java index d248a8d32b66..f51f895b24bf 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/AzureGlobalPropertiesAutoConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/context/AzureGlobalPropertiesAutoConfiguration.java @@ -48,7 +48,7 @@ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, () -> Binder.get(this.environment) .bindOrCreate(AzureGlobalProperties.PREFIX, AzureGlobalProperties.class)); - if (ClassUtils.isPresent(AZURE_AUTHENTICATION_TEMPLATE_CLASS_NAME, AzureGlobalPropertiesAutoConfiguration.class.getClassLoader())) { + if (ClassUtils.isPresent(AZURE_AUTHENTICATION_TEMPLATE_CLASS_NAME, null)) { definitionBuilder.addDependsOn(SPRING_TOKEN_CREDENTIAL_PROVIDER_CONTEXT_BEAN_NAME); } registry.registerBeanDefinition(AZURE_GLOBAL_PROPERTY_BEAN_NAME, definitionBuilder.getBeanDefinition()); From 993d3384aeb08cb7e53d4e216f61c5fe0316172a Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Tue, 29 Oct 2024 10:43:30 +0800 Subject: [PATCH 18/23] Fix ut failure, ignore provider bean creation since the custom class loader can not identity the filtered class(AzureAuthenticationTemplate) in configuration AzureGlobalPropertiesAutoConfiguration --- .../AadB2cResourceServerAutoConfigurationTests.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/aadb2c/configuration/AadB2cResourceServerAutoConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/aadb2c/configuration/AadB2cResourceServerAutoConfigurationTests.java index 4479495ec055..4bda51037b0d 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/aadb2c/configuration/AadB2cResourceServerAutoConfigurationTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/aadb2c/configuration/AadB2cResourceServerAutoConfigurationTests.java @@ -2,7 +2,6 @@ // Licensed under the MIT License. package com.azure.spring.cloud.autoconfigure.implementation.aadb2c.configuration; -import com.azure.identity.extensions.implementation.template.AzureAuthenticationTemplate; import com.azure.spring.cloud.autoconfigure.implementation.aadb2c.AadB2cConstants; import com.azure.spring.cloud.autoconfigure.implementation.aad.security.jwt.AadIssuerJwsKeySelector; import com.azure.spring.cloud.autoconfigure.implementation.aad.security.jwt.AadTrustedIssuerRepository; @@ -44,9 +43,9 @@ class AadB2cResourceServerAutoConfigurationTests extends AbstractAadB2cOAuth2Cli private WebApplicationContextRunner getResourceServerContextRunner() { return new WebApplicationContextRunner() - .withClassLoader(new FilteredClassLoader(AzureAuthenticationTemplate.class, - OAuth2LoginAuthenticationFilter.class)) + .withClassLoader(new FilteredClassLoader(OAuth2LoginAuthenticationFilter.class)) .withConfiguration(AutoConfigurations.of( + TestSpringTokenCredentialProviderContextProviderAutoConfiguration.class, AzureGlobalPropertiesAutoConfiguration.class, WebResourceServerTestApp.class, AadB2cResourceServerAutoConfiguration.class, From 4d317434de5616d202d03aab905607052e8fc61c Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Tue, 29 Oct 2024 13:57:25 +0800 Subject: [PATCH 19/23] Resolve comments --- ...eLettucePasswordlessAutoConfiguration.java | 22 ++++----- .../redis/lettuce/AzureRedisCredentials.java | 16 +++---- .../jdbc/JdbcPropertiesBeanPostProcessor.java | 8 +++- ...eBusJmsConnectionFactoryConfiguration.java | 13 ++---- ...ServiceBusJmsConnectionFactoryFactory.java | 27 ++++------- .../SpringPasswordlessPropertiesUtils.java | 45 +++++++++++-------- 6 files changed, 61 insertions(+), 70 deletions(-) diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/AzureLettucePasswordlessAutoConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/AzureLettucePasswordlessAutoConfiguration.java index d24cbbcfa647..b6a1a7ebfe79 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/AzureLettucePasswordlessAutoConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/AzureLettucePasswordlessAutoConfiguration.java @@ -3,19 +3,14 @@ package com.azure.spring.cloud.autoconfigure.implementation.data.redis; -import com.azure.identity.extensions.implementation.credential.TokenCredentialProviderOptions; -import com.azure.identity.extensions.implementation.credential.provider.TokenCredentialProvider; -import com.azure.identity.extensions.implementation.credential.provider.TokenCredentialProviders; import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; -import com.azure.spring.cloud.autoconfigure.implementation.passwordless.properties.AzureRedisPasswordlessProperties; import com.azure.spring.cloud.autoconfigure.implementation.data.redis.lettuce.AzureRedisCredentials; +import com.azure.spring.cloud.autoconfigure.implementation.passwordless.properties.AzureRedisPasswordlessProperties; import com.azure.spring.cloud.core.implementation.util.AzurePasswordlessPropertiesUtils; import io.lettuce.core.ClientOptions; import io.lettuce.core.RedisCredentials; import io.lettuce.core.RedisCredentialsProvider; import io.lettuce.core.protocol.ProtocolVersion; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; @@ -38,6 +33,7 @@ import java.util.Properties; import static com.azure.spring.cloud.autoconfigure.implementation.util.SpringPasswordlessPropertiesUtils.enhancePasswordlessProperties; +import static com.azure.spring.cloud.autoconfigure.implementation.util.SpringPasswordlessPropertiesUtils.registerTokenCredentialBean; /** @@ -53,8 +49,6 @@ @EnableConfigurationProperties(RedisProperties.class) public class AzureLettucePasswordlessAutoConfiguration { - private static final Log LOGGER = LogFactory.getLog(AzureLettucePasswordlessAutoConfiguration.class); - private final GenericApplicationContext applicationContext; AzureLettucePasswordlessAutoConfiguration(GenericApplicationContext applicationContext) { @@ -72,12 +66,12 @@ AzureRedisPasswordlessProperties redisPasswordlessProperties() { AzureRedisCredentials azureRedisCredentials(RedisProperties redisProperties, AzureRedisPasswordlessProperties azureRedisPasswordlessProperties, AzureGlobalProperties azureGlobalProperties) { - Properties properties = azureRedisPasswordlessProperties.toPasswordlessProperties(); - enhancePasswordlessProperties(applicationContext, "spring.data.redis.azure", - azureRedisPasswordlessProperties, properties); - TokenCredentialProvider provider = TokenCredentialProviders.createInstance(new TokenCredentialProviderOptions(properties)); - return new AzureRedisCredentials(redisProperties.getUsername(), - mergeAzureProperties(azureGlobalProperties, azureRedisPasswordlessProperties), provider); + AzureRedisPasswordlessProperties redisPasswordlessProperties = mergeAzureProperties(azureGlobalProperties, azureRedisPasswordlessProperties); + String passwordlessPropertiesPrefix = "spring.data.redis.azure"; + registerTokenCredentialBean(applicationContext, passwordlessPropertiesPrefix, redisPasswordlessProperties); + Properties passwordlessProperties = redisPasswordlessProperties.toPasswordlessProperties(); + enhancePasswordlessProperties(passwordlessPropertiesPrefix, redisPasswordlessProperties, passwordlessProperties); + return new AzureRedisCredentials(redisProperties.getUsername(), passwordlessProperties); } @Bean(name = "azureLettuceClientConfigurationBuilderCustomizer") diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/lettuce/AzureRedisCredentials.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/lettuce/AzureRedisCredentials.java index feb476e56309..8f9837d1b097 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/lettuce/AzureRedisCredentials.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/lettuce/AzureRedisCredentials.java @@ -4,7 +4,6 @@ package com.azure.spring.cloud.autoconfigure.implementation.data.redis.lettuce; import com.azure.core.credential.TokenCredential; -import com.azure.identity.extensions.implementation.credential.provider.TokenCredentialProvider; import com.azure.identity.extensions.implementation.template.AzureAuthenticationTemplate; import com.azure.spring.cloud.core.properties.PasswordlessProperties; import com.nimbusds.jwt.JWT; @@ -27,16 +26,17 @@ public class AzureRedisCredentials implements RedisCredentials { * Create instance of Azure Redis Credentials */ public AzureRedisCredentials(String username, PasswordlessProperties passwordlessProperties) { - this(username, passwordlessProperties, (TokenCredentialProvider) null); + Objects.requireNonNull(passwordlessProperties, "PasswordlessProperties is required."); + azureAuthenticationTemplate = new AzureAuthenticationTemplate(); + azureAuthenticationTemplate.init(passwordlessProperties.toPasswordlessProperties()); + this.username = resolveUsername(azureAuthenticationTemplate, username); } public AzureRedisCredentials(String username, - PasswordlessProperties passwordlessProperties, - TokenCredentialProvider tokenCredentialProvider) { - Objects.requireNonNull(passwordlessProperties, "PasswordlessProperties is required"); - azureAuthenticationTemplate = new AzureAuthenticationTemplate(tokenCredentialProvider, null); - Properties properties = passwordlessProperties.toPasswordlessProperties(); - azureAuthenticationTemplate.init(properties); + Properties passwordlessProperties) { + Objects.requireNonNull(passwordlessProperties, "PasswordlessProperties is required."); + azureAuthenticationTemplate = new AzureAuthenticationTemplate(); + azureAuthenticationTemplate.init(passwordlessProperties); this.username = resolveUsername(azureAuthenticationTemplate, username); } diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessor.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessor.java index 1d9e177c4606..a881cec96e00 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessor.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessor.java @@ -35,6 +35,7 @@ import static com.azure.spring.cloud.autoconfigure.implementation.jdbc.JdbcPropertyConstants.POSTGRESQL_PROPERTY_NAME_ASSUME_MIN_SERVER_VERSION; import static com.azure.spring.cloud.autoconfigure.implementation.jdbc.JdbcPropertyConstants.POSTGRESQL_PROPERTY_VALUE_ASSUME_MIN_SERVER_VERSION; import static com.azure.spring.cloud.autoconfigure.implementation.util.SpringPasswordlessPropertiesUtils.enhancePasswordlessProperties; +import static com.azure.spring.cloud.autoconfigure.implementation.util.SpringPasswordlessPropertiesUtils.registerTokenCredentialBean; /** @@ -139,9 +140,12 @@ private void enhanceUserAgent(DatabaseType databaseType, JdbcConnectionStringEnh } } - private Map buildEnhancedProperties(String passwordlessPropertiesPrefix, DatabaseType databaseType, AzureJdbcPasswordlessProperties properties) { + private Map buildEnhancedProperties(String passwordlessPropertiesPrefix, + DatabaseType databaseType, + AzureJdbcPasswordlessProperties properties) { + registerTokenCredentialBean(applicationContext, passwordlessPropertiesPrefix, properties); Map result = new HashMap<>(); - enhancePasswordlessProperties(applicationContext, passwordlessPropertiesPrefix, properties, result); + enhancePasswordlessProperties(passwordlessPropertiesPrefix, properties, result); databaseType.setDefaultEnhancedProperties(result); return result; } diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java index a7fd8a597416..5bdd4b541cff 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java @@ -3,8 +3,6 @@ package com.azure.spring.cloud.autoconfigure.implementation.jms; -import com.azure.identity.extensions.implementation.credential.TokenCredentialProviderOptions; -import com.azure.identity.extensions.implementation.credential.provider.TokenCredentialProvider; import com.azure.servicebus.jms.ServiceBusJmsConnectionFactory; import com.azure.spring.cloud.autoconfigure.implementation.jms.properties.AzureServiceBusJmsProperties; import com.azure.spring.cloud.autoconfigure.jms.AzureServiceBusJmsConnectionFactoryCustomizer; @@ -22,10 +20,9 @@ import org.springframework.context.support.GenericApplicationContext; import org.springframework.jms.connection.CachingConnectionFactory; -import java.util.Properties; import java.util.stream.Collectors; -import static com.azure.spring.cloud.autoconfigure.implementation.util.SpringPasswordlessPropertiesUtils.enhancePasswordlessProperties; +import static com.azure.spring.cloud.autoconfigure.implementation.util.SpringPasswordlessPropertiesUtils.registerTokenCredentialBean; @Configuration(proxyBeanMethods = false) @ConditionalOnMissingBean(ConnectionFactory.class) @@ -37,12 +34,10 @@ public class ServiceBusJmsConnectionFactoryConfiguration { this.applicationContext = applicationContext; } - private ServiceBusJmsConnectionFactory createJmsConnectionFactory(AzureServiceBusJmsProperties jmsProperties, + private ServiceBusJmsConnectionFactory createJmsConnectionFactory(AzureServiceBusJmsProperties serviceBusJmsProperties, ObjectProvider factoryCustomizers) { - Properties properties = jmsProperties.toPasswordlessProperties(); - enhancePasswordlessProperties(applicationContext, AzureServiceBusJmsProperties.PREFIX, jmsProperties, properties); - TokenCredentialProvider tokenCredentialProvider = TokenCredentialProvider.createDefault(new TokenCredentialProviderOptions(properties)); - return new ServiceBusJmsConnectionFactoryFactory(tokenCredentialProvider, jmsProperties, + registerTokenCredentialBean(applicationContext, AzureServiceBusJmsProperties.PREFIX, serviceBusJmsProperties); + return new ServiceBusJmsConnectionFactoryFactory(serviceBusJmsProperties, factoryCustomizers.orderedStream().collect(Collectors.toList())) .createConnectionFactory(ServiceBusJmsConnectionFactory.class); } diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryFactory.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryFactory.java index 721d58667016..b974a55f4c07 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryFactory.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryFactory.java @@ -16,36 +16,27 @@ import java.lang.reflect.InvocationTargetException; import java.util.Collections; import java.util.List; +import java.util.Properties; + +import static com.azure.spring.cloud.autoconfigure.implementation.util.SpringPasswordlessPropertiesUtils.enhancePasswordlessProperties; class ServiceBusJmsConnectionFactoryFactory { private final AzureServiceBusJmsProperties properties; private final List factoryCustomizers; - private final TokenCredentialProvider tokenCredentialProvider; ServiceBusJmsConnectionFactoryFactory(AzureServiceBusJmsProperties properties, List factoryCustomizers) { - this(null, properties, factoryCustomizers); - - } - - ServiceBusJmsConnectionFactoryFactory(TokenCredentialProvider tokenCredentialProvider, - AzureServiceBusJmsProperties properties, - List factoryCustomizers) { + Assert.notNull(properties, "Properties must not be null"); + this.properties = properties; + this.factoryCustomizers = (factoryCustomizers != null) ? factoryCustomizers : Collections.emptyList(); if (properties.isPasswordlessEnabled()) { - if (tokenCredentialProvider == null) { - this.tokenCredentialProvider = TokenCredentialProvider.createDefault( - new TokenCredentialProviderOptions(properties.toPasswordlessProperties())); - } else { - this.tokenCredentialProvider = tokenCredentialProvider; - } + Properties passwordlessProperties = properties.toPasswordlessProperties(); + enhancePasswordlessProperties(AzureServiceBusJmsProperties.PREFIX, properties, passwordlessProperties); + this.tokenCredentialProvider = TokenCredentialProvider.createDefault(new TokenCredentialProviderOptions(passwordlessProperties)); } else { this.tokenCredentialProvider = null; } - - Assert.notNull(properties, "Properties must not be null"); - this.properties = properties; - this.factoryCustomizers = (factoryCustomizers != null) ? factoryCustomizers : Collections.emptyList(); } T createConnectionFactory(Class factoryClass) { diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/util/SpringPasswordlessPropertiesUtils.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/util/SpringPasswordlessPropertiesUtils.java index ae37cd3b0d9b..e64b63f4e62a 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/util/SpringPasswordlessPropertiesUtils.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/util/SpringPasswordlessPropertiesUtils.java @@ -32,54 +32,61 @@ private SpringPasswordlessPropertiesUtils() { /** * Enhance the {@link PasswordlessProperties} implementation into the {@link Properties}. - * @param applicationContext the application context. * @param passwordlessPropertiesPrefix the prefix for the {@link PasswordlessProperties}. * @param passwordlessProperties the {@link PasswordlessProperties} implementation. * @param properties the {@link Properties} {@link Properties}. */ - public static void enhancePasswordlessProperties(GenericApplicationContext applicationContext, - String passwordlessPropertiesPrefix, + public static void enhancePasswordlessProperties(String passwordlessPropertiesPrefix, PasswordlessProperties passwordlessProperties, Properties properties) { if (!passwordlessProperties.isPasswordlessEnabled()) { - if (!passwordlessProperties.isPasswordlessEnabled()) { - LOGGER.debug("Feature passwordless authentication is not enabled({}.passwordless-enabled=false), " - + "skip enhancing properties.", passwordlessPropertiesPrefix); - return; - } + LOGGER.debug("Feature passwordless authentication is not enabled({}.passwordless-enabled=false), " + + "skip enhancing properties.", passwordlessPropertiesPrefix); + return; } String tokenCredentialBeanName = passwordlessProperties.getCredential().getTokenCredentialBeanName(); if (StringUtils.hasText(tokenCredentialBeanName)) { AuthProperty.TOKEN_CREDENTIAL_BEAN_NAME.setProperty(properties, tokenCredentialBeanName); } else { - TokenCredentialProvider tokenCredentialProvider = TokenCredentialProvider.createDefault(new TokenCredentialProviderOptions(properties)); - TokenCredential tokenCredential = tokenCredentialProvider.get(); - - tokenCredentialBeanName = PASSWORDLESS_TOKEN_CREDENTIAL_BEAN_NAME + "." + passwordlessPropertiesPrefix; - AuthProperty.TOKEN_CREDENTIAL_BEAN_NAME.setProperty(properties, tokenCredentialBeanName); - applicationContext.registerBean(tokenCredentialBeanName, TokenCredential.class, () -> tokenCredential); + AuthProperty.TOKEN_CREDENTIAL_BEAN_NAME.setProperty(properties, + PASSWORDLESS_TOKEN_CREDENTIAL_BEAN_NAME + "." + passwordlessPropertiesPrefix); } AuthProperty.TOKEN_CREDENTIAL_PROVIDER_CLASS_NAME.setProperty(properties, SpringTokenCredentialProvider.class.getName()); AuthProperty.AUTHORITY_HOST.setProperty(properties, passwordlessProperties.getProfile().getEnvironment().getActiveDirectoryEndpoint()); - } /** * Enhance the {@link PasswordlessProperties} implementation into the Map. - * @param applicationContext the application context. * @param passwordlessPropertiesPrefix the prefix for the {@link PasswordlessProperties}. * @param passwordlessProperties the {@link PasswordlessProperties} implementation. * @param result the Map. */ - public static void enhancePasswordlessProperties(GenericApplicationContext applicationContext, - String passwordlessPropertiesPrefix, + public static void enhancePasswordlessProperties(String passwordlessPropertiesPrefix, PasswordlessProperties passwordlessProperties, Map result) { Properties properties = new Properties(); result.forEach(properties::setProperty); - enhancePasswordlessProperties(applicationContext, passwordlessPropertiesPrefix, passwordlessProperties, properties); + enhancePasswordlessProperties(passwordlessPropertiesPrefix, passwordlessProperties, properties); properties.forEach((key, value) -> result.put((String) key, (String) value)); } + + /** + * Register a token credential bean for passwordless if the property token-credential-bean-name is not configured. + * @param applicationContext the application context. + * @param passwordlessPropertiesPrefix the prefix for the {@link PasswordlessProperties}. + * @param properties the {@link PasswordlessProperties} implementation. + */ + public static void registerTokenCredentialBean(GenericApplicationContext applicationContext, + String passwordlessPropertiesPrefix, + PasswordlessProperties properties) { + if (properties.isPasswordlessEnabled() && !StringUtils.hasText(properties.getCredential().getTokenCredentialBeanName())) { + TokenCredentialProvider tokenCredentialProvider = TokenCredentialProvider.createDefault( + new TokenCredentialProviderOptions(properties.toPasswordlessProperties())); + TokenCredential tokenCredential = tokenCredentialProvider.get(); + applicationContext.registerBean(PASSWORDLESS_TOKEN_CREDENTIAL_BEAN_NAME + "." + passwordlessPropertiesPrefix, + TokenCredential.class, () -> tokenCredential); + } + } } From 3413d56681093ed7802827b1c49d8eb885ae5c25 Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Wed, 30 Oct 2024 14:04:28 +0800 Subject: [PATCH 20/23] Resolve comments --- ...eLettucePasswordlessAutoConfiguration.java | 5 +- .../jdbc/JdbcPropertiesBeanPostProcessor.java | 2 - ...eBusJmsConnectionFactoryConfiguration.java | 3 - .../SpringPasswordlessPropertiesUtils.java | 30 +--------- .../JdbcPropertiesBeanPostProcessorTest.java | 57 ++++++++++++------- ...essorWithApplicationContextRunnerTest.java | 5 +- .../MySqlAzureJdbcAutoConfigurationTest.java | 6 +- ...tgreSqlAzureJdbcAutoConfigurationTest.java | 4 -- .../SpringTokenCredentialProvider.java | 9 ++- 9 files changed, 50 insertions(+), 71 deletions(-) diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/AzureLettucePasswordlessAutoConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/AzureLettucePasswordlessAutoConfiguration.java index b6a1a7ebfe79..ecd496746818 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/AzureLettucePasswordlessAutoConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/AzureLettucePasswordlessAutoConfiguration.java @@ -33,7 +33,6 @@ import java.util.Properties; import static com.azure.spring.cloud.autoconfigure.implementation.util.SpringPasswordlessPropertiesUtils.enhancePasswordlessProperties; -import static com.azure.spring.cloud.autoconfigure.implementation.util.SpringPasswordlessPropertiesUtils.registerTokenCredentialBean; /** @@ -67,10 +66,8 @@ AzureRedisCredentials azureRedisCredentials(RedisProperties redisProperties, AzureRedisPasswordlessProperties azureRedisPasswordlessProperties, AzureGlobalProperties azureGlobalProperties) { AzureRedisPasswordlessProperties redisPasswordlessProperties = mergeAzureProperties(azureGlobalProperties, azureRedisPasswordlessProperties); - String passwordlessPropertiesPrefix = "spring.data.redis.azure"; - registerTokenCredentialBean(applicationContext, passwordlessPropertiesPrefix, redisPasswordlessProperties); Properties passwordlessProperties = redisPasswordlessProperties.toPasswordlessProperties(); - enhancePasswordlessProperties(passwordlessPropertiesPrefix, redisPasswordlessProperties, passwordlessProperties); + enhancePasswordlessProperties("spring.data.redis.azure", redisPasswordlessProperties, passwordlessProperties); return new AzureRedisCredentials(redisProperties.getUsername(), passwordlessProperties); } diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessor.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessor.java index a881cec96e00..fe160a3e071b 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessor.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessor.java @@ -35,7 +35,6 @@ import static com.azure.spring.cloud.autoconfigure.implementation.jdbc.JdbcPropertyConstants.POSTGRESQL_PROPERTY_NAME_ASSUME_MIN_SERVER_VERSION; import static com.azure.spring.cloud.autoconfigure.implementation.jdbc.JdbcPropertyConstants.POSTGRESQL_PROPERTY_VALUE_ASSUME_MIN_SERVER_VERSION; import static com.azure.spring.cloud.autoconfigure.implementation.util.SpringPasswordlessPropertiesUtils.enhancePasswordlessProperties; -import static com.azure.spring.cloud.autoconfigure.implementation.util.SpringPasswordlessPropertiesUtils.registerTokenCredentialBean; /** @@ -143,7 +142,6 @@ private void enhanceUserAgent(DatabaseType databaseType, JdbcConnectionStringEnh private Map buildEnhancedProperties(String passwordlessPropertiesPrefix, DatabaseType databaseType, AzureJdbcPasswordlessProperties properties) { - registerTokenCredentialBean(applicationContext, passwordlessPropertiesPrefix, properties); Map result = new HashMap<>(); enhancePasswordlessProperties(passwordlessPropertiesPrefix, properties, result); databaseType.setDefaultEnhancedProperties(result); diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java index 5bdd4b541cff..2ce386c56888 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java @@ -22,8 +22,6 @@ import java.util.stream.Collectors; -import static com.azure.spring.cloud.autoconfigure.implementation.util.SpringPasswordlessPropertiesUtils.registerTokenCredentialBean; - @Configuration(proxyBeanMethods = false) @ConditionalOnMissingBean(ConnectionFactory.class) public class ServiceBusJmsConnectionFactoryConfiguration { @@ -36,7 +34,6 @@ public class ServiceBusJmsConnectionFactoryConfiguration { private ServiceBusJmsConnectionFactory createJmsConnectionFactory(AzureServiceBusJmsProperties serviceBusJmsProperties, ObjectProvider factoryCustomizers) { - registerTokenCredentialBean(applicationContext, AzureServiceBusJmsProperties.PREFIX, serviceBusJmsProperties); return new ServiceBusJmsConnectionFactoryFactory(serviceBusJmsProperties, factoryCustomizers.orderedStream().collect(Collectors.toList())) .createConnectionFactory(ServiceBusJmsConnectionFactory.class); diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/util/SpringPasswordlessPropertiesUtils.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/util/SpringPasswordlessPropertiesUtils.java index e64b63f4e62a..68e7e65a1176 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/util/SpringPasswordlessPropertiesUtils.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/util/SpringPasswordlessPropertiesUtils.java @@ -3,22 +3,16 @@ package com.azure.spring.cloud.autoconfigure.implementation.util; -import com.azure.core.credential.TokenCredential; -import com.azure.identity.extensions.implementation.credential.TokenCredentialProviderOptions; -import com.azure.identity.extensions.implementation.credential.provider.TokenCredentialProvider; import com.azure.identity.extensions.implementation.enums.AuthProperty; import com.azure.spring.cloud.core.properties.PasswordlessProperties; import com.azure.spring.cloud.service.implementation.identity.credential.provider.SpringTokenCredentialProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.context.support.GenericApplicationContext; import org.springframework.util.StringUtils; import java.util.Map; import java.util.Properties; -import static com.azure.spring.cloud.service.implementation.identity.credential.provider.SpringTokenCredentialProvider.PASSWORDLESS_TOKEN_CREDENTIAL_BEAN_NAME; - /** * Util class for passwordless properties enhancement. */ @@ -48,12 +42,8 @@ public static void enhancePasswordlessProperties(String passwordlessPropertiesPr String tokenCredentialBeanName = passwordlessProperties.getCredential().getTokenCredentialBeanName(); if (StringUtils.hasText(tokenCredentialBeanName)) { AuthProperty.TOKEN_CREDENTIAL_BEAN_NAME.setProperty(properties, tokenCredentialBeanName); - } else { - AuthProperty.TOKEN_CREDENTIAL_BEAN_NAME.setProperty(properties, - PASSWORDLESS_TOKEN_CREDENTIAL_BEAN_NAME + "." + passwordlessPropertiesPrefix); + AuthProperty.TOKEN_CREDENTIAL_PROVIDER_CLASS_NAME.setProperty(properties, SpringTokenCredentialProvider.class.getName()); } - - AuthProperty.TOKEN_CREDENTIAL_PROVIDER_CLASS_NAME.setProperty(properties, SpringTokenCredentialProvider.class.getName()); AuthProperty.AUTHORITY_HOST.setProperty(properties, passwordlessProperties.getProfile().getEnvironment().getActiveDirectoryEndpoint()); } @@ -71,22 +61,4 @@ public static void enhancePasswordlessProperties(String passwordlessPropertiesPr enhancePasswordlessProperties(passwordlessPropertiesPrefix, passwordlessProperties, properties); properties.forEach((key, value) -> result.put((String) key, (String) value)); } - - /** - * Register a token credential bean for passwordless if the property token-credential-bean-name is not configured. - * @param applicationContext the application context. - * @param passwordlessPropertiesPrefix the prefix for the {@link PasswordlessProperties}. - * @param properties the {@link PasswordlessProperties} implementation. - */ - public static void registerTokenCredentialBean(GenericApplicationContext applicationContext, - String passwordlessPropertiesPrefix, - PasswordlessProperties properties) { - if (properties.isPasswordlessEnabled() && !StringUtils.hasText(properties.getCredential().getTokenCredentialBeanName())) { - TokenCredentialProvider tokenCredentialProvider = TokenCredentialProvider.createDefault( - new TokenCredentialProviderOptions(properties.toPasswordlessProperties())); - TokenCredential tokenCredential = tokenCredentialProvider.get(); - applicationContext.registerBean(PASSWORDLESS_TOKEN_CREDENTIAL_BEAN_NAME + "." + passwordlessPropertiesPrefix, - TokenCredential.class, () -> tokenCredential); - } - } } 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 52cb9c3b2a67..26b5c7683436 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,7 +39,7 @@ 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/"; - public static final String PUBLIC_TOKEN_CREDENTIAL_BEAN_NAME_STRING = AuthProperty.TOKEN_CREDENTIAL_BEAN_NAME.getPropertyKey() + "=" + "passwordlessTokenCredential"; + 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; private static final String DEFAULT_PASSWORDLESS_PROPERTIES_SUFFIX = ".spring.datasource.azure"; @@ -103,9 +103,7 @@ void shouldPostprocessWhenSwitchOn() { String expectedJdbcUrl = enhanceJdbcUrl( DatabaseType.MYSQL, MYSQL_CONNECTION_STRING, - PUBLIC_TOKEN_CREDENTIAL_BEAN_NAME_STRING + DEFAULT_PASSWORDLESS_PROPERTIES_SUFFIX, - MYSQL_USER_AGENT, - AuthProperty.TOKEN_CREDENTIAL_PROVIDER_CLASS_NAME.getPropertyKey() + "=" + SpringTokenCredentialProvider.class.getName() + MYSQL_USER_AGENT ); assertEquals(expectedJdbcUrl, dataSourceProperties.getUrl()); @@ -151,9 +149,7 @@ void shouldGetCloudTypeFromAzureUsGov() { DatabaseType.MYSQL, MYSQL_CONNECTION_STRING, MYSQL_USER_AGENT, - AuthProperty.TOKEN_CREDENTIAL_PROVIDER_CLASS_NAME.getPropertyKey() + "=" + SpringTokenCredentialProvider.class.getName(), - US_AUTHORITY_HOST_STRING, - PUBLIC_TOKEN_CREDENTIAL_BEAN_NAME_STRING + DEFAULT_PASSWORDLESS_PROPERTIES_SUFFIX + US_AUTHORITY_HOST_STRING ); assertEquals(expectedJdbcUrl, dataSourceProperties.getUrl()); @@ -170,9 +166,7 @@ void mySqlUserAgentShouldConfigureIfConnectionAttributesIsEmpty() { String expectedJdbcUrl = enhanceJdbcUrl( DatabaseType.MYSQL, MYSQL_CONNECTION_STRING, - PUBLIC_TOKEN_CREDENTIAL_BEAN_NAME_STRING + DEFAULT_PASSWORDLESS_PROPERTIES_SUFFIX, - MYSQL_USER_AGENT, - AuthProperty.TOKEN_CREDENTIAL_PROVIDER_CLASS_NAME.getPropertyKey() + "=" + SpringTokenCredentialProvider.class.getName() + MYSQL_USER_AGENT ); assertEquals(expectedJdbcUrl, dataSourceProperties.getUrl()); @@ -191,9 +185,7 @@ void mySqlUserAgentShouldConfigureIfConnectionAttributesIsNotEmpty() { String expectedJdbcUrl = enhanceJdbcUrl( DatabaseType.MYSQL, - baseUrl + ",_extension_version:" + AzureSpringIdentifier.AZURE_SPRING_MYSQL_OAUTH, - AuthProperty.TOKEN_CREDENTIAL_PROVIDER_CLASS_NAME.getPropertyKey() + "=" + SpringTokenCredentialProvider.class.getName(), - PUBLIC_TOKEN_CREDENTIAL_BEAN_NAME_STRING + DEFAULT_PASSWORDLESS_PROPERTIES_SUFFIX + baseUrl + ",_extension_version:" + AzureSpringIdentifier.AZURE_SPRING_MYSQL_OAUTH ); assertEquals(expectedJdbcUrl, dataSourceProperties.getUrl()); @@ -212,9 +204,7 @@ void mySqlUserAgentShouldConfigureIfConnectionAttributes() { String expectedJdbcUrl = enhanceJdbcUrl( DatabaseType.MYSQL, - baseUrl + ",_extension_version:" + AzureSpringIdentifier.AZURE_SPRING_MYSQL_OAUTH, - AuthProperty.TOKEN_CREDENTIAL_PROVIDER_CLASS_NAME.getPropertyKey() + "=" + SpringTokenCredentialProvider.class.getName(), - PUBLIC_TOKEN_CREDENTIAL_BEAN_NAME_STRING + DEFAULT_PASSWORDLESS_PROPERTIES_SUFFIX + baseUrl + ",_extension_version:" + AzureSpringIdentifier.AZURE_SPRING_MYSQL_OAUTH ); assertEquals(expectedJdbcUrl, dataSourceProperties.getUrl()); } @@ -231,9 +221,7 @@ void postgreSqlUserAgentShouldConfigureIfNonApplicationNameProvided() { String expectedJdbcUrl = enhanceJdbcUrl( DatabaseType.POSTGRESQL, baseUrl, - AuthProperty.TOKEN_CREDENTIAL_PROVIDER_CLASS_NAME.getPropertyKey() + "=" + SpringTokenCredentialProvider.class.getName(), APPLICATION_NAME.getName() + "=" + AzureSpringIdentifier.AZURE_SPRING_POSTGRESQL_OAUTH, - PUBLIC_TOKEN_CREDENTIAL_BEAN_NAME_STRING + DEFAULT_PASSWORDLESS_PROPERTIES_SUFFIX, POSTGRESQL_ASSUME_MIN_SERVER_VERSION ); @@ -254,12 +242,41 @@ void postgreSqlUserAgentShouldNotConfigureIfApplicationNameExists() { String expectedJdbcUrl = enhanceJdbcUrl( DatabaseType.POSTGRESQL, baseUrl, - AuthProperty.TOKEN_CREDENTIAL_PROVIDER_CLASS_NAME.getPropertyKey() + "=" + SpringTokenCredentialProvider.class.getName(), - PUBLIC_TOKEN_CREDENTIAL_BEAN_NAME_STRING + DEFAULT_PASSWORDLESS_PROPERTIES_SUFFIX, POSTGRESQL_ASSUME_MIN_SERVER_VERSION ); assertEquals(expectedJdbcUrl, dataSourceProperties.getUrl()); } + @Test + void useDefaultTokenCredential() { + DataSourceProperties dataSourceProperties = new DataSourceProperties(); + dataSourceProperties.setUrl(MYSQL_CONNECTION_STRING); + this.mockEnvironment.setProperty("spring.datasource.azure.passwordless-enabled", "true"); + this.jdbcPropertiesBeanPostProcessor.postProcessBeforeInitialization(dataSourceProperties, "dataSourceProperties"); + String expectedJdbcUrl = enhanceJdbcUrl( + DatabaseType.MYSQL, + MYSQL_CONNECTION_STRING, + MYSQL_USER_AGENT + ); + assertEquals(expectedJdbcUrl, dataSourceProperties.getUrl()); + } + + @Test + void useTokenCredentialBeanName() { + DataSourceProperties dataSourceProperties = new DataSourceProperties(); + dataSourceProperties.setUrl(MYSQL_CONNECTION_STRING); + String tokenCredentialBeanName = "test-bean-name"; + this.mockEnvironment.setProperty("spring.datasource.azure.passwordless-enabled", "true"); + this.mockEnvironment.setProperty("spring.datasource.azure.credential.token-credential-bean-name", tokenCredentialBeanName); + this.jdbcPropertiesBeanPostProcessor.postProcessBeforeInitialization(dataSourceProperties, "dataSourceProperties"); + String expectedJdbcUrl = enhanceJdbcUrl( + DatabaseType.MYSQL, + MYSQL_CONNECTION_STRING, + MYSQL_USER_AGENT, + AuthProperty.TOKEN_CREDENTIAL_PROVIDER_CLASS_NAME.getPropertyKey() + "=" + SpringTokenCredentialProvider.class.getName(), + PUBLIC_TOKEN_CREDENTIAL_BEAN_NAME_STRING + tokenCredentialBeanName + ); + assertEquals(expectedJdbcUrl, dataSourceProperties.getUrl()); + } } diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessorWithApplicationContextRunnerTest.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessorWithApplicationContextRunnerTest.java index a63f8ec1b9aa..9692e539f4eb 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessorWithApplicationContextRunnerTest.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessorWithApplicationContextRunnerTest.java @@ -8,7 +8,6 @@ import com.azure.spring.cloud.autoconfigure.implementation.context.AzureGlobalPropertiesAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.context.AzureTokenCredentialAutoConfiguration; import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; -import com.azure.spring.cloud.service.implementation.identity.credential.provider.SpringTokenCredentialProvider; import com.azure.spring.cloud.autoconfigure.implementation.passwordless.properties.AzureJdbcPasswordlessProperties; import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; @@ -75,10 +74,8 @@ void mySqlAuthPluginOnClassPath() { String expectedJdbcUrl = enhanceJdbcUrl( DatabaseType.MYSQL, MYSQL_CONNECTION_STRING, - PUBLIC_TOKEN_CREDENTIAL_BEAN_NAME_STRING + ".spring.datasource.azure", PUBLIC_AUTHORITY_HOST_STRING, - MYSQL_USER_AGENT, - AuthProperty.TOKEN_CREDENTIAL_PROVIDER_CLASS_NAME.getPropertyKey() + "=" + SpringTokenCredentialProvider.class.getName() + MYSQL_USER_AGENT ); assertEquals(expectedJdbcUrl, dataSourceProperties.getUrl()); } diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/MySqlAzureJdbcAutoConfigurationTest.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/MySqlAzureJdbcAutoConfigurationTest.java index bda3308f5999..364a67e87d6a 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/MySqlAzureJdbcAutoConfigurationTest.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/MySqlAzureJdbcAutoConfigurationTest.java @@ -82,9 +82,9 @@ void enhanceUrlWithDefaultCredential() { DatabaseType.MYSQL, false, connectionString, - PUBLIC_TOKEN_CREDENTIAL_BEAN_NAME_STRING + ".spring.datasource.azure", +// PUBLIC_TOKEN_CREDENTIAL_BEAN_NAME_STRING + ".spring.datasource.azure", PUBLIC_AUTHORITY_HOST_STRING, - AUTHPROPERTY_TOKENCREDENTIALPROVIDERCLASSNAME_PROPERTY, +// AUTHPROPERTY_TOKENCREDENTIALPROVIDERCLASSNAME_PROPERTY, MYSQL_USER_AGENT ); assertEquals(expectedUrl, dataSourceProperties.getUrl()); @@ -109,8 +109,6 @@ void enhanceUrlWithCustomCredential() { false, connectionString, PUBLIC_AUTHORITY_HOST_STRING, - AUTHPROPERTY_CREDENTIAL_BEAN_NAME + ".spring.datasource.azure", - AUTHPROPERTY_TOKENCREDENTIALPROVIDERCLASSNAME_PROPERTY, MYSQL_USER_AGENT ); diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/PostgreSqlAzureJdbcAutoConfigurationTest.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/PostgreSqlAzureJdbcAutoConfigurationTest.java index 66be23a6c7df..b1764042ea82 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/PostgreSqlAzureJdbcAutoConfigurationTest.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/PostgreSqlAzureJdbcAutoConfigurationTest.java @@ -70,10 +70,8 @@ void enhanceUrlWithDefaultCredential() { DatabaseType.POSTGRESQL, false, connectionString, - PUBLIC_TOKEN_CREDENTIAL_BEAN_NAME_STRING + ".spring.datasource.azure", PUBLIC_AUTHORITY_HOST_STRING, POSTGRESQL_USER_AGENT, - AUTHPROPERTY_TOKENCREDENTIALPROVIDERCLASSNAME_PROPERTY, POSTGRESQL_ASSUME_MIN_SERVER_VERSION ); assertEquals(expectedUrl, dataSourceProperties.getUrl()); @@ -96,8 +94,6 @@ void enhanceUrlWithCustomCredential() { false, connectionString, PUBLIC_AUTHORITY_HOST_STRING, - AUTHPROPERTY_CREDENTIAL_BEAN_NAME + ".spring.datasource.azure", - AUTHPROPERTY_TOKENCREDENTIALPROVIDERCLASSNAME_PROPERTY, POSTGRESQL_USER_AGENT, POSTGRESQL_ASSUME_MIN_SERVER_VERSION ); diff --git a/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/identity/credential/provider/SpringTokenCredentialProvider.java b/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/identity/credential/provider/SpringTokenCredentialProvider.java index adf839122f5c..440b2fbb6f2f 100644 --- a/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/identity/credential/provider/SpringTokenCredentialProvider.java +++ b/sdk/spring/spring-cloud-azure-service/src/main/java/com/azure/spring/cloud/service/implementation/identity/credential/provider/SpringTokenCredentialProvider.java @@ -5,6 +5,7 @@ import com.azure.core.credential.TokenCredential; import com.azure.identity.extensions.implementation.credential.TokenCredentialProviderOptions; +import com.azure.identity.extensions.implementation.credential.provider.DefaultTokenCredentialProvider; import com.azure.identity.extensions.implementation.credential.provider.TokenCredentialProvider; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; @@ -13,7 +14,7 @@ import java.util.Objects; /** - * TokenCredentialProvider contains spring context. + * TokenCredentialProvider implementation for Spring context. */ public class SpringTokenCredentialProvider implements TokenCredentialProvider, ApplicationContextAware { @@ -23,6 +24,12 @@ public class SpringTokenCredentialProvider implements TokenCredentialProvider, A private ApplicationContext applicationContext; private String tokenCredentialBeanName = DEFAULT_TOKEN_CREDENTIAL_BEAN_NAME; + /** + * Create a {@link SpringTokenCredentialProvider} instance with a {@link TokenCredentialProviderOptions}. + * If option token-credential-bean-name is specified, it will get this bean from application context, + * otherwise it will delegate {@link DefaultTokenCredentialProvider} to create a token credential. + * @param options the token credential provider options. + */ public SpringTokenCredentialProvider(TokenCredentialProviderOptions options) { String beanName = options == null ? null : options.getTokenCredentialBeanName(); if (beanName != null && !beanName.isEmpty()) { From 5504e05826a7afc6bc36220f40d7cb63a39f0af7 Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Wed, 30 Oct 2024 15:05:20 +0800 Subject: [PATCH 21/23] Resolve comments --- .../implementation/util/SpringPasswordlessPropertiesUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/util/SpringPasswordlessPropertiesUtils.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/util/SpringPasswordlessPropertiesUtils.java index 68e7e65a1176..71c124fad317 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/util/SpringPasswordlessPropertiesUtils.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/util/SpringPasswordlessPropertiesUtils.java @@ -56,7 +56,7 @@ public static void enhancePasswordlessProperties(String passwordlessPropertiesPr public static void enhancePasswordlessProperties(String passwordlessPropertiesPrefix, PasswordlessProperties passwordlessProperties, Map result) { - Properties properties = new Properties(); + Properties properties = passwordlessProperties.toPasswordlessProperties(); result.forEach(properties::setProperty); enhancePasswordlessProperties(passwordlessPropertiesPrefix, passwordlessProperties, properties); properties.forEach((key, value) -> result.put((String) key, (String) value)); From 26ef97770bed986f446f93ac121e1ae2fc853986 Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Wed, 30 Oct 2024 16:11:16 +0800 Subject: [PATCH 22/23] Resolve comments --- ...eLettucePasswordlessAutoConfiguration.java | 15 +-------- .../redis/lettuce/AzureRedisCredentials.java | 14 +++----- .../SpringPasswordlessPropertiesUtils.java | 1 - .../JdbcPropertiesBeanPostProcessorTest.java | 32 +++++++++++++++---- ...essorWithApplicationContextRunnerTest.java | 4 +++ .../MySqlAzureJdbcAutoConfigurationTest.java | 15 ++++++--- ...tgreSqlAzureJdbcAutoConfigurationTest.java | 11 ++++++- 7 files changed, 57 insertions(+), 35 deletions(-) diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/AzureLettucePasswordlessAutoConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/AzureLettucePasswordlessAutoConfiguration.java index ecd496746818..e10df681b455 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/AzureLettucePasswordlessAutoConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/AzureLettucePasswordlessAutoConfiguration.java @@ -23,17 +23,12 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.support.GenericApplicationContext; import org.springframework.data.redis.connection.RedisConfiguration; import org.springframework.data.redis.connection.RedisSentinelConfiguration; import org.springframework.data.redis.connection.lettuce.LettuceConnection; import org.springframework.data.redis.connection.lettuce.RedisCredentialsProviderFactory; import reactor.core.publisher.Mono; -import java.util.Properties; - -import static com.azure.spring.cloud.autoconfigure.implementation.util.SpringPasswordlessPropertiesUtils.enhancePasswordlessProperties; - /** * Azure Redis passwordless connection configuration using Lettuce. @@ -48,12 +43,6 @@ @EnableConfigurationProperties(RedisProperties.class) public class AzureLettucePasswordlessAutoConfiguration { - private final GenericApplicationContext applicationContext; - - AzureLettucePasswordlessAutoConfiguration(GenericApplicationContext applicationContext) { - this.applicationContext = applicationContext; - } - @Bean @ConfigurationProperties(prefix = "spring.data.redis.azure") AzureRedisPasswordlessProperties redisPasswordlessProperties() { @@ -66,9 +55,7 @@ AzureRedisCredentials azureRedisCredentials(RedisProperties redisProperties, AzureRedisPasswordlessProperties azureRedisPasswordlessProperties, AzureGlobalProperties azureGlobalProperties) { AzureRedisPasswordlessProperties redisPasswordlessProperties = mergeAzureProperties(azureGlobalProperties, azureRedisPasswordlessProperties); - Properties passwordlessProperties = redisPasswordlessProperties.toPasswordlessProperties(); - enhancePasswordlessProperties("spring.data.redis.azure", redisPasswordlessProperties, passwordlessProperties); - return new AzureRedisCredentials(redisProperties.getUsername(), passwordlessProperties); + return new AzureRedisCredentials(redisProperties.getUsername(), redisPasswordlessProperties); } @Bean(name = "azureLettuceClientConfigurationBuilderCustomizer") diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/lettuce/AzureRedisCredentials.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/lettuce/AzureRedisCredentials.java index 8f9837d1b097..059b5db1f501 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/lettuce/AzureRedisCredentials.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/data/redis/lettuce/AzureRedisCredentials.java @@ -16,6 +16,8 @@ import java.util.Objects; import java.util.Properties; +import static com.azure.spring.cloud.autoconfigure.implementation.util.SpringPasswordlessPropertiesUtils.enhancePasswordlessProperties; + public class AzureRedisCredentials implements RedisCredentials { public static final Logger LOGGER = LoggerFactory.getLogger(AzureRedisCredentials.class); @@ -28,15 +30,9 @@ public class AzureRedisCredentials implements RedisCredentials { public AzureRedisCredentials(String username, PasswordlessProperties passwordlessProperties) { Objects.requireNonNull(passwordlessProperties, "PasswordlessProperties is required."); azureAuthenticationTemplate = new AzureAuthenticationTemplate(); - azureAuthenticationTemplate.init(passwordlessProperties.toPasswordlessProperties()); - this.username = resolveUsername(azureAuthenticationTemplate, username); - } - - public AzureRedisCredentials(String username, - Properties passwordlessProperties) { - Objects.requireNonNull(passwordlessProperties, "PasswordlessProperties is required."); - azureAuthenticationTemplate = new AzureAuthenticationTemplate(); - azureAuthenticationTemplate.init(passwordlessProperties); + Properties properties = passwordlessProperties.toPasswordlessProperties(); + enhancePasswordlessProperties("spring.data.redis.azure", passwordlessProperties, properties); + azureAuthenticationTemplate.init(properties); this.username = resolveUsername(azureAuthenticationTemplate, username); } diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/util/SpringPasswordlessPropertiesUtils.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/util/SpringPasswordlessPropertiesUtils.java index 71c124fad317..048534883a58 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/util/SpringPasswordlessPropertiesUtils.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/util/SpringPasswordlessPropertiesUtils.java @@ -44,7 +44,6 @@ public static void enhancePasswordlessProperties(String passwordlessPropertiesPr AuthProperty.TOKEN_CREDENTIAL_BEAN_NAME.setProperty(properties, tokenCredentialBeanName); AuthProperty.TOKEN_CREDENTIAL_PROVIDER_CLASS_NAME.setProperty(properties, SpringTokenCredentialProvider.class.getName()); } - AuthProperty.AUTHORITY_HOST.setProperty(properties, passwordlessProperties.getProfile().getEnvironment().getActiveDirectoryEndpoint()); } /** 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 26b5c7683436..b9d54f3beef1 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 @@ -42,6 +42,8 @@ class JdbcPropertiesBeanPostProcessorTest { 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 DEFAULT_PASSWORDLESS_PROPERTIES_SUFFIX = ".spring.datasource.azure"; private MockEnvironment mockEnvironment; @@ -103,6 +105,8 @@ void shouldPostprocessWhenSwitchOn() { String expectedJdbcUrl = enhanceJdbcUrl( DatabaseType.MYSQL, MYSQL_CONNECTION_STRING, + MANAGED_IDENTITY_ENABLED_DEFAULT, + SCOPES_DEFAULT, MYSQL_USER_AGENT ); @@ -146,10 +150,12 @@ void shouldGetCloudTypeFromAzureUsGov() { this.jdbcPropertiesBeanPostProcessor.postProcessBeforeInitialization(dataSourceProperties, "dataSourceProperties"); String expectedJdbcUrl = enhanceJdbcUrl( - DatabaseType.MYSQL, - MYSQL_CONNECTION_STRING, - MYSQL_USER_AGENT, - US_AUTHORITY_HOST_STRING + DatabaseType.MYSQL, + MYSQL_CONNECTION_STRING, + MANAGED_IDENTITY_ENABLED_DEFAULT, + SCOPES_DEFAULT, + MYSQL_USER_AGENT, + US_AUTHORITY_HOST_STRING ); assertEquals(expectedJdbcUrl, dataSourceProperties.getUrl()); @@ -166,6 +172,8 @@ void mySqlUserAgentShouldConfigureIfConnectionAttributesIsEmpty() { String expectedJdbcUrl = enhanceJdbcUrl( DatabaseType.MYSQL, MYSQL_CONNECTION_STRING, + MANAGED_IDENTITY_ENABLED_DEFAULT, + SCOPES_DEFAULT, MYSQL_USER_AGENT ); @@ -185,7 +193,9 @@ void mySqlUserAgentShouldConfigureIfConnectionAttributesIsNotEmpty() { String expectedJdbcUrl = enhanceJdbcUrl( DatabaseType.MYSQL, - baseUrl + ",_extension_version:" + AzureSpringIdentifier.AZURE_SPRING_MYSQL_OAUTH + baseUrl + ",_extension_version:" + AzureSpringIdentifier.AZURE_SPRING_MYSQL_OAUTH, + MANAGED_IDENTITY_ENABLED_DEFAULT, + SCOPES_DEFAULT ); assertEquals(expectedJdbcUrl, dataSourceProperties.getUrl()); @@ -204,7 +214,9 @@ void mySqlUserAgentShouldConfigureIfConnectionAttributes() { String expectedJdbcUrl = enhanceJdbcUrl( DatabaseType.MYSQL, - baseUrl + ",_extension_version:" + AzureSpringIdentifier.AZURE_SPRING_MYSQL_OAUTH + baseUrl + ",_extension_version:" + AzureSpringIdentifier.AZURE_SPRING_MYSQL_OAUTH, + MANAGED_IDENTITY_ENABLED_DEFAULT, + SCOPES_DEFAULT ); assertEquals(expectedJdbcUrl, dataSourceProperties.getUrl()); } @@ -221,6 +233,8 @@ void postgreSqlUserAgentShouldConfigureIfNonApplicationNameProvided() { String expectedJdbcUrl = enhanceJdbcUrl( DatabaseType.POSTGRESQL, baseUrl, + MANAGED_IDENTITY_ENABLED_DEFAULT, + SCOPES_DEFAULT, APPLICATION_NAME.getName() + "=" + AzureSpringIdentifier.AZURE_SPRING_POSTGRESQL_OAUTH, POSTGRESQL_ASSUME_MIN_SERVER_VERSION ); @@ -242,6 +256,8 @@ void postgreSqlUserAgentShouldNotConfigureIfApplicationNameExists() { String expectedJdbcUrl = enhanceJdbcUrl( DatabaseType.POSTGRESQL, baseUrl, + MANAGED_IDENTITY_ENABLED_DEFAULT, + SCOPES_DEFAULT, POSTGRESQL_ASSUME_MIN_SERVER_VERSION ); @@ -257,6 +273,8 @@ void useDefaultTokenCredential() { String expectedJdbcUrl = enhanceJdbcUrl( DatabaseType.MYSQL, MYSQL_CONNECTION_STRING, + MANAGED_IDENTITY_ENABLED_DEFAULT, + SCOPES_DEFAULT, MYSQL_USER_AGENT ); assertEquals(expectedJdbcUrl, dataSourceProperties.getUrl()); @@ -273,6 +291,8 @@ void useTokenCredentialBeanName() { String expectedJdbcUrl = enhanceJdbcUrl( DatabaseType.MYSQL, MYSQL_CONNECTION_STRING, + MANAGED_IDENTITY_ENABLED_DEFAULT, + SCOPES_DEFAULT, MYSQL_USER_AGENT, AuthProperty.TOKEN_CREDENTIAL_PROVIDER_CLASS_NAME.getPropertyKey() + "=" + SpringTokenCredentialProvider.class.getName(), PUBLIC_TOKEN_CREDENTIAL_BEAN_NAME_STRING + tokenCredentialBeanName diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessorWithApplicationContextRunnerTest.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessorWithApplicationContextRunnerTest.java index 9692e539f4eb..4dbb77bd62cd 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessorWithApplicationContextRunnerTest.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/JdbcPropertiesBeanPostProcessorWithApplicationContextRunnerTest.java @@ -18,6 +18,8 @@ import org.springframework.core.env.ConfigurableEnvironment; import static com.azure.spring.cloud.autoconfigure.implementation.jdbc.JdbcConnectionStringUtils.enhanceJdbcUrl; +import static com.azure.spring.cloud.autoconfigure.implementation.jdbc.JdbcPropertiesBeanPostProcessorTest.MANAGED_IDENTITY_ENABLED_DEFAULT; +import static com.azure.spring.cloud.autoconfigure.implementation.jdbc.JdbcPropertiesBeanPostProcessorTest.SCOPES_DEFAULT; import static com.azure.spring.cloud.autoconfigure.implementation.jdbc.MySqlAzureJdbcAutoConfigurationTest.MYSQL_USER_AGENT; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -75,6 +77,8 @@ void mySqlAuthPluginOnClassPath() { DatabaseType.MYSQL, MYSQL_CONNECTION_STRING, PUBLIC_AUTHORITY_HOST_STRING, + MANAGED_IDENTITY_ENABLED_DEFAULT, + SCOPES_DEFAULT, MYSQL_USER_AGENT ); assertEquals(expectedJdbcUrl, dataSourceProperties.getUrl()); diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/MySqlAzureJdbcAutoConfigurationTest.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/MySqlAzureJdbcAutoConfigurationTest.java index 364a67e87d6a..80b0c216784c 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/MySqlAzureJdbcAutoConfigurationTest.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/MySqlAzureJdbcAutoConfigurationTest.java @@ -9,6 +9,8 @@ import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; import org.springframework.boot.test.context.FilteredClassLoader; +import static com.azure.spring.cloud.autoconfigure.implementation.jdbc.JdbcPropertiesBeanPostProcessorTest.MANAGED_IDENTITY_ENABLED_DEFAULT; +import static com.azure.spring.cloud.autoconfigure.implementation.jdbc.JdbcPropertiesBeanPostProcessorTest.SCOPES_DEFAULT; import static com.azure.spring.cloud.autoconfigure.implementation.jdbc.JdbcPropertyConstants.MYSQL_AUTH_PLUGIN_CLASS_NAME; import static com.azure.spring.cloud.autoconfigure.implementation.jdbc.JdbcPropertyConstants.MYSQL_PROPERTY_CONNECTION_ATTRIBUTES_ATTRIBUTE_EXTENSION_VERSION; import static com.azure.spring.cloud.autoconfigure.implementation.jdbc.JdbcPropertyConstants.MYSQL_PROPERTY_CONNECTION_ATTRIBUTES_KV_DELIMITER; @@ -82,10 +84,10 @@ void enhanceUrlWithDefaultCredential() { DatabaseType.MYSQL, false, connectionString, -// PUBLIC_TOKEN_CREDENTIAL_BEAN_NAME_STRING + ".spring.datasource.azure", PUBLIC_AUTHORITY_HOST_STRING, -// AUTHPROPERTY_TOKENCREDENTIALPROVIDERCLASSNAME_PROPERTY, - MYSQL_USER_AGENT + MYSQL_USER_AGENT, + MANAGED_IDENTITY_ENABLED_DEFAULT, + SCOPES_DEFAULT ); assertEquals(expectedUrl, dataSourceProperties.getUrl()); }); @@ -109,7 +111,12 @@ void enhanceUrlWithCustomCredential() { false, connectionString, PUBLIC_AUTHORITY_HOST_STRING, - MYSQL_USER_AGENT + MYSQL_USER_AGENT, + "azure.clientId=fake-clientId", + "azure.clientSecret=fake-clientSecret", + MANAGED_IDENTITY_ENABLED_DEFAULT, + SCOPES_DEFAULT, + "azure.tenantId=fake-tenantId" ); assertEquals(expectedUrl, dataSourceProperties.getUrl()); diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/PostgreSqlAzureJdbcAutoConfigurationTest.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/PostgreSqlAzureJdbcAutoConfigurationTest.java index b1764042ea82..7ec7353b962e 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/PostgreSqlAzureJdbcAutoConfigurationTest.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jdbc/PostgreSqlAzureJdbcAutoConfigurationTest.java @@ -9,6 +9,8 @@ import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; import org.springframework.boot.test.context.FilteredClassLoader; +import static com.azure.spring.cloud.autoconfigure.implementation.jdbc.JdbcPropertiesBeanPostProcessorTest.MANAGED_IDENTITY_ENABLED_DEFAULT; +import static com.azure.spring.cloud.autoconfigure.implementation.jdbc.JdbcPropertiesBeanPostProcessorTest.SCOPES_DEFAULT; import static com.azure.spring.cloud.autoconfigure.implementation.jdbc.JdbcPropertyConstants.POSTGRESQL_PROPERTY_NAME_APPLICATION_NAME; import static com.azure.spring.cloud.autoconfigure.implementation.jdbc.JdbcPropertyConstants.POSTGRESQL_PROPERTY_NAME_ASSUME_MIN_SERVER_VERSION; import static com.azure.spring.cloud.autoconfigure.implementation.jdbc.JdbcPropertyConstants.POSTGRESQL_PROPERTY_NAME_AUTHENTICATION_PLUGIN_CLASSNAME; @@ -71,6 +73,8 @@ void enhanceUrlWithDefaultCredential() { false, connectionString, PUBLIC_AUTHORITY_HOST_STRING, + MANAGED_IDENTITY_ENABLED_DEFAULT, + SCOPES_DEFAULT, POSTGRESQL_USER_AGENT, POSTGRESQL_ASSUME_MIN_SERVER_VERSION ); @@ -95,7 +99,12 @@ void enhanceUrlWithCustomCredential() { connectionString, PUBLIC_AUTHORITY_HOST_STRING, POSTGRESQL_USER_AGENT, - POSTGRESQL_ASSUME_MIN_SERVER_VERSION + POSTGRESQL_ASSUME_MIN_SERVER_VERSION, + "azure.clientId=fake-clientId", + "azure.clientSecret=fake-clientSecret", + MANAGED_IDENTITY_ENABLED_DEFAULT, + SCOPES_DEFAULT, + "azure.tenantId=fake-tenantId" ); assertEquals(expectedUrl, dataSourceProperties.getUrl()); }); From 26fe49e0b88829ff381b60918f3ac052c05e2fae Mon Sep 17 00:00:00 2001 From: Moary Chen Date: Thu, 31 Oct 2024 09:47:43 +0800 Subject: [PATCH 23/23] Remove unused code --- .../jms/ServiceBusJmsConnectionFactoryConfiguration.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java index 2ce386c56888..4bb40a6f6646 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsConnectionFactoryConfiguration.java @@ -17,20 +17,13 @@ import org.springframework.boot.autoconfigure.jms.JmsProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.support.GenericApplicationContext; import org.springframework.jms.connection.CachingConnectionFactory; import java.util.stream.Collectors; @Configuration(proxyBeanMethods = false) @ConditionalOnMissingBean(ConnectionFactory.class) -public class ServiceBusJmsConnectionFactoryConfiguration { - - private final GenericApplicationContext applicationContext; - - ServiceBusJmsConnectionFactoryConfiguration(GenericApplicationContext applicationContext) { - this.applicationContext = applicationContext; - } +class ServiceBusJmsConnectionFactoryConfiguration { private ServiceBusJmsConnectionFactory createJmsConnectionFactory(AzureServiceBusJmsProperties serviceBusJmsProperties, ObjectProvider factoryCustomizers) {