Skip to content

Commit c1e0e3f

Browse files
authored
Add -FederatedToken on Connect-AzAccount (#16083)
* Add -FideratedID on Connect-AzAccount * Update Az.Accounts.psd1 * Update ChangeLog.md * Update docs * Update doc and ready for release * Update Az.Accounts.psd1 * Update Az.Accounts.psd1 * update doc * update code according to feedback
1 parent 0bd471b commit c1e0e3f

26 files changed

+1927
-24
lines changed

src/Accounts/Accounts/Account/ConnectAzureRmAccount.cs

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ public class ConnectAzureRmAccountCommand : AzureContextModificationCmdlet, IMod
5858
public const string ServicePrincipalCertificateParameterSet= "ServicePrincipalCertificateWithSubscriptionId";
5959
public const string ServicePrincipalCertificateFileParameterSet = "ServicePrincipalCertificateFileWithSubscriptionId";
6060
public const string AccessTokenParameterSet = "AccessTokenWithSubscriptionId";
61+
public const string ClientAssertionParameterSet = "ClientAssertionParameterSet";
6162
public const string ManagedServiceParameterSet = "ManagedServiceLogin";
6263
public const string MSIEndpointVariable = "MSI_ENDPOINT";
6364
public const string MSISecretVariable = "MSI_SECRET";
@@ -84,6 +85,8 @@ public class ConnectAzureRmAccountCommand : AzureContextModificationCmdlet, IMod
8485

8586
[Parameter(ParameterSetName = ServicePrincipalCertificateParameterSet,
8687
Mandatory = true, HelpMessage = "SPN")]
88+
[Parameter(ParameterSetName = ClientAssertionParameterSet,
89+
Mandatory = true, HelpMessage = "SPN")]
8790
[Parameter(ParameterSetName = ServicePrincipalCertificateFileParameterSet,
8891
Mandatory = true, HelpMessage = "SPN")]
8992
public string ApplicationId { get; set; }
@@ -94,6 +97,8 @@ public class ConnectAzureRmAccountCommand : AzureContextModificationCmdlet, IMod
9497
Mandatory = false)]
9598
[Parameter(ParameterSetName = ServicePrincipalCertificateFileParameterSet,
9699
Mandatory = false)]
100+
[Parameter(ParameterSetName = ClientAssertionParameterSet,
101+
Mandatory = false)]
97102
public SwitchParameter ServicePrincipal { get; set; }
98103

99104
[Parameter(ParameterSetName = UserParameterSet,
@@ -108,6 +113,8 @@ public class ConnectAzureRmAccountCommand : AzureContextModificationCmdlet, IMod
108113
Mandatory = true, HelpMessage = "Tenant name or ID")]
109114
[Parameter(ParameterSetName = ServicePrincipalCertificateFileParameterSet,
110115
Mandatory = true, HelpMessage = "Tenant name or ID")]
116+
[Parameter(ParameterSetName = ClientAssertionParameterSet,
117+
Mandatory = true, HelpMessage = "Tenant name or ID")]
111118
[Parameter(ParameterSetName = ManagedServiceParameterSet,
112119
Mandatory = false, HelpMessage = "Optional tenant name or ID")]
113120
[Alias("Domain", "TenantId")]
@@ -141,20 +148,7 @@ public class ConnectAzureRmAccountCommand : AzureContextModificationCmdlet, IMod
141148
public SwitchParameter Identity { get; set; }
142149

143150
[Alias("SubscriptionName", "SubscriptionId")]
144-
[Parameter(ParameterSetName = UserParameterSet,
145-
Mandatory = false, HelpMessage = "Subscription Name or ID", ValueFromPipeline = true)]
146-
[Parameter(ParameterSetName = UserWithCredentialParameterSet,
147-
Mandatory = false, HelpMessage = "Subscription Name or ID", ValueFromPipeline = true)]
148-
[Parameter(ParameterSetName = ServicePrincipalParameterSet,
149-
Mandatory = false, HelpMessage = "Subscription Name or ID", ValueFromPipeline = true)]
150-
[Parameter(ParameterSetName = ServicePrincipalCertificateParameterSet,
151-
Mandatory = false, HelpMessage = "Subscription Name or ID", ValueFromPipeline = true)]
152-
[Parameter(ParameterSetName = ServicePrincipalCertificateFileParameterSet,
153-
Mandatory = false, HelpMessage = "Subscription Name or ID", ValueFromPipeline = true)]
154-
[Parameter(ParameterSetName = AccessTokenParameterSet,
155-
Mandatory = false, HelpMessage = "Subscription Name or ID", ValueFromPipeline = true)]
156-
[Parameter(ParameterSetName = ManagedServiceParameterSet,
157-
Mandatory = false, HelpMessage = "Subscription Name or ID", ValueFromPipeline = true)]
151+
[Parameter(Mandatory = false, HelpMessage = "Subscription Name or ID", ValueFromPipeline = true)]
158152
[ValidateNotNullOrEmpty]
159153
public string Subscription { get; set; }
160154

