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
43 changes: 43 additions & 0 deletions src/KeyVault/KeyVault.Test/PesterTests/Certificate.Tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
BeforeAll {
$vaultName = 'nori-kv765'
. "..\Scripts\Common.ps1"
}

Describe "Import Certificate with policy" {
It "ImportCertificateFromFileWithPolicyParameterSet" {
$certName = Get-CertificateName
$certFilePath = "..\Resources\importCertWithPolicy.pfx"
$policy = New-AzKeyVaultCertificatePolicy -SecretContentType "application/x-pkcs12" -SubjectName "CN=contoso.com" -IssuerName "Self" -ValidityInMonths 6 -ReuseKeyOnRenewal

$cert = Import-AzKeyVaultCertificate -VaultName $vaultName -Name $certName -FilePath $certFilePath -PolicyObject $policy
$cert.Policy.SecretContentType | Should -Be "application/x-pkcs12"
}
It "ImportCertificateFromFileWithPolicyFileParameterSet" {
$certName = Get-CertificateName
$certFilePath = "..\Resources\importCertWithPolicy.pfx"
$policyPath = "..\Resources\certPolicy.json"

$cert = Import-AzKeyVaultCertificate -VaultName $vaultName -Name $certName -FilePath $certFilePath -PolicyPath $policyPath
$cert.Policy.SecretContentType | Should -Be "application/x-pkcs12"
}
It "ImportWithPrivateKeyFromStringWithPolicyFileParameterSet" {
$certName = Get-CertificateName
$certFilePath = "..\Resources\importCertWithPolicy.pfx"
$policyPath = "..\Resources\certPolicy.json"
$Base64StringCertificate = [System.Convert]::ToBase64String([System.IO.File]::ReadAllBytes($certFilePath))

$cert = Import-AzKeyVaultCertificate -VaultName $vaultName -Name $certName -CertificateString $Base64StringCertificate -PolicyPath $policyPath
$cert.Policy.SecretContentType | Should -Be "application/x-pkcs12"
}
It "ImportWithPrivateKeyFromCollectionWithPolicyFileParameterSet" {
$certName = Get-CertificateName
$certFilePath = "..\Resources\importCertWithPolicy.pfx"
$policyPath = "..\Resources\certPolicy.json"
$certCollection = [System.Security.Cryptography.X509Certificates.X509Certificate2Collection]::new()
$certCollection.Import($certFilePath, $null, [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable)

$cert = Import-AzKeyVaultCertificate -VaultName $vaultName -Name $certName -CertificateCollection $certCollection -PolicyPath $policyPath
$cert.Policy.SecretContentType | Should -Be "application/x-pkcs12"
}
}

40 changes: 40 additions & 0 deletions src/KeyVault/KeyVault.Test/Resources/certPolicy.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"id": "https://myvault.vault.azure.net/certificates/updateCert01/policy",
"key_props": {
"exportable": true,
"kty": "RSA",
"key_size": 2048,
"reuse_key": false
},

"secret_props": {
"contentType": "application/x-pkcs12"
},

"x509_props": {
"subject": "CN=KeyVaultTest",
"ekus": [],
"key_usage": [],
"validity_months": 297
},

"lifetime_actions": [
{
"trigger": {
"lifetime_percentage": 80
},
"action": {
"action_type": "EmailContacts"
}
}
],

"issuer": {
"name": "Unknown"
},
"attributes": {
"enabled": true,
"created": 1482188947,
"updated": 1482188947
}
}
Binary file not shown.
1 change: 1 addition & 0 deletions src/KeyVault/KeyVault/ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
- Additional information about change #1
-->
## Upcoming Release
* Added parameter `PolicyPath` and `PolicyObject` in `Import-AzKeyVaultCertificate` to support custom policy [#20780]

## Version 4.9.2
* Updated Azure.Core to 1.28.0.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,21 @@ public class ImportAzureKeyVaultCertificate : KeyVaultCmdletBase
HelpMessage = "Specifies the password for the certificate and private key base64 encoded string to import.")]
public SecureString Password { get; set; }

/// <summary>
/// File Path
/// </summary>
[Parameter(Mandatory = false,
HelpMessage = "A file path to specify management policy for the certificate that contains JSON encoded policy definition. Mutual-exclusive to PolicyObject.")]
public string PolicyPath { get; set; }

/// <summary>
/// File Path
/// </summary>
[Parameter(Mandatory = false,
ValueFromPipeline = true,
HelpMessage = "An in-memory object to specify management policy for the certificate. Mutual-exclusive to PolicyPath.")]
public PSKeyVaultCertificatePolicy PolicyObject { get; set; }

