Skip to content

Commit

Permalink
Use certificate file as input
Browse files Browse the repository at this point in the history
  • Loading branch information
msJinLei committed May 13, 2021
1 parent 2ec1fb2 commit 4aa9722
Show file tree
Hide file tree
Showing 15 changed files with 514 additions and 63 deletions.
49 changes: 40 additions & 9 deletions src/Accounts/Accounts/Account/ConnectAzureRmAccount.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
using Microsoft.WindowsAzure.Commands.Common;
using Microsoft.WindowsAzure.Commands.Utilities.Common;

using System.Runtime.InteropServices;

namespace Microsoft.Azure.Commands.Profile
{
/// <summary>
Expand All @@ -51,6 +53,7 @@ public class ConnectAzureRmAccountCommand : AzureContextModificationCmdlet, IMod
public const string UserWithCredentialParameterSet = "UserWithCredential";
public const string ServicePrincipalParameterSet = "ServicePrincipalWithSubscriptionId";
public const string ServicePrincipalCertificateParameterSet= "ServicePrincipalCertificateWithSubscriptionId";
public const string ServicePrincipalCertificateFileParameterSet = "ServicePrincipalCertificateFileWithSubscriptionId";
public const string AccessTokenParameterSet = "AccessTokenWithSubscriptionId";
public const string ManagedServiceParameterSet = "ManagedServiceLogin";
public const string MSIEndpointVariable = "MSI_ENDPOINT";
Expand All @@ -77,12 +80,16 @@ public class ConnectAzureRmAccountCommand : AzureContextModificationCmdlet, IMod

[Parameter(ParameterSetName = ServicePrincipalCertificateParameterSet,
Mandatory = true, HelpMessage = "SPN")]
[Parameter(ParameterSetName = ServicePrincipalCertificateFileParameterSet,
Mandatory = true, HelpMessage = "SPN")]
public string ApplicationId { get; set; }

[Parameter(ParameterSetName = ServicePrincipalParameterSet,
Mandatory = true)]
[Parameter(ParameterSetName = ServicePrincipalCertificateParameterSet,
Mandatory = false)]
[Parameter(ParameterSetName = ServicePrincipalCertificateFileParameterSet,
Mandatory = false)]
public SwitchParameter ServicePrincipal { get; set; }

[Parameter(ParameterSetName = UserParameterSet,
Expand All @@ -95,6 +102,8 @@ public class ConnectAzureRmAccountCommand : AzureContextModificationCmdlet, IMod
Mandatory = false, HelpMessage = "Tenant name or ID")]
[Parameter(ParameterSetName = ServicePrincipalCertificateParameterSet,
Mandatory = true, HelpMessage = "Tenant name or ID")]
[Parameter(ParameterSetName = ServicePrincipalCertificateFileParameterSet,
Mandatory = true, HelpMessage = "Tenant name or ID")]
[Parameter(ParameterSetName = ManagedServiceParameterSet,
Mandatory = false, HelpMessage = "Optional tenant name or ID")]
[Alias("Domain", "TenantId")]
Expand Down Expand Up @@ -149,6 +158,8 @@ public class ConnectAzureRmAccountCommand : AzureContextModificationCmdlet, IMod
Mandatory = false, HelpMessage = "Subscription Name or ID", ValueFromPipeline = true)]
[Parameter(ParameterSetName = ServicePrincipalCertificateParameterSet,
Mandatory = false, HelpMessage = "Subscription Name or ID", ValueFromPipeline = true)]
[Parameter(ParameterSetName = ServicePrincipalCertificateFileParameterSet,
Mandatory = false, HelpMessage = "Subscription Name or ID", ValueFromPipeline = true)]
[Parameter(ParameterSetName = AccessTokenParameterSet,
Mandatory = false, HelpMessage = "Subscription Name or ID", ValueFromPipeline = true)]
[Parameter(ParameterSetName = ManagedServiceParameterSet,
Expand Down Expand Up @@ -198,6 +209,7 @@ public class ConnectAzureRmAccountCommand : AzureContextModificationCmdlet, IMod
[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.")]
[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.")]
[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.")]
[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.")]
[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.")]
[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.")]
[PSDefaultValue(Help = DefaultMaxContextPopulationString, Value = DefaultMaxContextPopulation)]
Expand All @@ -212,9 +224,17 @@ public class ConnectAzureRmAccountCommand : AzureContextModificationCmdlet, IMod
[Parameter(Mandatory = false, HelpMessage = "Overwrite the existing context with the same name, if any.")]
public SwitchParameter Force { get; set; }

[Parameter(ParameterSetName = ServicePrincipalCertificateParameterSet, Mandatory = false, HelpMessage = "Specifies if the x5c claim (public key of the certificate) should be sent to the STS to achieve easy certificate rollover in Azure AD.")]
[Parameter(ParameterSetName = ServicePrincipalCertificateParameterSet, HelpMessage = "Specifies if the x5c claim (public key of the certificate) should be sent to the STS to achieve easy certificate rollover in Azure AD.")]
[Parameter(ParameterSetName = ServicePrincipalCertificateFileParameterSet, HelpMessage = "Specifies if the x5c claim (public key of the certificate) should be sent to the STS to achieve easy certificate rollover in Azure AD.")]
public SwitchParameter SendCertificateChain { get; set; }


[Parameter(ParameterSetName = ServicePrincipalCertificateFileParameterSet, Mandatory = true, HelpMessage = "The path of certficate file in pkcs#12 format.")]
public String CertificatePath { get; set; }

[Parameter(ParameterSetName = ServicePrincipalCertificateFileParameterSet, HelpMessage = "The password required to access the pkcs#12 certificate file.")]
public SecureString CertificatePassword { get; set; }

protected override IAzureContext DefaultContext
{
get
Expand Down Expand Up @@ -316,13 +336,7 @@ public override void ExecuteCmdlet()
azureAccount.SetProperty(AzureAccount.Property.KeyVaultAccessToken, KeyVaultAccessToken);
break;
case ServicePrincipalCertificateParameterSet:
if (SendCertificateChain)
{
azureAccount.SetProperty("SendCertificateChain", SendCertificateChain.ToString());
WriteDebug("SendCertificateChain is set.");
}
azureAccount.Type = AzureAccount.AccountType.ServicePrincipal;
break;
case ServicePrincipalCertificateFileParameterSet:
case ServicePrincipalParameterSet:
azureAccount.Type = AzureAccount.AccountType.ServicePrincipal;
break;
Expand Down Expand Up @@ -411,12 +425,29 @@ public override void ExecuteCmdlet()
azureAccount.SetThumbprint(CertificateThumbprint);
}

if( !string.IsNullOrWhiteSpace(CertificatePath))
{
azureAccount.SetProperty(AzureAccount.Property.CertificatePath, CertificatePath);
if (this.IsBound(nameof(CertificatePassword)))
{
azureAccount.SetProperty(AzureAccount.Property.CertificatePassword, CertificatePassword.ConvertToString());
}
}

if ((ParameterSetName == ServicePrincipalCertificateParameterSet || ParameterSetName == ServicePrincipalCertificateFileParameterSet)
&& SendCertificateChain)
{
//fixme
azureAccount.SetProperty(AzureAccount.Property.SendCertificateChain, SendCertificateChain.ToString());
WriteDebug("SendCertificateChain is set.");
}

if (!string.IsNullOrEmpty(Tenant))
{
azureAccount.SetProperty(AzureAccount.Property.Tenants, Tenant);
}

if (azureAccount.Type == AzureAccount.AccountType.ServicePrincipal && string.IsNullOrEmpty(CertificateThumbprint))
if (azureAccount.Type == AzureAccount.AccountType.ServicePrincipal && string.IsNullOrEmpty(CertificateThumbprint) && password != null)
{
azureAccount.SetProperty(AzureAccount.Property.ServicePrincipalSecret, password.ConvertToString());
if (GetContextModificationScope() == ContextModificationScope.CurrentUser)
Expand Down
3 changes: 2 additions & 1 deletion src/Accounts/Accounts/ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
## Upcoming Release
* Customized display format of PSAzureRmAccount to hide secret of service principal [#14208]
* Added optional parameter `AuthScope` to `Connect-AzAccount` to support enhanced authentication of data plane features
* Supported subject name issuer authentication.
* Supported subject name issuer authentication
* Supported certificate file as input parameter of Connect-AzAccount [#9160]

## Version 2.2.8
* Fallback to first valid context if current default context key is "Default" which is invalid
Expand Down
66 changes: 62 additions & 4 deletions src/Accounts/Accounts/help/Connect-AzAccount.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,15 @@ Connect-AzAccount [-Environment <String>] -CertificateThumbprint <String> -Appli
[-DefaultProfile <IAzureContextContainer>] [-WhatIf] [-Confirm] [<CommonParameters>]
```

### ServicePrincipalCertificateFileWithSubscriptionId
```
Connect-AzAccount [-Environment <String>] -ApplicationId <String> [-ServicePrincipal] -Tenant <String>
[-Subscription <String>] [-ContextName <String>] [-SkipContextPopulation] [-MaxContextPopulation <Int32>]
[-Force] [-SendCertificateChain] -CertificatePath <String> [-CertificatePassword <SecureString>]
[-Scope <ContextModificationScope>] [-DefaultProfile <IAzureContextContainer>] [-WhatIf] [-Confirm]
[<CommonParameters>]
```

### AccessTokenWithSubscriptionId
```
Connect-AzAccount [-Environment <String>] [-Tenant <String>] -AccessToken <String> [-GraphAccessToken <String>]
Expand Down Expand Up @@ -214,6 +223,25 @@ Account SubscriptionName TenantId Environment
------- ---------------- -------- -----------
yyyy-yyyy-yyyy-yyyy Subscription1 xxxx-xxxx-xxxx-xxxx AzureCloud
```

### Example 9: Connect using certificate file

This example connects to an Azure account using certificate-based service principal authentication.
The certificate file, which is specified by `CertficatePath`, should contains both certificate and private key as the input.

```powershell
$securePassword = $plainPassword | ConvertTo-SecureString -AsPlainText -Force
$TenantId = '4cd76576-b611-43d0-8f2b-adcb139531bf'
$ApplicationId = '3794a65a-e4e4-493d-ac1d-f04308d712dd'
Connect-AzAccount -ServicePrincipal -ApplicationId $ApplicationId -TenantId $TenantId -CertificatePath './certificatefortest.pfx' -CertificatePassword $securePassword
```

```Output
Account SubscriptionName TenantId Environment
------- ---------------- -------- -----------
xxxx-xxxx-xxxx-xxxx Subscription1 xxxx-xxxx-xxxx-xxxx AzureCloud
```

## PARAMETERS

### -AccessToken
Expand Down Expand Up @@ -273,7 +301,37 @@ Application ID of the service principal.
```yaml
Type: System.String
Parameter Sets: ServicePrincipalCertificateWithSubscriptionId
Parameter Sets: ServicePrincipalCertificateWithSubscriptionId, ServicePrincipalCertificateFileWithSubscriptionId
Aliases:

Required: True
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -CertificatePassword
The password required to access the pkcs#12 certificate file.
```yaml
Type: System.Security.SecureString
Parameter Sets: ServicePrincipalCertificateFileWithSubscriptionId
Aliases:

Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -CertificatePath
The path of certficate file in pkcs#12 format.
```yaml
Type: System.String
Parameter Sets: ServicePrincipalCertificateFileWithSubscriptionId
Aliases:

Required: True
Expand Down Expand Up @@ -532,7 +590,7 @@ Specifies if the x5c claim (public key of the certificate) should be sent to the

```yaml
Type: System.Management.Automation.SwitchParameter
Parameter Sets: ServicePrincipalCertificateWithSubscriptionId
Parameter Sets: ServicePrincipalCertificateWithSubscriptionId, ServicePrincipalCertificateFileWithSubscriptionId
Aliases:
Required: False
Expand Down Expand Up @@ -560,7 +618,7 @@ Accept wildcard characters: False

```yaml
Type: System.Management.Automation.SwitchParameter
Parameter Sets: ServicePrincipalCertificateWithSubscriptionId
Parameter Sets: ServicePrincipalCertificateWithSubscriptionId, ServicePrincipalCertificateFileWithSubscriptionId
Aliases:
Required: False
Expand Down Expand Up @@ -640,7 +698,7 @@ Accept wildcard characters: False

```yaml
Type: System.String
Parameter Sets: ServicePrincipalWithSubscriptionId, ServicePrincipalCertificateWithSubscriptionId
Parameter Sets: ServicePrincipalWithSubscriptionId, ServicePrincipalCertificateWithSubscriptionId, ServicePrincipalCertificateFileWithSubscriptionId
Aliases: Domain, TenantId
Required: True
Expand Down
Loading

0 comments on commit 4aa9722

Please sign in to comment.