@@ -196,13 +190,7 @@ public class ConnectAzureRmAccountCommand : AzureContextModificationCmdlet, IMod
196190
[Parameter(Mandatory = false, HelpMessage = "Skips context population if no contexts are found.")]
197191
public SwitchParameter SkipContextPopulation { get; set; }
198192

199-
[Parameter(ParameterSetName = UserParameterSet, Mandatory = false, HelpMessage = "Max subscription number to populate contexts after login. Default is "+ DefaultMaxContextPopulationString + ". To populate all subscriptions to contexts, set to -1.")]
200-
[Parameter(ParameterSetName = UserWithCredentialParameterSet, Mandatory = false, HelpMessage = "Max subscription number to populate contexts after login. Default is " + DefaultMaxContextPopulationString + ". To populate all subscriptions to contexts, set to -1.")]
201-
[Parameter(ParameterSetName = ServicePrincipalParameterSet, Mandatory = false, HelpMessage = "Max subscription number to populate contexts after login. Default is " + DefaultMaxContextPopulationString + ". To populate all subscriptions to contexts, set to -1.")]
202-
[Parameter(ParameterSetName = ServicePrincipalCertificateParameterSet, Mandatory = false, HelpMessage = "Max subscription number to populate contexts after login. Default is " + DefaultMaxContextPopulationString + ". To populate all subscriptions to contexts, set to -1.")]
203-
[Parameter(ParameterSetName = ServicePrincipalCertificateFileParameterSet, Mandatory = false, HelpMessage = "Max subscription number to populate contexts after login. Default is " + DefaultMaxContextPopulationString + ". To populate all subscriptions to contexts, set to -1.")]
204-
[Parameter(ParameterSetName = AccessTokenParameterSet, Mandatory = false, HelpMessage = "Max subscription number to populate contexts after login. Default is " + DefaultMaxContextPopulationString + ". To populate all subscriptions to contexts, set to -1.")]
205-
[Parameter(ParameterSetName = ManagedServiceParameterSet, Mandatory = false, HelpMessage = "Max subscription number to populate contexts after login. Default is " + DefaultMaxContextPopulationString + ". To populate all subscriptions to contexts, set to -1.")]
193+
[Parameter(Mandatory = false, HelpMessage = "Max subscription number to populate contexts after login. Default is "+ DefaultMaxContextPopulationString + ". To populate all subscriptions to contexts, set to -1.")]
206194
[PSDefaultValue(Help = DefaultMaxContextPopulationString, Value = DefaultMaxContextPopulation)]
207195
[ValidateRange(-1,int.MaxValue)]
208196
public int MaxContextPopulation { get; set; } = DefaultMaxContextPopulation;
@@ -226,6 +214,11 @@ public class ConnectAzureRmAccountCommand : AzureContextModificationCmdlet, IMod
226214
[Parameter(ParameterSetName = ServicePrincipalCertificateFileParameterSet, HelpMessage = "The password required to access the pkcs#12 certificate file.")]
227215
public SecureString CertificatePassword { get; set; }
228216

217+
[Parameter(ParameterSetName = ClientAssertionParameterSet, Mandatory = true, HelpMessage = "Specifies a token provided by another identity provider. The issuer and subject in this token must be first configured to be trusted by the ApplicationId.")]
218+
[Alias("ClientAssertion")]
219+
[ValidateNotNullOrEmpty]
220+
public string FederatedToken { get; set; }
221+
229222
protected override IAzureContext DefaultContext
230223
{
231224
get
@@ -315,6 +308,16 @@ public override void ExecuteCmdlet()
315308

316309
}
317310

311+
if(ClientAssertionParameterSet.Equals(ParameterSetName, StringComparison.OrdinalIgnoreCase))
312+
{
313+
string suppressWarningOrErrorValue = System.Environment.GetEnvironmentVariable(BreakingChangeAttributeHelper.SUPPRESS_ERROR_OR_WARNING_MESSAGE_ENV_VARIABLE_NAME);
314+
bool.TryParse(suppressWarningOrErrorValue, out bool suppressWarningOrError);
315+
if (!suppressWarningOrError)
316+
{
317+
WriteWarning("The feature related to parameter name 'FederatedToken' is under preview.");
318+
}
319+
}
320+
318321
var azureAccount = new AzureAccount();
319322

