Skip to content

Commit 3f04109

Browse files
committed
Add API to disable internal retry behavior
1 parent 1894fed commit 3f04109

File tree

5 files changed

+75
-8
lines changed

5 files changed

+75
-8
lines changed

msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/AbstractApplicationBase.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public abstract class AbstractApplicationBase implements IApplicationBase {
3232
private IHttpClient httpClient;
3333
private Integer connectTimeoutForDefaultHttpClient;
3434
private Integer readTimeoutForDefaultHttpClient;
35+
private boolean disableInternalRetries;
3536
String tenant;
3637

3738
//The following fields are set in only some applications and/or set internally by the library. To avoid excessive
@@ -150,6 +151,10 @@ public Integer readTimeoutForDefaultHttpClient() {
150151
return this.readTimeoutForDefaultHttpClient;
151152
}
152153

154+
boolean retriesDisabled() {
155+
return this.disableInternalRetries;
156+
}
157+
153158
String tenant() {
154159
return this.tenant;
155160
}
@@ -190,6 +195,7 @@ public abstract static class Builder<T extends Builder<T>> {
190195
Boolean onlySendFailureTelemetry = false;
191196
Integer connectTimeoutForDefaultHttpClient;
192197
Integer readTimeoutForDefaultHttpClient;
198+
boolean disableInternalRetries;
193199
private String clientId;
194200
private Authority authenticationAuthority = createDefaultAADAuthority();
195201

@@ -319,6 +325,17 @@ public T readTimeoutForDefaultHttpClient(Integer val) {
319325
return self();
320326
}
321327

328+
/**
329+
* Disables the library's internal retry logic for HTTP requests. Used alongside
330+
*
331+
* @param val timeout value in milliseconds
332+
* @return instance of the Builder on which method was called
333+
*/
334+
public T disableInternalRetries(boolean val) {
335+
disableInternalRetries = val;
336+
return self();
337+
}
338+
322339
T telemetryConsumer(Consumer<List<HashMap<String, String>>> val) {
323340
validateNotNull("telemetryConsumer", val);
324341

@@ -356,5 +373,16 @@ private static Authority createDefaultAADAuthority() {
356373
readTimeoutForDefaultHttpClient = builder.readTimeoutForDefaultHttpClient;
357374
authenticationAuthority = builder.authenticationAuthority;
358375
clientId = builder.clientId;
376+
disableInternalRetries = builder.disableInternalRetries;
377+
378+
if (builder.httpClient == null) {
379+
httpClient = new DefaultHttpClient(
380+
builder.proxy,
381+
builder.sslSocketFactory,
382+
builder.connectTimeoutForDefaultHttpClient,
383+
builder.readTimeoutForDefaultHttpClient);
384+
} else {
385+
httpClient = builder.httpClient;
386+
}
359387
}
360388
}

msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/AbstractClientApplicationBase.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -566,10 +566,7 @@ public T correlationId(String val) {
566566
super.serviceBundle = new ServiceBundle(
567567
builder.executorService,
568568
new TelemetryManager(telemetryConsumer, builder.onlySendFailureTelemetry),
569-
new HttpHelper(builder.httpClient == null ?
570-
new DefaultHttpClient(builder.proxy, builder.sslSocketFactory, builder.connectTimeoutForDefaultHttpClient, builder.readTimeoutForDefaultHttpClient) :
571-
builder.httpClient,
572-
new DefaultRetryPolicy())
569+
new HttpHelper(this, new DefaultRetryPolicy())
573570
);
574571

575572
if (aadAadInstanceDiscoveryResponse != null) {

msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/HttpHelper.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,19 @@ class HttpHelper implements IHttpHelper {
2626

2727
private IHttpClient httpClient;
2828
private IRetryPolicy retryPolicy;
29+
private boolean retriesDisabled;
2930

3031
HttpHelper(IHttpClient httpClient, IRetryPolicy retryPolicy) {
3132
this.httpClient = httpClient;
3233
this.retryPolicy = retryPolicy != null ? retryPolicy : new DefaultRetryPolicy();
3334
}
3435

36+
HttpHelper(AbstractApplicationBase application, IRetryPolicy retryPolicy) {
37+
this.httpClient = application.httpClient();
38+
this.retriesDisabled = application.retriesDisabled();
39+
this.retryPolicy = retryPolicy != null ? retryPolicy : new DefaultRetryPolicy();
40+
}
41+
3542
public IHttpResponse executeHttpRequest(HttpRequest httpRequest,
3643
RequestContext requestContext,
3744
ServiceBundle serviceBundle) {
@@ -145,6 +152,10 @@ IHttpResponse executeHttpRequestWithRetries(HttpRequest httpRequest, IHttpClient
145152
throws Exception {
146153
IHttpResponse httpResponse = httpClient.send(httpRequest);
147154

155+
if (retriesDisabled) {
156+
return httpResponse;
157+
}
158+
148159
int retryCount = 0;
149160
int maxRetries = retryPolicy.getMaxRetryCount(httpResponse);
150161

msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/ManagedIdentityApplication.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,7 @@ private ManagedIdentityApplication(Builder builder) {
3737
super.serviceBundle = new ServiceBundle(
3838
builder.executorService,
3939
new TelemetryManager(telemetryConsumer, builder.onlySendFailureTelemetry),
40-
new HttpHelper(builder.httpClient == null ?
41-
new DefaultHttpClient(builder.proxy, builder.sslSocketFactory, builder.connectTimeoutForDefaultHttpClient, builder.readTimeoutForDefaultHttpClient) :
42-
builder.httpClient,
43-
new ManagedIdentityRetryPolicy())
40+
new HttpHelper(this, new ManagedIdentityRetryPolicy())
4441
);
4542
log = LoggerFactory.getLogger(ManagedIdentityApplication.class);
4643

msal4j-sdk/src/test/java/com/microsoft/aad/msal4j/ManagedIdentityTests.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,40 @@ void managedIdentityTest_Retry(ManagedIdentitySourceType source, String endpoint
587587
fail("MsalServiceException is expected but not thrown.");
588588
}
589589

590+
@ParameterizedTest
591+
@MethodSource("com.microsoft.aad.msal4j.ManagedIdentityTestDataProvider#createDataWrongScope")
592+
void managedIdentityTest_RetriesDisabled(ManagedIdentitySourceType source, String endpoint, String resource) throws Exception {
593+
IEnvironmentVariables environmentVariables = new EnvironmentVariablesHelper(source, endpoint);
594+
ManagedIdentityApplication.setEnvironmentVariables(environmentVariables);
595+
596+
DefaultHttpClientManagedIdentity httpClientMock = mock(DefaultHttpClientManagedIdentity.class);
597+
if (source == SERVICE_FABRIC) {
598+
ServiceFabricManagedIdentitySource.setHttpClient(httpClientMock);
599+
}
600+
601+
miApp = ManagedIdentityApplication
602+
.builder(ManagedIdentityId.systemAssigned())
603+
.httpClient(httpClientMock)
604+
.disableInternalRetries(true)
605+
.build();
606+
607+
//Several specific 4xx and 5xx errors, such as 500, should trigger MSAL's retry logic
608+
when(httpClientMock.send(expectedRequest(source, resource))).thenReturn(expectedResponse(500, ManagedIdentityTestConstants.MSI_ERROR_RESPONSE_500));
609+
610+
try {
611+
acquireTokenCommon(resource).get();
612+
} catch (Exception exception) {
613+
assert(exception.getCause() instanceof MsalServiceException);
614+
615+
//But because retries are disabled at the app level, there should be no retries for any source except Service Fabric, which uses its own HttpClient
616+
if (source == SERVICE_FABRIC) {
617+
verify(httpClientMock, times(4)).send(any());
618+
} else {
619+
verify(httpClientMock, times(1)).send(any());
620+
}
621+
}
622+
}
623+
590624
@Test
591625
void managedIdentityTest_IMDSRetry() throws Exception {
592626
IEnvironmentVariables environmentVariables = new EnvironmentVariablesHelper(IMDS, ManagedIdentityTestConstants.IMDS_ENDPOINT);

0 commit comments

Comments
 (0)