/// <summary>
/// Certificate Collection
/// </summary>
Expand All @@ -131,6 +146,7 @@ public class ImportAzureKeyVaultCertificate : KeyVaultCmdletBase
protected override void BeginProcessing()
{
FilePath = this.TryResolvePath(FilePath);
PolicyPath = this.TryResolvePath(PolicyPath);
base.BeginProcessing();
}

Expand All @@ -143,6 +159,34 @@ private void ValidateParameters()
{
throw new AzPSArgumentException(string.Format(Resources.FileNotFound, this.FilePath), nameof(FilePath));
}
if (IsPemFile(FilePath))
{
ContentType = Constants.PemContentType;
}
else
{
ContentType = Constants.Pkcs12ContentType;
}
}
if (this.IsParameterBound(c => c.CertificateCollection))
{
ContentType = Constants.Pkcs12ContentType;
}
if (this.IsParameterBound(c => c.PolicyPath) && this.IsParameterBound(c => c.PolicyObject))
{
throw new AzPSArgumentException($"Parameter {nameof(PolicyPath)} conflicts with Parameter {nameof(PolicyObject)}. Only one of these 2 parameters could be imported at once.", nameof(PolicyPath));
}
if (this.IsParameterBound(c => c.PolicyPath))
{
if (!File.Exists(PolicyPath))
Comment on lines +179 to +181
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (this.IsParameterBound(c => c.PolicyPath))
{
if (!File.Exists(PolicyPath))
if (this.IsParameterBound(c => c.PolicyPath)&&!File.Exists(PolicyPath))

NIT

{
throw new AzPSArgumentException(string.Format(Resources.FileNotFound, this.PolicyPath), nameof(PolicyPath));
}
PolicyObject = PSKeyVaultCertificatePolicy.FromJsonFile(PolicyPath);
}
if (PolicyObject != null && PolicyObject.SecretContentType != ContentType)
{
throw new AzPSArgumentException($"User input {ContentType} conflicts with the ContentType stated as {PolicyObject.SecretContentType} in Certificate Policy.", ContentType);
}
}

