Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions sdk/identity/Azure.Identity/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
- Fixed an issue with `TokenCachePersistenceOptions` where credentials in the same process would share the same cache, even if they had different configured names.
- ManagedIdentityCredential now ignores empty ClientId values. [#37100](https://github.com/Azure/azure-sdk-for-net/issues/37100)
- ManagedIdentityCredential will no longer attempt to parse invalid json payloads on responses from the managed identity endpoint.
- When utilizing `EnvironmentCredential` from `DefaultAzureCredential` the credential will now override the `TENANT_ID` environment value if the TenantId value is set in `DefaultAzureCredentialOptions`.

### Other Changes
- All developer credentials in the `DefaultAzureCredential` credential chain will fall through to the next credential in the chain on any failure. Previously, some exceptions would throw `AuthenticationFailedException`, which stops further progress in the chain.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ public virtual TokenCredential CreateEnvironmentCredential()
{
var options = Options.Clone<EnvironmentCredentialOptions>();

if (!string.IsNullOrEmpty(options.TenantId))
{
options.TenantId = Options.TenantId;
}

return new EnvironmentCredential(Pipeline, options);
}

Expand Down
17 changes: 17 additions & 0 deletions sdk/identity/Azure.Identity/tests/CredentialTestHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,23 @@ public static string[] ExtractAdditionalTenantProperty(TokenCredential cred)
return additionallyAllowedTenantIds;
}

public static bool TryGetConfiguredTenantIdForMsalCredential(TokenCredential cred, out string tenantID)
{
var targetCred = cred is EnvironmentCredential environmentCredential ? environmentCredential.Credential : cred;
object clientObject = targetCred.GetType().GetProperty("Client", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(targetCred);
tenantID = clientObject switch
{
MsalPublicClient msalPub => msalPub?.TenantId,
MsalConfidentialClient msalConf => msalConf?.TenantId,
_ => null
};
if (tenantID == null)
{
tenantID = targetCred.GetType().GetProperty("TenantId", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(targetCred) as string;
}
return tenantID != null;
}

public static bool IsMsalCredential(TokenCredential cred)
{
var clientType = GetMsalClientType(cred);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,41 @@ public void AdditionallyAllowedTenantsOptionIsHonored(Type availableCredential)
}
}

[Test]
[TestCaseSource(nameof(AllCredentialTypes))]
public void TenantIdOptionOverridesEnvironment(Type availableCredential)
{
using (new TestEnvVar(new Dictionary<string, string> {
{ "AZURE_CLIENT_ID", "mockclientid" },
{ "AZURE_CLIENT_SECRET", null},
{ "AZURE_TENANT_ID", "mocktenantid" },
{"AZURE_USERNAME", "mockusername" },
{ "AZURE_PASSWORD", "mockpassword" },
{ "AZURE_CLIENT_CERTIFICATE_PATH", null },
{ "AZURE_FEDERATED_TOKEN_FILE", "c:/temp/token" }
}))
{
DefaultAzureCredentialOptions options = GetDacOptions(availableCredential, false, "overridetenantid");
var additionalTenant = Guid.NewGuid().ToString();
options.AdditionallyAllowedTenants.Add(additionalTenant);

var credential = new DefaultAzureCredential(options);
Assert.AreEqual(1, credential._sources.Length);
var targetCred = credential._sources[0];
if (CredentialTestHelpers.TryGetConfiguredTenantIdForMsalCredential(targetCred, out string tenantId))
{
if (availableCredential == typeof(ManagedIdentityCredential))
{
Assert.Ignore("ManagedIdentityCredential does not include a TenantId option.");
}
else
{
Assert.AreEqual("overridetenantid", tenantId);
}
}
}
}

[Test]
public void ExcludeWorkloadIdentityCredential_Disables_TokenExchangeManagedIdentitySource()
{
Expand Down Expand Up @@ -449,9 +484,9 @@ public void ExcludeWorkloadIdentityCredential_Disables_TokenExchangeManagedIdent
}
}

private static DefaultAzureCredentialOptions GetDacOptions(Type availableCredential, bool disableInstanceDiscovery)
private static DefaultAzureCredentialOptions GetDacOptions(Type availableCredential, bool disableInstanceDiscovery, string tenantId = null)
{
return new DefaultAzureCredentialOptions
var options = new DefaultAzureCredentialOptions
{
ExcludeEnvironmentCredential = availableCredential != typeof(EnvironmentCredential),
ExcludeWorkloadIdentityCredential = availableCredential != typeof(WorkloadIdentityCredential),
Expand All @@ -463,8 +498,13 @@ private static DefaultAzureCredentialOptions GetDacOptions(Type availableCredent
ExcludeAzureCliCredential = availableCredential != typeof(AzureCliCredential),
ExcludeAzurePowerShellCredential = availableCredential != typeof(AzurePowerShellCredential),
ExcludeInteractiveBrowserCredential = availableCredential != typeof(InteractiveBrowserCredential),
DisableInstanceDiscovery = disableInstanceDiscovery
DisableInstanceDiscovery = disableInstanceDiscovery,
};
if (tenantId != null)
{
options.TenantId = tenantId;
}
return options;
}

private static Type GetTargetCredentialOptionType(Type availableCredential)
Expand Down