320323
switch (ParameterSetName)
@@ -331,6 +334,9 @@ public override void ExecuteCmdlet()
331334
case ServicePrincipalParameterSet:
332335
azureAccount.Type = AzureAccount.AccountType.ServicePrincipal;
333336
break;
337+
case ClientAssertionParameterSet:
338+
azureAccount.Type = "ClientAssertion";
339+
break;
334340
case ManagedServiceParameterSet:
335341
azureAccount.Type = AzureAccount.AccountType.ManagedService;
336342
azureAccount.Id = this.IsBound(nameof(AccountId)) ? AccountId : $"{Constants.DefaultMsiAccountIdPrefix}{DefaultManagedServicePort}";
@@ -417,6 +423,17 @@ public override void ExecuteCmdlet()
417423
WriteWarning(string.Format(Resources.ServicePrincipalWarning, file, directory));
418424
}
419425
}
426+
if (azureAccount.Type == "ClientAssertion" && FederatedToken != null)
427+
{
428+
password = SecureStringExtensions.ConvertToSecureString(FederatedToken);
429+
azureAccount.SetProperty("ClientAssertion", FederatedToken);
430+
if (GetContextModificationScope() == ContextModificationScope.CurrentUser)
431+
{
432+
var file = AzureSession.Instance.ARMProfileFile;
433+
var directory = AzureSession.Instance.ARMProfileDirectory;
434+
WriteWarning(string.Format(Resources.ClientAssertionWarning, file, directory));
435+
}
436+
}
420437

421438
var resourceId = PreProcessAuthScope();
422439

src/Accounts/Accounts/ChangeLog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
-->
2020

2121
## Upcoming Release
22+
* Added `-FederatedToken` on `Connect-AzAccount`
2223
* Updated Azure.Core from 1.19.0 to 1.20.0.
2324

2425
## Version 2.5.4

src/Accounts/Accounts/Properties/Resources.Designer.cs

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Accounts/Accounts/Properties/Resources.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,9 @@
426426
<data name="ServicePrincipalWarning" xml:space="preserve">
427427
<value>The provided service principal secret will be included in the '{0}' file found in the user profile ( {1} ). Please ensure that this directory has appropriate protections.</value>
428428
</data>
429+
<data name="ClientAssertionWarning" xml:space="preserve">
430+
<value>The provided client id and assertion will be included in the '{0}' file found in the user profile ( {1} ). Please ensure that this directory has appropriate protections.</value>
431+
</data>
429432
<data name="MSITenantDomainNotFound" xml:space="preserve">
430433
<value>Please ensure that the managed service identity found on this machine has proper permissions to the provided tenant domain.</value>
431434
</data>

src/Accounts/Accounts/help/Connect-AzAccount.md

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,14 @@ Connect-AzAccount [-Environment <String>] -CertificateThumbprint <String> -Appli
4545
[<CommonParameters>]
4646
```
4747

48+
### ClientAssertionParameterSet
49+
```
50+
Connect-AzAccount [-Environment <String>] -ApplicationId <String> [-ServicePrincipal] -Tenant <String>
51+
[-Subscription <String>] [-ContextName <String>] [-SkipContextPopulation] [-MaxContextPopulation <Int32>]
52+
[-Force] -FederatedToken <String> [-Scope <ContextModificationScope>]
53+
[-DefaultProfile <IAzureContextContainer>] [-WhatIf] [-Confirm] [<CommonParameters>]
54+
```
55+
4856
### ServicePrincipalCertificateFileWithSubscriptionId
4957
```
5058
Connect-AzAccount [-Environment <String>] -ApplicationId <String> [-ServicePrincipal] -Tenant <String>
@@ -302,7 +310,7 @@ Application ID of the service principal.
302310
303311
```yaml
304312
Type: System.String
305-
Parameter Sets: ServicePrincipalCertificateWithSubscriptionId, ServicePrincipalCertificateFileWithSubscriptionId
313+
Parameter Sets: ServicePrincipalCertificateWithSubscriptionId, ClientAssertionParameterSet, ServicePrincipalCertificateFileWithSubscriptionId
306314
Aliases:
307315

308316
Required: True
@@ -440,6 +448,24 @@ Accept pipeline input: False
440448
Accept wildcard characters: False
441449
```
442450

