Skip to content

Commit 8ea8634

Browse files
authored
Include ManagedIdentitySource in managed identity error messages and request-failure logs
1 parent 6956b45 commit 8ea8634

3 files changed

Lines changed: 52 additions & 4 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
### New Features
55
- Exposed canonical OpenTelemetry tag names per metric via `MsalMetricsCatalog.CanonicalTagsByMetric` for discoverability and validation. [#6076](https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/pull/6076)
66

7+
### Changes
8+
- Managed identity error messages and request-failure logs now include the detected `ManagedIdentitySource` (e.g., `AppService`, `Imds`, `ServiceFabric`) so the host-issued `Managed Identity Correlation ID` can be traced to the correct host's telemetry. [#6095](https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/pull/6095)
9+
710
4.85.0
811
======
912

src/client/Microsoft.Identity.Client/ManagedIdentity/AbstractManagedIdentity.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ protected virtual Task<ManagedIdentityResponse> HandleResponseAsync(
188188

189189
string message = GetMessageFromErrorResponse(response);
190190

191-
_requestContext.Logger.Error($"[Managed Identity] request failed, HttpStatusCode: {response.StatusCode} Error message: {message}");
191+
_requestContext.Logger.Error($"[Managed Identity] request failed, Source: {_sourceType}, HttpStatusCode: {response.StatusCode} Error message: {message}");
192192

193193
MsalException exception = MsalServiceExceptionFactory.CreateManagedIdentityException(
194194
MsalError.ManagedIdentityRequestFailed,
@@ -281,7 +281,10 @@ private string ExtractErrorMessageFromManagedIdentityErrorResponse(ManagedIdenti
281281

282282
if (!string.IsNullOrEmpty(managedIdentityErrorResponse.CorrelationId))
283283
{
284-
stringBuilder.Append($"Managed Identity Correlation ID: {managedIdentityErrorResponse.CorrelationId} Use this Correlation ID for further investigation.");
284+
stringBuilder.Append(
285+
$"Managed Identity Correlation ID: {managedIdentityErrorResponse.CorrelationId} " +
286+
$"(issued by the '{_sourceType}' managed identity source; search that source's telemetry with this correlation ID). " +
287+
$"Use this Correlation ID for further investigation.");
285288
}
286289

287290
if (stringBuilder.Length == ManagedIdentityPrefix.Length)

tests/Microsoft.Identity.Test.Unit/ManagedIdentityTests/ManagedIdentityTests.cs

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -559,8 +559,8 @@ await mi.AcquireTokenForManagedIdentity(resource)
559559
}
560560

561561
[TestMethod]
562-
[DataRow("{\"statusCode\":500,\"message\":\"Error message\",\"correlationId\":\"GUID\"}", new string[] { "Error message", "GUID" })]
563-
[DataRow("{\"message\":\"Error message\",\"correlationId\":\"GUID\"}", new string[] { "Error message", "GUID" })]
562+
[DataRow("{\"statusCode\":500,\"message\":\"Error message\",\"correlationId\":\"GUID\"}", new string[] { "Error message", "GUID", "issued by the 'AppService' managed identity source" })]
563+
[DataRow("{\"message\":\"Error message\",\"correlationId\":\"GUID\"}", new string[] { "Error message", "GUID", "issued by the 'AppService' managed identity source" })]
564564
[DataRow("{\"error\":\"errorCode\",\"error_description\":\"Error message\"}", new string[] { "errorCode", "Error message" })]
565565
[DataRow("{\"error_description\":\"Error message\"}", new string[] { "Error message" })]
566566
[DataRow("{\"message\":\"Error message\"}", new string[] { "Error message" })]
@@ -606,6 +606,48 @@ await mi.AcquireTokenForManagedIdentity(Resource)
606606
}
607607
}
608608

609+
// The correlation-ID branch that attributes the host-issued correlation ID to a managed
610+
// identity source is source-agnostic, so this guards it against regression for a
611+
// non-AppService source (Imds) as well. It also asserts the full composed phrase rather
612+
// than a bare source name, so the check cannot pass merely because the source name appears
613+
// in the echoed error body.
614+
[TestMethod]
615+
[DataRow(ManagedIdentitySource.AppService, AppServiceEndpoint)]
616+
[DataRow(ManagedIdentitySource.Imds, ImdsEndpoint)]
617+
public async Task ManagedIdentityErrorMessageAttributesCorrelationIdToSourceAsync(ManagedIdentitySource managedIdentitySource, string endpoint)
618+
{
619+
using (new EnvVariableContext())
620+
using (var httpManager = new MockHttpManager(disableInternalRetries: true))
621+
{
622+
SetEnvironmentVariables(managedIdentitySource, endpoint);
623+
624+
var mi = ManagedIdentityApplicationBuilder.Create(ManagedIdentityId.SystemAssigned)
625+
.WithHttpManager(httpManager)
626+
.Build();
627+
628+
// camelCase "correlationId" maps to ManagedIdentityErrorResponse.CorrelationId, which
629+
// triggers the correlation-ID branch that names the managed identity source.
630+
const string errorResponse = "{\"statusCode\":500,\"message\":\"Error message\",\"correlationId\":\"some-correlation-id\"}";
631+
632+
httpManager.AddManagedIdentityMockHandler(endpoint, Resource, errorResponse,
633+
managedIdentitySource, statusCode: HttpStatusCode.InternalServerError);
634+
635+
MsalServiceException ex = await Assert.ThrowsAsync<MsalServiceException>(async () =>
636+
await mi.AcquireTokenForManagedIdentity(Resource)
637+
.ExecuteAsync().ConfigureAwait(false)).ConfigureAwait(false);
638+
639+
Assert.IsNotNull(ex);
640+
Assert.AreEqual(managedIdentitySource.ToString(), ex.AdditionalExceptionData[MsalException.ManagedIdentitySource]);
641+
Assert.AreEqual(MsalError.ManagedIdentityRequestFailed, ex.ErrorCode);
642+
643+
// Assert the exact composed phrase (position-independent-proof): only MSAL's message
644+
// builder produces this text, so it cannot be satisfied by the echoed error body.
645+
string expectedSourcePhrase = $"issued by the '{managedIdentitySource}' managed identity source";
646+
Assert.Contains(expectedSourcePhrase, ex.Message,
647+
$"Expected the message to attribute the correlation ID to the '{managedIdentitySource}' source. Actual error message: {ex.Message}");
648+
}
649+
}
650+
609651
[TestMethod]
610652
[DataRow("", ManagedIdentitySource.AppService, AppServiceEndpoint)]
611653
[DataRow(null, ManagedIdentitySource.AppService, AppServiceEndpoint)]

0 commit comments

Comments
 (0)