Expand All @@ -162,7 +206,7 @@ public override void ExecuteCmdlet()
if (IsPemFile(FilePath))
{
byte[] pemBytes = File.ReadAllBytes(FilePath);
certBundle = this.Track2DataClient.ImportCertificate(VaultName, Name, pemBytes, Password, Tag?.ConvertToDictionary(), Constants.PemContentType);
certBundle = this.Track2DataClient.ImportCertificate(VaultName, Name, pemBytes, Password, Tag?.ConvertToDictionary(), Constants.PemContentType, certPolicy: PolicyObject);
}
else
{
Expand All @@ -179,8 +223,9 @@ public override void ExecuteCmdlet()

if (doImport)
{

byte[] base64Bytes = userProvidedCertColl.Export(X509ContentType.Pfx, Password?.ConvertToString());
certBundle = this.Track2DataClient.ImportCertificate(VaultName, Name, base64Bytes, Password, Tag?.ConvertToDictionary());
certBundle = this.Track2DataClient.ImportCertificate(VaultName, Name, base64Bytes, Password, Tag?.ConvertToDictionary(), certPolicy: PolicyObject);
}
else
{
Expand All @@ -194,12 +239,11 @@ public override void ExecuteCmdlet()
break;

case ImportWithPrivateKeyFromCollectionParameterSet:
certBundle = this.DataServiceClient.ImportCertificate(VaultName, Name, CertificateCollection, Tag?.ConvertToDictionary());

certBundle = this.Track2DataClient.ImportCertificate(VaultName, Name, CertificateCollection, null, Tag?.ConvertToDictionary(), certPolicy: PolicyObject);
break;

case ImportWithPrivateKeyFromStringParameterSet:
certBundle = this.Track2DataClient.ImportCertificate(VaultName, Name, CertificateString, Password, Tag?.ConvertToDictionary(), ContentType);
certBundle = this.Track2DataClient.ImportCertificate(VaultName, Name, CertificateString, Password, Tag?.ConvertToDictionary(), ContentType, certPolicy: PolicyObject);

break;
}
Expand Down
6 changes: 3 additions & 3 deletions src/KeyVault/KeyVault/Models/IKeyVaultDataServiceClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -164,11 +164,11 @@ public interface IKeyVaultDataServiceClient

PSKeyVaultCertificate MergeCertificate(string vaultName, string certName, byte[] certBytes, Dictionary<string, string> tags);

PSKeyVaultCertificate ImportCertificate(string vaultName, string certName, byte[] certificate, SecureString certPassword, IDictionary<string, string> tags, string contentType = Constants.Pkcs12ContentType);
PSKeyVaultCertificate ImportCertificate(string vaultName, string certName, byte[] certificate, SecureString certPassword, IDictionary<string, string> tags, string contentType = Constants.Pkcs12ContentType, PSKeyVaultCertificatePolicy certPolicy = null);

PSKeyVaultCertificate ImportCertificate(string vaultName, string certName, string base64CertString, SecureString certPassword, IDictionary<string, string> tags, string contentType = Constants.Pkcs12ContentType);
PSKeyVaultCertificate ImportCertificate(string vaultName, string certName, string base64CertString, SecureString certPassword, IDictionary<string, string> tags, string contentType = Constants.Pkcs12ContentType, PSKeyVaultCertificatePolicy certPolicy = null);

PSKeyVaultCertificate ImportCertificate(string vaultName, string certName, X509Certificate2Collection certificateCollection, IDictionary<string, string> tags, string contentType = Constants.Pkcs12ContentType);
PSKeyVaultCertificate ImportCertificate(string vaultName, string certName, X509Certificate2Collection certificateCollection, SecureString certPassword, IDictionary<string, string> tags, string contentType = Constants.Pkcs12ContentType, PSKeyVaultCertificatePolicy certPolicy = null);

PSDeletedKeyVaultCertificate DeleteCertificate(string vaultName, string certName);

Expand Down
6 changes: 3 additions & 3 deletions src/KeyVault/KeyVault/Models/KeyVaultDataServiceClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -817,12 +817,12 @@ public PSKeyVaultCertificate MergeCertificate(string vaultName, string certName,

}

public PSKeyVaultCertificate ImportCertificate(string vaultName, string certName, byte[] certificate, SecureString certPassword, IDictionary<string, string> tags, string contentType = Constants.Pkcs12ContentType)
public PSKeyVaultCertificate ImportCertificate(string vaultName, string certName, byte[] certificate, SecureString certPassword, IDictionary<string, string> tags, string contentType = Constants.Pkcs12ContentType, PSKeyVaultCertificatePolicy certPolicyPath = null)
{
return ImportCertificate(vaultName, certName, Convert.ToBase64String(certificate), certPassword, tags, contentType);
}

public PSKeyVaultCertificate ImportCertificate(string vaultName, string certName, string base64CertColl, SecureString certPassword, IDictionary<string, string> tags, string contentType = Constants.Pkcs12ContentType)
public PSKeyVaultCertificate ImportCertificate(string vaultName, string certName, string base64CertColl, SecureString certPassword, IDictionary<string, string> tags, string contentType = Constants.Pkcs12ContentType, PSKeyVaultCertificatePolicy certPolicyPath = null)
{
if (string.IsNullOrEmpty(vaultName))
throw new ArgumentNullException(nameof(vaultName));
Expand Down Expand Up @@ -855,7 +855,7 @@ public PSKeyVaultCertificate ImportCertificate(string vaultName, string certName
return new PSKeyVaultCertificate(certBundle);
}

public PSKeyVaultCertificate ImportCertificate(string vaultName, string certName, X509Certificate2Collection certificateCollection, IDictionary<string, string> tags, string contentType = Constants.Pkcs12ContentType)
public PSKeyVaultCertificate ImportCertificate(string vaultName, string certName, X509Certificate2Collection certificateCollection, SecureString certPassword, IDictionary<string, string> tags, string contentType = Constants.Pkcs12ContentType, PSKeyVaultCertificatePolicy certPolicy = null)
{
if (string.IsNullOrEmpty(vaultName))
throw new ArgumentNullException(nameof(vaultName));
Expand Down
2 changes: 2 additions & 0 deletions src/KeyVault/KeyVault/Models/PSKeyVaultCertificate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public class PSKeyVaultCertificate : PSKeyVaultCertificateIdentityItem
public string SecretId { get; internal set; }
public string Thumbprint { get; set; }

public PSKeyVaultCertificatePolicy Policy { get; set; }
public string RecoveryLevel { get; private set; }

internal PSKeyVaultCertificate(CertificateBundle certificateBundle, VaultUriHelper vaultUriHelper)
Expand Down Expand Up @@ -156,6 +157,7 @@ internal PSKeyVaultCertificate(KeyVaultCertificateWithPolicy keyVaultCertificate

KeyId = keyVaultCertificate.KeyId?.ToString();
SecretId = keyVaultCertificate.SecretId?.ToString();
Policy = PSKeyVaultCertificatePolicy.FromTrack2CertificatePolicy(keyVaultCertificate.Policy);

if (keyVaultCertificate.Properties != null)
{
Expand Down
Loading