Skip to content

Commit ec5fafd

Browse files
authored
Let DAC chain continue for 400 responses with 'Identity not found' (Azure#46711)
1 parent 3fadc42 commit ec5fafd

File tree

3 files changed

+46
-5
lines changed

3 files changed

+46
-5
lines changed

sdk/identity/Azure.Identity/CHANGELOG.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,17 @@
77
### Breaking Changes
88

99
### Bugs Fixed
10-
- Fixed an issue that prevented ManagedIdentityCredential from attempting to detect if Workload Identity is enabled in the current environment. [#46653](https://github.com/Azure/azure-sdk-for-net/issues/46653)
10+
- Fixed an issue that prevented `ManagedIdentityCredential` from attempting to detect if Workload Identity is enabled in the current environment. [#46653](https://github.com/Azure/azure-sdk-for-net/issues/46653)
11+
- Fixed an issue that prevented `DefaultAzureCredential` from progressing past `ManagedIdentityCredential` in some scenarios where the identity was not available. [#46709](https://github.com/Azure/azure-sdk-for-net/issues/46709)
1112

1213
### Other Changes
1314

1415
## 1.13.0 (2024-10-14)
1516

17+
### Breaking Changes
18+
- Previously, if a clientID or ResourceID was specified for Cloud Shell managed identity, which is not supported, the clientID or resourceID would be silently ignored. Now, an exception will be thrown if a clientID or resourceID is specified for Cloud Shell managed identity.
19+
- Previously, if a clientID or ResourceID was specified for Service Fabric managed identity, which is not supported, the clientID or resourceID would be silently ignored. Now, an exception will be thrown if a clientID or resourceID is specified for Service Fabric managed identity.
20+
1621
### Features Added
1722
- `ManagedIdentityCredential` now supports specifying a user-assigned managed identity by object ID.
1823

sdk/identity/Azure.Identity/src/ImdsManagedIdentityProbeSource.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ protected override async ValueTask<AccessToken> HandleResponseAsync(bool async,
144144
// handle error status codes indicating managed identity is not available
145145
string baseMessage = response.Status switch
146146
{
147-
400 when IsProbeRequest(message) => throw new ProbeRequestResponseException(),
147+
400 when IsRetriableProbeRequest(message) => throw new ProbeRequestResponseException(),
148148
400 => IdentityUnavailableError,
149149
502 => GatewayError,
150150
504 => GatewayError,
@@ -169,10 +169,11 @@ protected override async ValueTask<AccessToken> HandleResponseAsync(bool async,
169169
return token;
170170
}
171171

172-
public static bool IsProbeRequest(HttpMessage message)
172+
public static bool IsRetriableProbeRequest(HttpMessage message)
173173
=> message.Request.Uri.Host == s_imdsEndpoint.Host &&
174174
message.Request.Uri.Path == s_imdsEndpoint.AbsolutePath &&
175-
!message.Request.Headers.TryGetValue(metadataHeaderName, out _);
175+
!message.Request.Headers.TryGetValue(metadataHeaderName, out _) &&
176+
(message.Response.Content?.ToString().IndexOf("Identity not found", StringComparison.InvariantCulture) < 0);
176177

177178
private class ImdsRequestFailedDetailsParser : RequestFailedDetailsParser
178179
{

sdk/identity/Azure.Identity/tests/ManagedIdentityCredentialTests.cs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ public void VerifyImdsRequestFailureForDockerDesktopThrowsCUE(string error)
390390
{
391391
using var environment = new TestEnvVar(new() { { "MSI_ENDPOINT", null }, { "MSI_SECRET", null }, { "IDENTITY_ENDPOINT", null }, { "IDENTITY_HEADER", null }, { "AZURE_POD_IDENTITY_AUTHORITY_HOST", null } });
392392

393-
var expectedMessage = $"connecting to 169.254.169.254:80: connecting to 169.254.169.254:80: dial tcp 169.254.169.254:80: connectex: A socket operation was attempted to an unreachable {error}.";
393+
var expectedMessage = error;
394394
var response = CreateInvalidJsonResponse(403, expectedMessage);
395395
var mockTransport = new MockTransport(response);
396396
var options = new TokenCredentialOptions() { Transport = mockTransport, IsChainedCredential = true };
@@ -422,6 +422,31 @@ public void VerifyImdsRequestFailureWithInvalidJsonPopulatesExceptionMessage()
422422
Assert.That(ex.Message, Does.Contain(expectedMessage));
423423
}
424424

425+
[NonParallelizable]
426+
[Test]
427+
[TestCase("""{"error":"invalid_request","error_description":"Identity not found"}""")]
428+
[TestCase(null)]
429+
public void VerifyImdsRequestFailureWithValidJsonIdentityNotFoundErrorThrowsCUE(string content)
430+
{
431+
using var environment = new TestEnvVar(new() { { "MSI_ENDPOINT", null }, { "MSI_SECRET", null }, { "IDENTITY_ENDPOINT", null }, { "IDENTITY_HEADER", null }, { "AZURE_POD_IDENTITY_AUTHORITY_HOST", null } });
432+
433+
var response = CreateResponse(400, content);
434+
var mockTransport = new MockTransport(req => response);
435+
var options = new TokenCredentialOptions() { Transport = mockTransport, IsChainedCredential = true };
436+
var pipeline = CredentialPipeline.GetInstance(options);
437+
438+
ManagedIdentityCredential credential = InstrumentClient(new ManagedIdentityCredential("mock-client-id", pipeline, options));
439+
if (content != null)
440+
{
441+
var ex = Assert.ThrowsAsync<CredentialUnavailableException>(async () => await credential.GetTokenAsync(new TokenRequestContext(MockScopes.Default)));
442+
Assert.That(ex.Message, Does.Contain(ImdsManagedIdentityProbeSource.IdentityUnavailableError));
443+
}
444+
else
445+
{
446+
var ex = Assert.ThrowsAsync<AuthenticationFailedException>(async () => await credential.GetTokenAsync(new TokenRequestContext(MockScopes.Default)));
447+
}
448+
}
449+
425450
[NonParallelizable]
426451
[Test]
427452
[TestCase(502, ImdsManagedIdentitySource.GatewayError)]
@@ -1128,5 +1153,15 @@ private static MockResponse CreateInvalidJsonResponse(int status, string message
11281153
response.SetContent(message);
11291154
return response;
11301155
}
1156+
1157+
private static MockResponse CreateResponse(int status, string message)
1158+
{
1159+
var response = new MockResponse(status);
1160+
if (message != null)
1161+
{
1162+
response.SetContent(message);
1163+
}
1164+
return response;
1165+
}
11311166
}
11321167
}

0 commit comments

Comments
 (0)