451+
### -FederatedToken
452+
Specifies a token provided by another identity provider. The issuer and subject in this token must be first configured to be trusted by the ApplicationId.
453+
454+
> [!CAUTION]
455+
> Federated tokens are a type of credential. You should take the appropriate security precautions to keep them confidential. Federated tokens also timeout and may prevent long running tasks from completing.
456+
457+
```yaml
458+
Type: System.String
459+
Parameter Sets: ClientAssertionParameterSet
460+
Aliases: ClientAssertion
461+
462+
Required: True
463+
Position: Named
464+
Default value: None
465+
Accept pipeline input: False
466+
Accept wildcard characters: False
467+
```
468+
443469
### -Force
444470

445471
Overwrite the existing context with the same name without prompting.
@@ -571,7 +597,7 @@ Accept wildcard characters: False
571597

572598
```yaml
573599
Type: System.Management.Automation.SwitchParameter
574-
Parameter Sets: ServicePrincipalCertificateWithSubscriptionId, ServicePrincipalCertificateFileWithSubscriptionId
600+
Parameter Sets: ServicePrincipalCertificateWithSubscriptionId, ClientAssertionParameterSet, ServicePrincipalCertificateFileWithSubscriptionId
575601
Aliases:
576602
577603
Required: False
@@ -651,7 +677,7 @@ Accept wildcard characters: False
651677

652678
```yaml
653679
Type: System.String
654-
Parameter Sets: ServicePrincipalWithSubscriptionId, ServicePrincipalCertificateWithSubscriptionId, ServicePrincipalCertificateFileWithSubscriptionId
680+
Parameter Sets: ServicePrincipalWithSubscriptionId, ServicePrincipalCertificateWithSubscriptionId, ClientAssertionParameterSet, ServicePrincipalCertificateFileWithSubscriptionId
655681
Aliases: Domain, TenantId
656682
657683
Required: True
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// ----------------------------------------------------------------------------------
2+
//
3+
// Copyright Microsoft Corporation
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
// ----------------------------------------------------------------------------------
14+
15+
using Microsoft.Azure.Commands.Common.Authentication.Abstractions;
16+
using System.Security;
17+
18+
namespace Microsoft.Azure.Commands.Common.Authentication
19+
{
20+
/// <summary>
21+
/// The parameters for application client. See https://aka.ms/msal-net-client-assertion
22+
/// </summary>
23+
public class ClientAssertionParameters : AuthenticationParameters
24+
{
25+
/// <summary>
26+
/// Client ID (also known as App ID) of the application as registered in the application registration portal
27+
/// </summary>
28+
public string ClientId { get; set; }
29+
30+
/// <summary>
31+
/// The client assertion used to prove the identity of the application to Azure AD. This is a Base-64 encoded JWT.
32+
/// </summary>
33+
public SecureString ClientAssertion { get; set; }
34+
35+
public ClientAssertionParameters(
36+
PowerShellTokenCacheProvider tokenCacheProvider,
37+
IAzureEnvironment environment,
38+
IAzureTokenCache tokenCache,
39+
string tenantId,
40+
string resourceId,
41+
string clientId,
42+
SecureString clientAssertion) : base(tokenCacheProvider, environment, tokenCache, tenantId, resourceId)
43+
{
44+
this.ClientId = clientId;
45+
this.ClientAssertion = clientAssertion;
46+
}
47+
}
48+
}

src/Accounts/Authentication/Factories/AuthenticationFactory.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,7 @@ public ServiceClientCredentials GetServiceClientCredentials(IAzureContext contex
380380
case AzureAccount.AccountType.ManagedService:
381381
case AzureAccount.AccountType.User:
382382
case AzureAccount.AccountType.ServicePrincipal:
383+
case "ClientAssertion":
383384
token = Authenticate(context.Account, context.Environment, tenant, null, ShowDialog.Never, null, context.Environment.GetTokenAudience(targetEndpoint));
384385
break;
385386
default:
@@ -565,6 +566,9 @@ private AuthenticationParameters GetAuthenticationParameters(
565566
return new ManagedServiceIdentityParameters(tokenCacheProvider, environment, tokenCache, tenant, resourceId, account);
566567
case AzureAccount.AccountType.AccessToken:
567568
return new AccessTokenParameters(tokenCacheProvider, environment, tokenCache, tenant, resourceId, account);
569+
case "ClientAssertion":
570+
password = password ?? ConvertToSecureString(account.GetProperty("ClientAssertion"));
571+
return new ClientAssertionParameters(tokenCacheProvider, environment, tokenCache, tenant, resourceId, account.Id, password);
568572
default:
569573
return null;
570574
}

0 commit comments

Comments
 (0)