From 66deb6fb6a7b0a889f67723e2e42dabcbc45b040 Mon Sep 17 00:00:00 2001 From: Beisi Zhou Date: Thu, 13 Jan 2022 17:11:21 +0800 Subject: [PATCH] wip --- src/Accounts/Accounts.sln | 24 +++ src/Accounts/Accounts/Accounts.csproj | 7 +- src/Accounts/Accounts/Directory.Build.targets | 4 +- .../Authentication/Authentication.csproj | 7 +- .../Authentication/AzureTokenCredential.cs | 37 ++++ .../Authentication/RenewingTokenCredential.cs | 5 +- .../Extensions/ArmClientOptionExtension.cs | 80 +++++++++ .../Extensions/ServiceClientExtension.cs | 49 +---- .../Factories/AuthenticationFactory.cs | 81 +++++++++ .../Authentication/Factories/ClientFactory.cs | 55 ++++++ .../AzPsHttpPipelineSynchronousPolicy.cs | 48 +++++ .../Authentication/Policy/HttpRetryTimes.cs | 52 ++++++ src/KeyVault/KeyVault.sln | 24 +++ .../KeyVault/Commands/GetAzureKeyVault.cs | 3 +- src/KeyVault/KeyVault/KeyVault.csproj | 10 +- .../KeyVault/Models/KeyVaultCmdletBase.cs | 1 + .../Models/KeyVaultManagementCmdletBase.cs | 14 +- src/KeyVault/KeyVault/Models/PSKeyVault.cs | 31 ++++ .../Models/VaultCreationOrUpdateParameters.cs | 170 +++++++++++++++++- .../Track2KeyVaultManagementClient.cs | 40 +++++ .../Track2ManagedHsmManagementClient.cs | 10 ++ .../Track2ModelConvertionExtensions.cs | 72 ++++++++ .../Track2Models/Track2TokenCredential.cs | 11 +- .../Track2VaultManagementClient.cs | 67 +++++++ tools/Common.Netcore.Dependencies.targets | 9 +- .../MockCertificateAuthenticationFactory.cs | 17 ++ .../Mocks/MockClientFactory.cs | 11 ++ .../Mocks/MockTokenAuthenticationFactory.cs | 17 ++ tools/TestFx/TestClientFactory.cs | 11 +- 29 files changed, 899 insertions(+), 68 deletions(-) create mode 100644 src/Accounts/Authentication/Authentication/AzureTokenCredential.cs create mode 100644 src/Accounts/Authentication/Extensions/ArmClientOptionExtension.cs create mode 100644 src/Accounts/Authentication/Policy/AzPsHttpPipelineSynchronousPolicy.cs create mode 100644 src/Accounts/Authentication/Policy/HttpRetryTimes.cs create mode 100644 src/KeyVault/KeyVault/Track2Models/Track2KeyVaultManagementClient.cs create mode 100644 src/KeyVault/KeyVault/Track2Models/Track2ManagedHsmManagementClient.cs create mode 100644 src/KeyVault/KeyVault/Track2Models/Track2VaultManagementClient.cs diff --git a/src/Accounts/Accounts.sln b/src/Accounts/Accounts.sln index 08af4b6e000f..63a3ae757b79 100644 --- a/src/Accounts/Accounts.sln +++ b/src/Accounts/Accounts.sln @@ -22,6 +22,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Authentication.Test", "Auth EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AuthenticationAssemblyLoadContext", "AuthenticationAssemblyLoadContext\AuthenticationAssemblyLoadContext.csproj", "{D06EF9FC-4C3E-4A51-A4AD-D39AD426EF8C}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Authentication.Abstractions", "..\..\..\azure-powershell-common\src\Authentication.Abstractions\Authentication.Abstractions.csproj", "{97A8C183-F5DF-466D-B45B-B7FF70C04639}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Common", "..\..\..\azure-powershell-common\src\Common\Common.csproj", "{E464D47C-DF5C-4B52-910E-59D326E0C1F7}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Graph.Rbac", "..\..\..\azure-powershell-common\src\Graph.Rbac\Graph.Rbac.csproj", "{A49450CD-4FC5-430B-BE9C-B3272E0981EB}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ResourceManager", "..\..\..\azure-powershell-common\src\ResourceManager\ResourceManager.csproj", "{E05F1B15-5799-4864-8D20-CA8F04AB50EB}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -64,6 +72,22 @@ Global {D06EF9FC-4C3E-4A51-A4AD-D39AD426EF8C}.Debug|Any CPU.Build.0 = Debug|Any CPU {D06EF9FC-4C3E-4A51-A4AD-D39AD426EF8C}.Release|Any CPU.ActiveCfg = Release|Any CPU {D06EF9FC-4C3E-4A51-A4AD-D39AD426EF8C}.Release|Any CPU.Build.0 = Release|Any CPU + {97A8C183-F5DF-466D-B45B-B7FF70C04639}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {97A8C183-F5DF-466D-B45B-B7FF70C04639}.Debug|Any CPU.Build.0 = Debug|Any CPU + {97A8C183-F5DF-466D-B45B-B7FF70C04639}.Release|Any CPU.ActiveCfg = Release|Any CPU + {97A8C183-F5DF-466D-B45B-B7FF70C04639}.Release|Any CPU.Build.0 = Release|Any CPU + {E464D47C-DF5C-4B52-910E-59D326E0C1F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E464D47C-DF5C-4B52-910E-59D326E0C1F7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E464D47C-DF5C-4B52-910E-59D326E0C1F7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E464D47C-DF5C-4B52-910E-59D326E0C1F7}.Release|Any CPU.Build.0 = Release|Any CPU + {A49450CD-4FC5-430B-BE9C-B3272E0981EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A49450CD-4FC5-430B-BE9C-B3272E0981EB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A49450CD-4FC5-430B-BE9C-B3272E0981EB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A49450CD-4FC5-430B-BE9C-B3272E0981EB}.Release|Any CPU.Build.0 = Release|Any CPU + {E05F1B15-5799-4864-8D20-CA8F04AB50EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E05F1B15-5799-4864-8D20-CA8F04AB50EB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E05F1B15-5799-4864-8D20-CA8F04AB50EB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E05F1B15-5799-4864-8D20-CA8F04AB50EB}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Accounts/Accounts/Accounts.csproj b/src/Accounts/Accounts/Accounts.csproj index a9e7a81f1f0f..08dbe4c7215b 100644 --- a/src/Accounts/Accounts/Accounts.csproj +++ b/src/Accounts/Accounts/Accounts.csproj @@ -46,9 +46,12 @@ - + + + + - + True diff --git a/src/Accounts/Accounts/Directory.Build.targets b/src/Accounts/Accounts/Directory.Build.targets index fa3748d4339a..e672a08e92f7 100644 --- a/src/Accounts/Accounts/Directory.Build.targets +++ b/src/Accounts/Accounts/Directory.Build.targets @@ -1,8 +1,8 @@ - + diff --git a/src/Accounts/Authentication/Authentication.csproj b/src/Accounts/Authentication/Authentication.csproj index 388c5e5f8e2e..9535656a502a 100644 --- a/src/Accounts/Authentication/Authentication.csproj +++ b/src/Accounts/Authentication/Authentication.csproj @@ -14,7 +14,12 @@ - + + + + + + True diff --git a/src/Accounts/Authentication/Authentication/AzureTokenCredential.cs b/src/Accounts/Authentication/Authentication/AzureTokenCredential.cs new file mode 100644 index 000000000000..837f83cdf85e --- /dev/null +++ b/src/Accounts/Authentication/Authentication/AzureTokenCredential.cs @@ -0,0 +1,37 @@ +using Azure.Core; + +using Microsoft.Azure.Commands.Common.Authentication.Abstractions; + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.Azure.Commands.Common.Authentication.Authentication +{ + public class AzureTokenCredential : TokenCredential + { + public string AccessToken { get; set; } + + private readonly Func GetTokenImpl; + + public AzureTokenCredential(string accessToken, Func getTokenImpl = null) + { + AccessToken = accessToken; + GetTokenImpl = getTokenImpl; + } + + public override AccessToken GetToken(TokenRequestContext requestContext, CancellationToken cancellationToken) + { + return new AccessToken(GetTokenImpl == null ? AccessToken : GetTokenImpl(), + DateTimeOffset.UtcNow); + } + + public override ValueTask GetTokenAsync(TokenRequestContext requestContext, CancellationToken cancellationToken) + { + return new ValueTask(this.GetToken(requestContext, cancellationToken)); + } + } +} diff --git a/src/Accounts/Authentication/Authentication/RenewingTokenCredential.cs b/src/Accounts/Authentication/Authentication/RenewingTokenCredential.cs index a8fbf1b4df86..8b53d53b972d 100644 --- a/src/Accounts/Authentication/Authentication/RenewingTokenCredential.cs +++ b/src/Accounts/Authentication/Authentication/RenewingTokenCredential.cs @@ -1,4 +1,7 @@ -// ---------------------------------------------------------------------------------- + + + +// ---------------------------------------------------------------------------------- // // Copyright Microsoft Corporation // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/src/Accounts/Authentication/Extensions/ArmClientOptionExtension.cs b/src/Accounts/Authentication/Extensions/ArmClientOptionExtension.cs new file mode 100644 index 000000000000..d57647ac4324 --- /dev/null +++ b/src/Accounts/Authentication/Extensions/ArmClientOptionExtension.cs @@ -0,0 +1,80 @@ +using Azure.Core; +using Azure.Core.Pipeline; +using Azure.ResourceManager; + +using Microsoft.Azure.Commands.Common.Authentication.Policy; +using Microsoft.WindowsAzure.Commands.Utilities.Common; + +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Threading; +using System.Threading.Tasks; + +using static Azure.Core.HttpHeader; + +namespace Microsoft.Azure.Commands.Common.Authentication.Extensions +{ + internal static class ArmClientOptionExtension + { + + internal class AzPsHttpMessageHandler : HttpMessageHandler + { + private IEnumerable _userAgent; + + public AzPsHttpMessageHandler(IEnumerable userAgent) + { + _userAgent = userAgent; + } + protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + _userAgent?.ForEach((agent) => { + request.Headers.UserAgent.Add(agent); + }); + + return SendAsync(request, cancellationToken); + } + } + + /// + /// Set max retry times of retry after handler that is used to handle the response with retry-after header + /// from environement variable AZURE_PS_HTTP_MAX_RETRIES_FOR_429 + /// + /// Whether succeed to set max retry times or not + public static void AddUserAgent(this ArmClientOptions option, ProductInfoHeaderValue[] userAgent) + { + if (null == option.Transport || default(HttpPipelineTransport) == option.Transport) + { + option.Transport = new HttpClientTransport(new AzPsHttpMessageHandler(userAgent)); + } + else + { + throw new Exception("Client Transport already has defined."); + } + } + + /// + /// Set max retry times of retry after handler that is used to handle the response with retry-after header + /// from environement variable AZURE_PS_HTTP_MAX_RETRIES_FOR_429 + /// + /// Whether succeed to set max retry times or not + public static void SetMaxDelayForRetryOption(this ArmClientOptions option, int maxDelay) + { + int? maxretriesfor429 = HttpRetryTimes.AzurePsHttpMaxRetriesFor429; + if (maxretriesfor429 != null && maxretriesfor429 >= 0) + { + option.Retry.MaxDelay = new TimeSpan(); + } + } + + /// + /// Set max retry count of retry policy from environement variable AZURE_PS_HTTP_MAX_RETRIES + /// + /// Whether succeed to set retry count or not + public static void SetMaxRetryCountofRetryOption(this ArmClientOptions option, int maxRetries) + { + option.Retry.MaxRetries = maxRetries; + } + } +} diff --git a/src/Accounts/Authentication/Extensions/ServiceClientExtension.cs b/src/Accounts/Authentication/Extensions/ServiceClientExtension.cs index 013b4b323129..0946ed016d62 100644 --- a/src/Accounts/Authentication/Extensions/ServiceClientExtension.cs +++ b/src/Accounts/Authentication/Extensions/ServiceClientExtension.cs @@ -12,6 +12,7 @@ // limitations under the License. // ---------------------------------------------------------------------------------- +using Microsoft.Azure.Commands.Common.Authentication.Policy; using Microsoft.Rest.TransientFaultHandling; using System; @@ -19,52 +20,6 @@ namespace Microsoft.Azure.Commands.Common.Authentication.Abstractions { internal static class ServiceClientExtension { - private class HttpRetryTimes - { - private const string maxRetriesVariableName = "AZURE_PS_HTTP_MAX_RETRIES"; - private const string maxRetriesFor429VariableName = "AZURE_PS_HTTP_MAX_RETRIES_FOR_429"; - - public static int? AzurePsHttpMaxRetries - { - get - { - return TryGetAzurePsHttpMaxRetries(); - } - } - public static int? AzurePsHttpMaxRetriesFor429 - { - get - { - return TryGetAzurePsHttpMaxRetriesFor429(); - } - } - - private static int? TryGetValue(string environmentVariable) - { - int? retries = null; - var value = Environment.GetEnvironmentVariable(environmentVariable); - if (value != null) - { - int valueParsed = int.MinValue; - if (int.TryParse(value, out valueParsed)) - { - retries = valueParsed; - } - } - return retries; - } - - private static int? TryGetAzurePsHttpMaxRetries() - { - return TryGetValue(maxRetriesVariableName); - } - - private static int? TryGetAzurePsHttpMaxRetriesFor429() - { - return TryGetValue(maxRetriesFor429VariableName); - } - } - private static bool SetMaxTimesForRetryAfterHandler(this Microsoft.Rest.ServiceClient serviceClient, uint retrytimes) where TClient : Microsoft.Rest.ServiceClient { bool findRetryHandler = false; @@ -101,7 +56,7 @@ public static bool TrySetMaxTimesForRetryAfterHandler(this Microsoft.Re /// Whether succeed to set retry count or not public static bool TrySetRetryCountofRetryPolicy(this Microsoft.Rest.ServiceClient serviceClient) where TClient : Microsoft.Rest.ServiceClient { - int? maxretries = ServiceClientExtension.HttpRetryTimes.AzurePsHttpMaxRetries; + int? maxretries = HttpRetryTimes.AzurePsHttpMaxRetries; if (maxretries != null && maxretries >= 0) { TimeSpan defaultBackoffDelta = new TimeSpan(0, 0, 10); diff --git a/src/Accounts/Authentication/Factories/AuthenticationFactory.cs b/src/Accounts/Authentication/Factories/AuthenticationFactory.cs index b9edba033041..16bac11c6822 100644 --- a/src/Accounts/Authentication/Factories/AuthenticationFactory.cs +++ b/src/Accounts/Authentication/Factories/AuthenticationFactory.cs @@ -12,6 +12,8 @@ // limitations under the License. // ---------------------------------------------------------------------------------- +using Azure.Core; + using Hyak.Common; using Microsoft.Azure.Commands.Common.Authentication.Abstractions; using Microsoft.Azure.Commands.Common.Authentication.Authentication; @@ -324,6 +326,85 @@ public SubscriptionCloudCredentials GetSubscriptionCloudCredentials(IAzureContex } } + public TokenCredential GetTokenCredential(IAzureContext context) => + GetTokenCredential(context, AzureEnvironment.Endpoint.ActiveDirectoryServiceEndpointResourceId); + + public TokenCredential GetTokenCredential(IAzureContext context, string targetEndpoint) + { + if (context == null) + { + throw new AzPSApplicationException("Azure context is empty"); + } + return GetTokenCredential(context, targetEndpoint, context.Environment.GetTokenAudience(targetEndpoint)); + } + + public TokenCredential GetTokenCredential(IAzureContext context, string targetEndpoint, string resourceId) + { + if (context.Account == null) + { + throw new AzPSArgumentException(Resources.ArmAccountNotFound, "context.Account", ErrorKind.UserError); + } + switch (context.Account.Type) + { + case AzureAccount.AccountType.Certificate: + throw new NotSupportedException(AzureAccount.AccountType.Certificate.ToString()); + case AzureAccount.AccountType.AccessToken: + return new AzureTokenCredential(GetEndpointToken(context.Account, targetEndpoint), + () => GetEndpointToken(context.Account, targetEndpoint)); + } + + string tenant = null; + + if (context.Subscription != null && context.Account != null) + { + tenant = context.Subscription.GetPropertyAsArray(AzureSubscription.Property.Tenants) + .Intersect(context.Account.GetPropertyAsArray(AzureAccount.Property.Tenants)) + .FirstOrDefault(); + } + + if (tenant == null && context.Tenant != null && new Guid(context.Tenant.Id) != Guid.Empty) + { + tenant = context.Tenant.Id.ToString(); + } + + if (tenant == null) + { + throw new ArgumentException(Resources.NoTenantInContext); + } + + try + { + TracingAdapter.Information(Resources.UPNAuthenticationTrace, + context.Account.Id, context.Environment.Name, tenant); + + IAccessToken accesstoken = null; + switch (context.Account.Type) + { + case AzureAccount.AccountType.ManagedService: + case AzureAccount.AccountType.User: + case AzureAccount.AccountType.ServicePrincipal: + case "ClientAssertion": + accesstoken = Authenticate(context.Account, context.Environment, tenant, null, ShowDialog.Never, null, resourceId); + break; + default: + throw new NotSupportedException(context.Account.Type.ToString()); + } + + TracingAdapter.Information(Resources.UPNAuthenticationTokenTrace, + accesstoken.LoginType, accesstoken.TenantId, accesstoken.UserId); + return new AzureTokenCredential(accesstoken.AccessToken); + } + catch (Exception ex) + { + TracingAdapter.Information(Resources.AdalAuthException, ex.Message); + throw new AzPSArgumentException(Resources.InvalidArmContext + System.Environment.NewLine + ex.Message, ex); + } + } + + public TokenCredential GetTokenCredential(string accessToken, Func renew = null) + { + return new AzureTokenCredential(accessToken, renew); + } public ServiceClientCredentials GetServiceClientCredentials(IAzureContext context) { diff --git a/src/Accounts/Authentication/Factories/ClientFactory.cs b/src/Accounts/Authentication/Factories/ClientFactory.cs index cb841ec16171..abc592902cce 100644 --- a/src/Accounts/Authentication/Factories/ClientFactory.cs +++ b/src/Accounts/Authentication/Factories/ClientFactory.cs @@ -12,12 +12,18 @@ // limitations under the License. // ---------------------------------------------------------------------------------- +using Azure.Core; +using Azure.Core.Pipeline; +using Azure.ResourceManager; + using Hyak.Common; using Microsoft.Azure.Commands.Common.Authentication.Abstractions; #if NETSTANDARD using Microsoft.Azure.Commands.Common.Authentication.Abstractions.Core; +using Microsoft.Azure.Commands.Common.Authentication.Extensions; #endif using Microsoft.Azure.Commands.Common.Authentication.Models; +using Microsoft.Azure.Commands.Common.Authentication.Policy; using Microsoft.Azure.Commands.Common.Authentication.Properties; using Microsoft.Azure.Commands.Common.Exceptions; using System; @@ -72,6 +78,54 @@ public virtual TClient CreateArmClient(IAzureContext context, string en return client; } + public virtual ArmClient CreateArmClient(IAzureContext context, + string endpoint = AzureEnvironment.Endpoint.ActiveDirectoryServiceEndpointResourceId) + { + if (context == null) + { + throw new AzPSApplicationException(Resources.NoSubscriptionInContext, ErrorKind.UserError); + } + + return CreateCustomArmClient(context, endpoint); + } + + public virtual ArmClient CreateCustomArmClient(IAzureContext context, + string endpoint = AzureEnvironment.Endpoint.ActiveDirectoryServiceEndpointResourceId, + ArmClientOptions option = null) + { + if (context == null) + { + throw new AzPSApplicationException(Resources.NoSubscriptionInContext, ErrorKind.UserError); + } + + option = option ?? new ArmClientOptions(); + // Add Azure PowerShell policy into option + + // Add user agents + if (UserAgents != null && UserAgents.Length >= 0) + { + option.AddUserAgent(UserAgents); + } + + // Set max retries + int? maxRetries = HttpRetryTimes.AzurePsHttpMaxRetries; + if (maxRetries != null && maxRetries >= 0) + { + option.SetMaxRetryCountofRetryOption((int)maxRetries); + } + + // Set max delay + + int? maxretriesfor429 = HttpRetryTimes.AzurePsHttpMaxRetriesFor429; + if (maxretriesfor429 != null && maxretriesfor429 >= 0) + { + option.SetMaxDelayForRetryOption((int)maxretriesfor429); + } + + var creds = AzureSession.Instance.AuthenticationFactory.GetTokenCredential(context, endpoint); + return new ArmClient(context.Subscription.Id.ToString(), creds, option); + } + public virtual TClient CreateCustomArmClient(params object[] parameters) where TClient : Microsoft.Rest.ServiceClient { List types = new List(); @@ -380,6 +434,7 @@ private static string GetProductInfoHeaderKey(string productName) } return productInfoHeaderKey; } + /// /// Adds user agent to UserAgents collection. /// diff --git a/src/Accounts/Authentication/Policy/AzPsHttpPipelineSynchronousPolicy.cs b/src/Accounts/Authentication/Policy/AzPsHttpPipelineSynchronousPolicy.cs new file mode 100644 index 000000000000..567524b3ba02 --- /dev/null +++ b/src/Accounts/Authentication/Policy/AzPsHttpPipelineSynchronousPolicy.cs @@ -0,0 +1,48 @@ +using Azure.Core; +using Azure.Core.Pipeline; + +using Microsoft.WindowsAzure.Commands.Utilities.Common; + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +using static Azure.Core.HttpHeader; + +namespace Microsoft.Azure.Commands.Common.Authentication.Policy +{ + internal class AzPsHttpPipelineSynchronousPolicy: HttpPipelineSynchronousPolicy + { + private IList userAgents; + + public AzPsHttpPipelineSynchronousPolicy() + { + userAgents = new List(); + } + + public void AddUserAgent(ProductInfoHeaderValue userAgent) + { + userAgents.Add(userAgent); + } + + public void AddUserAgent(ProductInfoHeaderValue[] userAgent) + { + userAgents?.ForEach((agent) => { + userAgents.Add(agent); + }); + } + + public override void OnSendingRequest(HttpMessage message) + { + userAgents?.ForEach((agent)=> { + message.Request.Headers.Add(Names.UserAgent, agent.ToString()); + }); + } + + } +} diff --git a/src/Accounts/Authentication/Policy/HttpRetryTimes.cs b/src/Accounts/Authentication/Policy/HttpRetryTimes.cs new file mode 100644 index 000000000000..2170a40faa65 --- /dev/null +++ b/src/Accounts/Authentication/Policy/HttpRetryTimes.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Microsoft.Azure.Commands.Common.Authentication.Policy +{ + internal class HttpRetryTimes + { + private const string maxRetriesVariableName = "AZURE_PS_HTTP_MAX_RETRIES"; + private const string maxRetriesFor429VariableName = "AZURE_PS_HTTP_MAX_RETRIES_FOR_429"; + + public static int? AzurePsHttpMaxRetries + { + get + { + return TryGetAzurePsHttpMaxRetries(); + } + } + public static int? AzurePsHttpMaxRetriesFor429 + { + get + { + return TryGetAzurePsHttpMaxRetriesFor429(); + } + } + + private static int? TryGetValue(string environmentVariable) + { + int? retries = null; + var value = Environment.GetEnvironmentVariable(environmentVariable); + if (value != null) + { + int valueParsed = int.MinValue; + if (int.TryParse(value, out valueParsed)) + { + retries = valueParsed; + } + } + return retries; + } + + private static int? TryGetAzurePsHttpMaxRetries() + { + return TryGetValue(maxRetriesVariableName); + } + + private static int? TryGetAzurePsHttpMaxRetriesFor429() + { + return TryGetValue(maxRetriesFor429VariableName); + } + } +} diff --git a/src/KeyVault/KeyVault.sln b/src/KeyVault/KeyVault.sln index 55dc33aeb681..5941cc4e1fda 100644 --- a/src/KeyVault/KeyVault.sln +++ b/src/KeyVault/KeyVault.sln @@ -20,6 +20,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ScenarioTest.ResourceManage EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestFx", "..\..\tools\TestFx\TestFx.csproj", "{BC80A1D0-FFA4-43D9-AA74-799F5CB54B58}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Authentication.Abstractions", "..\..\..\azure-powershell-common\src\Authentication.Abstractions\Authentication.Abstractions.csproj", "{2075B9EE-EFCF-47B8-81F9-A8F20BE448CE}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Common", "..\..\..\azure-powershell-common\src\Common\Common.csproj", "{399BABE1-C102-46EA-8245-B1FCC2E96315}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Graph.Rbac", "..\..\..\azure-powershell-common\src\Graph.Rbac\Graph.Rbac.csproj", "{1E118AF8-366F-414D-BC71-0A9456FB0237}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ResourceManager", "..\..\..\azure-powershell-common\src\ResourceManager\ResourceManager.csproj", "{BDAC6B32-B466-4D48-862F-B57BC5180466}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -58,6 +66,22 @@ Global {BC80A1D0-FFA4-43D9-AA74-799F5CB54B58}.Debug|Any CPU.Build.0 = Debug|Any CPU {BC80A1D0-FFA4-43D9-AA74-799F5CB54B58}.Release|Any CPU.ActiveCfg = Release|Any CPU {BC80A1D0-FFA4-43D9-AA74-799F5CB54B58}.Release|Any CPU.Build.0 = Release|Any CPU + {0EF04F42-C0BA-4E13-858C-E61E2B9FF50A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0EF04F42-C0BA-4E13-858C-E61E2B9FF50A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0EF04F42-C0BA-4E13-858C-E61E2B9FF50A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0EF04F42-C0BA-4E13-858C-E61E2B9FF50A}.Release|Any CPU.Build.0 = Release|Any CPU + {6F00993F-EE39-46D7-9FA2-1D9F5DCC61A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6F00993F-EE39-46D7-9FA2-1D9F5DCC61A3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6F00993F-EE39-46D7-9FA2-1D9F5DCC61A3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6F00993F-EE39-46D7-9FA2-1D9F5DCC61A3}.Release|Any CPU.Build.0 = Release|Any CPU + {C55DD13C-A383-4D4F-AA02-7154A866853E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C55DD13C-A383-4D4F-AA02-7154A866853E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C55DD13C-A383-4D4F-AA02-7154A866853E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C55DD13C-A383-4D4F-AA02-7154A866853E}.Release|Any CPU.Build.0 = Release|Any CPU + {D3FE5CA5-206C-401E-92BF-1B3FCD356D2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D3FE5CA5-206C-401E-92BF-1B3FCD356D2F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D3FE5CA5-206C-401E-92BF-1B3FCD356D2F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D3FE5CA5-206C-401E-92BF-1B3FCD356D2F}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/KeyVault/KeyVault/Commands/GetAzureKeyVault.cs b/src/KeyVault/KeyVault/Commands/GetAzureKeyVault.cs index c028d6a1a896..eeef30d13f45 100644 --- a/src/KeyVault/KeyVault/Commands/GetAzureKeyVault.cs +++ b/src/KeyVault/KeyVault/Commands/GetAzureKeyVault.cs @@ -115,7 +115,8 @@ public override void ExecuteCmdlet() } else { - WriteObject(TopLevelWildcardFilter(ResourceGroupName, VaultName, ListVaults(ResourceGroupName, Tag)), true); + // WriteObject(TopLevelWildcardFilter(ResourceGroupName, VaultName, ListVaults(ResourceGroupName, Tag)), true); + WriteObject(this.Track2VaultManagementClient.ListVaults(ResourceGroupName)); } break; diff --git a/src/KeyVault/KeyVault/KeyVault.csproj b/src/KeyVault/KeyVault/KeyVault.csproj index 0de53f397778..cf19408070d6 100644 --- a/src/KeyVault/KeyVault/KeyVault.csproj +++ b/src/KeyVault/KeyVault/KeyVault.csproj @@ -13,14 +13,22 @@ - + + + + + + + + + True diff --git a/src/KeyVault/KeyVault/Models/KeyVaultCmdletBase.cs b/src/KeyVault/KeyVault/Models/KeyVaultCmdletBase.cs index fb9d8afddef6..e42c89e6f722 100644 --- a/src/KeyVault/KeyVault/Models/KeyVaultCmdletBase.cs +++ b/src/KeyVault/KeyVault/Models/KeyVaultCmdletBase.cs @@ -21,6 +21,7 @@ using Microsoft.Azure.Commands.Common.Authentication; using Microsoft.Azure.Commands.KeyVault.Track2Models; using Microsoft.Azure.Commands.ResourceManager.Common; +using Track2sdk = Azure.ResourceManager.KeyVault; namespace Microsoft.Azure.Commands.KeyVault.Models { diff --git a/src/KeyVault/KeyVault/Models/KeyVaultManagementCmdletBase.cs b/src/KeyVault/KeyVault/Models/KeyVaultManagementCmdletBase.cs index 90da7d04c64b..7ec1c5520493 100644 --- a/src/KeyVault/KeyVault/Models/KeyVaultManagementCmdletBase.cs +++ b/src/KeyVault/KeyVault/Models/KeyVaultManagementCmdletBase.cs @@ -40,14 +40,16 @@ using Microsoft.Azure.Commands.Common.MSGraph.Version1_0.DirectoryObjects; using Microsoft.Azure.Commands.KeyVault.Helpers; using Microsoft.WindowsAzure.Commands.Common.Attributes; +using Microsoft.Azure.Commands.KeyVault.Track2Models; namespace Microsoft.Azure.Commands.KeyVault { [SupportsSubscriptionId] public class KeyVaultManagementCmdletBase : AzureRMCmdlet { - private VaultManagementClient _keyVaultManagementClient; private DataServiceCredential _dataServiceCredential; + + private VaultManagementClient _keyVaultManagementClient; public VaultManagementClient KeyVaultManagementClient { get @@ -58,6 +60,16 @@ public VaultManagementClient KeyVaultManagementClient set { _keyVaultManagementClient = value; } } + private Track2VaultManagementClient _track2VaultManagementClient; + public Track2VaultManagementClient Track2VaultManagementClient + { + get + { + return _track2VaultManagementClient ?? (_track2VaultManagementClient = new Track2VaultManagementClient(AzureSession.Instance.ClientFactory, DefaultContext)); + } + + set { _track2VaultManagementClient = value; } + } private IMicrosoftGraphClient _graphClient; public IMicrosoftGraphClient GraphClient diff --git a/src/KeyVault/KeyVault/Models/PSKeyVault.cs b/src/KeyVault/KeyVault/Models/PSKeyVault.cs index b0be5b0ed9dd..39758db942b7 100644 --- a/src/KeyVault/KeyVault/Models/PSKeyVault.cs +++ b/src/KeyVault/KeyVault/Models/PSKeyVault.cs @@ -19,6 +19,7 @@ using System.Collections.Generic; using System.Linq; using Microsoft.Azure.Commands.Common.MSGraph.Version1_0; +using Track2ManagementSdk = Azure.ResourceManager.KeyVault; namespace Microsoft.Azure.Commands.KeyVault.Models { @@ -28,6 +29,36 @@ public PSKeyVault() { } + public PSKeyVault(Track2ManagementSdk.Vault vault, IMicrosoftGraphClient graphClient) + { + if (!vault.HasData) + { + vault = vault.Get(); + } + + VaultName = vault.Data.Name; + Location = vault.Data.Location; + ResourceId = vault.Data.Id; + ResourceGroupName = new ResourceIdentifier(ResourceId).ResourceGroupName; + Tags = TagsConversionHelper.CreateTagHashtable(vault.Data.Tags.ToDictionary(pair => pair.Key, pair => pair.Value)); + Sku = vault.Data.Properties.Sku.Name.ToString(); + TenantId = vault.Data.Properties.TenantId; + var vaultTenantDisplayName = ModelExtensions.GetDisplayNameForTenant(vault.Data.Properties.TenantId, graphClient); + TenantName = vaultTenantDisplayName; + VaultUri = vault.Data.Properties.VaultUri; + EnabledForDeployment = vault.Data.Properties.EnabledForDeployment ?? false; + EnabledForTemplateDeployment = vault.Data.Properties.EnabledForTemplateDeployment; + EnabledForDiskEncryption = vault.Data.Properties.EnabledForDiskEncryption; + EnableSoftDelete = vault.Data.Properties.EnableSoftDelete; + EnablePurgeProtection = vault.Data.Properties.EnablePurgeProtection; + EnableRbacAuthorization = vault.Data.Properties.EnableRbacAuthorization; + SoftDeleteRetentionInDays = vault.Data.Properties.SoftDeleteRetentionInDays; + AccessPolicies = vault.Data.Properties.AccessPolicies.Select(ap => new PSKeyVaultAccessPolicy(ap.ToTrack1AccessPolicyEntry(), graphClient)).ToArray(); + NetworkAcls = InitNetworkRuleSet(vault.Data.Properties.ToTrack1VaultProperties()); + OriginalVault = vault.ToTrack1Vault(); + } + + public PSKeyVault(Vault vault, IMicrosoftGraphClient graphClient) { var vaultTenantDisplayName = ModelExtensions.GetDisplayNameForTenant(vault.Properties.TenantId, graphClient); diff --git a/src/KeyVault/KeyVault/Models/VaultCreationOrUpdateParameters.cs b/src/KeyVault/KeyVault/Models/VaultCreationOrUpdateParameters.cs index ebbf0319ec75..45953d9ee49c 100644 --- a/src/KeyVault/KeyVault/Models/VaultCreationOrUpdateParameters.cs +++ b/src/KeyVault/KeyVault/Models/VaultCreationOrUpdateParameters.cs @@ -12,9 +12,14 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using Microsoft.Azure.Management.KeyVault.Models; using System; using System.Collections; +using Track2ManagementSdk = Azure.ResourceManager.KeyVault.Models; +using Track1ManagementSdk = Microsoft.Azure.Management.KeyVault.Models; +using System.ComponentModel; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Azure.Commands.ResourceManager.Common.Tags; namespace Microsoft.Azure.Commands.KeyVault.Models { @@ -34,9 +39,166 @@ public class VaultCreationOrUpdateParameters public bool? EnableRbacAuthorization { get; set; } public int? SoftDeleteRetentionInDays { get; set; } public Guid TenantId { get; set; } - public AccessPolicyEntry AccessPolicy { get; set; } - public NetworkRuleSet NetworkAcls { get; set; } - public CreateMode? CreateMode { get; set; } + public Track1ManagementSdk.AccessPolicyEntry AccessPolicy { get; set; } + public Track1ManagementSdk.NetworkRuleSet NetworkAcls { get; set; } + public Track1ManagementSdk.CreateMode? CreateMode { get; set; } public string[] Administrator { get; set; } + + public Track1ManagementSdk.VaultCreateOrUpdateParameters ToTrack1VaultCreateOrUpdateParameters( + PSKeyVaultNetworkRuleSet networkRuleSet = null) + { + if (string.IsNullOrWhiteSpace(Name)) + throw new ArgumentNullException("parameters.Name"); + if (string.IsNullOrWhiteSpace(ResourceGroupName)) + throw new ArgumentNullException("parameters.ResourceGroupName"); + if (string.IsNullOrWhiteSpace(Location)) + throw new ArgumentNullException("parameters.Location"); + + var properties = new Track1ManagementSdk.VaultProperties(); + + if (CreateMode != Track1ManagementSdk.CreateMode.Recover) + { + if (string.IsNullOrWhiteSpace(SkuFamilyName)) + throw new ArgumentNullException("parameters.SkuFamilyName"); + if (TenantId == Guid.Empty) + throw new ArgumentException("parameters.TenantId"); + if (!string.IsNullOrWhiteSpace(SkuName)) + { + if (Enum.TryParse(SkuName, true, out Track1ManagementSdk.SkuName skuName)) + { + properties.Sku = new Track1ManagementSdk.Sku(skuName); + } + else + { + throw new InvalidEnumArgumentException("parameters.SkuName"); + } + } + properties.EnabledForDeployment = EnabledForDeployment; + properties.EnabledForTemplateDeployment = EnabledForTemplateDeployment; + properties.EnabledForDiskEncryption = EnabledForDiskEncryption; + properties.EnableSoftDelete = EnableSoftDelete; + properties.EnablePurgeProtection = EnablePurgeProtection; + properties.EnableRbacAuthorization = EnableRbacAuthorization; + properties.SoftDeleteRetentionInDays = SoftDeleteRetentionInDays; + properties.TenantId = TenantId; + properties.VaultUri = ""; + properties.AccessPolicies = (AccessPolicy != null) ? new[] { AccessPolicy } : + new Track1ManagementSdk.AccessPolicyEntry[] { }; + + properties.NetworkAcls = NetworkAcls; + if (networkRuleSet != null) + { + UpdateVaultNetworkRuleSetProperties(properties, networkRuleSet); + } + } + else + { + properties.CreateMode = Track1ManagementSdk.CreateMode.Recover; + } + + return new Track1ManagementSdk.VaultCreateOrUpdateParameters + { + Location = Location, + Tags = TagsConversionHelper.CreateTagDictionary(Tags, validate: true), + Properties = properties + }; + } + + public Track2ManagementSdk.VaultCreateOrUpdateParameters ToTrack2VaultCreateOrUpdateParameters() + { + if (this == null) + throw new ArgumentNullException("parameters"); + if (string.IsNullOrWhiteSpace(Name)) + throw new ArgumentNullException("parameters.Name"); + if (string.IsNullOrWhiteSpace(ResourceGroupName)) + throw new ArgumentNullException("parameters.ResourceGroupName"); + if (string.IsNullOrWhiteSpace(Location)) + throw new ArgumentNullException("parameters.Location"); + + Track2ManagementSdk.Sku sku = null; + Track2ManagementSdk.VaultProperties properties = null; + + if (CreateMode != Track1ManagementSdk.CreateMode.Recover) + { + if (string.IsNullOrWhiteSpace(SkuFamilyName)) + throw new ArgumentNullException("parameters.SkuFamilyName"); + if (TenantId == Guid.Empty) + throw new ArgumentException("parameters.TenantId"); + + if (!string.IsNullOrWhiteSpace(SkuName) && !string.IsNullOrWhiteSpace(SkuFamilyName)) + { + if (Enum.TryParse(SkuName, true, out Track2ManagementSdk.SkuName skuName) && + Enum.TryParse(SkuFamilyName, true, out Track2ManagementSdk.SkuFamily skuFamily)) + { + sku = new Track2ManagementSdk.Sku(skuFamily, skuName); + } + else + { + throw new InvalidEnumArgumentException("parameters.SkuName"); + } + } + + properties = new Track2ManagementSdk.VaultProperties(TenantId, sku) + { + EnabledForDeployment = EnabledForDeployment, + EnabledForTemplateDeployment = EnabledForTemplateDeployment, + EnabledForDiskEncryption = EnabledForDiskEncryption, + EnableSoftDelete = EnableSoftDelete, + EnablePurgeProtection = EnablePurgeProtection, + EnableRbacAuthorization = EnableRbacAuthorization, + SoftDeleteRetentionInDays = SoftDeleteRetentionInDays, + TenantId = TenantId, + VaultUri = "" + }; + /*properties.AccessPolicies = (parameters.AccessPolicy != null) ? new[] { parameters.AccessPolicy } : + new Track1ManagementSdk.AccessPolicyEntry[] { }; + + properties.NetworkAcls = parameters.NetworkAcls; + if (networkRuleSet != null) + { + UpdateVaultNetworkRuleSetProperties(properties, networkRuleSet); + }*/ + } + else + { + properties.CreateMode = Track2ManagementSdk.CreateMode.Recover; + } + + return new Track2ManagementSdk.VaultCreateOrUpdateParameters(Location, properties); + } + + private void UpdateVaultNetworkRuleSetProperties(Track1ManagementSdk.VaultProperties vaultProperties, PSKeyVaultNetworkRuleSet psRuleSet) + { + if (vaultProperties == null) + return; + + var updatedRuleSet = new Track1ManagementSdk.NetworkRuleSet(); // It contains default settings + if (psRuleSet != null) + { + updatedRuleSet.DefaultAction = psRuleSet.DefaultAction.ToString(); + updatedRuleSet.Bypass = psRuleSet.Bypass.ToString(); + + if (psRuleSet.IpAddressRanges != null && psRuleSet.IpAddressRanges.Count > 0) + { + updatedRuleSet.IpRules = psRuleSet.IpAddressRanges.Select(ipAddress => new Track1ManagementSdk.IPRule { Value = ipAddress }).ToList(); + } + else + { // Send empty array [] to server to override default + updatedRuleSet.IpRules = new List(); + } + + if (psRuleSet.VirtualNetworkResourceIds != null && psRuleSet.VirtualNetworkResourceIds.Count > 0) + { + updatedRuleSet.VirtualNetworkRules = psRuleSet.VirtualNetworkResourceIds.Select(resourceId => new Track1ManagementSdk.VirtualNetworkRule { Id = resourceId }).ToList(); + } + else + { // Send empty array [] to server to override default + updatedRuleSet.VirtualNetworkRules = new List(); + } + } + + vaultProperties.NetworkAcls = updatedRuleSet; + } + } } diff --git a/src/KeyVault/KeyVault/Track2Models/Track2KeyVaultManagementClient.cs b/src/KeyVault/KeyVault/Track2Models/Track2KeyVaultManagementClient.cs new file mode 100644 index 000000000000..8aa9da8b66f0 --- /dev/null +++ b/src/KeyVault/KeyVault/Track2Models/Track2KeyVaultManagementClient.cs @@ -0,0 +1,40 @@ +using Azure.ResourceManager; +using Azure.ResourceManager.KeyVault; +using Azure.ResourceManager.KeyVault.Models; +using Azure.ResourceManager.Resources; + +using Microsoft.Azure.Commands.Common.Authentication; +using Microsoft.Azure.Commands.Common.Authentication.Abstractions; + +using System.Collections.Generic; + +namespace Microsoft.Azure.Commands.KeyVault.Track2Models +{ + internal class Track2KeyVaultManagementClient + { + private ArmClient _armClient; + private string _subscription; + private IClientFactory _clientFactory; + + public Track2KeyVaultManagementClient(IClientFactory clientFactory, IAzureContext context) + { + _clientFactory = clientFactory; + _armClient = _clientFactory.CreateArmClient(context, AzureEnvironment.Endpoint.ActiveDirectoryServiceEndpointResourceId); + _subscription = context.Subscription.Id; + } + + private ResourceGroup GetResourceGroup(string resourcegroup) => + _armClient.GetResourceGroup(new ResourceIdentifier( + string.Format("/subscriptions/{0}/resourceGroups/{1}", _subscription, resourcegroup))); + + public IEnumerable ListVaults(string resourcegroup) => + GetResourceGroup(resourcegroup).GetVaults().GetAll(); + + public Vault GetVault(string resourcegroup, string vaultName) => + _armClient.GetVault(Vault.CreateResourceIdentifier(_subscription, resourcegroup, vaultName)); + + public Vault CreateVault(string resourcegroup, string vaultName, VaultCreateOrUpdateParameters parameters) => + GetResourceGroup(resourcegroup).GetVaults().CreateOrUpdate(vaultName, parameters).Value; + + } +} diff --git a/src/KeyVault/KeyVault/Track2Models/Track2ManagedHsmManagementClient.cs b/src/KeyVault/KeyVault/Track2Models/Track2ManagedHsmManagementClient.cs new file mode 100644 index 000000000000..08f347e45d66 --- /dev/null +++ b/src/KeyVault/KeyVault/Track2Models/Track2ManagedHsmManagementClient.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Microsoft.Azure.Commands.KeyVault.Track2Models +{ + public class Track2ManagedHsmManagementClient + { + } +} diff --git a/src/KeyVault/KeyVault/Track2Models/Track2ModelConvertionExtensions.cs b/src/KeyVault/KeyVault/Track2Models/Track2ModelConvertionExtensions.cs index 4227bcdb4fde..932ddd456017 100644 --- a/src/KeyVault/KeyVault/Track2Models/Track2ModelConvertionExtensions.cs +++ b/src/KeyVault/KeyVault/Track2Models/Track2ModelConvertionExtensions.cs @@ -3,8 +3,11 @@ using System.Text; using Track2Sdk = Azure.Security.KeyVault.Keys; using Track1Sdk = Microsoft.Azure.KeyVault.WebKey; +using Track1ManagementSdk = Microsoft.Azure.Management.KeyVault; +using Track2ManagementSdk = Azure.ResourceManager.KeyVault; using System.Security.Cryptography; using System.Linq; +using Azure.ResourceManager; namespace Microsoft.Azure.Commands.KeyVault { @@ -55,5 +58,74 @@ public static Track1Sdk.JsonWebKey ToTrack1JsonWebKey(this Track2Sdk.JsonWebKey return track1Key; } + + public static Track1ManagementSdk.Models.NetworkRuleSet ToTrack1NetworkRuleSet(this Track2ManagementSdk.Models.NetworkRuleSet track2NetworkRuleSet) => + new Track1ManagementSdk.Models.NetworkRuleSet() + { + Bypass = track2NetworkRuleSet.Bypass.ToString(), + DefaultAction = track2NetworkRuleSet.DefaultAction.ToString(), + IpRules = track2NetworkRuleSet.IpRules.Select(ipRule => new Track1ManagementSdk.Models.IPRule(ipRule.Value)).ToList(), + VirtualNetworkRules = track2NetworkRuleSet.VirtualNetworkRules.Select(vnRule => new Track1ManagementSdk.Models.VirtualNetworkRule(vnRule.Id)).ToList() + }; + + public static Track1ManagementSdk.Models.CreateMode? ToTrack1CreateMode(this Track2ManagementSdk.Models.CreateMode track2CreateMode) + { + if (!Enum.TryParse(track2CreateMode.ToString(), out Track1ManagementSdk.Models.CreateMode track1CreateMode)) + { + return null; + } + return track1CreateMode; + } + + public static Track1ManagementSdk.Models.Permissions ToTrack1Permissions(this Track2ManagementSdk.Models.Permissions track2Permissions) => + new Track1ManagementSdk.Models.Permissions(track2Permissions.Keys.Select(key => key.ToString()).ToList(), + track2Permissions.Secrets.Select(key => key.ToString()).ToList(), + track2Permissions.Certificates.Select(key => key.ToString()).ToList(), + track2Permissions.Storage.Select(key => key.ToString()).ToList()); + + public static Track1ManagementSdk.Models.AccessPolicyEntry ToTrack1AccessPolicyEntry(this Track2ManagementSdk.Models.AccessPolicyEntry track2AccessPolicyEntry) => + new Track1ManagementSdk.Models.AccessPolicyEntry + { + ApplicationId = track2AccessPolicyEntry.ApplicationId, + ObjectId = track2AccessPolicyEntry.ObjectId, + Permissions = track2AccessPolicyEntry.Permissions?.ToTrack1Permissions(), + TenantId = track2AccessPolicyEntry.TenantId + }; + + public static Track1ManagementSdk.Models.Sku ToTrack1Sku(this Track2ManagementSdk.Models.Sku track2Sku) + { + Track1ManagementSdk.Models.Sku track1Sku = new Track1ManagementSdk.Models.Sku(); + + if (!Enum.TryParse(track2Sku.Name.ToString(), out Track1ManagementSdk.Models.SkuName track1SkuName)) + { + return null; + } + track1Sku.Name = track1SkuName; + return track1Sku; + } + + public static Track1ManagementSdk.Models.PrivateEndpointConnectionItem ToTrack1PrivateEndpointConnectionItem(this Track2ManagementSdk.Models.PrivateEndpointConnectionItem track2PrivateEndpointConnectionItem) => + new Track1ManagementSdk.Models.PrivateEndpointConnectionItem() + { + PrivateEndpoint = new Track1ManagementSdk.Models.PrivateEndpoint(track2PrivateEndpointConnectionItem.PrivateEndpoint.Id), + PrivateLinkServiceConnectionState = new Track1ManagementSdk.Models.PrivateLinkServiceConnectionState( + track2PrivateEndpointConnectionItem.PrivateLinkServiceConnectionState.Status?.ToString(), + track2PrivateEndpointConnectionItem.PrivateLinkServiceConnectionState.Description, + track2PrivateEndpointConnectionItem.PrivateLinkServiceConnectionState.ActionsRequired?.ToString()), + ProvisioningState = track2PrivateEndpointConnectionItem.ProvisioningState?.ToString() + }; + + public static Track1ManagementSdk.Models.VaultProperties ToTrack1VaultProperties(this Track2ManagementSdk.Models.VaultProperties track2VaultProperties) => + new Track1ManagementSdk.Models.VaultProperties(track2VaultProperties.TenantId, track2VaultProperties.Sku?.ToTrack1Sku(), + track2VaultProperties.AccessPolicies.Select(ap => ap?.ToTrack1AccessPolicyEntry()).ToList(), track2VaultProperties.VaultUri, + track2VaultProperties.EnabledForDeployment, track2VaultProperties.EnabledForDiskEncryption, track2VaultProperties.EnabledForTemplateDeployment, + track2VaultProperties.EnableSoftDelete, track2VaultProperties.SoftDeleteRetentionInDays, track2VaultProperties.EnableRbacAuthorization, + track2VaultProperties.CreateMode?.ToTrack1CreateMode(), track2VaultProperties.EnablePurgeProtection, + track2VaultProperties.NetworkAcls?.ToTrack1NetworkRuleSet(), track2VaultProperties.PrivateEndpointConnections.Select(peCon => peCon?.ToTrack1PrivateEndpointConnectionItem()).ToList()); + + public static Track1ManagementSdk.Models.Vault ToTrack1Vault(this Track2ManagementSdk.Vault track2Vault) => + new Track1ManagementSdk.Models.Vault( + track2Vault.Data.Properties?.ToTrack1VaultProperties(), + track2Vault.Data.Id, track2Vault.Data.Name, track2Vault.Data.Type, track2Vault.Data.Location, track2Vault.Data.Tags.ToDictionary(pair => pair.Key, pair => pair.Value)); } } diff --git a/src/KeyVault/KeyVault/Track2Models/Track2TokenCredential.cs b/src/KeyVault/KeyVault/Track2Models/Track2TokenCredential.cs index 5a30578274d0..849ae7cddf91 100644 --- a/src/KeyVault/KeyVault/Track2Models/Track2TokenCredential.cs +++ b/src/KeyVault/KeyVault/Track2Models/Track2TokenCredential.cs @@ -8,16 +8,21 @@ namespace Microsoft.Azure.Commands.KeyVault.Track2Models { internal class Track2TokenCredential : TokenCredential { - private readonly DataServiceCredential dataServiceCredential; + private readonly string _token; public Track2TokenCredential(DataServiceCredential dataServiceCredential) { - this.dataServiceCredential = dataServiceCredential; + this._token = dataServiceCredential.GetToken(); + } + + public Track2TokenCredential(string token) + { + this._token = token; } public override AccessToken GetToken(TokenRequestContext requestContext, CancellationToken cancellationToken) { - return new AccessToken(dataServiceCredential.GetToken(), DateTimeOffset.UtcNow); + return new AccessToken(_token, DateTimeOffset.UtcNow); } public override ValueTask GetTokenAsync(TokenRequestContext requestContext, CancellationToken cancellationToken) diff --git a/src/KeyVault/KeyVault/Track2Models/Track2VaultManagementClient.cs b/src/KeyVault/KeyVault/Track2Models/Track2VaultManagementClient.cs new file mode 100644 index 000000000000..5a473080bc6a --- /dev/null +++ b/src/KeyVault/KeyVault/Track2Models/Track2VaultManagementClient.cs @@ -0,0 +1,67 @@ +using Azure.ResourceManager; +using Azure.ResourceManager.KeyVault.Models; + +using Microsoft.Azure.Commands.Common.Authentication; +using Microsoft.Azure.Commands.Common.Authentication.Abstractions; +using Microsoft.Azure.Commands.Common.MSGraph.Version1_0; +using Microsoft.Azure.Commands.KeyVault.Models; +using Microsoft.WindowsAzure.Commands.Utilities.Common; + +using System; +using System.Collections.Generic; + +using KeyVaultProperties = Microsoft.Azure.Commands.KeyVault.Properties; + + +namespace Microsoft.Azure.Commands.KeyVault.Track2Models +{ + public class Track2VaultManagementClient + { + + private IClientFactory _clientFactory; + private IAzureContext _context; + + private Track2KeyVaultManagementClient Track2KeyVaultManagementClient => + _track2KeyVaultManagementClient ?? (_track2KeyVaultManagementClient = new Track2KeyVaultManagementClient(_clientFactory, _context)); + private Track2KeyVaultManagementClient _track2KeyVaultManagementClient; + + public Track2VaultManagementClient(IClientFactory clientFactory , IAzureContext context) + { + _context = context ?? throw new ArgumentNullException(nameof(context)); + _clientFactory = clientFactory ?? throw new ArgumentNullException(nameof(clientFactory)); + + if (context.Environment == null) + { + throw new ArgumentException(KeyVaultProperties.Resources.InvalidAzureEnvironment); + } + } + + #region Vault-related METHODS + public PSKeyVault CreateVault(string resourcegroup, string vaultName, VaultCreationOrUpdateParameters parameters, IMicrosoftGraphClient msGraphClient = null) => + new PSKeyVault(Track2KeyVaultManagementClient.CreateVault(resourcegroup, vaultName, parameters.ToTrack2VaultCreateOrUpdateParameters()), msGraphClient); + + public IList ListVaults(string resourcegroup, IMicrosoftGraphClient msGraphClient = null) + { + var vaults = new List(); + var response = Track2KeyVaultManagementClient.ListVaults(resourcegroup); + response?.ForEach(vault => + { + vaults.Add(new PSKeyVault(vault, msGraphClient)); + }); + return vaults; + } + + public PSKeyVault GetVault(string resourcegroup, string vaultName, IMicrosoftGraphClient msGraphClient = null) => + new PSKeyVault(Track2KeyVaultManagementClient.GetVault(resourcegroup, vaultName), msGraphClient); + + #endregion + + private Track2ManagedHsmManagementClient Track2ManagedHsmManagementClient => + _track2ManagedHsmManagementClient ?? (_track2ManagedHsmManagementClient = new Track2ManagedHsmManagementClient()); + private Track2ManagedHsmManagementClient _track2ManagedHsmManagementClient; + + #region ManagedHsm-related METHODS + + #endregion + } +} diff --git a/tools/Common.Netcore.Dependencies.targets b/tools/Common.Netcore.Dependencies.targets index 66fd7cc819d7..146da3767395 100644 --- a/tools/Common.Netcore.Dependencies.targets +++ b/tools/Common.Netcore.Dependencies.targets @@ -1,19 +1,20 @@ + - + - + - + - + diff --git a/tools/ScenarioTest.ResourceManager/Mocks/MockCertificateAuthenticationFactory.cs b/tools/ScenarioTest.ResourceManager/Mocks/MockCertificateAuthenticationFactory.cs index db57ca108dec..7da483126a3e 100644 --- a/tools/ScenarioTest.ResourceManager/Mocks/MockCertificateAuthenticationFactory.cs +++ b/tools/ScenarioTest.ResourceManager/Mocks/MockCertificateAuthenticationFactory.cs @@ -12,6 +12,8 @@ // limitations under the License. // ---------------------------------------------------------------------------------- +using Azure.Core; + using Microsoft.Azure; using Microsoft.Azure.Commands.Common.Authentication; using Microsoft.Azure.Commands.Common.Authentication.Abstractions; @@ -105,5 +107,20 @@ public void RemoveUser(IAzureAccount account, IAzureTokenCache tokenCache) { throw new NotImplementedException(); } + + public TokenCredential GetTokenCredential(IAzureContext context) + { + throw new NotImplementedException(); + } + + public TokenCredential GetTokenCredential(IAzureContext context, string targetEndpoint) + { + throw new NotImplementedException(); + } + + public TokenCredential GetTokenCredential(string accessToken, Func renew = null) + { + throw new NotImplementedException(); + } } } diff --git a/tools/ScenarioTest.ResourceManager/Mocks/MockClientFactory.cs b/tools/ScenarioTest.ResourceManager/Mocks/MockClientFactory.cs index 56761d025589..8167b8cb2fde 100644 --- a/tools/ScenarioTest.ResourceManager/Mocks/MockClientFactory.cs +++ b/tools/ScenarioTest.ResourceManager/Mocks/MockClientFactory.cs @@ -33,6 +33,7 @@ using System.Reflection; using System.Threading; using System.Threading.Tasks; +using Azure.ResourceManager; #if NETSTANDARD using Microsoft.Azure.Commands.Common.Authentication.Abstractions.Core; #endif @@ -295,5 +296,15 @@ public void RemoveUserAgent(string name) { UniqueUserAgents.RemoveWhere((p) => string.Equals(p.Product.Name, name, StringComparison.OrdinalIgnoreCase)); } + + public ArmClient CreateArmClient(IAzureContext context, string endpoint) + { + throw new NotImplementedException(); + } + + public ArmClient CreateCustomArmClient(IAzureContext context, string endpoint, ArmClientOptions option) + { + throw new NotImplementedException(); + } } } diff --git a/tools/ScenarioTest.ResourceManager/Mocks/MockTokenAuthenticationFactory.cs b/tools/ScenarioTest.ResourceManager/Mocks/MockTokenAuthenticationFactory.cs index 62f226986fc0..ec9c36446fc0 100644 --- a/tools/ScenarioTest.ResourceManager/Mocks/MockTokenAuthenticationFactory.cs +++ b/tools/ScenarioTest.ResourceManager/Mocks/MockTokenAuthenticationFactory.cs @@ -12,6 +12,8 @@ // limitations under the License. // ---------------------------------------------------------------------------------- +using Azure.Core; + using Microsoft.Azure; using Microsoft.Azure.Commands.Common.Authentication; using Microsoft.Azure.Commands.Common.Authentication.Abstractions; @@ -145,5 +147,20 @@ public void RemoveUser(IAzureAccount account, IAzureTokenCache tokenCache) { throw new NotImplementedException(); } + + public TokenCredential GetTokenCredential(IAzureContext context) + { + throw new NotImplementedException(); + } + + public TokenCredential GetTokenCredential(IAzureContext context, string targetEndpoint) + { + throw new NotImplementedException(); + } + + public TokenCredential GetTokenCredential(string accessToken, Func renew = null) + { + throw new NotImplementedException(); + } } } diff --git a/tools/TestFx/TestClientFactory.cs b/tools/TestFx/TestClientFactory.cs index 21e34010483f..50b6f4b0b0b4 100644 --- a/tools/TestFx/TestClientFactory.cs +++ b/tools/TestFx/TestClientFactory.cs @@ -22,6 +22,7 @@ using Microsoft.Azure.Commands.Common.Authentication.Abstractions; using Microsoft.Azure.Commands.Common.Authentication.Models; using Microsoft.Rest.ClientRuntime.Azure.TestFramework; +using Azure.ResourceManager; #if NETSTANDARD using Microsoft.Azure.Commands.Common.Authentication.Abstractions.Core; #endif @@ -36,6 +37,15 @@ public TestClientFactory(MockContext mockContext) { _mockContext = mockContext ?? throw new ArgumentNullException(nameof(mockContext)); } + public ArmClient CreateArmClient(IAzureContext context, string endpoint) + { + throw new NotImplementedException(); + } + + public ArmClient CreateCustomArmClient(IAzureContext context, string endpoint, ArmClientOptions option) + { + throw new NotImplementedException(); + } public TClient CreateArmClient(IAzureContext context, string endpoint) where TClient : Rest.ServiceClient { @@ -140,7 +150,6 @@ public TClient CreateCustomClient(params object[] parameters) where TCl { throw new NotImplementedException(); } - #endregion }