Skip to content

Commit 7882e55

Browse files
authored
Implement AZURE_TOKEN_CREDENTIALS (Azure#50021)
1 parent 478b9df commit 7882e55

File tree

5 files changed

+300
-51
lines changed

5 files changed

+300
-51
lines changed

sdk/identity/Azure.Identity/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
# Release History
22

3-
## 1.14.0 (2025-05-12)
3+
## 1.14.0 (2025-05-13)
44

55
### Other Changes
66

77
- Removed references to `Username`, `Password`, `AZURE_USERNAME`, and `AZURE_PASSWORD` in XML comments from `EnvironmentCredentialOptions` and `EnvironmentCredential` due to lack of MFA support. See [MFA enforcement details](https://aka.ms/azsdk/identity/mfa).
88
- Marked `AZURE_USERNAME` and `AZURE_PASSWORD` as obsolete due to lack of MFA support. See [MFA enforcement details](https://aka.ms/azsdk/identity/mfa).
9+
- Added support for the `AZURE_TOKEN_CREDENTIALS` environment variable to `DefaultAzureCredential`, which allows for choosing between 'deployed service' and 'developer tools' credentials. Valid values are 'dev' for developer tools and 'prod' for deployed service.
910

1011
## 1.14.0-beta.4 (2025-05-01)
1112

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,9 @@ internal class Constants
3737
public const string ManagedIdentityResourceId = "mi_res_id";
3838
public const string MiSourceNoUserAssignedIdentityMessage = "User-assigned managed identity is not supported by the detected managed identity environment.";
3939
public const string MiSeviceFabricNoUserAssignedIdentityMessage = "Specifying a clientId or resourceId is not supported by the Service Fabric managed identity environment. The managed identity configuration is determined by the Service Fabric cluster resource configuration. See https://aka.ms/servicefabricmi for more information.";
40+
41+
// Credential selection options
42+
public const string DevCredentials = "dev";
43+
public const string ProdCredentials = "prod";
4044
}
4145
}

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

Lines changed: 80 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
using System;
55
using System.Collections.Generic;
6-
using System.Diagnostics.CodeAnalysis;
76
using System.Reflection;
87
using Azure.Core;
98

@@ -21,9 +20,7 @@ public DefaultAzureCredentialFactory(DefaultAzureCredentialOptions options)
2120
protected DefaultAzureCredentialFactory(DefaultAzureCredentialOptions options, CredentialPipeline pipeline)
2221
{
2322
Pipeline = pipeline;
24-
2523
_useDefaultCredentialChain = options == null;
26-
2724
Options = options?.Clone<DefaultAzureCredentialOptions>() ?? new DefaultAzureCredentialOptions();
2825
}
2926

@@ -32,70 +29,104 @@ protected DefaultAzureCredentialFactory(DefaultAzureCredentialOptions options, C
3229

3330
public TokenCredential[] CreateCredentialChain()
3431
{
35-
if (_useDefaultCredentialChain)
36-
{
37-
return s_defaultCredentialChain;
38-
}
39-
40-
List<TokenCredential> chain = new(10);
32+
string credentialSelection = EnvironmentVariables.CredentialSelection?.Trim();
33+
bool _useDevCredentials = Constants.DevCredentials.Equals(credentialSelection, StringComparison.OrdinalIgnoreCase);
34+
bool _useProdCredentials = Constants.ProdCredentials.Equals(credentialSelection, StringComparison.OrdinalIgnoreCase);
4135

42-
if (!Options.ExcludeEnvironmentCredential)
36+
if (credentialSelection != null && !_useDevCredentials && !_useProdCredentials)
4337
{
44-
chain.Add(CreateEnvironmentCredential());
38+
throw new InvalidOperationException($"Invalid value for environment variable AZURE_TOKEN_CREDENTIALS: {credentialSelection}. Valid values are '{Constants.DevCredentials}' or '{Constants.ProdCredentials}'.");
4539
}
4640

47-
if (!Options.ExcludeWorkloadIdentityCredential)
41+
if (_useDefaultCredentialChain)
4842
{
49-
chain.Add(CreateWorkloadIdentityCredential());
43+
if (_useDevCredentials)
44+
{
45+
return
46+
[
47+
CreateVisualStudioCredential(),
48+
CreateAzureCliCredential(),
49+
CreateAzurePowerShellCredential(),
50+
CreateAzureDeveloperCliCredential()
51+
];
52+
}
53+
else if (_useProdCredentials)
54+
{
55+
return
56+
[
57+
CreateEnvironmentCredential(),
58+
CreateWorkloadIdentityCredential(),
59+
CreateManagedIdentityCredential()
60+
];
61+
}
62+
return s_defaultCredentialChain;
5063
}
5164

52-
if (!Options.ExcludeManagedIdentityCredential)
53-
{
54-
chain.Add(CreateManagedIdentityCredential());
55-
}
65+
List<TokenCredential> chain = new(10);
5666

57-
if (!Options.ExcludeSharedTokenCacheCredential)
67+
if (!_useDevCredentials)
5868
{
59-
chain.Add(CreateSharedTokenCacheCredential());
69+
if (!Options.ExcludeEnvironmentCredential)
70+
{
71+
chain.Add(CreateEnvironmentCredential());
72+
}
73+
74+
if (!Options.ExcludeWorkloadIdentityCredential)
75+
{
76+
chain.Add(CreateWorkloadIdentityCredential());
77+
}
78+
79+
if (!Options.ExcludeManagedIdentityCredential)
80+
{
81+
chain.Add(CreateManagedIdentityCredential());
82+
}
6083
}
6184

62-
if (!Options.ExcludeVisualStudioCredential)
85+
if (!_useProdCredentials)
6386
{
64-
chain.Add(CreateVisualStudioCredential());
65-
}
87+
if (!Options.ExcludeSharedTokenCacheCredential)
88+
{
89+
chain.Add(CreateSharedTokenCacheCredential());
90+
}
91+
92+
if (!Options.ExcludeVisualStudioCredential)
93+
{
94+
chain.Add(CreateVisualStudioCredential());
95+
}
6696

6797
#pragma warning disable CS0618 // Type or member is obsolete
68-
if (!Options.ExcludeVisualStudioCodeCredential)
69-
{
70-
chain.Add(CreateVisualStudioCodeCredential());
71-
}
98+
if (!Options.ExcludeVisualStudioCodeCredential)
99+
{
100+
chain.Add(CreateVisualStudioCodeCredential());
101+
}
72102
#pragma warning restore CS0618 // Type or member is obsolete
73103

74-
if (!Options.ExcludeAzureCliCredential)
75-
{
76-
chain.Add(CreateAzureCliCredential());
77-
}
78-
79-
if (!Options.ExcludeAzurePowerShellCredential)
80-
{
81-
chain.Add(CreateAzurePowerShellCredential());
82-
}
83-
84-
if (!Options.ExcludeAzureDeveloperCliCredential)
85-
{
86-
chain.Add(CreateAzureDeveloperCliCredential());
87-
}
88-
89-
if (!Options.ExcludeInteractiveBrowserCredential)
90-
{
91-
chain.Add(CreateInteractiveBrowserCredential());
92-
}
104+
if (!Options.ExcludeAzureCliCredential)
105+
{
106+
chain.Add(CreateAzureCliCredential());
107+
}
108+
109+
if (!Options.ExcludeAzurePowerShellCredential)
110+
{
111+
chain.Add(CreateAzurePowerShellCredential());
112+
}
113+
114+
if (!Options.ExcludeAzureDeveloperCliCredential)
115+
{
116+
chain.Add(CreateAzureDeveloperCliCredential());
117+
}
118+
119+
if (!Options.ExcludeInteractiveBrowserCredential)
120+
{
121+
chain.Add(CreateInteractiveBrowserCredential());
122+
}
93123
#if PREVIEW_FEATURE_FLAG
94-
if (!Options.ExcludeBrokerCredential && TryCreateDevelopmentBrokerOptions(out InteractiveBrowserCredentialOptions brokerOptions))
95-
{
96-
chain.Add(CreateBrokerAuthenticationCredential(brokerOptions));
97-
}
124+
if (!Options.ExcludeBrokerCredential && TryCreateDevelopmentBrokerOptions(out InteractiveBrowserCredentialOptions brokerOptions))
125+
{
126+
chain.Add(CreateBrokerAuthenticationCredential(brokerOptions));
127+
}
98128
#endif
129+
}
99130
if (chain.Count == 0)
100131
{
101132
throw new ArgumentException("At least one credential type must be included in the authentication flow.", "options");

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ internal class EnvironmentVariables
3333

3434
public static string AzureFederatedTokenFile => GetNonEmptyStringOrNull(Environment.GetEnvironmentVariable("AZURE_FEDERATED_TOKEN_FILE"));
3535

36+
public static string CredentialSelection => GetNonEmptyStringOrNull(Environment.GetEnvironmentVariable("AZURE_TOKEN_CREDENTIALS"));
37+
3638
private static string GetNonEmptyStringOrNull(string str)
3739
{
3840
return !string.IsNullOrEmpty(str) ? str : null;

0 commit comments

Comments
 (0)