Skip to content

Commit 81944b4

Browse files
authored
Apply Spring application id to Azure Identity (Azure#33212)
* test the azure-identity ua * make the test work
1 parent 58418f2 commit 81944b4

File tree

7 files changed

+115
-36
lines changed

7 files changed

+115
-36
lines changed

sdk/spring/spring-cloud-azure-autoconfigure/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,12 @@
144144
<version>1.36.0</version> <!-- {x-version-update;com.azure:azure-core;dependency} -->
145145
<optional>true</optional>
146146
</dependency>
147+
<dependency>
148+
<groupId>com.azure</groupId>
149+
<artifactId>azure-identity</artifactId>
150+
<version>1.8.0</version> <!-- {x-version-update;com.azure:azure-identity;dependency} -->
151+
<optional>true</optional>
152+
</dependency>
147153
<dependency>
148154
<groupId>com.azure</groupId>
149155
<artifactId>azure-cosmos</artifactId>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
package com.azure.spring.cloud.autoconfigure.useragent.http;
5+
6+
import ch.qos.logback.classic.Level;
7+
import com.azure.core.credential.TokenCredential;
8+
import com.azure.core.credential.TokenRequestContext;
9+
import com.azure.core.http.policy.HttpLogDetailLevel;
10+
import com.azure.core.http.policy.HttpLogOptions;
11+
import com.azure.identity.ClientSecretCredentialBuilder;
12+
import com.azure.spring.cloud.autoconfigure.context.AzureGlobalPropertiesAutoConfiguration;
13+
import com.azure.spring.cloud.autoconfigure.context.AzureTokenCredentialAutoConfiguration;
14+
import com.azure.spring.cloud.core.customizer.AzureServiceClientBuilderCustomizer;
15+
import com.azure.spring.cloud.core.implementation.util.AzureSpringIdentifier;
16+
import org.junit.jupiter.api.Test;
17+
import org.junit.jupiter.api.extension.ExtendWith;
18+
import org.junit.jupiter.api.parallel.Isolated;
19+
import org.slf4j.LoggerFactory;
20+
import org.springframework.boot.autoconfigure.AutoConfigurations;
21+
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
22+
import org.springframework.boot.test.system.CapturedOutput;
23+
import org.springframework.boot.test.system.OutputCaptureExtension;
24+
import org.springframework.context.annotation.Bean;
25+
26+
import java.util.Arrays;
27+
import java.util.HashSet;
28+
import java.util.Set;
29+
30+
import static org.assertj.core.api.Assertions.assertThat;
31+
import static org.junit.jupiter.api.Assertions.assertTrue;
32+
33+
@Isolated("Run this by itself as it captures System.out")
34+
@ExtendWith(OutputCaptureExtension.class)
35+
class IdentityUserAgentTests {
36+
37+
@Test
38+
void userAgentTest(CapturedOutput output) {
39+
new ApplicationContextRunner()
40+
.withConfiguration(AutoConfigurations.of(
41+
AzureTokenCredentialAutoConfiguration.class,
42+
AzureGlobalPropertiesAutoConfiguration.class
43+
))
44+
.withUserConfiguration(CredentialCustomizerConfiguration.class)
45+
.withPropertyValues(
46+
"spring.cloud.azure.profile.tenant-id=sample",
47+
"spring.cloud.azure.credential.client-id=sample",
48+
"spring.cloud.azure.credential.client-secret=sample",
49+
"spring.cloud.azure.retry.fixed.delay=1",
50+
"spring.cloud.azure.retry.fixed.max-retries=0",
51+
"spring.cloud.azure.retry.mode=fixed"
52+
)
53+
.run(context -> {
54+
// see https://github.com/Azure/azure-sdk-for-java/blob/c8aecbf72f6826de8e465bdf6ae1ddcf2d09fe4e/sdk/core/azure-core/src/main/java/com/azure/core/http/policy/HttpLoggingPolicy.java#L456
55+
ch.qos.logback.classic.Logger httpLoggingPolicyLogger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger("");
56+
httpLoggingPolicyLogger.setLevel(Level.DEBUG);
57+
58+
assertThat(context).hasSingleBean(TokenCredential.class);
59+
60+
TokenCredential tokenCredential = context.getBean(TokenCredential.class);
61+
try {
62+
final TokenRequestContext request = new TokenRequestContext();
63+
request.setScopes(Arrays.asList("https://servicebus.azure.net/.default"));
64+
tokenCredential.getTokenSync(request);
65+
66+
} catch (Exception exception) {
67+
// Eat it because we just want the log.
68+
}
69+
String allOutput = output.getAll();
70+
String format1 = String.format("User-Agent:%s", AzureSpringIdentifier.AZURE_SPRING_IDENTITY);
71+
String format2 = String.format("\"User-Agent\":\"%s", AzureSpringIdentifier.AZURE_SPRING_IDENTITY);
72+
assertTrue(allOutput.contains(format1) || allOutput.contains(format2));
73+
});
74+
}
75+
76+
static class CredentialCustomizerConfiguration {
77+
78+
@Bean
79+
AzureServiceClientBuilderCustomizer<ClientSecretCredentialBuilder> httpLogOptionsCustomizer() {
80+
return builder -> {
81+
final HttpLogOptions httpLogOptions = new HttpLogOptions();
82+
httpLogOptions.setLogLevel(HttpLogDetailLevel.HEADERS);
83+
Set<String> allowedHeaderNames = new HashSet<>();
84+
allowedHeaderNames.add("User-Agent");
85+
httpLogOptions.setAllowedHeaderNames(allowedHeaderNames);
86+
builder.httpLogOptions(httpLogOptions);
87+
};
88+
}
89+
}
90+
91+
92+
}

sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/factory/credential/AbstractAzureCredentialBuilderFactory.java

Lines changed: 6 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
import com.azure.identity.CredentialBuilderBase;
1515
import com.azure.spring.cloud.core.implementation.credential.descriptor.AuthenticationDescriptor;
1616
import com.azure.spring.cloud.core.implementation.factory.AbstractAzureHttpClientBuilderFactory;
17+
import com.azure.spring.cloud.core.implementation.util.AzureSpringIdentifier;
1718
import com.azure.spring.cloud.core.properties.AzureProperties;
18-
import com.azure.spring.cloud.core.provider.RetryOptionsProvider;
1919
import org.slf4j.Logger;
2020
import org.slf4j.LoggerFactory;
2121

@@ -38,6 +38,7 @@ public abstract class AbstractAzureCredentialBuilderFactory<T extends Credential
3838
*/
3939
protected AbstractAzureCredentialBuilderFactory(AzureProperties azureProperties) {
4040
this.azureProperties = azureProperties;
41+
this.setSpringIdentifier(AzureSpringIdentifier.AZURE_SPRING_IDENTITY);
4142
}
4243

4344
@Override
@@ -60,37 +61,14 @@ protected BiConsumer<T, Configuration> consumeConfiguration() {
6061
return T::configuration;
6162
}
6263

63-
@Override
64-
protected void configureRetry(T builder) {
65-
RetryOptionsProvider.RetryOptions retry = null;
66-
if (azureProperties instanceof RetryOptionsProvider) {
67-
retry = ((RetryOptionsProvider) azureProperties).getRetry();
68-
}
69-
70-
if (retry == null) {
71-
return;
72-
}
73-
74-
if (RetryOptionsProvider.RetryMode.EXPONENTIAL == retry.getMode()) {
75-
if (retry.getExponential() != null && retry.getExponential().getMaxRetries() != null) {
76-
builder.maxRetry(retry.getExponential().getMaxRetries());
77-
}
78-
} else if (RetryOptionsProvider.RetryMode.FIXED == retry.getMode()
79-
&& retry.getFixed() != null
80-
&& retry.getFixed().getMaxRetries() != null) {
81-
builder.maxRetry(retry.getFixed().getMaxRetries());
82-
}
83-
84-
}
85-
8664
@Override
8765
protected List<AuthenticationDescriptor<?>> getAuthenticationDescriptors(T builder) {
8866
return Collections.emptyList();
8967
}
9068

9169
@Override
9270
protected BiConsumer<T, ClientOptions> consumeClientOptions() {
93-
return (a, b) -> { };
71+
return T::clientOptions;
9472
}
9573

9674
@Override
@@ -105,18 +83,17 @@ protected BiConsumer<T, String> consumeConnectionString() {
10583

10684
@Override
10785
protected BiConsumer<T, HttpLogOptions> consumeHttpLogOptions() {
108-
return (a, b) -> { };
86+
return T::httpLogOptions;
10987
}
11088

11189
@Override
11290
protected BiConsumer<T, HttpPipelinePolicy> consumeHttpPipelinePolicy() {
113-
return (a, b) -> { };
91+
return T::addPolicy;
11492
}
11593

11694
@Override
11795
protected BiConsumer<T, RetryPolicy> consumeRetryPolicy() {
118-
LOGGER.debug("No need to specify retry policy.");
119-
return (a, b) -> { };
96+
return T::retryPolicy;
12097
}
12198

12299
@Override

sdk/spring/spring-cloud-azure-core/src/main/java/com/azure/spring/cloud/core/implementation/util/AzureSpringIdentifier.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ private AzureSpringIdentifier() {
8181
* Azure Spring B2C
8282
*/
8383
public static final String AZURE_SPRING_B2C = "az-sp-b2c";
84+
public static final String AZURE_SPRING_IDENTITY = "az-sp-id/" + VERSION;
8485

8586
private static String getVersion() {
8687
String version = "unknown";

sdk/spring/spring-cloud-azure-integration-tests/pom.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,14 @@
125125
<scope>test</scope>
126126
</dependency>
127127

128+
<!-- Azure SDKs-->
129+
<!-- Explicitly referencing azure-identity. It's possible that the dependent versions below conflict with our
130+
currently released version and a lower version is resolved. -->
131+
<dependency>
132+
<groupId>com.azure</groupId>
133+
<artifactId>azure-identity</artifactId>
134+
<version>1.8.0</version> <!-- {x-version-update;com.azure:azure-identity;dependency} -->
135+
</dependency>
128136
</dependencies>
129137

130138
<build>

sdk/spring/spring-cloud-azure-service/src/test/java/com/azure/spring/cloud/service/implementation/AzureHttpClientBuilderFactoryBaseTests.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,6 @@ void fixedRetrySettingsCanWork() {
107107
B builder = factory.build();
108108
buildClient(builder);
109109
verifyRetryOptionsCalled(builder, properties, times(1));
110-
111110
}
112111

113112
@Test

sdk/spring/spring-cloud-azure-service/src/test/java/com/azure/spring/cloud/service/implementation/credential/AzureDefaultAzureCredentialBuilderFactoryTests.java

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,11 @@
66
import com.azure.core.credential.TokenCredential;
77
import com.azure.core.http.HttpClient;
88
import com.azure.core.http.policy.HttpPipelinePolicy;
9+
import com.azure.core.http.policy.RetryPolicy;
910
import com.azure.core.util.HttpClientOptions;
1011
import com.azure.identity.DefaultAzureCredentialBuilder;
1112
import com.azure.spring.cloud.core.implementation.factory.credential.DefaultAzureCredentialBuilderFactory;
1213
import com.azure.spring.cloud.core.properties.AzureProperties;
13-
import com.azure.spring.cloud.core.properties.retry.RetryProperties;
14-
import com.azure.spring.cloud.core.provider.RetryOptionsProvider;
1514
import com.azure.spring.cloud.service.implementation.AzureHttpClientBuilderFactoryBaseTests;
1615
import org.junit.jupiter.api.Test;
1716
import org.mockito.verification.VerificationMode;
@@ -97,10 +96,7 @@ protected void verifyHttpClientCalled(DefaultAzureCredentialBuilder builder, Ver
9796

9897
@Override
9998
protected void verifyRetryOptionsCalled(DefaultAzureCredentialBuilder builder, AzureIdentityTestProperties properties, VerificationMode mode) {
100-
RetryProperties retry = properties.getRetry();
101-
Integer maxRetries = RetryOptionsProvider.RetryMode.EXPONENTIAL.equals(retry.getMode())
102-
? retry.getExponential().getMaxRetries() : retry.getFixed().getMaxRetries();
103-
verify(builder, mode).maxRetry(maxRetries);
99+
verify(builder, mode).retryPolicy(any(RetryPolicy.class));
104100
}
105101

106102
private ThreadPoolExecutor getThreadPoolExecutor() {

0 commit comments

Comments
 (0)