Skip to content

Commit e7c17aa

Browse files
authored
handle json parsing errors (Azure#24166)
* handle json parsing errors
1 parent f993f9d commit e7c17aa

File tree

2 files changed

+84
-10
lines changed

2 files changed

+84
-10
lines changed

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

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ namespace Azure.Identity
1313
internal abstract class ManagedIdentitySource
1414
{
1515
internal const string AuthenticationResponseInvalidFormatError = "Invalid response, the authentication response was not in the expected format.";
16+
internal const string UnexpectedResponse = "Managed Identity response was not in the expected format. See the inner exception for details.";
1617
private ManagedIdentityResponseClassifier _responseClassifier;
1718

1819
protected ManagedIdentitySource(CredentialPipeline pipeline)
@@ -40,20 +41,35 @@ public virtual async ValueTask<AccessToken> AuthenticateAsync(bool async, TokenR
4041
return await HandleResponseAsync(async, context, message.Response, cancellationToken).ConfigureAwait(false);
4142
}
4243

43-
protected virtual async ValueTask<AccessToken> HandleResponseAsync(bool async, TokenRequestContext context, Response response, CancellationToken cancellationToken)
44+
protected virtual async ValueTask<AccessToken> HandleResponseAsync(
45+
bool async,
46+
TokenRequestContext context,
47+
Response response,
48+
CancellationToken cancellationToken)
4449
{
45-
using JsonDocument json = async
46-
? await JsonDocument.ParseAsync(response.ContentStream, default, cancellationToken).ConfigureAwait(false)
47-
: JsonDocument.Parse(response.ContentStream);
48-
if (response.Status == 200)
50+
string message;
51+
Exception exception = null;
52+
try
53+
{
54+
using JsonDocument json = async
55+
? await JsonDocument.ParseAsync(response.ContentStream, default, cancellationToken).ConfigureAwait(false)
56+
: JsonDocument.Parse(response.ContentStream);
57+
if (response.Status == 200)
58+
{
59+
return GetTokenFromResponse(json.RootElement);
60+
}
61+
62+
message = GetMessageFromResponse(json.RootElement);
63+
}
64+
catch (Exception e)
4965
{
50-
return GetTokenFromResponse(json.RootElement);
66+
exception = e;
67+
message = UnexpectedResponse;
5168
}
5269

53-
string message = GetMessageFromResponse(json.RootElement);
5470
throw async
55-
? await Pipeline.Diagnostics.CreateRequestFailedExceptionAsync(response, message).ConfigureAwait(false)
56-
: Pipeline.Diagnostics.CreateRequestFailedException(response, message);
71+
? await Pipeline.Diagnostics.CreateRequestFailedExceptionAsync(response, message, innerException: exception).ConfigureAwait(false)
72+
: Pipeline.Diagnostics.CreateRequestFailedException(response, message, innerException: exception);
5773
}
5874

5975
protected abstract Request CreateRequest(string[] scopes);

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

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
using System;
55
using System.Collections.Generic;
66
using System.IO;
7-
using System.Net.Http;
87
using System.Text;
98
using System.Threading;
109
using System.Threading.Tasks;
@@ -459,6 +458,58 @@ public async Task VerifyClientAuthenticateThrows()
459458
await Task.CompletedTask;
460459
}
461460

461+
[Test]
462+
public async Task VerifyClientAuthenticateReturnsInvalidJson([Values(200, 404)] int status)
463+
{
464+
using var environment = new TestEnvVar(
465+
new()
466+
{
467+
{ "MSI_ENDPOINT", null },
468+
{ "MSI_SECRET", null },
469+
{ "IDENTITY_ENDPOINT", null },
470+
{ "IDENTITY_HEADER", null },
471+
{ "AZURE_POD_IDENTITY_AUTHORITY_HOST", null }
472+
});
473+
var mockTransport = new MockTransport(request => CreateInvalidJsonResponse(status));
474+
var options = new TokenCredentialOptions() { Transport = mockTransport };
475+
options.Retry.MaxDelay = TimeSpan.Zero;
476+
var pipeline = CredentialPipeline.GetInstance(options);
477+
478+
ManagedIdentityCredential credential = InstrumentClient(new ManagedIdentityCredential("mock-client-id", pipeline));
479+
480+
var ex = Assert.ThrowsAsync<AuthenticationFailedException>(async () => await credential.GetTokenAsync(new TokenRequestContext(MockScopes.Default)));
481+
Assert.IsInstanceOf(typeof(RequestFailedException), ex.InnerException);
482+
Assert.That(ex.Message, Does.Contain(ManagedIdentitySource.UnexpectedResponse));
483+
await Task.CompletedTask;
484+
}
485+
486+
[Test]
487+
public async Task VerifyClientAuthenticateReturnsErrorResponse()
488+
{
489+
using var environment = new TestEnvVar(
490+
new()
491+
{
492+
{ "MSI_ENDPOINT", null },
493+
{ "MSI_SECRET", null },
494+
{ "IDENTITY_ENDPOINT", null },
495+
{ "IDENTITY_HEADER", null },
496+
{ "AZURE_POD_IDENTITY_AUTHORITY_HOST", null }
497+
});
498+
var errorMessage = "Some error happened";
499+
var mockTransport = new MockTransport(request => CreateErrorMockResponse(404, errorMessage));
500+
var options = new TokenCredentialOptions { Transport = mockTransport};
501+
options.Retry.MaxDelay = TimeSpan.Zero;
502+
var pipeline = CredentialPipeline.GetInstance(options);
503+
504+
ManagedIdentityCredential credential = InstrumentClient(new ManagedIdentityCredential("mock-client-id", pipeline));
505+
506+
var ex = Assert.ThrowsAsync<AuthenticationFailedException>(async () => await credential.GetTokenAsync(new TokenRequestContext(MockScopes.Default)));
507+
Assert.IsInstanceOf(typeof(RequestFailedException), ex.InnerException);
508+
Assert.That(ex.Message, Does.Contain(errorMessage));
509+
510+
await Task.CompletedTask;
511+
}
512+
462513
[Test]
463514
[TestCaseSource("ExceptionalEnvironmentConfigs")]
464515
public async Task VerifyAuthenticationFailedExceptionsAreDeferredToGetToken(Dictionary<string, string> environmentVariables)
@@ -503,5 +554,12 @@ private MockResponse CreateErrorMockResponse(int responseCode, string message)
503554
response.SetContent($"{{\"StatusCode\":400,\"Message\":\"{message}\",\"CorrelationId\":\"f3c9aec0-7fa2-4184-ad0f-0c68ce5fc748\"}}");
504555
return response;
505556
}
557+
558+
private static MockResponse CreateInvalidJsonResponse(int status)
559+
{
560+
var response = new MockResponse(status);
561+
response.SetContent("invalid json");
562+
return response;
563+
}
506564
}
507565
}

0 commit comments

Comments
 (0)