-
Notifications
You must be signed in to change notification settings - Fork 4.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ensure Options are passed down to ManagedIdentityClient #34078
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -58,7 +58,7 @@ public MsalConfidentialClient(CredentialPipeline pipeline, string tenantId, stri | |
: base(pipeline, tenantId, clientId, options) | ||
{ | ||
_appTokenProviderCallback = appTokenProviderCallback; | ||
_authority = options?.AuthorityHost ?? AzureAuthorityHosts.AzurePublicCloud; | ||
_authority = options?.AuthorityHost ?? pipeline.AuthorityHost ?? AzureAuthorityHosts.AzurePublicCloud; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This isn't strictly necessary, but it seems like a reasonable fallback. What do you think? |
||
} | ||
|
||
internal string RegionalAuthority { get; } = EnvironmentVariables.AzureRegionalAuthorityName; | ||
|
@@ -146,7 +146,7 @@ public virtual async ValueTask<AuthenticationResult> AcquireTokenForClientCoreAs | |
|
||
if (!string.IsNullOrEmpty(tenantId)) | ||
{ | ||
builder.WithAuthority(Pipeline.AuthorityHost.AbsoluteUri, tenantId); | ||
builder.WithTenantId(tenantId); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This code path is hit by the ChallengeBasedAuthenticationPolicy in KeyVault. The Switching to I think this alone would be sufficient to fix the bug, but it's really subtle. |
||
} | ||
return await builder | ||
.ExecuteAsync(async, cancellationToken) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -74,9 +74,7 @@ private ManagedIdentityCredential CreateManagedIdentityCredential(string clientI | |
{ | ||
options = InstrumentClientOptions(options ?? new TokenCredentialOptions()); | ||
|
||
var pipeline = CredentialPipeline.GetInstance(options); | ||
|
||
var cred = new ManagedIdentityCredential(new ManagedIdentityClient(pipeline, clientId)); | ||
var cred = new ManagedIdentityCredential(clientId, options); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using the public constructor here instead of the internal one, now that the public one passes through options correctly. |
||
|
||
return cred; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -137,11 +137,9 @@ public async Task VerifyImdsRequestWithClientIdAndNonPubCloudMockAsync(Uri autho | |
var pipeline = new CredentialPipeline(authority, _pipeline, new ClientDiagnostics(options)); | ||
|
||
ManagedIdentityCredential credential = InstrumentClient( | ||
new ManagedIdentityCredential( | ||
new ManagedIdentityClient( | ||
new ManagedIdentityClientOptions { Pipeline = pipeline, ClientId = "mock-client-id", Options = options }))); | ||
new ManagedIdentityCredential("mock-client-id", pipeline, options)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again, making use of the public constructor instead of the internal one. |
||
|
||
AccessToken actualToken = await credential.GetTokenAsync(new TokenRequestContext(MockScopes.Default)); | ||
AccessToken actualToken = await credential.GetTokenAsync(new TokenRequestContext(MockScopes.Default, tenantId: "mock-tenant-id")); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Adding the tenantId here exercises the code-path that hits the original bug. |
||
|
||
Assert.AreEqual(ExpectedToken, actualToken.Token); | ||
|
||
|
@@ -216,9 +214,9 @@ public async Task VerifyServiceFabricRequestWithResourceIdMockAsync(string clien | |
|
||
ManagedIdentityCredential credential = (clientId, includeResourceIdentifier) switch | ||
{ | ||
(Item1: null, Item2: true) => InstrumentClient(new ManagedIdentityCredential(new ResourceIdentifier(_expectedResourceId), pipeline, true)), | ||
(Item1: not null, Item2: false) => InstrumentClient(new ManagedIdentityCredential(clientId, pipeline, true)), | ||
_ => InstrumentClient(new ManagedIdentityCredential(clientId: null, pipeline, true)) | ||
(Item1: null, Item2: true) => InstrumentClient(new ManagedIdentityCredential(new ResourceIdentifier(_expectedResourceId), pipeline, preserveTransport: true)), | ||
(Item1: not null, Item2: false) => InstrumentClient(new ManagedIdentityCredential(clientId, pipeline, preserveTransport: true)), | ||
_ => InstrumentClient(new ManagedIdentityCredential(clientId: null, pipeline, preserveTransport: true)) | ||
}; | ||
|
||
AccessToken actualToken = await credential.GetTokenAsync(new TokenRequestContext(MockScopes.Default)); | ||
|
@@ -605,7 +603,7 @@ public async Task VerifyCloudShellMsiRequestWithClientIdMockAsync(string clientI | |
|
||
[NonParallelizable] | ||
[Test] | ||
public async Task VerifyMsiUnavailableOnIMDSAggregateExcpetion() | ||
public async Task VerifyMsiUnavailableOnIMDSAggregateException() | ||
{ | ||
using var environment = new TestEnvVar(new() { { "MSI_ENDPOINT", null }, { "MSI_SECRET", null }, { "IDENTITY_ENDPOINT", null }, { "IDENTITY_HEADER", null }, { "AZURE_POD_IDENTITY_AUTHORITY_HOST", "http://169.254.169.001/" } }); | ||
|
||
|
@@ -623,7 +621,7 @@ public async Task VerifyMsiUnavailableOnIMDSAggregateExcpetion() | |
|
||
[NonParallelizable] | ||
[Test] | ||
public async Task VerifyMsiUnavailableOnIMDSRequestFailedExcpetion() | ||
public async Task VerifyMsiUnavailableOnIMDSRequestFailedException() | ||
{ | ||
using var environment = new TestEnvVar(new() { { "MSI_ENDPOINT", null }, { "MSI_SECRET", null }, { "IDENTITY_ENDPOINT", null }, { "IDENTITY_HEADER", null }, { "AZURE_POD_IDENTITY_AUTHORITY_HOST", "http://169.254.169.001/" } }); | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,7 +25,7 @@ public override TokenCredential CreateEnvironmentCredential() | |
=> new EnvironmentCredential(Pipeline, Options); | ||
|
||
public override TokenCredential CreateManagedIdentityCredential() | ||
=> new ManagedIdentityCredential(new ManagedIdentityClient(Pipeline, Options.ManagedIdentityClientId)); | ||
=> new ManagedIdentityCredential(Options.ManagedIdentityClientId, Pipeline, Options); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again, using the public constructor instead of the internal one. |
||
|
||
public override TokenCredential CreateSharedTokenCacheCredential() | ||
=> new SharedTokenCacheCredential(Options.SharedTokenCacheTenantId, Options.SharedTokenCacheUsername, Options, Pipeline); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This (and the related changes in constructors below) is really the key fix. Ensuring that
options
gets passed down to the inner ManagedIdentityClient and eventually into the MsalConfidentialClient.This is the big difference between using the ManagedIdentityCredential stand-alone versus via DefaultAzureCredential. DefaultAzureCredential's factory calls one of the internal constructors, correctly passing in Options. So what I'm doing here is making sure the two approaches have the same behavior.
This fix alone would be enough to fix the bug.