Skip to content

Commit 22a0299

Browse files
harsimartrask
andauthored
Support for AAD Audience in connection string (for sovereign cloud) (#4121)
Co-authored-by: Trask Stalnaker <[email protected]>
1 parent 5773690 commit 22a0299

File tree

6 files changed

+77
-26
lines changed

6 files changed

+77
-26
lines changed

.github/workflows/build-common.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ on:
88
required: false
99

1010
env:
11-
EXPORTER_VERSION: 1.0.0-beta.1 # to be updated with the latest version
11+
EXPORTER_VERSION: 1.1.0 # to be updated with the latest version
1212

1313
jobs:
1414
spotless:

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
# CHANGELOG
2+
## Version 3.7.2 GA (Unreleased)
3+
* Support for using the AAD Audience from the connection string ([#4121](https://github.com/microsoft/ApplicationInsights-Java/pull/4121))
24

35
## Version 3.7.1 GA (02/26/2025)
46

agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/httpclient/LazyHttpClient.java

Lines changed: 62 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
import com.azure.core.http.HttpClient;
99
import com.azure.core.http.HttpPipeline;
1010
import com.azure.core.http.HttpPipelineBuilder;
11+
import com.azure.core.http.HttpPipelineCallContext;
12+
import com.azure.core.http.HttpPipelineNextPolicy;
13+
import com.azure.core.http.HttpPipelineNextSyncPolicy;
14+
import com.azure.core.http.HttpPipelinePosition;
1115
import com.azure.core.http.HttpRequest;
1216
import com.azure.core.http.HttpResponse;
1317
import com.azure.core.http.ProxyOptions;
@@ -31,15 +35,13 @@
3135
import java.util.List;
3236
import java.util.concurrent.CountDownLatch;
3337
import java.util.concurrent.TimeUnit;
38+
import java.util.function.Supplier;
3439
import javax.annotation.Nullable;
3540
import reactor.core.publisher.Mono;
3641
import reactor.netty.resources.LoopResources;
3742

3843
public class LazyHttpClient implements HttpClient {
3944

40-
private static final String APPLICATIONINSIGHTS_AUTHENTICATION_SCOPE =
41-
"https://monitor.azure.com//.default";
42-
4345
private static final HttpClient INSTANCE = new LazyHttpClient();
4446

4547
public static final CountDownLatch safeToInitLatch = new CountDownLatch(1);
@@ -113,16 +115,21 @@ private static HttpClient init() {
113115
}
114116

115117
public static HttpPipeline newHttpPipeLineWithDefaultRedirect(
116-
@Nullable Configuration.AadAuthentication aadConfiguration) {
117-
return newHttpPipeLine(aadConfiguration, new RedirectPolicy(new DefaultRedirectStrategy()));
118+
@Nullable Configuration.AadAuthentication aadConfiguration,
119+
Supplier<String> aadAudienceWithScope) {
120+
return newHttpPipeLine(
121+
aadConfiguration, aadAudienceWithScope, new RedirectPolicy(new DefaultRedirectStrategy()));
118122
}
119123

120124
public static HttpPipeline newHttpPipeLine(
121125
@Nullable Configuration.AadAuthentication aadConfiguration,
126+
Supplier<String> aadAudienceWithScope,
122127
HttpPipelinePolicy... additionalPolicies) {
123128
List<HttpPipelinePolicy> policies = new ArrayList<>();
124129
if (aadConfiguration != null && aadConfiguration.enabled) {
125-
policies.add(getAuthenticationPolicy(aadConfiguration));
130+
policies.add(
131+
new LazyHttpPipelinePolicy(
132+
() -> getAuthenticationPolicy(aadConfiguration, aadAudienceWithScope.get())));
126133
}
127134
policies.addAll(asList(additionalPolicies));
128135
// Add Logging Policy. Can be enabled using AZURE_LOG_LEVEL.
@@ -144,31 +151,31 @@ public Mono<HttpResponse> send(HttpRequest request, Context context) {
144151
}
145152

146153
private static HttpPipelinePolicy getAuthenticationPolicy(
147-
Configuration.AadAuthentication configuration) {
154+
Configuration.AadAuthentication configuration, String aadAudienceWithScope) {
148155
switch (configuration.type) {
149156
case UAMI:
150-
return getAuthenticationPolicyWithUami(configuration);
157+
return getAuthenticationPolicyWithUami(configuration, aadAudienceWithScope);
151158
case SAMI:
152-
return getAuthenticationPolicyWithSami();
159+
return getAuthenticationPolicyWithSami(aadAudienceWithScope);
153160
case VSCODE:
154-
return getAuthenticationPolicyWithVsCode();
161+
return getAuthenticationPolicyWithVsCode(aadAudienceWithScope);
155162
case CLIENTSECRET:
156-
return getAuthenticationPolicyWithClientSecret(configuration);
163+
return getAuthenticationPolicyWithClientSecret(configuration, aadAudienceWithScope);
157164
}
158165
throw new IllegalStateException(
159166
"Invalid Authentication Type used in AAD Authentication: " + configuration.type);
160167
}
161168

162169
private static HttpPipelinePolicy getAuthenticationPolicyWithUami(
163-
Configuration.AadAuthentication configuration) {
170+
Configuration.AadAuthentication configuration, String aadAudienceWithScope) {
164171
ManagedIdentityCredentialBuilder managedIdentityCredential =
165172
new ManagedIdentityCredentialBuilder().clientId(configuration.clientId);
166173
return new BearerTokenAuthenticationPolicy(
167-
managedIdentityCredential.build(), APPLICATIONINSIGHTS_AUTHENTICATION_SCOPE);
174+
managedIdentityCredential.build(), aadAudienceWithScope);
168175
}
169176

170177
private static HttpPipelinePolicy getAuthenticationPolicyWithClientSecret(
171-
Configuration.AadAuthentication configuration) {
178+
Configuration.AadAuthentication configuration, String aadAudienceWithScope) {
172179
ClientSecretCredentialBuilder credential =
173180
new ClientSecretCredentialBuilder()
174181
.tenantId(configuration.tenantId)
@@ -177,21 +184,54 @@ private static HttpPipelinePolicy getAuthenticationPolicyWithClientSecret(
177184
if (configuration.authorityHost != null) {
178185
credential.authorityHost(configuration.authorityHost);
179186
}
180-
return new BearerTokenAuthenticationPolicy(
181-
credential.build(), APPLICATIONINSIGHTS_AUTHENTICATION_SCOPE);
187+
return new BearerTokenAuthenticationPolicy(credential.build(), aadAudienceWithScope);
182188
}
183189

184-
private static HttpPipelinePolicy getAuthenticationPolicyWithVsCode() {
190+
private static HttpPipelinePolicy getAuthenticationPolicyWithVsCode(String aadAudienceWithScope) {
185191
VisualStudioCodeCredential visualStudioCodeCredential =
186192
new VisualStudioCodeCredentialBuilder().build();
187-
return new BearerTokenAuthenticationPolicy(
188-
visualStudioCodeCredential, APPLICATIONINSIGHTS_AUTHENTICATION_SCOPE);
193+
return new BearerTokenAuthenticationPolicy(visualStudioCodeCredential, aadAudienceWithScope);
189194
}
190195

191-
private static HttpPipelinePolicy getAuthenticationPolicyWithSami() {
196+
private static HttpPipelinePolicy getAuthenticationPolicyWithSami(String aadAudienceWithScope) {
192197
ManagedIdentityCredential managedIdentityCredential =
193198
new ManagedIdentityCredentialBuilder().build();
194-
return new BearerTokenAuthenticationPolicy(
195-
managedIdentityCredential, APPLICATIONINSIGHTS_AUTHENTICATION_SCOPE);
199+
return new BearerTokenAuthenticationPolicy(managedIdentityCredential, aadAudienceWithScope);
200+
}
201+
202+
private static class LazyHttpPipelinePolicy implements HttpPipelinePolicy {
203+
204+
private final Supplier<HttpPipelinePolicy> supplier;
205+
private volatile HttpPipelinePolicy delegate;
206+
207+
LazyHttpPipelinePolicy(Supplier<HttpPipelinePolicy> supplier) {
208+
this.supplier = supplier;
209+
}
210+
211+
@Override
212+
public Mono<HttpResponse> process(
213+
HttpPipelineCallContext context, HttpPipelineNextPolicy next) {
214+
createDelegateFirstTime();
215+
return delegate.process(context, next);
216+
}
217+
218+
@Override
219+
public HttpResponse processSync(
220+
HttpPipelineCallContext context, HttpPipelineNextSyncPolicy next) {
221+
createDelegateFirstTime();
222+
return delegate.processSync(context, next);
223+
}
224+
225+
@Override
226+
public HttpPipelinePosition getPipelinePosition() {
227+
createDelegateFirstTime();
228+
return delegate.getPipelinePosition();
229+
}
230+
231+
private void createDelegateFirstTime() {
232+
if (delegate == null) {
233+
delegate = supplier.get();
234+
}
235+
}
196236
}
197237
}

agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/SecondEntryPoint.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,9 @@ public void customize(AutoConfigurationCustomizer autoConfiguration) {
201201
if (telemetryClient.getConnectionString() != null) {
202202
statsbeatModule.start(
203203
AzureMonitorHelper.createStatsbeatTelemetryItemExporter(
204-
LazyHttpClient.newHttpPipeLine(null), statsbeatModule, tempDir),
204+
LazyHttpClient.newHttpPipeLine(null, telemetryClient::getAadAudienceWithScope),
205+
statsbeatModule,
206+
tempDir),
205207
telemetryClient::getStatsbeatConnectionString,
206208
telemetryClient::getInstrumentationKey,
207209
configuration.internal.statsbeat.disabledAll,
@@ -224,7 +226,8 @@ public void customize(AutoConfigurationCustomizer autoConfiguration) {
224226
if (configuration.preview.liveMetrics.enabled) {
225227
quickPulse =
226228
QuickPulse.create(
227-
LazyHttpClient.newHttpPipeLineWithDefaultRedirect(configuration.authentication),
229+
LazyHttpClient.newHttpPipeLineWithDefaultRedirect(
230+
configuration.authentication, telemetryClient::getAadAudienceWithScope),
228231
() -> {
229232
ConnectionString connectionString = telemetryClient.getConnectionString();
230233
return connectionString == null ? null : connectionString.getLiveEndpoint();

agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/profiler/ProfilingInitializer.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ private synchronized void performInit() {
121121
httpPipeline =
122122
LazyHttpClient.newHttpPipeLine(
123123
telemetryClient.getAadAuthentication(),
124+
telemetryClient::getAadAudienceWithScope,
124125
new RedirectPolicy(
125126
new DefaultRedirectStrategy(
126127
3,

agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/telemetry/TelemetryClient.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,10 +223,10 @@ public BatchItemProcessor getMetricsBatchItemProcessor() {
223223

224224
private BatchItemProcessor initBatchItemProcessor(
225225
int exportQueueCapacity, int maxExportBatchSize, String queueName) {
226-
227226
HttpPipeline httpPipeline =
228227
LazyHttpClient.newHttpPipeLine(
229228
aadAuthentication,
229+
this::getAadAudienceWithScope,
230230
new NetworkStatsbeatHttpPipelinePolicy(statsbeatModule.getNetworkStatsbeat()));
231231
// TODO (heya) refactor the following by using AzureMonitorHelper.createTelemetryItemExporter by
232232
// passing in getNonessentialStatsbeat
@@ -353,6 +353,11 @@ public ConnectionString getConnectionString() {
353353
return connectionString;
354354
}
355355

356+
@Nullable
357+
public String getAadAudienceWithScope() {
358+
return connectionString.getAadAudienceWithScope();
359+
}
360+
356361
@Nullable
357362
public String getRoleName() {
358363
return roleName;

0 commit comments

Comments
 (0)