Skip to content
This repository has been archived by the owner on Jul 19, 2024. It is now read-only.

Commit

Permalink
Merge pull request #3 from wantedfast/Dev-updateSDK
Browse files Browse the repository at this point in the history
Update key vault data sdk to T2, mangement SDK to latest.
  • Loading branch information
jongio authored Nov 18, 2020
2 parents 68df659 + eb181a1 commit 589d10a
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 174 deletions.
5 changes: 3 additions & 2 deletions AzureKeyVaultRecoverySamples.csproj
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Azure.KeyVault" Version="3.0.0" />
<PackageReference Include="Azure.Identity" Version="1.2.3" />
<PackageReference Include="Azure.Security.KeyVault.Secrets" Version="4.1.0" />
<PackageReference Include="Microsoft.Azure.Management.KeyVault.Fluent" Version="1.6.0" />
<PackageReference Include="Microsoft.Azure.Management.ResourceManager.Fluent" Version="1.6.0" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="4.4.1" />
Expand Down
42 changes: 5 additions & 37 deletions ClientContext.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
using System;
using System.Configuration;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using Microsoft.Rest;
using Microsoft.Rest.Azure.Authentication;
using System;
using System.Threading.Tasks;

namespace AzureKeyVaultRecoverySamples
{
Expand Down Expand Up @@ -60,7 +58,7 @@ public static ClientContext Build(string tenantId, string objectId, string appId
/// </summary>
/// <param name="certificateThumbprint"></param>
/// <returns></returns>
public static Task<ServiceClientCredentials> GetServiceCredentialsAsync( string tenantId, string applicationId, string appSecret )
public static Task<ServiceClientCredentials> GetServiceCredentialsAsync(string tenantId, string applicationId, string appSecret)
{
if (_servicePrincipalCredential == null)
{
Expand All @@ -69,41 +67,11 @@ public static Task<ServiceClientCredentials> GetServiceCredentialsAsync( string

return ApplicationTokenProvider.LoginSilentAsync(
tenantId,
_servicePrincipalCredential,
_servicePrincipalCredential,
ActiveDirectoryServiceSettings.Azure,
TokenCache.DefaultShared);
}

/// <summary>
/// Generic ADAL Authentication callback
/// </summary>
public static async Task<string> AcquireTokenAsync(string authority, string resource, string scope)
{
if (_servicePrincipalCredential == null)
{
// read directly from config
var appId = ConfigurationManager.AppSettings[SampleConstants.ConfigKeys.ApplicationId];
var spSecret = ConfigurationManager.AppSettings[SampleConstants.ConfigKeys.SPSecret];

_servicePrincipalCredential = new ClientCredential(appId, spSecret);
}

AuthenticationContext ctx = new AuthenticationContext(authority, false, TokenCache.DefaultShared);
AuthenticationResult result = await ctx.AcquireTokenAsync(resource, _servicePrincipalCredential).ConfigureAwait(false);

return result.AccessToken;
}

/// <summary>
/// Generic authentication callback for a specific tenant
/// </summary>
/// <param name="tenantId">Identifier of tenant where authentication takes place.</param>
/// <returns>Authentication callback.</returns>
/// <remarks>Consider moving this class out from Controllers.Core into a separate top-level lib.</remarks>
public static Func<Task<string>> GetAuthenticationCallback(string authority, string resource, string scope)
{
return () => { return AcquireTokenAsync(authority, resource, scope); };
}
#endregion
}
}
99 changes: 39 additions & 60 deletions KeyVaultEntityRecoverySamples.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
using System;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Azure.KeyVault.Models;
using Azure;
using Azure.Security.KeyVault.Secrets;
using Microsoft.Azure.Management.KeyVault.Fluent;
using Microsoft.Azure.Management.KeyVault.Fluent.Models;
using Microsoft.Azure.Management.ResourceManager.Fluent;
using Microsoft.Rest.Azure;
using System;
using System.Net;
using System.Threading;
using System.Threading.Tasks;

namespace AzureKeyVaultRecoverySamples
{
Expand Down Expand Up @@ -54,23 +55,26 @@ public static async Task DemonstrateRecoveryAndPurgeAsync()
// retrieve the vault (or create, if it doesn't exist)
var vault = await sample.CreateOrRetrieveVaultAsync(rgName, vaultName, enableSoftDelete: true, enablePurgeProtection: false);
var vaultUri = vault.Properties.VaultUri;

SecretClient secretClient = sample.GetDataClient(new Uri(vaultUri));

Console.WriteLine("Operating with vault name '{0}' in resource group '{1}' and location '{2}'", vaultName, rgName, vault.Location);

try
{
// set a secret
Console.Write("Setting a new value for secret '{0}'...", secretName);
var secretResponse = await sample.DataClient.SetSecretWithHttpMessagesAsync(vaultUri, secretName, Guid.NewGuid().ToString()).ConfigureAwait(false);
await secretClient.SetSecretAsync(secretName, Guid.NewGuid().ToString());
Console.WriteLine("done.");

// confirm existence
Console.Write("Verifying secret creation...");
var retrievedSecretResponse = await sample.DataClient.GetSecretWithHttpMessagesAsync(vaultUri, secretName, secretVersion: String.Empty).ConfigureAwait(false);
Response<KeyVaultSecret> retrievedSecretResponse = await secretClient.GetSecretAsync(secretName);
Console.WriteLine("done.");

// confirm recovery is possible
Console.Write("Verifying the secret deletion is recoverable...");
var recoveryLevel = retrievedSecretResponse.Body.Attributes.RecoveryLevel;
var recoveryLevel = retrievedSecretResponse.Value.Properties.RecoveryLevel;
if (!recoveryLevel.ToLowerInvariant().Contains("Recoverable".ToLowerInvariant()))
{
Console.WriteLine("failed; soft-delete is not enabled for this vault.");
Expand All @@ -79,64 +83,41 @@ public static async Task DemonstrateRecoveryAndPurgeAsync()
}
Console.WriteLine("done.");


// delete secret
Console.Write("Deleting secret...");
await sample.DataClient.DeleteSecretWithHttpMessagesAsync(vaultUri, secretName).ConfigureAwait(false);
Console.WriteLine("done.");
DeleteSecretOperation deleteSecretOperation = await secretClient.StartDeleteSecretAsync(secretName);

// retrieve deleted secret; recoverable deletion is an asynchronous operation, during which the secret
// is not accessible, either as an active entity or a deleted one. Polling for up to 45s should be sufficient.
Console.Write("Retrieving the deleted secret...");
AzureOperationResponse<DeletedSecretBundle> deletedSecretResponse = null;
await RetryHttpRequestAsync(
async () => { return deletedSecretResponse = await sample.DataClient.GetDeletedSecretWithHttpMessagesAsync(vaultUri, secretName).ConfigureAwait(false); },
"get deleted secret",
SampleConstants.RetryPolicies.DefaultSoftDeleteRetryPolicy)
.ConfigureAwait(false);
// When deleting a secret asynchronously before you purge it, you can await the WaitForCompletionAsync method on the operation
await deleteSecretOperation.WaitForCompletionAsync();
Console.WriteLine("done.");

// recover secret
Console.Write("Recovering deleted secret...");
var recoveredSecretResponse = await sample.DataClient.RecoverDeletedSecretWithHttpMessagesAsync(vaultUri, secretName).ConfigureAwait(false);
RecoverDeletedSecretOperation recoverDeletedSecretOperation = await secretClient.StartRecoverDeletedSecretAsync(secretName);
await recoverDeletedSecretOperation.WaitForCompletionAsync();
Console.WriteLine("done.");

// confirm recovery
Console.Write("Retrieving recovered secret...");
await RetryHttpRequestAsync(
async () => { return retrievedSecretResponse = await sample.DataClient.GetSecretWithHttpMessagesAsync(vaultUri, secretName, secretVersion: String.Empty).ConfigureAwait(false); },
"recover deleted secret",
SampleConstants.RetryPolicies.DefaultSoftDeleteRetryPolicy)
.ConfigureAwait(false);
await secretClient.GetSecretAsync(secretName);
Console.WriteLine("done.");

// delete secret
Console.Write("Deleting secret (pass #2)...");
await sample.DataClient.DeleteSecretWithHttpMessagesAsync(vaultUri, secretName).ConfigureAwait(false);
Console.Write("Deleting recorvered secret...");
DeleteSecretOperation deleteRecoveredSecretOperation = await secretClient.StartDeleteSecretAsync(secretName);
await deleteRecoveredSecretOperation.WaitForCompletionAsync();
Console.WriteLine("done.");

// retrieve deleted secret
Console.Write("Retrieving the deleted secret (pass #2)...");
await RetryHttpRequestAsync(
async () => { return deletedSecretResponse = await sample.DataClient.GetDeletedSecretWithHttpMessagesAsync(vaultUri, secretName); },
"get deleted secret",
SampleConstants.RetryPolicies.DefaultSoftDeleteRetryPolicy)
.ConfigureAwait(false);
Console.WriteLine("done.");

// purge secret
Console.Write("Purging deleted secret...");
await sample.DataClient.PurgeDeletedSecretWithHttpMessagesAsync(vaultUri, secretName).ConfigureAwait(false);
Console.Write("Retrieving the deleted secret...");
await secretClient.GetDeletedSecretAsync(secretName);
Console.WriteLine("done.");
}
catch (KeyVaultErrorException kvee)
{
Console.WriteLine("Unexpected KeyVault exception encountered: {0}", kvee.Message);
catch (RequestFailedException ex)

throw;
}
catch (CloudException ce)
{
Console.WriteLine("Unexpected ARM exception encountered: {0}", ce.Message);
Console.WriteLine("Unexpected Key Vault exception encountered: {0}", ex.Message);

throw;
}
Expand Down Expand Up @@ -166,50 +147,48 @@ public static async Task DemonstrateBackupAndRestoreAsync()
// retrieve the vault (or create, if it doesn't exist)
var vault = await sample.CreateOrRetrieveVaultAsync(rgName, vaultName, enableSoftDelete: false, enablePurgeProtection: false);
var vaultUri = vault.Properties.VaultUri;

SecretClient secretClient = sample.GetDataClient(new Uri(vaultUri));

Console.WriteLine("Operating with vault name '{0}' in resource group '{1}' and location '{2}'", vaultName, rgName, vault.Location);

try
{
// set a secret
Console.Write("Setting a new value for secret '{0}'...", secretName);
var secretResponse = await sample.DataClient.SetSecretWithHttpMessagesAsync(vaultUri, secretName, Guid.NewGuid().ToString()).ConfigureAwait(false);
await secretClient.SetSecretAsync(secretName, Guid.NewGuid().ToString());
Console.WriteLine("done.");

// confirm existence
Console.Write("Verifying secret creation...");
var retrievedSecretResponse = await sample.DataClient.GetSecretWithHttpMessagesAsync(vaultUri, secretName, secretVersion: String.Empty).ConfigureAwait(false);
await secretClient.GetSecretAsync(secretName);
Console.WriteLine("done.");

// backup secret
Console.Write("Backing up secret...");
var backupResponse = await sample.DataClient.BackupSecretWithHttpMessagesAsync(vaultUri, secretName).ConfigureAwait(false);
Response<byte[]> backupResponse = await secretClient.BackupSecretAsync(secretName);
Console.WriteLine("done.");

// delete secret
Console.Write("Deleting secret...");
await sample.DataClient.DeleteSecretWithHttpMessagesAsync(vaultUri, secretName).ConfigureAwait(false);
DeleteSecretOperation deleteSecretOperation = await secretClient.StartDeleteSecretAsync(secretName);
// When deleting a secret asynchronously before you purge it, you can await the WaitForCompletionAsync method on the operation
await deleteSecretOperation.WaitForCompletionAsync();
Console.WriteLine("done.");

// restore secret
Console.Write("Restoring secret from backup...");
byte[] secretBackup = backupResponse.Body.Value;
var restoreResponse = await sample.DataClient.RestoreSecretWithHttpMessagesAsync(vaultUri, secretBackup).ConfigureAwait(false);
await secretClient.RestoreSecretBackupAsync(backupResponse.Value);
Console.WriteLine("done.");

// confirm existence
Console.Write("Verifying secret restoration...");
retrievedSecretResponse = await sample.DataClient.GetSecretWithHttpMessagesAsync(vaultUri, secretName, secretVersion: String.Empty).ConfigureAwait(false);
await secretClient.GetSecretAsync(secretName);
Console.WriteLine("done.");
}
catch (KeyVaultErrorException kvee)
{
Console.WriteLine("Unexpected KeyVault exception encountered: {0}", kvee.Message);

throw;
}
catch (CloudException ce)
catch (RequestFailedException ex)
{
Console.WriteLine("Unexpected ARM exception encountered: {0}", ce.Message);
Console.WriteLine("Unexpected Key Vault exception encountered: {0}", ex.Message);

throw;
}
Expand Down
12 changes: 6 additions & 6 deletions KeyVaultRecoverySamples.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
using System;
using Microsoft.Azure.Management.KeyVault.Fluent;
using Microsoft.Azure.Management.KeyVault.Fluent.Models;
using Microsoft.Azure.Management.ResourceManager.Fluent;
using System;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Azure.Management.KeyVault.Fluent;
using Microsoft.Azure.Management.KeyVault.Fluent.Models;
using Microsoft.Azure.Management.ResourceManager.Fluent;

namespace AzureKeyVaultRecoverySamples
{
Expand All @@ -25,7 +25,7 @@ public sealed class KeyVaultRecoverySamples : KeyVaultSampleBase
/// <param name="resourceGroupName">Resource group name.</param>
/// <param name="vaultLocation">Location of the vault.</param>
/// <param name="vaultName">Vault name.</param>
public KeyVaultRecoverySamples( string tenantId, string objectId, string appId, string appCredX5T, string subscriptionId, string resourceGroupName, string vaultLocation, string vaultName )
public KeyVaultRecoverySamples(string tenantId, string objectId, string appId, string appCredX5T, string subscriptionId, string resourceGroupName, string vaultLocation, string vaultName)
: base(tenantId, objectId, appId, appCredX5T, subscriptionId, resourceGroupName, vaultLocation, vaultName)
{ }

Expand Down Expand Up @@ -79,7 +79,7 @@ public static async Task DemonstrateRecoveryAndPurgeForNewVaultAsync()
Console.WriteLine("done.");

// confirm the existence of the deleted vault
Console.Write("Retrieving deleted vault...");
Console.Write("Retrieving deleted vault...");
deletedVault = await sample.ManagementClient.Vaults.GetDeletedAsync(vaultName, retrievedVault.Location).ConfigureAwait(false);
Console.WriteLine("done; '{0}' deleted on: {1}, scheduled for purge on: {2}", deletedVault.Id, deletedVault.Properties.DeletionDate, deletedVault.Properties.ScheduledPurgeDate);

Expand Down
39 changes: 14 additions & 25 deletions KeyVaultSampleBase.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
using System;
using Azure;
using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
using Microsoft.Azure.Management.KeyVault.Fluent;
using Microsoft.Azure.Management.KeyVault.Fluent.Models;
using Microsoft.Rest;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Azure.KeyVault;
using Microsoft.Azure.KeyVault.Models;
using Microsoft.Azure.Management.KeyVault.Fluent;
using Microsoft.Azure.Management.KeyVault.Fluent.Models;
using Microsoft.Rest;

namespace AzureKeyVaultRecoverySamples
{
Expand All @@ -30,7 +31,10 @@ public class KeyVaultSampleBase
/// <summary>
/// KeyVault data (Data Plane) client instance.
/// </summary>
public KeyVaultClient DataClient { get; private set; }
public SecretClient GetDataClient(Uri vaultUri)
{
return new SecretClient(vaultUri, new DefaultAzureCredential());
}

/// <summary>
/// Builds a sample object from the specified parameters.
Expand Down Expand Up @@ -75,10 +79,7 @@ private void InstantiateSample(string tenantId, string objectId, string appId, s

// instantiate the management client
ManagementClient = new KeyVaultManagementClient(serviceCredentials);
ManagementClient.SubscriptionId = subscriptionId;

// instantiate the data client
DataClient = new KeyVaultClient(ClientContext.AcquireTokenAsync);
ManagementClient.SubscriptionId = subscriptionId;
}

#region utilities
Expand Down Expand Up @@ -139,23 +140,11 @@ public async Task EnableRecoveryOptionsOnExistingVaultAsync(string resourceGroup
if (vault.Properties.EnableSoftDelete.HasValue
&& vault.Properties.EnableSoftDelete.Value)
{
//if (!(vault.Properties.EnablePurgeProtection ^ enablePurgeProtection))
//{
Console.WriteLine("The required recovery protection level is already enabled on vault {0}.", vaultName);

return;
//}

// check if this is an attempt to lower the recovery level.
//if (vault.Properties.EnablePurgeProtection
// && !enablePurgeProtection)
//{
// throw new InvalidOperationException("The recovery level on an existing vault cannot be lowered.");
//}
}

vault.Properties.EnableSoftDelete = true;
//vault.Properties.EnablePurgeProtection = enablePurgeProtection;

// prepare the update operation on the vault
var updateParameters = new VaultCreateOrUpdateParametersInner
Expand Down Expand Up @@ -228,9 +217,9 @@ public async static Task<HttpOperationResponse> RetryHttpRequestAsync(

break;
}
catch (KeyVaultErrorException kvee)
catch (RequestFailedException kvee)
{
var statusCode = kvee.Response.StatusCode;
HttpStatusCode statusCode = (HttpStatusCode)kvee.Status;

Console.Write("attempt #{0} to {1} returned: {2};", idx, functionName, statusCode);
if (continueOn.Contains(statusCode))
Expand Down
Loading

0 comments on commit 589d10a

Please sign in to comment.