diff --git a/AzurePowershell.Test.targets b/AzurePowershell.Test.targets index f31479edbba2..48ec3a016fda 100644 --- a/AzurePowershell.Test.targets +++ b/AzurePowershell.Test.targets @@ -20,6 +20,7 @@ .\src\ServiceManagement\Sql\Commands.SqlDatabase.Test\bin\Debug\Microsoft.WindowsAzure.Commands.SqlDatabase.Test.dll .\src\ServiceManagement\HDInsight\Commands.HDInsight.Test\bin\Debug\Microsoft.WindowsAzure.Commands.HDInsight.Test.dll .\src\ServiceManagement\Storage\Commands.Storage.Test\bin\Debug\Microsoft.WindowsAzure.Commands.Storage.Test.dll + .\src\ResourceManager\KeyVault\Commands.KeyVault.Test\bin\Debug\Microsoft.Azure.Commands.KeyVault.Test.dll "!Functional&!Scenario&!AzureRTScenario&!Sequential&!PIRTest&!Preview&!ADDomain" All "OneSDK&CIT" @@ -131,6 +132,13 @@ + + + + + + diff --git a/build.proj b/build.proj index 842a3404259d..dce09d5fcd58 100644 --- a/build.proj +++ b/build.proj @@ -194,7 +194,7 @@ - + diff --git a/setup/azurecmdfiles.wxi b/setup/azurecmdfiles.wxi index a32a2abc0bf9..6fdc8829bb14 100644 --- a/setup/azurecmdfiles.wxi +++ b/setup/azurecmdfiles.wxi @@ -149,6 +149,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2027,6 +2086,25 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/AzurePowershell.sln b/src/AzurePowershell.sln index d06e75409380..8515793e1ade 100644 --- a/src/AzurePowershell.sln +++ b/src/AzurePowershell.sln @@ -143,6 +143,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Commands.Network", "Service EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Commands.Network.Test", "ServiceManagement\Network\Commands.Network.Test\Commands.Network.Test.csproj", "{FDB897BD-FCB4-44A1-8D66-AC99F22EC737}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Commands.KeyVault", "ResourceManager\KeyVault\Commands.KeyVault\Commands.KeyVault.csproj", "{9FFC40CC-A341-4D0C-A25D-DC6B78EF6C94}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Commands.KeyVault.Test", "ResourceManager\KeyVault\Commands.KeyVault.Test\Commands.KeyVault.Test.csproj", "{080B0477-7E52-4455-90AB-23BD13D1B1CE}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Commands.RecoveryServices", "ServiceManagement\RecoveryServices\Commands.RecoveryServices\Commands.RecoveryServices.csproj", "{98B10548-DF97-4FB1-8D82-2A12945D4F21}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Commands.RecoveryServices.Test", "ServiceManagement\RecoveryServices\Commands.RecoveryServices.Test\Commands.RecoveryServices.Test.csproj", "{A415F75B-EB6A-49A6-934E-5BA71B83D6EB}" @@ -341,6 +345,10 @@ Global {FDB897BD-FCB4-44A1-8D66-AC99F22EC737}.Debug|Any CPU.Build.0 = Debug|Any CPU {FDB897BD-FCB4-44A1-8D66-AC99F22EC737}.Release|Any CPU.ActiveCfg = Release|Any CPU {FDB897BD-FCB4-44A1-8D66-AC99F22EC737}.Release|Any CPU.Build.0 = Release|Any CPU + {9FFC40CC-A341-4D0C-A25D-DC6B78EF6C94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9FFC40CC-A341-4D0C-A25D-DC6B78EF6C94}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9FFC40CC-A341-4D0C-A25D-DC6B78EF6C94}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9FFC40CC-A341-4D0C-A25D-DC6B78EF6C94}.Release|Any CPU.Build.0 = Release|Any CPU {98B10548-DF97-4FB1-8D82-2A12945D4F21}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {98B10548-DF97-4FB1-8D82-2A12945D4F21}.Debug|Any CPU.Build.0 = Debug|Any CPU {98B10548-DF97-4FB1-8D82-2A12945D4F21}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -349,6 +357,10 @@ Global {A415F75B-EB6A-49A6-934E-5BA71B83D6EB}.Debug|Any CPU.Build.0 = Debug|Any CPU {A415F75B-EB6A-49A6-934E-5BA71B83D6EB}.Release|Any CPU.ActiveCfg = Release|Any CPU {A415F75B-EB6A-49A6-934E-5BA71B83D6EB}.Release|Any CPU.Build.0 = Release|Any CPU + {080B0477-7E52-4455-90AB-23BD13D1B1CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {080B0477-7E52-4455-90AB-23BD13D1B1CE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {080B0477-7E52-4455-90AB-23BD13D1B1CE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {080B0477-7E52-4455-90AB-23BD13D1B1CE}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -378,5 +390,6 @@ Global {F4ABAD68-64A5-4B23-B09C-42559A7524DE} = {95C16AED-FD57-42A0-86C3-2CF4300A4817} {FDB897BD-FCB4-44A1-8D66-AC99F22EC737} = {95C16AED-FD57-42A0-86C3-2CF4300A4817} {A415F75B-EB6A-49A6-934E-5BA71B83D6EB} = {95C16AED-FD57-42A0-86C3-2CF4300A4817} + {080B0477-7E52-4455-90AB-23BD13D1B1CE} = {95C16AED-FD57-42A0-86C3-2CF4300A4817} EndGlobalSection EndGlobal diff --git a/src/Common/Commands.Common.Test/Mocks/MockCertificateAuthenticationFactory.cs b/src/Common/Commands.Common.Test/Mocks/MockCertificateAuthenticationFactory.cs index 746486b575b3..ed6693abdaad 100644 --- a/src/Common/Commands.Common.Test/Mocks/MockCertificateAuthenticationFactory.cs +++ b/src/Common/Commands.Common.Test/Mocks/MockCertificateAuthenticationFactory.cs @@ -33,7 +33,8 @@ public MockCertificateAuthenticationFactory(string userId, X509Certificate2 cert Certificate = certificate; } - public IAccessToken Authenticate(AzureAccount account, AzureEnvironment environment, string tenant, SecureString password, ShowDialog promptBehavior) + public IAccessToken Authenticate(AzureAccount account, AzureEnvironment environment, string tenant, SecureString password, ShowDialog promptBehavior, + AzureEnvironment.Endpoint resourceId = AzureEnvironment.Endpoint.ActiveDirectoryServiceEndpointResourceId) { if (account.Id == null) { diff --git a/src/Common/Commands.Common.Test/Mocks/MockTokenAuthenticationFactory.cs b/src/Common/Commands.Common.Test/Mocks/MockTokenAuthenticationFactory.cs index ee85746615f2..e7f44786bfa0 100644 --- a/src/Common/Commands.Common.Test/Mocks/MockTokenAuthenticationFactory.cs +++ b/src/Common/Commands.Common.Test/Mocks/MockTokenAuthenticationFactory.cs @@ -43,7 +43,8 @@ public MockTokenAuthenticationFactory(string userId, string accessToken) }; } - public IAccessToken Authenticate(AzureAccount account, AzureEnvironment environment, string tenant, SecureString password, ShowDialog promptBehavior) + public IAccessToken Authenticate(AzureAccount account, AzureEnvironment environment, string tenant, SecureString password, ShowDialog promptBehavior, + AzureEnvironment.Endpoint resourceId = AzureEnvironment.Endpoint.ActiveDirectoryServiceEndpointResourceId) { if (account.Id == null) { diff --git a/src/Common/Commands.Common/Common/ManagementConstants.cs b/src/Common/Commands.Common/Common/ManagementConstants.cs index 3b79dca0460f..ae5d4331c79f 100644 --- a/src/Common/Commands.Common/Common/ManagementConstants.cs +++ b/src/Common/Commands.Common/Common/ManagementConstants.cs @@ -117,5 +117,9 @@ public static class AzureEnvironmentConstants public const string AzureTrafficManagerDnsSuffix = "trafficmanager.net"; public const string ChinaTrafficManagerDnsSuffix = "trafficmanager.cn"; + + public const string AzureKeyVaultDnsSuffix = "vault.azure.net"; + + public const string AzureKeyVaultServiceEndpointResourceId = "https://vault.azure.net"; } } \ No newline at end of file diff --git a/src/Common/Commands.Common/Common/RequiredResourceLookup.cs b/src/Common/Commands.Common/Common/RequiredResourceLookup.cs index cef962cafef4..1805032afe26 100644 --- a/src/Common/Commands.Common/Common/RequiredResourceLookup.cs +++ b/src/Common/Commands.Common/Common/RequiredResourceLookup.cs @@ -52,7 +52,8 @@ internal static IList RequiredProvidersForResourceManager() where T : "microsoft.visualstudio", "microsoft.insights", "successbricks.cleardb", - "microsoft.cache" }; + "microsoft.cache", + "Microsoft.KeyVault"}; } if (typeof(T).FullName.EndsWith("BatchManagementClient")) { diff --git a/src/Common/Commands.Common/Factories/AuthenticationFactory.cs b/src/Common/Commands.Common/Factories/AuthenticationFactory.cs index a897f4fe3b7e..5a033b2e96b1 100644 --- a/src/Common/Commands.Common/Factories/AuthenticationFactory.cs +++ b/src/Common/Commands.Common/Factories/AuthenticationFactory.cs @@ -31,14 +31,15 @@ public AuthenticationFactory() } public ITokenProvider TokenProvider { get; set; } + - public IAccessToken Authenticate(AzureAccount account, AzureEnvironment environment, string tenant, SecureString password, ShowDialog promptBehavior) + public IAccessToken Authenticate(AzureAccount account, AzureEnvironment environment, string tenant, SecureString password, ShowDialog promptBehavior, + AzureEnvironment.Endpoint resourceId = AzureEnvironment.Endpoint.ActiveDirectoryServiceEndpointResourceId) { - var token = TokenProvider.GetAccessToken(GetAdalConfiguration(environment, tenant), promptBehavior, account.Id, password, account.Type); + var token = TokenProvider.GetAccessToken(GetAdalConfiguration(environment, tenant, resourceId), promptBehavior, account.Id, password, account.Type); account.Id = token.UserId; return token; } - public SubscriptionCloudCredentials GetSubscriptionCloudCredentials(AzureContext context) { if (context.Subscription == null) @@ -76,20 +77,21 @@ public SubscriptionCloudCredentials GetSubscriptionCloudCredentials(AzureContext throw new ArgumentException(Resources.InvalidSubscriptionState, ex); } } - - private AdalConfiguration GetAdalConfiguration(AzureEnvironment environment, string tenantId) + + + private AdalConfiguration GetAdalConfiguration(AzureEnvironment environment, string tenantId, + AzureEnvironment.Endpoint resourceId) { if (environment == null) { throw new ArgumentNullException("environment"); } var adEndpoint = environment.Endpoints[AzureEnvironment.Endpoint.ActiveDirectory]; - var adResourceId = environment.Endpoints[AzureEnvironment.Endpoint.ActiveDirectoryServiceEndpointResourceId]; - + return new AdalConfiguration { AdEndpoint = adEndpoint, - ResourceClientUri = adResourceId, + ResourceClientUri = environment.Endpoints[resourceId], AdDomain = tenantId }; } diff --git a/src/Common/Commands.Common/Interfaces/IAuthenticationFactory.cs b/src/Common/Commands.Common/Interfaces/IAuthenticationFactory.cs index 9e052857a09d..46748f8d811a 100644 --- a/src/Common/Commands.Common/Interfaces/IAuthenticationFactory.cs +++ b/src/Common/Commands.Common/Interfaces/IAuthenticationFactory.cs @@ -28,8 +28,9 @@ public interface IAuthenticationFactory /// /// /// - /// - IAccessToken Authenticate(AzureAccount account, AzureEnvironment environment, string tenant, SecureString password, ShowDialog promptBehavior); + /// + IAccessToken Authenticate(AzureAccount account, AzureEnvironment environment, string tenant, SecureString password, ShowDialog promptBehavior, + AzureEnvironment.Endpoint resourceId = AzureEnvironment.Endpoint.ActiveDirectoryServiceEndpointResourceId); SubscriptionCloudCredentials GetSubscriptionCloudCredentials(AzureContext context); } diff --git a/src/Common/Commands.Common/Models/AzureEnvironment.Methods.cs b/src/Common/Commands.Common/Models/AzureEnvironment.Methods.cs index a4d3d0fee987..5525bad09fde 100644 --- a/src/Common/Commands.Common/Models/AzureEnvironment.Methods.cs +++ b/src/Common/Commands.Common/Models/AzureEnvironment.Methods.cs @@ -97,6 +97,8 @@ private string StorageFileEndpointFormat() { AzureEnvironment.Endpoint.SqlDatabaseDnsSuffix, AzureEnvironmentConstants.AzureSqlDatabaseDnsSuffix }, { AzureEnvironment.Endpoint.Graph, AzureEnvironmentConstants.AzureGraphEndpoint }, { AzureEnvironment.Endpoint.TrafficManagerDnsSuffix, AzureEnvironmentConstants.AzureTrafficManagerDnsSuffix }, + { AzureEnvironment.Endpoint.AzureKeyVaultDnsSuffix, AzureEnvironmentConstants.AzureKeyVaultDnsSuffix }, + { AzureEnvironment.Endpoint.AzureKeyVaultServiceEndpointResourceId, AzureEnvironmentConstants.AzureKeyVaultServiceEndpointResourceId }, } } }, @@ -255,7 +257,7 @@ public string GetPublishSettingsFileUrlWithRealm(string realm = null) public enum Endpoint { - ActiveDirectoryServiceEndpointResourceId, + ActiveDirectoryServiceEndpointResourceId, AdTenant, @@ -278,6 +280,10 @@ public enum Endpoint Graph, TrafficManagerDnsSuffix, + + AzureKeyVaultDnsSuffix, + + AzureKeyVaultServiceEndpointResourceId, } } } diff --git a/src/Common/Commands.ScenarioTests.Common/Constants.cs b/src/Common/Commands.ScenarioTests.Common/Constants.cs index 8bbf163f0c4f..3dfea33dcccf 100644 --- a/src/Common/Commands.ScenarioTests.Common/Constants.cs +++ b/src/Common/Commands.ScenarioTests.Common/Constants.cs @@ -50,6 +50,8 @@ public class Category public const string Scheduler = "Scheduler"; + public const string KeyVault = "KeyVault"; + public const string Network = "Network"; // Owners diff --git a/src/ResourceManager.sln b/src/ResourceManager.sln index 2d9218889c15..26263e8addc8 100644 --- a/src/ResourceManager.sln +++ b/src/ResourceManager.sln @@ -37,6 +37,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Commands.RedisCache", "Reso EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Commands.RedisCache.Test", "ResourceManager\RedisCache\Commands.RedisCache.Test\Commands.RedisCache.Test.csproj", "{4AE5705F-62CF-461D-B72E-DD9DCD9B3609}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Commands.KeyVault", "ResourceManager\KeyVault\Commands.KeyVault\Commands.KeyVault.csproj", "{9FFC40CC-A341-4D0C-A25D-DC6B78EF6C94}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Commands.KeyVault.Test", "ResourceManager\KeyVault\Commands.KeyVault.Test\Commands.KeyVault.Test.csproj", "{080B0477-7E52-4455-90AB-23BD13D1B1CE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Commands.Sql.Test", "ResourceManager\Sql\Commands.Sql.Test\Commands.Sql.Test.csproj", "{56ED8C97-53B9-4DF6-ACB5-7E6800105BF8}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -95,6 +101,18 @@ Global {4AE5705F-62CF-461D-B72E-DD9DCD9B3609}.Debug|Any CPU.Build.0 = Debug|Any CPU {4AE5705F-62CF-461D-B72E-DD9DCD9B3609}.Release|Any CPU.ActiveCfg = Release|Any CPU {4AE5705F-62CF-461D-B72E-DD9DCD9B3609}.Release|Any CPU.Build.0 = Release|Any CPU + {9FFC40CC-A341-4D0C-A25D-DC6B78EF6C94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9FFC40CC-A341-4D0C-A25D-DC6B78EF6C94}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9FFC40CC-A341-4D0C-A25D-DC6B78EF6C94}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9FFC40CC-A341-4D0C-A25D-DC6B78EF6C94}.Release|Any CPU.Build.0 = Release|Any CPU + {080B0477-7E52-4455-90AB-23BD13D1B1CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {080B0477-7E52-4455-90AB-23BD13D1B1CE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {080B0477-7E52-4455-90AB-23BD13D1B1CE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {080B0477-7E52-4455-90AB-23BD13D1B1CE}.Release|Any CPU.Build.0 = Release|Any CPU + {56ED8C97-53B9-4DF6-ACB5-7E6800105BF8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {56ED8C97-53B9-4DF6-ACB5-7E6800105BF8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {56ED8C97-53B9-4DF6-ACB5-7E6800105BF8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {56ED8C97-53B9-4DF6-ACB5-7E6800105BF8}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -105,5 +123,7 @@ Global {C1BDA476-A5CC-4394-914D-48B0EC31A710} = {95C16AED-FD57-42A0-86C3-2CF4300A4817} {D4EDAD6F-6A1D-4295-9A88-CD3F69EAD42B} = {95C16AED-FD57-42A0-86C3-2CF4300A4817} {4AE5705F-62CF-461D-B72E-DD9DCD9B3609} = {95C16AED-FD57-42A0-86C3-2CF4300A4817} + {080B0477-7E52-4455-90AB-23BD13D1B1CE} = {95C16AED-FD57-42A0-86C3-2CF4300A4817} + {56ED8C97-53B9-4DF6-ACB5-7E6800105BF8} = {95C16AED-FD57-42A0-86C3-2CF4300A4817} EndGlobalSection EndGlobal diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Commands.KeyVault.Test.csproj b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Commands.KeyVault.Test.csproj new file mode 100644 index 000000000000..030eb98b9cb6 --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Commands.KeyVault.Test.csproj @@ -0,0 +1,164 @@ + + + + + Debug + AnyCPU + {080B0477-7E52-4455-90AB-23BD13D1B1CE} + Library + Properties + Microsoft.Azure.Commands.KeyVault.Test + Microsoft.Azure.Commands.KeyVault.Test + v4.5 + 512 + + ..\..\ + true + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + + + true + full + false + bin\Debug + DEBUG;TRACE + prompt + 4 + true + true + false + + + bin\Release + TRACE;SIGN + true + pdbonly + AnyCPU + bin\Release\Common.Test.dll.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + MinimumRecommendedRules.ruleset + ;$(ProgramFiles)\Microsoft Visual Studio 12.0\Team Tools\Static Analysis Tools\Rule Sets + ;$(ProgramFiles)\Microsoft Visual Studio 12.0\Team Tools\Static Analysis Tools\FxCop\Rules + true + MSSharedLibKey.snk + true + true + false + + + + ..\..\..\packages\Hydra.HttpRecorder.1.0.5406.28672-prerelease\lib\net45\Microsoft.Azure.Utilities.HttpRecorder.dll + + + False + ..\..\..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.11.10918.1222\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll + + + False + ..\..\..\packages\Microsoft.KeyVault.Client.1.0.0.20\lib\net45\Microsoft.KeyVault.Client.dll + + + False + ..\..\..\packages\Microsoft.KeyVault.WebKey.1.0.0.10\lib\net45\Microsoft.KeyVault.WebKey.dll + + + ..\..\..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll + + + ..\..\..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll + + + ..\..\..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll + + + + False + ..\..\..\packages\Microsoft.WindowsAzure.Common.1.4.0\lib\net45\Microsoft.WindowsAzure.Common.dll + + + False + ..\..\..\packages\Microsoft.WindowsAzure.Common.1.4.0\lib\net45\Microsoft.WindowsAzure.Common.NetFramework.dll + + + ..\..\..\packages\Hydra.SpecTestSupport.1.0.5406.28672-prerelease\lib\net45\Microsoft.WindowsAzure.Testing.dll + + + False + ..\..\..\packages\Moq.4.2.1409.1722\lib\net40\Moq.dll + + + False + ..\..\..\packages\Newtonsoft.Json.6.0.4\lib\net45\Newtonsoft.Json.dll + + + False + C:\Windows\Microsoft.NET\assembly\GAC_MSIL\System.Management.Automation\v4.0_3.0.0.0__31bf3856ad364e35\System.Management.Automation.dll + + + + + + ..\..\..\packages\Microsoft.Net.Http.2.2.28\lib\net45\System.Net.Http.Extensions.dll + + + ..\..\..\packages\Microsoft.Net.Http.2.2.28\lib\net45\System.Net.Http.Primitives.dll + + + + ..\..\..\packages\xunit.1.9.2\lib\net20\xunit.dll + + + + + + True + True + Resource.resx + + + + + + + + + + + Designer + + + + + + {5ee72c53-1720-4309-b54b-5fb79703195f} + Commands.Common + + + {c1bda476-a5cc-4394-914d-48b0ec31a710} + Commands.ScenarioTests.Common + + + {9ffc40cc-a341-4d0c-a25d-dc6b78ef6c94} + Commands.KeyVault + + + + + ResXFileCodeGenerator + Resource.Designer.cs + + + + + + + + + + + + xcopy "$(SolutionDir)Package\$(ConfigurationName)\*.*" $(TargetDir) /Y /E + + \ No newline at end of file diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault.Test/MSSharedLibKey.snk b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/MSSharedLibKey.snk new file mode 100644 index 000000000000..695f1b38774e Binary files /dev/null and b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/MSSharedLibKey.snk differ diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Models/UtilitiesTests.cs b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Models/UtilitiesTests.cs new file mode 100644 index 000000000000..8ec81185f135 --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Models/UtilitiesTests.cs @@ -0,0 +1,72 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using System; +using Microsoft.Azure.Commands.KeyVault.Models; +using Microsoft.KeyVault.WebKey; +using Microsoft.WindowsAzure.Commands.ScenarioTest; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using Xunit; +using System.Security.Cryptography.X509Certificates; + +namespace Microsoft.Azure.Commands.KeyVault.Test.Models +{ + public class UtilitiesTests + { + [Fact] + [Trait(Category.KeyVault, Category.CheckIn)] + public void ConvertStringAndSecureString() + { + var origStr = "this is test string"; + var secureString = origStr.ToSecureString(); + var convStr = secureString.ToStringExt(); + + Assert.Equal( origStr, convStr ); + } + + [Fact] + [Trait(Category.KeyVault, Category.CheckIn)] + public void GetWebKeyFromByok() + { + Random rnd = new Random(); + byte[] byokBlob = new byte[100]; + rnd.NextBytes(byokBlob); + string tempPath = Path.GetTempFileName() + ".byok"; + File.WriteAllBytes(tempPath, byokBlob); + IWebKeyConverter converters = WebKeyConverterFactory.CreateConverterChain(); + var webKey = converters.ConvertKeyFromFile(new FileInfo(tempPath), null); + + Assert.True(webKey.T.SequenceEqual(byokBlob)); + Assert.Equal(webKey.Kty, JsonWebKeyType.RsaHsm); + } + + [Fact] + [Trait(Category.KeyVault, Category.CheckIn)] + public void GetWebKeyFromCertificate() + { + string password = "123"; + string tempPath = Path.GetTempFileName() + ".pfx"; + File.WriteAllBytes(tempPath, Resource.pfxCert); + + IWebKeyConverter converters = WebKeyConverterFactory.CreateConverterChain(); + var webKey = converters.ConvertKeyFromFile(new FileInfo(tempPath), password.ToSecureString()); + + Assert.True(webKey.HasPrivateKey()); + Assert.True(webKey.IsValid()); + Assert.Equal(webKey.Kty, JsonWebKeyType.Rsa); + } + } +} diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Properties/AssemblyInfo.cs b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Properties/AssemblyInfo.cs new file mode 100644 index 000000000000..f00455fcb2ac --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Properties/AssemblyInfo.cs @@ -0,0 +1,50 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle( "Microsoft.Azure.Commands.KeyVault.Test" )] +[assembly: AssemblyDescription( "" )] +[assembly: AssemblyConfiguration( "" )] +[assembly: AssemblyCompany( "" )] +[assembly: AssemblyProduct( "Microsoft.Azure.Commands.KeyVault.Test" )] +[assembly: AssemblyCopyright( "Copyright © 2014" )] +[assembly: AssemblyTrademark( "" )] +[assembly: AssemblyCulture( "" )] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible( false )] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid( "92c42e00-f56b-406a-af5d-0d870d454f55" )] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion( "1.0.0.0" )] +[assembly: AssemblyFileVersion( "1.0.0.0" )] diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Resource.Designer.cs b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Resource.Designer.cs new file mode 100644 index 000000000000..e6ee07174dcb --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Resource.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.18449 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Microsoft.Azure.Commands.KeyVault.Test { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resource { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resource() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.Azure.Commands.KeyVault.Test.Resource", typeof(Resource).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] pfxCert { + get { + object obj = ResourceManager.GetObject("pfxCert", resourceCulture); + return ((byte[])(obj)); + } + } + } +} diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Resource.resx b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Resource.resx new file mode 100644 index 000000000000..2d24425dc6d2 --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Resource.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + Resources\pshtest.pfx;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Resources/pshtest.pfx b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Resources/pshtest.pfx new file mode 100644 index 000000000000..fefc03c0d0a0 Binary files /dev/null and b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Resources/pshtest.pfx differ diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/Common.ps1 b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/Common.ps1 new file mode 100644 index 000000000000..35857d0d61ac --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/Common.ps1 @@ -0,0 +1,264 @@ +# ---------------------------------------------------------------------------------- +# +# Copyright Microsoft Corporation +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# http://www.apache.org/licenses/LICENSE-2.0 +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------------- + +$global:createdKeys = @() +$global:createdSecrets = @() + +$invocationPath = Split-Path $MyInvocation.MyCommand.Definition; + +<# +.SYNOPSIS +Get test key name +#> +function Get-KeyVault([bool] $haspermission=$true) +{ + if ($global:testEnv -eq 'BVT' -and $haspermission) + { + return 'powershellbvt' + } + elseif ($global:testEnv -eq 'BVT') + { + return 'azkmstestbvteu2' + } + elseif ($haspermission) + { + return 'azkmspsprodeus' + } + else + { + return 'azkmspsnopermprodeus' + } +} + +<# +.SYNOPSIS +Get test key name +#> +function Get-KeyName([string]$suffix) +{ + return 'pshtk-' + $global:testns+ '-' + $suffix +} + +<# +.SYNOPSIS +Get test secret name +#> +function Get-SecretName([string]$suffix) +{ + return 'pshts-' + $global:testns+ '-' + $suffix +} + + +<# +.SYNOPSIS +Get key file path to be imported +The name convention of a key file is $filesuffixtest.$filesuffix +#> +function Get-ImportKeyFile([string]$filesuffix, [bool] $exists=$true) +{ + if ($exists) + { + $file = "$filesuffix"+"test.$filesuffix" + } + else + { + $file = "notexist" + ".$filesuffix" + } + + if ($global:testEnv -eq 'BVT') + { + return Join-Path $invocationPath "bvtdata\$file" + } + else + { + return Join-Path $invocationPath "proddata\$file" + } +} + +<# +.SYNOPSIS +Remove log file under a folder +#> +function Cleanup-Log([string]$rootfolder) +{ + Get-ChildItem –Path $rootfolder -Include *.debug_log -Recurse | where {$_.mode -match "a"} | Remove-Item -Force +} + +<# +.SYNOPSIS +Remove log file under a folder +#> +function Move-Log([string]$rootfolder) +{ + $logfolder = Join-Path $rootfolder ("$global:testEnv"+"$global:testns"+"log") + if (Test-Path $logfolder) + { + Cleanup-Log $logfolder + } + else + { + New-Item $logfolder -type directory -force + } + + Get-ChildItem –Path $rootfolder -Include *.debug_log -Recurse | Move-Item -Destination $logfolder +} + + +<# +.SYNOPSIS +Removes all keys starting with the prefix +#> +function Initialize-KeyTest +{ + $keyVault = Get-KeyVault + $keyPattern = Get-KeyName '*' + Get-AzureKeyVaultKey $keyVault | Where-Object {$_.KeyName -like $keyPattern} | Remove-AzureKeyVaultKey -Force -Confirm:$false +} + +<# +.SYNOPSIS +Removes all secrets starting with the prefix +#> +function Initialize-SecretTest +{ + $keyVault = Get-KeyVault + $secretPattern = Get-SecretName '*' + Get-AzureKeyVaultSecret $keyVault | Where-Object {$_.SecretName -like $secretPattern} | Remove-AzureKeyVaultSecret -Force -Confirm:$false +} + + + +<# +.SYNOPSIS +Removes all created keys. +#> +function Cleanup-SingleKeyTest +{ + $global:createdKeys | % { + if ($_ -ne $null) + { + try + { + $keyVault = Get-KeyVault + Write-Debug "Removing key with name $_ in vault $keyVault" + $catch = Remove-AzureKeyVaultKey $keyVault $_ -Force -Confirm:$false + } + catch + { + } + } + } + + $global:createdKeys.Clear() +} + +<# +.SYNOPSIS +Removes all created secrets. +#> +function Cleanup-SingleSecretTest +{ + $global:createdSecrets | % { + if ($_ -ne $null) + { + try + { + $keyVault = Get-KeyVault + Write-Debug "Removing secret with name $_ in vault $keyVault" + $catch = Remove-AzureKeyVaultSecret $keyVault $_ -Force -Confirm:$false + } + catch + { + } + } + } + + $global:createdSecrets.Clear() +} + +<# +.SYNOPSIS +Run a key test, with cleanup. +#> +function Run-KeyTest ([ScriptBlock] $test, [string] $testName) +{ + try + { + Run-Test $test $testName *>> "$testName.debug_log" + } + finally + { + Cleanup-SingleKeyTest *>> "$testName.debug_log" + } +} + +function Run-SecretTest ([ScriptBlock] $test, [string] $testName) +{ + try + { + Run-Test $test $testName *>> "$testName.debug_log" + } + finally + { + Cleanup-SingleSecretTest *>> "$testName.debug_log" + } +} + +function Write-FileReport +{ + $fileName = "$global:testEnv"+"$global:testns"+"Summary.debug_log" + Get-TestRunReport *>> $fileName +} + + +function Get-TestRunReport +{ + + Write-Output "PASSED TEST Count=$global:passedCount" + Write-Output "Total TEST Count=$global:totalCount" + Write-Output "Start Time=$global:startTime" + Write-Output "End Time=$global:endTime" + $elapsed=$global:endTime - $global:startTime + Write-Output "Elapsed=$elapsed" + + Write-Output "Passed TEST`tExecutionTime" + $global:passedTests | % { $extime=$global:times[$_]; Write-Output $_`t$extime } + Write-Output "Failed TEST lists" + $global:failedTests | % { $extime=$global:times[$_]; Write-Output $_`t$extime } +} + +function Write-ConsoleReport +{ + Write-Host + Write-Host -ForegroundColor Green "$global:passedCount / $global:totalCount Key Vault Tests Pass" + Write-Host -ForegroundColor Green "============" + Write-Host -ForegroundColor Green "PASSED TESTS" + Write-Host -ForegroundColor Green "============" + $global:passedTests | % { Write-Host -ForegroundColor Green "PASSED "$_": "($global:times[$_]).ToString()} + Write-Host -ForegroundColor Green "============" + Write-Host + Write-Host -ForegroundColor Red "============" + Write-Host -ForegroundColor Red "FAILED TESTS" + Write-Host -ForegroundColor Red "============" + $global:failedTests | % { Write-Host -ForegroundColor Red "FAILED "$_": "($global:times[$_]).ToString()} + Write-Host -ForegroundColor Red "============" + Write-Host + Write-Host -ForegroundColor Green "=======" + Write-Host -ForegroundColor Green "TIMES" + Write-Host -ForegroundColor Green "=======" + Write-Host + Write-Host -ForegroundColor Green "Start Time: $global:startTime" + Write-Host -ForegroundColor Green "End Time: $global:endTime" + Write-Host -ForegroundColor Green "Elapsed: "($global:endTime - $global:startTime).ToString() +} \ No newline at end of file diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/PSHCommon/Assert.ps1 b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/PSHCommon/Assert.ps1 new file mode 100644 index 000000000000..eb7db0931910 --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/PSHCommon/Assert.ps1 @@ -0,0 +1,345 @@ +# ---------------------------------------------------------------------------------- +# +# Copyright Microsoft Corporation +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# http://www.apache.org/licenses/LICENSE-2.0 +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------------- + +###################### +# +# Validate that the given code block throws the given exception +# +# param [ScriptBlock] $script : The code to test +# param [string] $message : The text of the exception that should be thrown +####################### +function Assert-Throws +{ + param([ScriptBlock] $script, [string] $message) + try + { + &$script + } + catch + { + if ($message -ne "") + { + $actualMessage = $_.Exception.Message + Write-Output ("Caught exception: '$actualMessage'") + + if ($actualMessage -eq $message) + { + return $true; + } + else + { + throw "Expected exception not received: '$message' the actual message is '$actualMessage'"; + } + } + else + { + return $true; + } + } + + throw "No exception occured"; +} + +###################### +# +# Validate that the given code block throws the given exception +# +# param [ScriptBlock] $script : The code to test +# param [ScriptBlock] $compare : Predicate used to determine if the message meets criteria +####################### +function Assert-ThrowsContains +{ + param([ScriptBlock] $script, [string] $compare) + try + { + &$script + } + catch + { + if ($message -ne "") + { + $actualMessage = $_.Exception.Message + Write-Output ("Caught exception: '$actualMessage'") + if ($actualMessage.Contains($compare)) + { + return $true; + } + else + { + throw "Expected exception does not contain expected text '$compare', the actual message is '$actualMessage'"; + } + } + else + { + return $true; + } + } + + throw "No exception occured"; +} + +<# +.SYNOPSIS +Given a list of variable names, assert that all of them are defined +#> +function Assert-Env +{ + param([string[]] $vars) + $tmp = Get-Item env: + $env = @{} + $tmp | % { $env.Add($_.Key, $_.Value)} + $vars | % { Assert-True {$env.ContainsKey($_)} "Environment Variable $_ Is Required. Please set the value before runnign the test"} +} + +################### +# +# Verify that the given scriptblock returns true +# +# param [ScriptBlock] $script : The script to execute +# param [string] $message : The message to return if the given script does not return true +#################### +function Assert-True +{ + param([ScriptBlock] $script, [string] $message) + + if (!$message) + { + $message = "Assertion failed: " + $script + } + + $result = &$script + if (-not $result) + { + Write-Debug "Failure: $message" + throw $message + } + + return $true +} + +################### +# +# Verify that the given scriptblock returns false +# +# param [ScriptBlock] $script : The script to execute +# param [string] $message : The message to return if the given script does not return false +#################### +function Assert-False +{ + param([ScriptBlock] $script, [string] $message) + + if (!$message) + { + $message = "Assertion failed: " + $script + } + + $result = &$script + if ($result) + { + throw $message + } + + return $true +} + +################### +# +# Verify that the given scriptblock returns false +# +# param [ScriptBlock] $script : The script to execute +# param [string] $message : The message to return if the given script does not return false +#################### +function Assert-False +{ + param([ScriptBlock] $script, [string] $message) + + if (!$message) + { + $message = "Assertion failed: " + $script + } + + $result = &$script + if ($result) + { + throw $message + } + + return $true +} + +################### +# +# Verify that the given scriptblock does not return null +# +# param [object] $actual : The actual object +# param [string] $message : The message to return if the given script does not return true +#################### +function Assert-NotNull +{ + param([object] $actual, [string] $message) + + if (!$message) + { + $message = "Assertion failed because the object is null: " + $actual + } + + if ($actual -eq $null) + { + throw $message + } + + return $true +} + +###################### +# +# Assert that the given file exists +# +# param [string] $path : The path to the file to test +# param [string] $message: The text of the exception to throw if the file doesn't exist +###################### +function Assert-Exists +{ + param([string] $path, [string] $message) + return Assert-True {Test-Path $path} $message +} + +################### +# +# Verify that two given objects are equal +# +# param [object] $expected : The expected object +# param [object] $actual : The actual object +# param [string] $message : The message to return if the given objects are not equal +#################### +function Assert-AreEqual +{ + param([object] $expected, [object] $actual, [string] $message) + + if (!$message) + { + $message = "Assertion failed because expected '$expected' does not match actual '$actual'" + } + + if ($expected -ne $actual) + { + throw $message + } + + return $true +} + +################### +# +# Verify that two given arrays are equal +# +# param [array] $expected : The expected array +# param [array] $actual : The actual array +# param [string] $message : The message to return if the given arrays are not equal. +#################### +function Assert-AreEqualArray +{ + param([object] $expected, [object] $actual, [string] $message) + + if (!$message) + { + $message = "Assertion failed because expected '$expected' does not match actual '$actual'" + } + + $diff = Compare-Object $expected $actual -PassThru + + if ($diff -ne $null) + { + throw $message + } + + return $true +} + +################### +# +# Verify that two given objects have equal properties +# +# param [object] $expected : The expected object +# param [object] $actual : The actual object +# param [string] $message : The message to return if the given objects are not equal. +#################### +function Assert-AreEqualObjectProperties +{ + param([object] $expected, [object] $actual, [string] $message) + + $properties = $expected | Get-Member -MemberType "Property" | Select -ExpandProperty Name + $diff = Compare-Object $expected $actual -Property $properties + + if ($diff -ne $null) + { + if (!$message) + { + $message = "Assert failed because the objects don't match. Expected: " + $diff[0] + " Actual: " + $diff[1] + } + + throw $message + } + + return $true +} + +################### +# +# Verify that the given value is null +# +# param [object] $actual : The actual object +# param [string] $message : The message to return if the given object is not null +#################### +function Assert-Null +{ + param([object] $actual, [string] $message) + + if (!$message) + { + $message = "Assertion failed because the object is not null: " + $actual + } + + if ($actual -ne $null) + { + throw $message + } + + return $true +} + +################### +# +# Verify that two given objects are not equal +# +# param [object] $expected : The expected object +# param [object] $actual : The actual object +# param [string] $message : The message to return if the given objects are equal +#################### +function Assert-AreNotEqual +{ + param([object] $expected, [object] $actual, [string] $message) + + if (!$message) + { + $message = "Assertion failed because expected '$expected' does match actual '$actual'" + } + + if ($expected -eq $actual) + { + throw $message + } + + return $true +} \ No newline at end of file diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/PSHCommon/Common.ps1 b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/PSHCommon/Common.ps1 new file mode 100644 index 000000000000..dadbcab9bceb --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/PSHCommon/Common.ps1 @@ -0,0 +1,363 @@ +# ---------------------------------------------------------------------------------- +# +# Copyright Microsoft Corporation +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# http://www.apache.org/licenses/LICENSE-2.0 +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------------- + +$excludedExtensions = @(".dll", ".zip", ".msi", ".exe") +################################### +# +# Retrievce the contents of a powershrell transcript, stripping headers and footers +# +# param [string] $path: The path to the transript file to read +################################### +function Get-Transcript +{ + param([string] $path) + return Get-Content $path | + Select-String -InputObject {$_} -Pattern "^Start Time\s*:.*" -NotMatch | + Select-String -InputObject {$_} -Pattern "^End Time\s*:.*" -NotMatch | + Select-String -InputObject {$_} -Pattern "^Machine\s*:.*" -NotMatch | + Select-String -InputObject {$_} -Pattern "^Username\s*:.*" -NotMatch | + Select-String -InputObject {$_} -Pattern "^Transcript started, output file is.*" -NotMatch +} + +######################## +# +# Get a random file name in the current directory +# +# param [string] $rootPath: The path of the directory to contain the random file (optional) +######################## +function Get-LogFile +{ + param([string] $rootPath = ".") + return [System.IO.Path]::Combine($rootPath, ([System.IO.Path]::GetRandomFileName())) +} + +################# +# +# Execute a test, no exception thrown means the test passes. Can also be used to compare test +# output to a baseline file, or to generate a baseline file +# +# param [scriptblock] $test: The test code to run +# param [string] $testScript: The path to the baseline file (optional) +# param [switch] $generate: Set if the baseline file should be generated, otherwise +# the baseline file would be used for comparison with test output +################## +function Run-Test +{ + param([scriptblock]$test, [string] $testName = $null, [string] $testScript = $null, [switch] $generate = $false) + Test-Setup + $transFile = $testName + ".log" + if ($testName -eq $null) + { + $transFile = Get-LogFile "." + } + if($testScript) + { + if ($generate) + { + Write-Log "[run-test]: generating script file $testScript" + $transFile = $testScript + } + else + { + Write-Log "[run-test]: writing output to $transFile, using validation script $testScript" + } + } + else + { + Write-Log "[run-test]: Running test without file comparison" + } + + $oldPref = $ErrorActionPreference + $ErrorActionPreference = "SilentlyContinue" + #Start-Transcript -Path $transFile + $success = $false; + $ErrorActionPreference = $oldPref + try + { + &$test + $success = $true; + } + finally + { + Test-Cleanup + $oldPref = $ErrorActionPreference + $ErrorActionPreference = "SilentlyContinue" + #Stop-Transcript + $ErrorActionPreference = $oldPref + if ($testScript) + { + if ($success -and -not $generate) + { + $result = Compare-Object (Get-Transcript $testScript) (Get-Transcript $transFile) + if ($result -ne $null) + { + throw "[run-test]: Test Failed " + (Out-String -InputObject $result) + ", Transcript at $transFile" + } + + } + } + + if ($success) + { + Write-Log "[run-test]: Test Passed" + } + } + +} + +################## +# +# Format a string for proper output to host and transcript +# +# param [string] $message: The text to write +################## +function Write-Log +{ + [CmdletBinding()] + param( [Object] [Parameter(Position=0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$false)] $obj = "") + PROCESS + { + $obj | Out-String | Write-Verbose + } +} + +function Check-SubscriptionMatch +{ + param([string] $baseSubscriptionName, [Microsoft.WindowsAzure.Commands.Utilities.Common.SubscriptionData] $checkedSubscription) + Write-Log ("[CheckSubscriptionMatch]: base subscription: '$baseSubscriptionName', validating '" + ($checkedSubscription.SubscriptionName)+ "'") + Format-Subscription $checkedSubscription | Write-Log + if ($baseSubscriptionName -ne $checkedSubscription.SubscriptionName) + { + throw ("[Check-SubscriptionMatch]: Subscription Match Failed '" + ($baseSubscriptionName) + "' != '" + ($checkedSubscription.SubscriptionName) + "'") + } + + Write-Log ("CheckSubscriptionMatch]: subscription check succeeded.") +} + + +########################## +# +# Return the fully qualified filename of a given file +# +# param [string] $path: The relative path to the file +# +########################## +function Get-FullName +{ + param([string] $path) + $pathObj = Get-Item $path + return ($pathObj.FullName) +} + +############################# +# +# PowerShell environment setup for running a test, save previous snvironment settings and +# enable verbose, debug, and warning streams +# +############################# +function Test-Setup +{ + $global:oldConfirmPreference = $global:ConfirmPreference + $global:oldDebugPreference = $global:DebugPreference + $global:oldErrorActionPreference = $global:ErrorActionPreference + $global:oldFormatEnumerationLimit = $global:FormatEnumerationLimit + $global:oldProgressPreference = $global:ProgressPreference + $global:oldVerbosePreference = $global:VerbosePreference + $global:oldWarningPreference = $global:WarningPreference + $global:oldWhatIfPreference = $global:WhatIfPreference + $global:ConfirmPreference = "None" + $global:DebugPreference = "Continue" + $global:ErrorActionPreference = "Stop" + $global:FormatEnumerationLimit = 10000 + $global:ProgressPreference = "SilentlyContinue" + $global:VerbosePreference = "Continue" + $global:WarningPreference = "Continue" + $global:WhatIfPreference = 0 +} + +############################# +# +# PowerShell environment cleanup for running a test, restore previous snvironment settings +# +############################# +function Test-Cleanup +{ + $global:ConfirmPreference = $global:oldConfirmPreference + $global:DebugPreference = $global:oldDebugPreference + $global:ErrorActionPreference = $global:oldErrorActionPreference + $global:FormatEnumerationLimit = $global:oldFormatEnumerationLimit + $global:ProgressPreference = $global:oldProgressPreference + $global:VerbosePreference = $global:oldVerbosePreference + $global:WarningPreference = $global:oldWarningPreference + $global:WhatIfPreference = $global:oldWhatIfPreference +} + +####################### +# +# Dump the contents of a directory to the output stream +# +# param [string] $rootPath: The path to the directory +# param [switch] $resurse : True if we should recurse directories +###################### +function Dump-Contents +{ + param([string] $rootPath = ".", [switch] $recurse = $false) + if (-not ((Test-Path $rootPath) -eq $true)) + { + throw "[dump-contents]: $rootPath does not exist" + } + + foreach ($item in Get-ChildItem $rootPath) + { + Write-Log + Write-Log "---------------------------" + Write-Log $item.Name + Write-Log "---------------------------" + Write-Log + if (!$item.PSIsContainer) + { + if (Test-BinaryFile $item) + { + Write-Log "---- binary data excluded ----" + } + else + { + Get-Content ($item.PSPath) + } + } + elseif ($recurse) + { + Dump-Contents ($item.PSPath) -recurse + } + } +} + +function Test-BinaryFile +{ + param ([System.IO.FileInfo] $file) + ($excludedExtensions | Where-Object -FilterScript {$_ -eq $file.Extension}) -ne $null +} + + +<# +.SYNOPSIS +Removes all current subscriptions. +#> +function Remove-AllSubscriptions +{ + Get-AzureSubscription | Remove-AzureSubscription -Force +} + +<# +.SYNOPSIS +Waits on the specified job with the given timeout. + +.PARAMETER scriptBlock +The script block to execute. + +.PARAMETER timeout +The maximum timeout for the script. +#> +function Wait-Function +{ + param([ScriptBlock] $scriptBlock, [object] $breakCondition, [int] $timeout) + + if ($timeout -eq 0) { $timeout = 60 * 5 } + $start = [DateTime]::Now + $current = [DateTime]::Now + $diff = $current - $start + + do + { + Start-Sleep -s 5 + $current = [DateTime]::Now + $diff = $current - $start + $result = &$scriptBlock + } + while(($result -ne $breakCondition) -and ($diff.TotalSeconds -lt $timeout)) + + if ($diff.TotalSeconds -ge $timeout) + { + Write-Warning "The script block '$scriptBlock' exceeded the timeout." + # End the processing so the test does not blow up + exit + } +} + + +<# +.SYNOPSIS +Waits for specified duration if not-mocked, otherwise skips wait. + +.PARAMETER timeout +Timeout in seconds +#> +function Wait-Seconds +{ + param([int] $timeout) + + [Microsoft.WindowsAzure.Testing.TestUtilities]::Wait($timeout * 1000) +} + + +<# +.SYNOPSIS +Retires the specified job the given numer of times, waiting the given interval between tries + +.PARAMETER scriptBlock +The script block to execute. Must be a predicate (return true or false) + +.PARAMETER argument +Argument to pass to the script block + +.PARAMETER maxTries +The maximum number of times to retry + +.PARAMETER interval +The number of seconds to wait before retrying +#> +function Retry-Function +{ + param([ScriptBlock] $scriptBlock, [Object] $argument, [int] $maxTries, [int] $interval) + + if ($interval -eq 0) { $interval = 60 } + + $result = Invoke-Command -ScriptBlock $scriptBlock -ArgumentList $argument; + $tries = 1; + while(( $result -ne $true) -and ($tries -le $maxTries)) + { + Start-Sleep -s $interval + $result = Invoke-Command -ScriptBlock $scriptBlock -ArgumentList $argument; + $tries++; + } + + return $result; +} + +function getAssetName +{ + $stack = Get-PSCallStack + $testName = $null; + foreach ($frame in $stack) + { + if ($frame.Command.StartsWith("Test-", "CurrentCultureIgnoreCase")) + { + $testName = $frame.Command + } + } + + $assetName = [Microsoft.Azure.Utilities.HttpRecorder.HttpMockServer]::GetAssetName($testName, "onesdk") + + return $assetName +} \ No newline at end of file diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/RunKeyVaultTests.ps1 b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/RunKeyVaultTests.ps1 new file mode 100644 index 000000000000..ae3fe0a01533 --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/RunKeyVaultTests.ps1 @@ -0,0 +1,172 @@ +Param( + [Parameter(Mandatory=$True,Position=0)] + [ValidateSet('BVT','PROD')] + [string]$testenv, + [Parameter(Mandatory=$True,Position=1)] + [string]$testns +) + +$invocationPath = Split-Path $MyInvocation.MyCommand.Definition; +. (Join-Path $invocationPath "PSHCommon\Common.ps1"); +. (Join-Path $invocationPath "PSHCommon\Assert.ps1"); +. (Join-Path $invocationPath "Common.ps1"); +. (Join-Path $invocationPath "VaultKeyTests.ps1"); +. (Join-Path $invocationPath "VaultSecretTests.ps1"); + +$global:totalCount = 0; +$global:passedCount = 0; +$global:passedTests = @() +$global:failedTests = @() +$global:times = @{} +$global:testEnv = $testenv.ToUpperInvariant() +$global:testns = $testns + +function Run-TestProtected +{ + param([ScriptBlock]$script, [string] $testName) + $testStart = Get-Date + try + { + Write-Host -ForegroundColor Green ===================================== + Write-Host -ForegroundColor Green "Running test $testName" + Write-Host -ForegroundColor Green ===================================== + Write-Host + &$script + $global:passedCount = $global:passedCount + 1 + Write-Host + Write-Host -ForegroundColor Green ===================================== + Write-Host -ForegroundColor Green "Test Passed" + Write-Host -ForegroundColor Green ===================================== + Write-Host + $global:passedTests += $testName + } + catch + { + Out-String -InputObject $_.Exception | Write-Host -ForegroundColor Red + Write-Host + Write-Host -ForegroundColor Red ===================================== + Write-Host -ForegroundColor Red "Test Failed" + Write-Host -ForegroundColor Red ===================================== + Write-Host + $global:failedTests += $testName + } + finally + { + $testEnd = Get-Date + $testElapsed = $testEnd - $testStart + $global:times[$testName] = $testElapsed + $global:totalCount = $global:totalCount + 1 + } +} + +# Initialize +Write-Host Delete log files +Cleanup-Log $invocationPath + +$testkeyVault = Get-KeyVault +Write-Host Test key vault is $testKeyVault +Write-Host Initializing Key Tests +Initialize-KeyTest +Write-Host Initializing Secret Tests +Initialize-SecretTest +Write-Host Initialization Completed + +$global:startTime = Get-Date + +# Add-AzureKeyVaultKey tests +Run-TestProtected { Run-KeyTest {Test_CreateSoftwareKeyWithDefaultAttributes} "Test_CreateSoftwareKeyWithDefaultAttributes" } "Test_CreateSoftwareKeyWithDefaultAttributes" +Run-TestProtected { Run-KeyTest {Test_CreateSoftwareKeyWithCustomAttributes} "Test_CreateSoftwareKeyWithCustomAttributes" } "Test_CreateSoftwareKeyWithCustomAttributes" +Run-TestProtected { Run-KeyTest {Test_CreateHsmKeyWithDefaultAttributes} "Test_CreateHsmKeyWithDefaultAttributes" } "Test_CreateHsmKeyWithDefaultAttributes" +Run-TestProtected { Run-KeyTest {Test_CreateHsmKeyWithCustomAttributes} "Test_CreateHsmKeyWithCustomAttributes" } "Test_CreateHsmKeyWithCustomAttributes" +Run-TestProtected { Run-KeyTest {Test_ImportPfxWithDefaultAttributes} "Test_ImportPfxWithDefaultAttributes" } "Test_ImportPfxWithDefaultAttributes" +Run-TestProtected { Run-KeyTest {Test_ImportPfxWithCustomAttributes} "Test_ImportPfxWithCustomAttributes" } "Test_ImportPfxWithCustomAttributes" +Run-TestProtected { Run-KeyTest {Test_ImportPfxAsHsmWithDefaultAttributes} "Test_ImportPfxAsHsmWithDefaultAttributes" } "Test_ImportPfxAsHsmWithDefaultAttributes" +Run-TestProtected { Run-KeyTest {Test_ImportPfxAsHsmWithCustomAttributes} "Test_ImportPfxAsHsmWithCustomAttributes" } "Test_ImportPfxAsHsmWithCustomAttributes" +Run-TestProtected { Run-KeyTest {Test_ImportByokWithDefaultAttributes} "Test_ImportByokWithDefaultAttributes" } "Test_ImportByokWithDefaultAttributes" +Run-TestProtected { Run-KeyTest {Test_ImportByokWithCustomAttributes} "Test_ImportByokWithCustomAttributes" } "Test_ImportByokWithCustomAttributes" +Run-TestProtected { Run-KeyTest {Test_AddKeyPositionalParameter} "Test_AddKeyPositionalParameter" } "Test_AddKeyPositionalParameter" +Run-TestProtected { Run-KeyTest {Test_AddKeyAliasParameter} "Test_AddKeyAliasParameter" } "Test_AddKeyAliasParameter" +Run-TestProtected { Run-KeyTest {Test_ImportNonExistPfxFile} "Test_ImportNonExistPfxFile" } "Test_ImportNonExistPfxFile" +Run-TestProtected { Run-KeyTest {Test_ImportPfxFileWithIncorrectPassword} "Test_ImportPfxFileWithIncorrectPassword" } "Test_ImportPfxFileWithIncorrectPassword" +Run-TestProtected { Run-KeyTest {Test_ImportNonExistByokFile} "Test_ImportNonExistByokFile" } "Test_ImportNonExistByokFile" +Run-TestProtected { Run-KeyTest {Test_CreateKeyInNonExistVault} "Test_CreateKeyInNonExistVault" } "Test_CreateKeyInNonExistVault" +Run-TestProtected { Run-KeyTest {Test_ImportByokAsSoftwareKey} "Test_ImportByokAsSoftwareKey" } "Test_ImportByokAsSoftwareKey" +Run-TestProtected { Run-KeyTest {Test_CreateKeyInNoPermissionVault} "Test_CreateKeyInNoPermissionVault" } "Test_CreateKeyInNoPermissionVault" + +# Set-AzureKeyVaultKey tests +# Uncomment it after fix bug +#Run-TestProtected { Run-KeyTest {Test_UpdateIndividualAttributes} "Test_UpdateIndividualAttributes" } "Test_UpdateIndividualAttributes" +Run-TestProtected { Run-KeyTest {Test_UpdateAllEditableAttributes} "Test_UpdateAllEditableAttributes" } "Test_UpdateAllEditableAttributes" +Run-TestProtected { Run-KeyTest {Test_SetKeyPositionalParameter} "Test_SetKeyPositionalParameter" } "Test_SetKeyPositionalParameter" +Run-TestProtected { Run-KeyTest {Test_SetKeyAliasParameter} "Test_SetKeyAliasParameter" } "Test_SetKeyAliasParameter" +Run-TestProtected { Run-KeyTest {Test_SetKeyInNonExistVault} "Test_SetKeyInNonExistVault" } "Test_SetKeyInNonExistVault" +Run-TestProtected { Run-KeyTest {Test_SetNonExistKey} "Test_SetNonExistKey" } "Test_SetNonExistKey" +Run-TestProtected { Run-KeyTest {Test_SetInvalidAttributes} "Test_SetInvalidAttributes" } "Test_SetInvalidAttributes" +Run-TestProtected { Run-KeyTest {Test_SetKeyInNoPermissionVault} "Test_SetKeyInNoPermissionVault" } "Test_SetKeyInNoPermissionVault" + +# Get-AzureKeyVaultKey tests +Run-TestProtected { Run-KeyTest {Test_GetOneKey} "Test_GetOneKey" } "Test_GetOneKey" +Run-TestProtected { Run-KeyTest {Test_GetAllKeys} "Test_GetAllKeys" } "Test_GetAllKeys" +Run-TestProtected { Run-KeyTest {Test_GetKeyPositionalParameter} "Test_GetKeyPositionalParameter" } "Test_GetKeyPositionalParameter" +Run-TestProtected { Run-KeyTest {Test_GetKeyAliasParameter} "Test_GetKeyAliasParameter" } "Test_GetKeyAliasParameter" +Run-TestProtected { Run-KeyTest {Test_GetKeysInNonExistVault} "Test_GetKeysInNonExistVault" } "Test_GetKeysInNonExistVault" +Run-TestProtected { Run-KeyTest {Test_GetNonExistKey} "Test_GetNonExistKey" } "Test_GetNonExistKey" +Run-TestProtected { Run-KeyTest {Test_GetKeyInNoPermissionVault} "Test_GetKeyInNoPermissionVault" } "Test_GetKeyInNoPermissionVault" + + +# Remove-AzureKeyVaultKey tests +Run-TestProtected { Run-KeyTest {Test_RemoveKeyWithoutPrompt} "Test_RemoveKeyWithoutPrompt" } "Test_RemoveKeyWithoutPrompt" +Run-TestProtected { Run-KeyTest {Test_RemoveKeyWhatIf} "Test_RemoveKeyWhatIf" } "Test_RemoveKeyWhatIf" +Run-TestProtected { Run-KeyTest {Test_RemoveKeyPositionalParameter} "Test_RemoveKeyPositionalParameter" } "Test_RemoveKeyPositionalParameter" +Run-TestProtected { Run-KeyTest {Test_RemoveKeyAliasParameter} "Test_RemoveKeyAliasParameter" } "Test_RemoveKeyAliasParameter" +Run-TestProtected { Run-KeyTest {Test_RemoveKeyInNonExistVault} "Test_RemoveKeyInNonExistVault" } "Test_RemoveKeyInNonExistVault" +Run-TestProtected { Run-KeyTest {Test_RemoveNonExistKey} "Test_RemoveNonExistKey" } "Test_RemoveNonExistKey" +Run-TestProtected { Run-KeyTest {Test_RemoveKeyInNoPermissionVault} "Test_RemoveKeyInNoPermissionVault" } "Test_RemoveKeyInNoPermissionVault" + +# *-AzureKeyVaultKey pipeline tests +Run-TestProtected { Run-KeyTest {Test_PipelineUpdateKeys} "Test_PipelineUpdateKeys" } "Test_PipelineUpdateKeys" +Run-TestProtected { Run-KeyTest {Test_PipelineRemoveKeys} "Test_PipelineRemoveKeys" } "Test_PipelineRemoveKeys" + + +# Set-AzureKeyVaultSecret tests +Run-TestProtected { Run-SecretTest {Test_CreateSecret} "Test_CreateSecret" } "Test_CreateSecret" +Run-TestProtected { Run-SecretTest {Test_UpdateSecret} "Test_UpdateSecret" } "Test_UpdateSecret" +Run-TestProtected { Run-SecretTest {Test_SetSecretPositionalParameter} "Test_SetSecretPositionalParameter" } "Test_SetSecretPositionalParameter" +Run-TestProtected { Run-SecretTest {Test_SetSecretAliasParameter} "Test_SetSecretAliasParameter" } "Test_SetSecretAliasParameter" +Run-TestProtected { Run-SecretTest {Test_SetSecretInNonExistVault} "Test_SetSecretInNonExistVault" } "Test_SetSecretInNonExistVault" +Run-TestProtected { Run-SecretTest {Test_SetSecretInNoPermissionVault} "Test_SetSecretInNoPermissionVault" } "Test_SetSecretInNoPermissionVault" + +# Get-AzureKeyVaultSecret tests +Run-TestProtected { Run-SecretTest {Test_GetOneSecret} "Test_GetOneSecret" } "Test_GetOneSecret" +Run-TestProtected { Run-SecretTest {Test_GetAllSecrets} "Test_GetAllSecrets" } "Test_GetAllSecrets" +Run-TestProtected { Run-SecretTest {Test_GetSecretPositionalParameter} "Test_GetSecretPositionalParameter" } "Test_GetSecretPositionalParameter" +Run-TestProtected { Run-SecretTest {Test_GetSecretAliasParameter} "Test_GetSecretAliasParameter" } "Test_GetSecretAliasParameter" +Run-TestProtected { Run-SecretTest {Test_GetSecretInNonExistVault} "Test_GetSecretInNonExistVault" } "Test_GetSecretInNonExistVault" +Run-TestProtected { Run-SecretTest {Test_GetNonExistSecret} "Test_GetNonExistSecret" } "Test_GetNonExistSecret" +Run-TestProtected { Run-SecretTest {Test_GetSecretInNoPermissionVault} "Test_GetSecretInNoPermissionVault" } "Test_GetSecretInNoPermissionVault" + +# Remove-AzureKeyVaultSecret tests +Run-TestProtected { Run-SecretTest {Test_RemoveSecretWithoutPrompt} "Test_RemoveSecretWithoutPrompt" } "Test_RemoveSecretWithoutPrompt" +Run-TestProtected { Run-SecretTest {Test_RemoveSecretWhatIf} "Test_RemoveSecretWhatIf" } "Test_RemoveSecretWhatIf" +Run-TestProtected { Run-SecretTest {Test_RemoveSecretPositionalParameter} "Test_RemoveSecretPositionalParameter" } "Test_RemoveSecretPositionalParameter" +Run-TestProtected { Run-SecretTest {Test_RemoveSecretAliasParameter} "Test_RemoveSecretAliasParameter" } "Test_RemoveSecretAliasParameter" +Run-TestProtected { Run-SecretTest {Test_RemoveSecretInNonExistVault} "Test_RemoveSecretInNonExistVault" } "Test_RemoveSecretInNonExistVault" +Run-TestProtected { Run-SecretTest {Test_RemoveNonExistSecret} "Test_RemoveNonExistSecret" } "Test_RemoveNonExistSecret" +Run-TestProtected { Run-SecretTest {Test_RemoveSecretInNoPermissionVault} "Test_RemoveSecretInNoPermissionVault" } "Test_RemoveSecretInNoPermissionVault" + + +# *-AzureKeyVaultKey pipeline tests +Run-TestProtected { Run-SecretTest {Test_PipelineUpdateSecrets} "Test_PipelineUpdateSecrets" } "Test_PipelineUpdateSecrets" +Run-TestProtected { Run-SecretTest {Test_PipelineRemoveSecrets} "Test_PipelineRemoveSecrets" } "Test_PipelineRemoveSecrets" + +$global:endTime = Get-Date + +# Report +Write-FileReport +Write-ConsoleReport + + +# Post run +Move-Log $invocationPath + + diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/RunUITests.ps1 b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/RunUITests.ps1 new file mode 100644 index 000000000000..0152b97a708f --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/RunUITests.ps1 @@ -0,0 +1,95 @@ +Param( + [Parameter(Mandatory=$True,Position=0)] + [ValidateSet('BVT','PROD')] + [string]$testenv, + [Parameter(Mandatory=$True,Position=1)] + [string]$testns +) + +$invocationPath = Split-Path $MyInvocation.MyCommand.Definition; +. (Join-Path $invocationPath "PSHCommon\Common.ps1"); +. (Join-Path $invocationPath "PSHCommon\Assert.ps1"); +. (Join-Path $invocationPath "Common.ps1"); +. (Join-Path $invocationPath "VaultUITests.ps1"); + +$global:totalCount = 0; +$global:passedCount = 0; +$global:passedTests = @() +$global:failedTests = @() +$global:times = @{} +$global:testEnv = $testenv.ToUpperInvariant() +$global:testns = $testns+"UI" + +function Run-TestProtected +{ + param([ScriptBlock]$script, [string] $testName) + $testStart = Get-Date + try + { + Write-Host -ForegroundColor Green ===================================== + Write-Host -ForegroundColor Green "Running test $testName" + Write-Host -ForegroundColor Green ===================================== + Write-Host + &$script + $global:passedCount = $global:passedCount + 1 + Write-Host + Write-Host -ForegroundColor Green ===================================== + Write-Host -ForegroundColor Green "Test Passed" + Write-Host -ForegroundColor Green ===================================== + Write-Host + $global:passedTests += $testName + } + catch + { + Out-String -InputObject $_.Exception | Write-Host -ForegroundColor Red + Write-Host + Write-Host -ForegroundColor Red ===================================== + Write-Host -ForegroundColor Red "Test Failed" + Write-Host -ForegroundColor Red ===================================== + Write-Host + $global:failedTests += $testName + } + finally + { + $testEnd = Get-Date + $testElapsed = $testEnd - $testStart + $global:times[$testName] = $testElapsed + $global:totalCount = $global:totalCount + 1 + } +} + +# Initialize +Write-Host Delete log files +Cleanup-Log $invocationPath + +$testkeyVault = Get-KeyVault +Write-Host Test key vault is $testKeyVault +Write-Host Initializing Key Tests +Initialize-KeyTest +Write-Host Initializing Secret Tests +Initialize-SecretTest +Write-Host Initialization Completed + +$global:startTime = Get-Date + +# Run key tests +Run-TestProtected { Run-KeyTest {Test_RemoveKeyWithTwoConfirmations} "Test_RemoveKeyWithTwoConfirmations" } "Test_RemoveKeyWithTwoConfirmations" +Run-TestProtected { Run-KeyTest {Test_RemoveKeyWithOneConfirmations} "Test_RemoveKeyWithOneConfirmations" } "Test_RemoveKeyWithOneConfirmations" +Run-TestProtected { Run-KeyTest {Test_CancelKeyRemovalOnce} "Test_CancelKeyRemovalOnce" } "Test_CancelKeyRemovalOnce" +Run-TestProtected { Run-KeyTest {Test_ConfirmThenCancelKeyRemoval} "Test_ConfirmThenCancelKeyRemoval" } "Test_ConfirmThenCancelKeyRemoval" + +# Run secret tests +Run-TestProtected { Run-SecretTest {Test_RemoveSecretWithTwoConfirmations} "Test_RemoveSecretWithTwoConfirmations" } "Test_RemoveSecretWithTwoConfirmations" +Run-TestProtected { Run-SecretTest {Test_RemoveSecretWithOneConfirmations} "Test_RemoveSecretWithOneConfirmations" } "Test_RemoveSecretWithOneConfirmations" +Run-TestProtected { Run-SecretTest {Test_CancelSecretRemovalOnce} "Test_CancelSecretRemovalOnce" } "Test_CancelSecretRemovalOnce" +Run-TestProtected { Run-SecretTest {Test_ConfirmThenCancelSecretRemoval} "Test_ConfirmThenCancelSecretRemoval" } "Test_ConfirmThenCancelSecretRemoval" + + +$global:endTime = Get-Date + +# Report +Write-FileReport +Write-ConsoleReport + +# Post run +Move-Log $invocationPath diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/VaultKeyTests.ps1 b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/VaultKeyTests.ps1 new file mode 100644 index 000000000000..897e178719dd --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/VaultKeyTests.ps1 @@ -0,0 +1,693 @@ +$pfxpwd='123' +$securepfxpwd=$pfxpwd | ConvertTo-SecureString -AsPlainText -Force +$expires= (Get-Date).AddYears(2).ToUniversalTime() +$nbf=(Get-Date).ToUniversalTime() +$newexpires= (Get-Date).AddYears(5).ToUniversalTime() +$newnbf=(Get-Date).AddYears(1).ToUniversalTime() +$ops = "decrypt", "verify" +$delta=[TimeSpan]::FromMinutes(2) + +function Equal-DateTime($left, $right) +{ + if ($left -eq $null -and $right -eq $null) + { + return $true + } + if ($left -eq $null -or $right -eq $null) + { + return $false + } + + return (($left - $right).Duration() -le $delta) +} + +function Assert-KeyAttributes($keyAttr, $keytype, $keyenable, $keyexp, $keynbf, $keyops) +{ + Assert-NotNull $keyAttr, "keyAttr is null." + Assert-AreEqual $keytype $keyAttr.KeyType "Expect $keytype. Get $keyAttr.KeyType" + Assert-AreEqual $keyenable $keyAttr.Enabled "Expect $keyenable. Get $keyAttr.Enabled" + if ($keyexp -ne $null) + { + Assert-True { Equal-DateTime $keyexp $keyAttr.Expires } "Expect $keyexp. Get $keyAttr.Expires" + } + if ($keynbf -ne $null) + { + Assert-True { Equal-DateTime $keynbf $keyAttr.NotBefore} "Expect $keynbf. Get $keyAttr.NotBefore" + } +} + + +<# +.SYNOPSIS +Tests create software key with default attributes +#> + +function Test_CreateSoftwareKeyWithDefaultAttributes +{ + $keyVault = Get-KeyVault + $keyname=Get-KeyName 'soft' + $key=Add-AzureKeyVaultKey -VaultName $keyVault -Name $keyname + Assert-NotNull $key + $global:createdKeys += $keyname + Assert-KeyAttributes $key.Attributes 'RSA' $true $null $null $null +} + +<# +.SYNOPSIS +Tests create software key with custom attributes +#> +function Test_CreateSoftwareKeyWithCustomAttributes +{ + $keyVault = Get-KeyVault + $keyname=Get-KeyName 'attr' + $key=Add-AzureKeyVaultKey -VaultName $keyVault -Name $keyname -Destination 'Software' -Expires $expires -NotBefore $nbf -KeyOps $ops -Disable + Assert-NotNull $key + $global:createdKeys += $keyname + Assert-KeyAttributes $key.Attributes 'RSA' $false $expires $nbf $ops +} + +<# +.SYNOPSIS +Tests create Hsm key with custom attributes +#> +function Test_CreateHsmKeyWithDefaultAttributes +{ + $keyVault = Get-KeyVault + $keyname=Get-KeyName 'hsm' + $key=Add-AzureKeyVaultKey -VaultName $keyVault -Name $keyname -Destination 'HSM' + Assert-NotNull $key + $global:createdKeys += $keyname + Assert-KeyAttributes $key.Attributes 'RSA-HSM' $true $null $null $null +} + +<# +.SYNOPSIS +Tests create Hsm key with custom attributes +#> +function Test_CreateHsmKeyWithCustomAttributes +{ + $keyVault = Get-KeyVault + $keyname=Get-KeyName 'attrhsm' + $key=Add-AzureKeyVaultKey -VaultName $keyVault -Name $keyname -Destination 'HSM' -Expires $expires -NotBefore $nbf -KeyOps $keyOps -Disable + Assert-NotNull $key + $global:createdKeys += $keyname + Assert-KeyAttributes $key.Attributes 'RSA-HSM' $false $expires $nbf $ops +} + +<# +.SYNOPSIS +Tests import pfx with default attributes +#> +function Test_ImportPfxWithDefaultAttributes +{ + $keyVault = Get-KeyVault + $keyname=Get-KeyName 'pfx' + $pfxpath = Get-ImportKeyFile 'pfx' + $key=Add-AzureKeyVaultKey -VaultName $keyVault -Name $keyname -KeyFilePath $pfxpath -KeyFilePassword $securepfxpwd + Assert-NotNull $key + $global:createdKeys += $keyname + Assert-KeyAttributes $key.Attributes 'RSA' $true $null $null $null + } + +<# +.SYNOPSIS +Tests import pfx with custom attributes +#> +function Test_ImportPfxWithCustomAttributes +{ + $keyVault = Get-KeyVault + $keyname=Get-KeyName 'attrpfx' + $pfxpath = Get-ImportKeyFile 'pfx' + $key=Add-AzureKeyVaultKey -VaultName $keyVault -Name $keyname -Destination 'Software' -KeyFilePath $pfxpath -KeyFilePassword $securepfxpwd -Expires $expires -NotBefore $nbf -KeyOps $keyOps -Disable + Assert-NotNull $key + $global:createdKeys += $keyname + Assert-KeyAttributes $key.Attributes 'RSA' $false $expires $nbf $ops +} + +<# +.SYNOPSIS +Tests import pfx as Hsm with default attributes +#> +function Test_ImportPfxAsHsmWithDefaultAttributes +{ + $keyVault = Get-KeyVault + $keyname=Get-KeyName 'pfxashsm' + $pfxpath = Get-ImportKeyFile 'pfx' + $key=Add-AzureKeyVaultKey -VaultName $keyVault -Name $keyname -Destination 'HSM' -KeyFilePath $pfxpath -KeyFilePassword $securepfxpwd + Assert-NotNull $key + $global:createdKeys += $keyname + Assert-KeyAttributes $key.Attributes 'RSA-HSM' $true $null $null $null +} + +<# +.SYNOPSIS +Tests import pfx as Hsm with custom attributes +#> +function Test_ImportPfxAsHsmWithCustomAttributes +{ + $keyVault = Get-KeyVault + $keyname=Get-KeyName 'attrpfxashsm' + $pfxpath = Get-ImportKeyFile 'pfx' + $key=Add-AzureKeyVaultKey -VaultName $keyVault -Name $keyname -Destination 'HSM' -KeyFilePath $pfxpath -KeyFilePassword $securepfxpwd -Expires $expires -NotBefore $nbf -KeyOps $keyOps -Disable + Assert-NotNull $key + $global:createdKeys += $keyname + Assert-KeyAttributes $key.Attributes 'RSA-HSM' $false $expires $nbf $ops +} + +<# +.SYNOPSIS +Tests import byok with default attributes +#> +function Test_ImportByokWithDefaultAttributes +{ + $keyVault = Get-KeyVault + $keyname=Get-KeyName 'byok' + $byokpath = Get-ImportKeyFile 'byok' + $key=Add-AzureKeyVaultKey -VaultName $keyVault -Name $keyname -KeyFilePath $byokpath + Assert-NotNull $key + $global:createdKeys += $keyname + Assert-KeyAttributes $key.Attributes 'RSA-HSM' $true $null $null $null +} + +<# +.SYNOPSIS +Tests import byok with custom attributes +#> +function Test_ImportByokWithCustomAttributes +{ + $keyVault = Get-KeyVault + $keyname=Get-KeyName 'attrbyok' + $byokpath = Get-ImportKeyFile 'byok' + $key=Add-AzureKeyVaultKey -VaultName $keyVault -Name $keyname -Destination 'HSM' -KeyFilePath $byokpath -Expires $expires -NotBefore $nbf -KeyOps $keyOps -Disable + Assert-NotNull $key + $global:createdKeys += $keyname + Assert-KeyAttributes $key.Attributes 'RSA-HSM' $false $expires $nbf $ops +} + +<# +.SYNOPSIS +Tests import byok with custom attributes +#> +function Test_ImportByokWithCustomAttributes +{ + $keyVault = Get-KeyVault + $keyname=Get-KeyName 'attrbyok' + $byokpath = Get-ImportKeyFile 'byok' + $key=Add-AzureKeyVaultKey -VaultName $keyVault -Name $keyname -Destination 'HSM' -KeyFilePath $byokpath -Expires $expires -NotBefore $nbf -KeyOps $keyOps -Disable + Assert-NotNull $key + $global:createdKeys += $keyname + Assert-KeyAttributes $key.Attributes 'RSA-HSM' $false $expires $nbf $ops +} + +<# +.SYNOPSIS +Tests Add-AzureKeyVaultKey with positionalParameter +#> +function Test_AddKeyPositionalParameter +{ + $keyVault = Get-KeyVault + $keyname=Get-KeyName 'positional' + $key=Add-AzureKeyVaultKey $keyVault $keyname + Assert-NotNull $key + $global:createdKeys += $keyname +} + +<# +.SYNOPSIS +Tests Add-AzureKeyVaultKey with parameter alias +#> +function Test_AddKeyAliasParameter +{ + $keyVault = Get-KeyVault + $keyname=Get-KeyName 'alias' + $key=Add-AzureKeyVaultKey -VaultName $keyVault -KeyName $keyname + Assert-NotNull $key + $global:createdKeys += $keyname +} + + +<# +.SYNOPSIS +Tests import non-exist pfx file +#> +function Test_ImportNonExistPfxFile +{ + $keyVault = Get-KeyVault + $keyname=Get-KeyName 'nonexistpfx' + $nonexistpfx = Get-ImportKeyFile 'pfx' $false + Assert-Throws {Add-AzureKeyVaultKey -VaultName $keyVault -KeyName $keyname -KeyFilePath $nonexistpfx -KeyFilePassword $securepfxpwd} +} + +<# +.SYNOPSIS +Tests import non-exist pfx file +#> +function Test_ImportPfxFileWithIncorrectPassword +{ + $keyVault = Get-KeyVault + $keyname=Get-KeyName 'wrongpwdpfx' + $pfxpath = Get-ImportKeyFile 'pfx' + $wrongpwd= 'foo' | ConvertTo-SecureString -AsPlainText -Force + Assert-Throws {Add-AzureKeyVaultKey -VaultName $keyVault -KeyName $keyname -Name $keyname -KeyFilePath $pfxpath -KeyFilePassword $wrongpwd} +} + +<# +.SYNOPSIS +Tests import non-exist pfx file +#> +function Test_ImportNonExistByokFile +{ + $keyVault = Get-KeyVault + $keyname=Get-KeyName 'nonexistbyok' + $nonexistbyok = Get-ImportKeyFile 'byok' $false + Assert-Throws {Add-AzureKeyVaultKey -VaultName $keyVault -KeyName $keyname -KeyFilePath $nonexistbyok} +} + +<# +.SYNOPSIS +Tests import non-exist pfx file +#> +function Test_CreateKeyInNonExistVault +{ + $keyVault = 'notexistvault' + $keyname= 'notexitkey' + Assert-Throws {Add-AzureKeyVaultKey -VaultName $keyVault -KeyName $keyname} +} + +<# +.SYNOPSIS +Tests import non-exist pfx file +#> +function Test_ImportByokAsSoftwareKey +{ + $keyVault = Get-KeyVault + $keyname= Get-KeyName 'byokassoftware' + Assert-Throws {Add-AzureKeyVaultKey -VaultName $keyVault -Name $keyname -Destination 'Software' -KeyFilePath $byokpath} +} + +<# +.SYNOPSIS +Tests create key in a vault not have permission +#> +function Test_CreateKeyInNoPermissionVault +{ + $keyVault = Get-KeyVault $false + $keyname= Get-KeyName 'nopermission' + Assert-Throws {Add-AzureKeyVaultKey -VaultName $keyVault -Name $keyname} +} + + +<# +.SYNOPSIS +Tests update individual key attributes +#> +function Test_UpdateIndividualAttributes +{ + # Create a software key for updating + $keyVault = Get-KeyVault + $keyname=Get-KeyName 'updatesoft' + $key=Add-AzureKeyVaultKey -VaultName $keyVault -Name $keyname -Destination 'Software' -Expires $expires -NotBefore $nbf -KeyOps $ops -Disable + Assert-NotNull $key + $global:createdKeys += $keyname + Assert-KeyAttributes $key.Attributes 'RSA' $false $expires $nbf $ops + + # Update Expires + $key=Set-AzureKeyVaultKey -VaultName $keyVault -Name $keyname -Expires $newexpires + Assert-NotNull $key + Assert-KeyAttributes $key.Attributes 'RSA' $false $newexpires $nbf $null + + # Update NotBefore + $key=Set-AzureKeyVaultKey -VaultName $keyVault -Name $keyname -NotBefore $newnbf + Assert-NotNull $key + Assert-KeyAttributes $key.Attributes 'RSA' $false $newexpires $newnbf $null + + # Update Enable + $key=Set-AzureKeyVaultKey -VaultName $keyVault -Name $keyname -Enable $true + Assert-NotNull $key + Assert-KeyAttributes $key.Attributes 'RSA' $true $newexpires $newnbf $null +} + +<# +.SYNOPSIS +Tests update individual key attributes +#> +function Test_UpdateAllEditableAttributes +{ + # Create a software key for updating + $keyVault = Get-KeyVault + $keyname=Get-KeyName 'usoft' + $key=Add-AzureKeyVaultKey -VaultName $keyVault -Name $keyname -Destination 'Software' -Expires $expires -NotBefore $nbf -KeyOps $ops -Disable + Assert-NotNull $key + $global:createdKeys += $keyname + Assert-KeyAttributes $key.Attributes 'RSA' $false $expires $nbf $ops + + # Update Expires + $key=Set-AzureKeyVaultKey -VaultName $keyVault -Name $keyname -Expires $newexpires -NotBefore $newnbf -Enable $true + Assert-KeyAttributes $key.Attributes 'RSA' $true $newexpires $newnbf $null + + # Create a hsm key for updating + $keyname=Get-KeyName 'uhsm' + $key=Add-AzureKeyVaultKey -VaultName $keyVault -Name $keyname -Destination 'HSM' -Expires $expires -NotBefore $nbf -KeyOps $ops -Disable + Assert-NotNull $key + $global:createdKeys += $keyname + Assert-KeyAttributes $key.Attributes 'RSA-HSM' $false $expires $nbf $ops + + # Update Expires + $key=Set-AzureKeyVaultKey -VaultName $keyVault -Name $keyname -Expires $newexpires -NotBefore $newnbf -Enable $true + Assert-KeyAttributes $key.Attributes 'RSA-HSM' $true $newexpires $newnbf $null +} + + +<# +.SYNOPSIS +Tests Set-AzureKeyVaultKey with positionalParameter +#> +function Test_SetKeyPositionalParameter +{ + $keyVault = Get-KeyVault + $keyname=Get-KeyName 'positional' + $key=Add-AzureKeyVaultKey -VaultName $keyVault -Name $keyname + Assert-NotNull $key + $global:createdKeys += $keyname + + Set-AzureKeyVaultKey $keyVault $keyname -Expires $newexpires -NotBefore $newnbf -Enable $true +} + +<# +.SYNOPSIS +Tests Set-AzureKeyVaultKey with parameter alias +#> +function Test_SetKeyAliasParameter +{ + $keyVault = Get-KeyVault + $keyname=Get-KeyName 'alias' + $key=Add-AzureKeyVaultKey -VaultName $keyVault -Name $keyname + Assert-NotNull $key + $global:createdKeys += $keyname + + Set-AzureKeyVaultKey -VaultName $keyVault -KeyName $keyname -Expires $newexpires -NotBefore $newnbf -Enable $true +} + +<# +.SYNOPSIS +Tests set a key in non-exist key vault +#> +function Test_SetKeyInNonExistVault +{ + $keyVault = 'notexistvault' + $keyname=Get-KeyName 'nonexist' + Assert-Throws {Set-AzureKeyVaultKey -VaultName $keyVault -KeyName $keyname -Enable $true} +} + +<# +.SYNOPSIS +Tests set an not exist key +#> +function Test_SetNonExistKey +{ + $keyVault = Get-KeyVault + $keyname=Get-KeyName 'nonexist' + Assert-Throws {Set-AzureKeyVaultKey -VaultName $keyVault -KeyName $keyname -Enable $true} +} + +<# +.SYNOPSIS +Tests set invalid +#> +function Test_SetInvalidAttributes +{ + $keyVault = Get-KeyVault + $keyname=Get-KeyName 'invalidattr' + $key=Add-AzureKeyVaultKey -VaultName $keyVault -Name $keyname + Assert-NotNull $key + $global:createdKeys += $keyname + + Assert-Throws {Set-AzureKeyVaultKey -VaultName $keyVault -KeyName $keyname -Expires $nbf -NotBefore $expires } + +} + +<# +.SYNOPSIS +Tests set key in a vault not have permission +#> +function Test_SetKeyInNoPermissionVault +{ + $keyVault = Get-KeyVault $false + $keyname= Get-KeyName 'nopermission' + Assert-Throws {Set-AzureKeyVaultKey -VaultName $keyVault -Name $keyname -Enable $true} +} + + +<# +.SYNOPSIS +Tests get one key from key vault +#> + +function Test_GetOneKey +{ + $keyVault = Get-KeyVault + $keyname=Get-KeyName 'getone' + $key=Add-AzureKeyVaultKey -VaultName $keyVault -Name $keyname + Assert-NotNull $key + $global:createdKeys += $keyname + Assert-KeyAttributes $key.Attributes 'RSA' $true $null $null $null + + $key=Get-AzureKeyVaultKey -VaultName $keyVault -Name $keyname + Assert-KeyAttributes $key.Attributes 'RSA' $true $null $null $null +} + +<# +.SYNOPSIS +Tests get all keys from key vault +#> + +function Test_GetAllKeys +{ + $keyVault = Get-KeyVault + $keypartialname=Get-KeyName 'get' + $total=2 + for ($i=0;$i -lt $total; $i++) + { + $keyname = $keypartialname+$i; + $key=Add-AzureKeyVaultKey -VaultName $keyVault -Name $keyname + Assert-NotNull $key + $global:createdKeys += $keyname + } + + $keys=Get-AzureKeyVaultKey -VaultName $keyVault + Assert-True { $keys.Count -ge $total } +} + +<# +.SYNOPSIS +Tests Get-AzureKeyVaultKey with positional Parameter +#> +function Test_GetKeyPositionalParameter +{ + $keyVault = Get-KeyVault + $keyname=Get-KeyName 'positional' + $key=Add-AzureKeyVaultKey -VaultName $keyVault -Name $keyname + Assert-NotNull $key + $global:createdKeys += $keyname + + $key=Get-AzureKeyVaultKey $keyVault $keyname + Assert-NotNull $key +} + +<# +.SYNOPSIS +Tests Get-AzureKeyVaultKey with parameter alias +#> +function Test_GetKeyAliasParameter +{ + $keyVault = Get-KeyVault + $keyname=Get-KeyName 'alias' + $key=Add-AzureKeyVaultKey -VaultName $keyVault -Name $keyname + Assert-NotNull $key + $global:createdKeys += $keyname + + $key=Get-AzureKeyVaultKey -VaultName $keyVault -KeyName $keyname + Assert-NotNull $key +} + +<# +.SYNOPSIS +Tests get a key from non-exist key vault +#> +function Test_GetKeysInNonExistVault +{ + $keyVault = 'notexistvault' + Assert-Throws {Get-AzureKeyVaultKey -VaultName $keyVault} +} + +<# +.SYNOPSIS +Tests get a non-exist key +#> +function Test_GetNonExistKey +{ + $keyVault = Get-KeyVault + $keyname = 'notexist' + Assert-Throws {Get-AzureKeyVaultKey -VaultName $keyVault -KeyName $keyname} +} + +<# +.SYNOPSIS +Tests get key in a vault not have permission +#> +function Test_GetKeyInNoPermissionVault +{ + $keyVault = Get-KeyVault $false + Assert-Throws {Get-AzureKeyVaultKey -VaultName $keyVault} +} + + +<# +.SYNOPSIS +Tests remove a key +#> +function Test_RemoveKeyWithoutPrompt +{ + $keyVault = Get-KeyVault + $keyname=Get-KeyName 'remove' + $key=Add-AzureKeyVaultKey -VaultName $keyVault -Name $keyname + Assert-NotNull $key + $global:createdKeys += $keyname + + $key=Remove-AzureKeyVaultKey -VaultName $keyVault -Name $keyname -Force -Confirm:$false -PassThru + Assert-NotNull $key + + Assert-Throws { Get-AzureKeyVaultKey -VaultName $keyVault -Name $keyname} +} + +<# +.SYNOPSIS +Tests Remove-AzureKeyVaultKey with whatif option +#> +function Test_RemoveKeyWhatIf +{ + $keyVault = Get-KeyVault + $keyname=Get-KeyName 'whatif' + $key=Add-AzureKeyVaultKey -VaultName $keyVault -Name $keyname + Assert-NotNull $key + $global:createdKeys += $keyname + + Remove-AzureKeyVaultKey -VaultName $keyVault -Name $keyname -WhatIf + + $key=Get-AzureKeyVaultKey -VaultName $keyVault -Name $keyname + Assert-NotNull $key +} + +<# +.SYNOPSIS +Tests Remove-AzureKeyVaultKey with positional Parameter +#> +function Test_RemoveKeyPositionalParameter +{ + $keyVault = Get-KeyVault + $keyname=Get-KeyName 'positional' + $key=Add-AzureKeyVaultKey -VaultName $keyVault -Name $keyname + Assert-NotNull $key + $global:createdKeys += $keyname + + Remove-AzureKeyVaultKey $keyVault $keyname -Force -Confirm:$false + + Assert-Throws { Get-AzureKeyVaultKey -VaultName $keyVault -Name $keyname} +} + +<# +.SYNOPSIS +Tests Remove-AzureKeyVaultKey with parameter alias +#> +function Test_RemoveKeyAliasParameter +{ + $keyVault = Get-KeyVault + $keyname=Get-KeyName 'alias' + $key=Add-AzureKeyVaultKey -VaultName $keyVault -Name $keyname + Assert-NotNull $key + $global:createdKeys += $keyname + + Remove-AzureKeyVaultKey -VaultName $keyVault -KeyName $keyname -Force -Confirm:$false + + Assert-Throws { Get-AzureKeyVaultKey -VaultName $keyVault -Name $keyname} +} + +<# +.SYNOPSIS +Tests get a key from non-exist key vault +#> +function Test_RemoveKeyInNonExistVault +{ + $keyVault = 'notexistvault' + $keyname = 'notexist' + Assert-Throws {Remove-AzureKeyVaultKey -VaultName $keyVault -Name $keyname -Force -Confirm:$false} +} + +<# +.SYNOPSIS +Tests get a non-exist key +#> +function Test_RemoveNonExistKey +{ + $keyVault = Get-KeyVault + $keyname = 'notexist' + Assert-Throws {Remove-AzureKeyVaultKey -VaultName $keyVault -Name $keyname -Force -Confirm:$false} +} + +<# +.SYNOPSIS +Tests remove key in a vault not have permission +#> +function Test_RemoveKeyInNoPermissionVault +{ + $keyVault = Get-KeyVault $false + $keyname= Get-KeyName 'nopermission' + Assert-Throws {Remove-AzureKeyVaultKey -VaultName $keyVault -Name $keyname -Enable $true -Force -Confirm:$false} +} + +<# +.SYNOPSIS +Tests pipeline commands to update attributes of multiple keys +#> + +function Test_PipelineUpdateKeys +{ + $keyVault = Get-KeyVault + $keypartialname=Get-KeyName 'pipeupdate' + $total=2 + for ($i=0;$i -lt $total; $i++) + { + $keyname = $keypartialname+$i; + $key=Add-AzureKeyVaultKey -VaultName $keyVault -Name $keyname + Assert-NotNull $key + $global:createdKeys += $keyname + } + + Get-AzureKeyVaultKey $keyVault | Where-Object {$_.KeyName -like $keypartialname+'*'} | Set-AzureKeyVaultKey -Enable $false + + Get-AzureKeyVaultKey $keyVault | Where-Object {$_.KeyName -like $keypartialname+'*'} | ForEach-Object { Assert-False { return $_.Attributes.Enable } } + } + +<# +.SYNOPSIS +Tests pipeline commands to remove multiple keys +#> + +function Test_PipelineRemoveKeys +{ + $keyVault = Get-KeyVault + $keypartialname=Get-KeyName 'piperemove' + $total=2 + for ($i=0;$i -lt $total; $i++) + { + $keyname = $keypartialname+$i; + $key=Add-AzureKeyVaultKey -VaultName $keyVault -Name $keyname + Assert-NotNull $key + $global:createdKeys += $keyname + } + + Get-AzureKeyVaultKey $keyVault | Where-Object {$_.KeyName -like $keypartialname+'*'} | Remove-AzureKeyVaultKey -Force -Confirm:$false + + $keys = Get-AzureKeyVaultKey $keyVault | Where-Object {$_.KeyName -like $keypartialname+'*'} + Assert-AreEqual $keys.Count 0 +} \ No newline at end of file diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/VaultSecretTests.ps1 b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/VaultSecretTests.ps1 new file mode 100644 index 000000000000..4038295e9829 --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/VaultSecretTests.ps1 @@ -0,0 +1,353 @@ +$data=123 +$securedata=$data | ConvertTo-SecureString -AsPlainText -Force +$newdata=456 +$newsecuredata=$newdata | ConvertTo-SecureString -AsPlainText -Force + +<# +.SYNOPSIS +Create a secret +#> + +function Test_CreateSecret +{ + $keyVault = Get-KeyVault + $secretname= Get-SecretName 'default' + $sec=Set-AzureKeyVaultSecret -VaultName $keyVault -Name $secretname -SecretValue $securedata + Assert-NotNull $sec + $global:createdSecrets += $secretname + Assert-AreEqual $sec.SecretValueText $data +} + + +<# +.SYNOPSIS +Update a secret +#> + +function Test_UpdateSecret +{ + $keyVault = Get-KeyVault + $secretname= Get-SecretName 'update' + $sec=Set-AzureKeyVaultSecret -VaultName $keyVault -Name $secretname -SecretValue $securedata + Assert-NotNull $sec + $global:createdSecrets += $secretname + Assert-AreEqual $sec.SecretValueText $data + + $sec=Set-AzureKeyVaultSecret -VaultName $keyVault -Name $secretname -SecretValue $newsecuredata + Assert-NotNull $sec + Assert-AreEqual $sec.SecretValueText $newdata +} + +<# +.SYNOPSIS +Tests Set-AzureKeyVaultSecret with positional parameter +#> +function Test_SetSecretPositionalParameter +{ + $keyVault = Get-KeyVault + $secretname= Get-SecretName 'positional' + $sec=Set-AzureKeyVaultSecret $keyVault $secretname $securedata + Assert-NotNull $sec + $global:createdSecrets += $secretname + Assert-AreEqual $sec.SecretValueText $data +} + +<# +.SYNOPSIS +Tests Set-AzureKeyVaultSecret with parameter alias +#> +function Test_SetSecretAliasParameter +{ + $keyVault = Get-KeyVault + $secretname= Get-SecretName 'alias' + $sec=Set-AzureKeyVaultSecret -VaultName $keyVault -SecretName $secretname -SecretValue $securedata + Assert-NotNull $sec + $global:createdSecrets += $secretname + Assert-AreEqual $sec.SecretValueText $data +} + +<# +.SYNOPSIS +Tests set a secret in non-exist key vault +#> +function Test_SetSecretInNonExistVault +{ + $keyVault = 'notexistvault' + $secretname= Get-SecretName 'nonexist' + Assert-Throws {Set-AzureKeyVaultSecret -VaultName $keyVault -Name $secretname -SecretValue $securedata} +} + +<# +.SYNOPSIS +Tests set secret in a vault the user does not have permission +#> +function Test_SetSecretInNoPermissionVault +{ + $keyVault = Get-KeyVault $false + $secretname= Get-SecretName 'nopermission' + Assert-Throws {Set-AzureKeyVaultSecret -VaultName $keyVault -Name $secretname -SecretValue $securedata} +} + +<# +.SYNOPSIS +Tests get one secret from key vault +#> + +function Test_GetOneSecret +{ + $keyVault = Get-KeyVault + $secretname= Get-SecretName 'getone' + $sec=Set-AzureKeyVaultSecret -VaultName $keyVault -Name $secretname -SecretValue $securedata + Assert-NotNull $sec + $global:createdSecrets += $secretname + Assert-AreEqual $sec.SecretValueText $data + + $sec=Get-AzureKeyVaultSecret -VaultName $keyVault -Name $secretname + Assert-NotNull $sec + Assert-AreEqual $sec.SecretValueText $data +} + +<# +.SYNOPSIS +Tests get all secrets from key vault +#> + +function Test_GetAllSecrets +{ + $keyVault = Get-KeyVault + $secretpartialname=Get-SecretName 'get' + $total=2 + for ($i=0;$i -lt $total; $i++) + { + $secretname = $secretpartialname+$i; + $sec=Set-AzureKeyVaultSecret -VaultName $keyVault -Name $secretname -SecretValue $securedata + Assert-NotNull $sec + $global:createdSecrets += $secretname + } + + $secs=Get-AzureKeyVaultSecret -VaultName $keyVault + Assert-True { $secs.Count -ge $total } +} + +<# +.SYNOPSIS +Tests Get-AzureKeyVaultSecret with positional parameter +#> +function Test_GetSecretPositionalParameter +{ + $keyVault = Get-KeyVault + $secretname= Get-SecretName 'positional' + $sec=Set-AzureKeyVaultSecret -VaultName $keyVault -Name $secretname -SecretValue $securedata + Assert-NotNull $sec + $global:createdSecrets += $secretname + Assert-AreEqual $sec.SecretValueText $data + + $sec=Get-AzureKeyVaultSecret $keyVault $secretname + Assert-NotNull $sec + Assert-AreEqual $sec.SecretValueText $data +} + +<# +.SYNOPSIS +Tests Get-AzureKeyVaultSecret with parameter alias +#> +function Test_GetSecretAliasParameter +{ + $keyVault = Get-KeyVault + $secretname= Get-SecretName 'alias' + $sec=Set-AzureKeyVaultSecret -VaultName $keyVault -Name $secretname -SecretValue $securedata + Assert-NotNull $sec + $global:createdSecrets += $secretname + Assert-AreEqual $sec.SecretValueText $data + + $sec=Get-AzureKeyVaultSecret -VaultName $keyVault -SecretName $secretname + Assert-NotNull $sec + Assert-AreEqual $sec.SecretValueText $data +} + +<# +.SYNOPSIS +Tests get a secret in non-exist key vault +#> +function Test_GetSecretInNonExistVault +{ + $keyVault = 'notexistvault' + Assert-Throws {Get-AzureKeyVaultSecret -VaultName $keyVault} +} + +<# +.SYNOPSIS +Tests get a non-exist secret +#> +function Test_GetNonExistSecret +{ + $keyVault = Get-KeyVault + $secretname= Get-SecretName 'notexistvault' + + Assert-Throws {Get-AzureKeyVaultSecret -VaultName $keyVault -Name $secretname} +} + +<# +.SYNOPSIS +Tests get secret in a vault the user does not have permission +#> +function Test_GetSecretInNoPermissionVault +{ + $keyVault = Get-KeyVault $false + Assert-Throws {Get-AzureKeyVaultSecret -VaultName $keyVault} +} + +<# +.SYNOPSIS +Tests remove a secret +#> +function Test_RemoveSecretWithoutPrompt +{ + $keyVault = Get-KeyVault + $secretname= Get-SecretName 'remove' + $sec=Set-AzureKeyVaultSecret -VaultName $keyVault -Name $secretname -SecretValue $securedata + Assert-NotNull $sec + $global:createdSecrets += $secretname + + $sec=Remove-AzureKeyVaultSecret -VaultName $keyVault -Name $secretname -Force -Confirm:$false -PassThru + Assert-NotNull $sec + + Assert-Throws { Get-AzureKeyVaultSecret -VaultName $keyVault -Name $secretname } +} + +<# +.SYNOPSIS +Tests Remove-AzureKeyVaultSecret with whatif option +#> +function Test_RemoveSecretWhatIf +{ + $keyVault = Get-KeyVault + $secretname= Get-SecretName 'whatif' + $sec=Set-AzureKeyVaultSecret -VaultName $keyVault -Name $secretname -SecretValue $securedata + Assert-NotNull $sec + $global:createdSecrets += $secretname + + Remove-AzureKeyVaultSecret -VaultName $keyVault -Name $secretname -WhatIf + + $sec=Get-AzureKeyVaultSecret -VaultName $keyVault -Name $secretname + Assert-NotNull $sec +} + +<# +.SYNOPSIS +Tests Remove-AzureKeyVaultSecret with positional parameter +#> +function Test_RemoveSecretPositionalParameter +{ + $keyVault = Get-KeyVault + $secretname= Get-SecretName 'positional' + $sec=Set-AzureKeyVaultSecret -VaultName $keyVault -Name $secretname -SecretValue $securedata + Assert-NotNull $sec + $global:createdSecrets += $secretname + Assert-AreEqual $sec.SecretValueText $data + + Remove-AzureKeyVaultSecret $keyVault $secretname -Force -Confirm:$false + + Assert-Throws {Get-AzureKeyVaultSecret -VaultName $keyVault -Name $secretname} +} + +<# +.SYNOPSIS +Tests Remove-AzureKeyVaultSecret with parameter alias +#> +function Test_RemoveSecretAliasParameter +{ + $keyVault = Get-KeyVault + $secretname= Get-SecretName 'alias' + $sec=Set-AzureKeyVaultSecret -VaultName $keyVault -Name $secretname -SecretValue $securedata + Assert-NotNull $sec + $global:createdSecrets += $secretname + Assert-AreEqual $sec.SecretValueText $data + + Remove-AzureKeyVaultSecret -VaultName $keyVault -SecretName $secretname -Force -Confirm:$false + + Assert-Throws {Get-AzureKeyVaultSecret -VaultName $keyVault -Name $secretname} +} + +<# +.SYNOPSIS +Tests remove a secret in non-exist key vault +#> +function Test_RemoveSecretInNonExistVault +{ + $keyVault = 'notexistvault' + $secretname= Get-SecretName 'notexistvault' + Assert-Throws {Remove-AzureKeyVaultSecret -VaultName $keyVault -Name $secretname -Force -Confirm:$false} +} + +<# +.SYNOPSIS +Tests remove a non-exist secret +#> +function Test_RemoveNonExistSecret +{ + $keyVault = Get-KeyVault + $secretname= Get-SecretName 'notexistvault' + + Assert-Throws {Remove-AzureKeyVaultSecret -VaultName $keyVault -Name $secretname -Force -Confirm:$false} +} + +<# +.SYNOPSIS +Tests Remove a secret in a vault the user does not have permission +#> +function Test_RemoveSecretInNoPermissionVault +{ + $keyVault = Get-KeyVault $false + $secretname= Get-SecretName 'nopermission' + Assert-Throws {Remove-AzureKeyVaultSecret -VaultName $keyVault -Name $secretname -Force -Confirm:$false} +} + +<# +.SYNOPSIS +Tests pipeline commands to update attributes of multiple secret +#> + +function Test_PipelineUpdateSecrets +{ + $keyVault = Get-KeyVault + $secretpartialname=Get-KeyName 'pipeupdate' + $total=2 + for ($i=0;$i -lt $total; $i++) + { + $secretname = $secretpartialname+$i; + $sec=Set-AzureKeyVaultSecret -VaultName $keyVault -Name $secretname -SecretValue $securedata + Assert-NotNull $sec + $global:createdSecrets += $secretname + Assert-AreEqual $sec.SecretValueText $data + } + + Get-AzureKeyVaultSecret $keyVault | Where-Object {$_.SecretName -like $secretpartialname+'*'} | Set-AzureKeyVaultSecret -SecretValue $newsecuredata + Get-AzureKeyVaultSecret $keyVault | Where-Object {$_.SecretName -like $secretpartialname+'*'} | ForEach-Object { Assert-AreEqual $_.SecretValueText $newdata } +} + +<# +.SYNOPSIS +Tests pipeline commands to remove multiple secrets +#> + +function Test_PipelineRemoveSecrets +{ + $keyVault = Get-KeyVault + $secretpartialname=Get-KeyName 'piperemove' + $total=2 + for ($i=0;$i -lt $total; $i++) + { + $secretname = $secretpartialname+$i; + $sec=Set-AzureKeyVaultSecret -VaultName $keyVault -Name $secretname -SecretValue $securedata + Assert-NotNull $sec + $global:createdSecrets += $secretname + Assert-AreEqual $sec.SecretValueText $data + } + + + Get-AzureKeyVaultSecret $keyVault | Where-Object {$_.SecretName -like $secretpartialname+'*'} | Remove-AzureKeyVaultSecret -Force -Confirm:$false + + $secs = Get-AzureKeyVaultSecret $keyVault | Where-Object {$_.SecretName -like $secretpartialname+'*'} + Assert-AreEqual $secs.Count 0 +} \ No newline at end of file diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/VaultUITests.ps1 b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/VaultUITests.ps1 new file mode 100644 index 000000000000..7aacc6e8d024 --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/VaultUITests.ps1 @@ -0,0 +1,181 @@ +$pfxpwd='123' +$securepfxpwd=$pfxpwd | ConvertTo-SecureString -AsPlainText -Force +$data=123 +$securedata=$data | ConvertTo-SecureString -AsPlainText -Force + +<# +.SYNOPSIS +Tests remove a key with two confirmations +#> +function Test_RemoveKeyWithTwoConfirmations +{ + Write-Host "Type 'Yes' twice" + $keyVault = Get-KeyVault + $keyname=Get-KeyName 'remove' + $key=Add-AzureKeyVaultKey -VaultName $keyVault -Name $keyname + Assert-NotNull $key + $global:createdKeys += $keyname + + $cr=$global:ConfirmPreference + $global:ConfirmPreference="High" + Remove-AzureKeyVaultKey -VaultName $keyVault -Name $keyname + $global:ConfirmPreference=$cr + + Assert-Throws { Get-AzureKeyVaultKey -VaultName $keyVault -Name $keyname} +} + +<# +.SYNOPSIS +Tests remove a key with one confirmation +#> +function Test_RemoveKeyWithOneConfirmations +{ + Write-Host "Type 'Yes' once" + $keyVault = Get-KeyVault + $keyname=Get-KeyName 'remove' + $key=Add-AzureKeyVaultKey -VaultName $keyVault -Name $keyname + Assert-NotNull $key + $global:createdKeys += $keyname + + $cr=$global:ConfirmPreference + $global:ConfirmPreference="High" + Remove-AzureKeyVaultKey -VaultName $keyVault -Name $keyname -Force + $global:ConfirmPreference=$cr + + Assert-Throws { Get-AzureKeyVaultKey -VaultName $keyVault -Name $keyname} +} + +<# +.SYNOPSIS +Tests cancel removing a key with once +#> +function Test_CancelKeyRemovalOnce +{ + Write-Host "Type 'No' once" + $keyVault = Get-KeyVault + $keyname=Get-KeyName 'remove' + $key=Add-AzureKeyVaultKey -VaultName $keyVault -Name $keyname + Assert-NotNull $key + $global:createdKeys += $keyname + + $cr=$global:ConfirmPreference + $global:ConfirmPreference="High" + Remove-AzureKeyVaultKey -VaultName $keyVault -Name $keyname + $global:ConfirmPreference=$cr + + $key=Get-AzureKeyVaultKey -VaultName $keyVault -Name $keyname + Assert-NotNull $key +} + +<# +.SYNOPSIS +Tests cancel removing a key with two prompts +#> +function Test_ConfirmThenCancelKeyRemoval +{ + Write-Host "Type 'Yes' first. Then type 'No'" + $keyVault = Get-KeyVault + $keyname=Get-KeyName 'remove' + $key=Add-AzureKeyVaultKey -VaultName $keyVault -Name $keyname + Assert-NotNull $key + $global:createdKeys += $keyname + + $cr=$global:ConfirmPreference + $global:ConfirmPreference="High" + Remove-AzureKeyVaultKey -VaultName $keyVault -Name $keyname + $global:ConfirmPreference=$cr + + $key=Get-AzureKeyVaultKey -VaultName $keyVault -Name $keyname + Assert-NotNull $key +} + + + +<# +.SYNOPSIS +Tests remove a secret with two confirmations +#> +function Test_RemoveSecretWithTwoConfirmations +{ + Write-Host "Type 'Yes' twice" + $keyVault = Get-KeyVault + $secretname= Get-SecretName 'remove' + $sec=Set-AzureKeyVaultSecret -VaultName $keyVault -Name $secretname -SecretValue $securedata + Assert-NotNull $sec + $global:createdSecrets += $secretname + + $cr=$global:ConfirmPreference + $global:ConfirmPreference="High" + Remove-AzureKeyVaultSecret -VaultName $keyVault -Name $secretname + $global:ConfirmPreference=$cr + + Assert-Throws { Get-AzureKeyVaultSecret -VaultName $keyVault -Name $secretname } +} + +<# +.SYNOPSIS +Tests remove a secret with one confirmations +#> +function Test_RemoveSecretWithOneConfirmations +{ + Write-Host "Type 'Yes' once" + $keyVault = Get-KeyVault + $secretname= Get-SecretName 'remove' + $sec=Set-AzureKeyVaultSecret -VaultName $keyVault -Name $secretname -SecretValue $securedata + Assert-NotNull $sec + $global:createdSecrets += $secretname + + $cr=$global:ConfirmPreference + $global:ConfirmPreference="High" + Remove-AzureKeyVaultSecret -VaultName $keyVault -Name $secretname -Force + $global:ConfirmPreference=$cr + + Assert-Throws { Get-AzureKeyVaultSecret -VaultName $keyVault -Name $secretname } +} + +<# +.SYNOPSIS +Tests cancel removing a secret with once +#> +function Test_CancelSecretRemovalOnce +{ + Write-Host "Type 'No' once" + $keyVault = Get-KeyVault + $secretname= Get-SecretName 'remove' + $sec=Set-AzureKeyVaultSecret -VaultName $keyVault -Name $secretname -SecretValue $securedata + Assert-NotNull $sec + $global:createdSecrets += $secretname + + $cr=$global:ConfirmPreference + $global:ConfirmPreference="High" + Remove-AzureKeyVaultSecret -VaultName $keyVault -Name $secretname + $global:ConfirmPreference=$cr + + $sec=Get-AzureKeyVaultSecret -VaultName $keyVault -Name $secretname + Assert-NotNull $sec +} + +<# +.SYNOPSIS +Tests cancel removing a secret with two prompts +#> +function Test_ConfirmThenCancelSecretRemoval +{ + Write-Host "Type 'Yes' first. Then type 'No'" + $keyVault = Get-KeyVault + $secretname= Get-SecretName 'remove' + $sec=Set-AzureKeyVaultSecret -VaultName $keyVault -Name $secretname -SecretValue $securedata + Assert-NotNull $sec + $global:createdSecrets += $secretname + + $cr=$global:ConfirmPreference + $global:ConfirmPreference="High" + Remove-AzureKeyVaultSecret -VaultName $keyVault -Name $secretname + $global:ConfirmPreference=$cr + + $sec=Get-AzureKeyVaultSecret -VaultName $keyVault -Name $secretname + Assert-NotNull $sec +} + + + diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/bvtdata/byoktest.byok b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/bvtdata/byoktest.byok new file mode 100644 index 000000000000..a8c9ed149309 Binary files /dev/null and b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/bvtdata/byoktest.byok differ diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/bvtdata/pfxtest.pfx b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/bvtdata/pfxtest.pfx new file mode 100644 index 000000000000..fefc03c0d0a0 Binary files /dev/null and b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/bvtdata/pfxtest.pfx differ diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/proddata/byoktest.byok b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/proddata/byoktest.byok new file mode 100644 index 000000000000..690e20b0319e Binary files /dev/null and b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/proddata/byoktest.byok differ diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/proddata/pfxtest.pfx b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/proddata/pfxtest.pfx new file mode 100644 index 000000000000..fefc03c0d0a0 Binary files /dev/null and b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/proddata/pfxtest.pfx differ diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/readme.txt b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/readme.txt new file mode 100644 index 000000000000..dd7823dab9f9 --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/readme.txt @@ -0,0 +1,5 @@ +This folder contains ps1 scripts testing Azure Key Vault cmdlets. +The steps to run these tests are: +1. Copy this folder on a server 2012 R2 or windows 8.1 machine with Azure Powershell msi installed. +2. Setup Azure account. Please refer to "Key Vault Powershell Sign-off criteria" in spec store for user account setup. +3. Run 63 scripting tests using RunKeyVaultTests.ps1. Run 8 tests required user inputs using RunUITests.ps1. \ No newline at end of file diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault.Test/UnitTests/KeyVaultUnitTestBase.cs b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/UnitTests/KeyVaultUnitTestBase.cs new file mode 100644 index 000000000000..e6040c9a9014 --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/UnitTests/KeyVaultUnitTestBase.cs @@ -0,0 +1,54 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using Microsoft.Azure.Commands.KeyVault.Models; +using Moq; +using System.Management.Automation; + +namespace Microsoft.Azure.Commands.KeyVault.Test +{ + public class KeyVaultUnitTestBase + { + protected const string subscriptionId = "subscriptionid"; + + protected const string ResourceGroupName = "bar"; + + protected const string Location = "centralus"; + + protected const string VaultName = "vaultname"; + + protected const string KeyName = "keyfoo"; + + protected const string KeyName2 = "keyfoo2"; + + protected const string SecretValue = "secval"; + + protected const string SecretValue2 = "secval2"; + + protected const string SecretName = "secfoo"; + + protected const string SecretName2 = "secfoo2"; + + protected Mock keyVaultClientMock; + + protected Mock commandRuntimeMock; + + public virtual void SetupTest() + { + keyVaultClientMock = new Mock(); + + commandRuntimeMock = new Mock(); + } + } +} diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault.Test/UnitTests/RemoveKeyVaultKeyTests.cs b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/UnitTests/RemoveKeyVaultKeyTests.cs new file mode 100644 index 000000000000..71fb8d666652 --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/UnitTests/RemoveKeyVaultKeyTests.cs @@ -0,0 +1,125 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using Microsoft.Azure.Commands.KeyVault.Cmdlets; +using Microsoft.Azure.Commands.KeyVault.Models; +using Microsoft.WindowsAzure.Commands.ScenarioTest; +using Moq; +using System; +using System.Management.Automation; +using Xunit; + +namespace Microsoft.Azure.Commands.KeyVault.Test.UnitTests +{ + public class RemoveKeyVaultKeyTests : KeyVaultUnitTestBase + { + private RemoveAzureKeyVaultKey cmdlet; + private KeyAttributes keyAttributes; + private Microsoft.KeyVault.WebKey.JsonWebKey webKey; + private KeyBundle keyBundle; + + public RemoveKeyVaultKeyTests() + { + base.SetupTest(); + + cmdlet = new RemoveAzureKeyVaultKey() + { + CommandRuntime = commandRuntimeMock.Object, + DataServiceClient = keyVaultClientMock.Object, + VaultName = VaultName + }; + + keyAttributes = new KeyAttributes(true, DateTime.Now, DateTime.Now, "HSM", new string[]{"All"}); + webKey = new Microsoft.KeyVault.WebKey.JsonWebKey(); + keyBundle = new KeyBundle() { Attributes = keyAttributes, Key = webKey, KeyName = KeyName, VaultName = VaultName }; + } + + [Fact] + [Trait(Category.AcceptanceType, Category.CheckIn)] + public void CanRemvoeKeyWithPassThruTest() + { + KeyBundle expected = keyBundle; + keyVaultClientMock.Setup(kv => kv.DeleteKey(VaultName, KeyName)).Returns(expected).Verifiable(); + + // Mock the should process to return true + commandRuntimeMock.Setup(cr => cr.ShouldProcess(KeyName, It.IsAny())).Returns(true); + cmdlet.Name = KeyName; + cmdlet.Force = true; + cmdlet.PassThru = true; + cmdlet.ExecuteCmdlet(); + + // Assert + keyVaultClientMock.VerifyAll(); + commandRuntimeMock.Verify(f => f.WriteObject(expected), Times.Once()); + } + + [Fact] + [Trait(Category.AcceptanceType, Category.CheckIn)] + public void CanRemoveKeyWithNoPassThruTest() + { + KeyBundle expected = keyBundle; + keyVaultClientMock.Setup(kv => kv.DeleteKey(VaultName, KeyName)).Returns(expected).Verifiable(); + + // Mock the should process to return true + commandRuntimeMock.Setup(cr => cr.ShouldProcess(KeyName, It.IsAny())).Returns(true); + cmdlet.Name = KeyName; + cmdlet.Force = true; + cmdlet.ExecuteCmdlet(); + + keyVaultClientMock.VerifyAll(); + + // Without PassThru never call WriteObject + commandRuntimeMock.Verify(f => f.WriteObject(expected), Times.Never()); + } + + [Fact] + [Trait(Category.AcceptanceType, Category.CheckIn)] + public void CannotRemoveKeyWithoutShouldProcessOrForceConfirmationTest() + { + KeyBundle expected = null; + + cmdlet.Name = KeyName; + cmdlet.PassThru = true; + cmdlet.ExecuteCmdlet(); + + // Write object should be called with null input + commandRuntimeMock.Verify(f => f.WriteObject(expected), Times.Once()); + + // Should process but without force + commandRuntimeMock.Setup(cr => cr.ShouldProcess(KeyName, It.IsAny())).Returns(false); + cmdlet.ExecuteCmdlet(); + + // Write object should be called with null input + commandRuntimeMock.Verify(f => f.WriteObject(expected), Times.Exactly(2)); + } + + [Fact] + [Trait(Category.AcceptanceType, Category.CheckIn)] + public void ErrorRemvoeKeyWithPassThruTest() + { + keyVaultClientMock.Setup(kv => kv.DeleteKey(VaultName, KeyName)).Throws(new Exception()).Verifiable(); + + // Mock the should process to return true + commandRuntimeMock.Setup(cr => cr.ShouldProcess(KeyName, It.IsAny())).Returns(true); + cmdlet.Name = KeyName; + cmdlet.Force = true; + cmdlet.PassThru = true; + cmdlet.ExecuteCmdlet(); + + // Assert + keyVaultClientMock.VerifyAll(); + commandRuntimeMock.Verify(f => f.WriteError(It.IsAny()), Times.Once()); + } + } +} diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault.Test/UnitTests/RemoveKeyVaultSecretTests.cs b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/UnitTests/RemoveKeyVaultSecretTests.cs new file mode 100644 index 000000000000..3eed1bd872a6 --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/UnitTests/RemoveKeyVaultSecretTests.cs @@ -0,0 +1,129 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using Microsoft.Azure.Commands.KeyVault.Cmdlets; +using Microsoft.Azure.Commands.KeyVault.Models; +using Microsoft.WindowsAzure.Commands.ScenarioTest; +using Moq; +using System; +using System.Management.Automation; +using System.Security; +using Xunit; + +namespace Microsoft.Azure.Commands.KeyVault.Test.UnitTests +{ + public class RemoveKeyVaultSecretTests : KeyVaultUnitTestBase + { + private RemoveAzureKeyVaultSecret cmdlet; + + public RemoveKeyVaultSecretTests() + { + base.SetupTest(); + + cmdlet = new RemoveAzureKeyVaultSecret() + { + CommandRuntime = commandRuntimeMock.Object, + DataServiceClient = keyVaultClientMock.Object, + VaultName = VaultName + }; + } + + [Fact] + [Trait(Category.AcceptanceType, Category.CheckIn)] + public void CanRemoveSecretWithPassThruTest() + { + SecureString secureSecretValue = SecretValue.ToSecureString(); + Secret expected = new Secret() { SecretName = SecretName, VaultName = VaultName, SecretValue = secureSecretValue }; + keyVaultClientMock.Setup(kv => kv.DeleteSecret(VaultName, SecretName)).Returns(expected).Verifiable(); + + // Mock the should process to return true + commandRuntimeMock.Setup(cr => cr.ShouldProcess(SecretName, It.IsAny())).Returns(true); + cmdlet.Name = SecretName; + cmdlet.Force = true; + cmdlet.PassThru = true; + cmdlet.ExecuteCmdlet(); + + keyVaultClientMock.VerifyAll(); + commandRuntimeMock.Verify(f => f.WriteObject(expected), Times.Once()); + + //No force but should continue + commandRuntimeMock.Setup(cr => cr.ShouldProcess(SecretName, It.IsAny())).Returns(true); + commandRuntimeMock.Setup(cr => cr.ShouldContinue(It.IsAny(), It.IsAny())).Returns(true); + cmdlet.Force = false; + cmdlet.PassThru = true; + cmdlet.ExecuteCmdlet(); + + keyVaultClientMock.VerifyAll(); + commandRuntimeMock.Verify(f => f.WriteObject(expected), Times.Exactly(2)); + } + + [Fact] + [Trait(Category.AcceptanceType, Category.CheckIn)] + public void CanRemoveSecretWithNoPassThruTest() + { + SecureString secureSecretValue = SecretValue.ToSecureString(); + Secret expected = new Secret() { SecretName = SecretName, VaultName = VaultName, SecretValue = secureSecretValue }; + keyVaultClientMock.Setup(kv => kv.DeleteSecret(VaultName, SecretName)).Returns(expected).Verifiable(); + + // Mock the should process to return true + commandRuntimeMock.Setup(cr => cr.ShouldProcess(SecretName, It.IsAny())).Returns(true); + cmdlet.Name = SecretName; + cmdlet.Force = true; + cmdlet.ExecuteCmdlet(); + + keyVaultClientMock.VerifyAll(); + + // Without PassThru never call WriteObject + commandRuntimeMock.Verify(f => f.WriteObject(expected), Times.Never()); + } + + [Fact] + [Trait(Category.AcceptanceType, Category.CheckIn)] + public void CannotRemoveSecretWithoutShouldProcessOrForceConfirmationTest() + { + Secret expected = null; + + cmdlet.Name = SecretName; + cmdlet.PassThru = true; + cmdlet.ExecuteCmdlet(); + + // Write object should be called with null input + commandRuntimeMock.Verify(f => f.WriteObject(expected), Times.Once()); + + // Should process but without force + commandRuntimeMock.Setup(cr => cr.ShouldProcess(SecretName, It.IsAny())).Returns(true); + cmdlet.ExecuteCmdlet(); + + // Write object should be called with null input + commandRuntimeMock.Verify(f => f.WriteObject(expected), Times.Exactly(2)); + } + + [Fact] + [Trait(Category.AcceptanceType, Category.CheckIn)] + public void ErrorRemoveSecretWithPassThruTest() + { + keyVaultClientMock.Setup(kv => kv.DeleteSecret(VaultName, SecretName)).Throws(new Exception()).Verifiable(); + + // Mock the should process to return true + commandRuntimeMock.Setup(cr => cr.ShouldProcess(SecretName, It.IsAny())).Returns(true); + cmdlet.Name = SecretName; + cmdlet.Force = true; + cmdlet.PassThru = true; + cmdlet.ExecuteCmdlet(); + + keyVaultClientMock.VerifyAll(); + commandRuntimeMock.Verify(f => f.WriteError(It.IsAny()), Times.Once()); + } + } +} diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault.Test/UnitTests/SetKeyVaultKeyTests.cs b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/UnitTests/SetKeyVaultKeyTests.cs new file mode 100644 index 000000000000..f8f5ed4d6c70 --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/UnitTests/SetKeyVaultKeyTests.cs @@ -0,0 +1,92 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using Microsoft.Azure.Commands.KeyVault.Cmdlets; +using Microsoft.Azure.Commands.KeyVault.Models; +using Microsoft.WindowsAzure.Commands.ScenarioTest; +using Moq; +using System; +using System.Management.Automation; +using Xunit; + +namespace Microsoft.Azure.Commands.KeyVault.Test.UnitTests +{ + public class SetKeyVaultKeyTests : KeyVaultUnitTestBase + { + private SetAzureKeyVaultKey cmdlet; + private KeyAttributes keyAttributes; + private Microsoft.KeyVault.WebKey.JsonWebKey webKey; + private KeyBundle keyBundle; + + public SetKeyVaultKeyTests() + { + base.SetupTest(); + + keyAttributes = new KeyAttributes(true, DateTime.Now, DateTime.Now, null, null); + webKey = new Microsoft.KeyVault.WebKey.JsonWebKey(); + keyBundle = new KeyBundle() { Attributes = keyAttributes, Key = webKey, KeyName = KeyName, VaultName = VaultName }; + + cmdlet = new SetAzureKeyVaultKey() + { + CommandRuntime = commandRuntimeMock.Object, + DataServiceClient = keyVaultClientMock.Object, + VaultName = VaultName, + Enable = keyAttributes.Enabled, + Expires = keyAttributes.Expires, + NotBefore = keyAttributes.NotBefore, + Name = KeyName + }; + } + + [Fact] + [Trait(Category.AcceptanceType, Category.CheckIn)] + public void CanSetKeyTest() + { + KeyBundle expected = keyBundle; + keyVaultClientMock.Setup(kv => kv.SetKey(VaultName, KeyName, + It.Is(kt => kt.Enabled == keyAttributes.Enabled + && kt.Expires == keyAttributes.Expires + && kt.NotBefore == keyAttributes.NotBefore + && kt.KeyType == keyAttributes.KeyType + && kt.KeyOps == keyAttributes.KeyOps))) + .Returns(expected).Verifiable(); + + cmdlet.ExecuteCmdlet(); + + // Assert + keyVaultClientMock.VerifyAll(); + commandRuntimeMock.Verify(f => f.WriteObject(expected), Times.Once()); + } + + [Fact] + [Trait(Category.AcceptanceType, Category.CheckIn)] + public void ErrorSetKeyTest() + { + KeyBundle expected = keyBundle; + keyVaultClientMock.Setup(kv => kv.SetKey(VaultName, KeyName, + It.Is(kt => kt.Enabled == keyAttributes.Enabled + && kt.Expires == keyAttributes.Expires + && kt.NotBefore == keyAttributes.NotBefore + && kt.KeyType == keyAttributes.KeyType + && kt.KeyOps == keyAttributes.KeyOps))) + .Throws(new Exception("exception")).Verifiable(); + + cmdlet.ExecuteCmdlet(); + + // Assert + keyVaultClientMock.VerifyAll(); + commandRuntimeMock.Verify(f => f.WriteError(It.IsAny()), Times.Once()); + } + } +} diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault.Test/UnitTests/SetKeyVaultSecretTests.cs b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/UnitTests/SetKeyVaultSecretTests.cs new file mode 100644 index 000000000000..125643140684 --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/UnitTests/SetKeyVaultSecretTests.cs @@ -0,0 +1,76 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using Microsoft.Azure.Commands.KeyVault.Cmdlets; +using Microsoft.Azure.Commands.KeyVault.Models; +using Microsoft.WindowsAzure.Commands.ScenarioTest; +using Moq; +using System; +using System.Management.Automation; +using System.Security; +using Xunit; + +namespace Microsoft.Azure.Commands.KeyVault.Test.UnitTests +{ + public class SetKeyVaultSecretTests : KeyVaultUnitTestBase + { + private SetAzureKeyVaultSecret cmdlet; + + public SetKeyVaultSecretTests() + { + base.SetupTest(); + + cmdlet = new SetAzureKeyVaultSecret() + { + CommandRuntime = commandRuntimeMock.Object, + DataServiceClient = keyVaultClientMock.Object, + VaultName = VaultName + }; + } + + [Fact] + [Trait(Category.AcceptanceType, Category.CheckIn)] + public void CanSetSecretTest() + { + SecureString secureSecretValue = SecretValue.ToSecureString(); + Secret expected = new Secret() { SecretName = SecretName, VaultName = VaultName, SecretValue = secureSecretValue }; + keyVaultClientMock.Setup(kv => kv.SetSecret(VaultName, SecretName, secureSecretValue)).Returns(expected).Verifiable(); + + cmdlet.Name = SecretName; + cmdlet.SecretValue = secureSecretValue; + cmdlet.ExecuteCmdlet(); + + // Assert + keyVaultClientMock.VerifyAll(); + commandRuntimeMock.Verify(f => f.WriteObject(expected), Times.Once()); + } + + [Fact] + [Trait(Category.AcceptanceType, Category.CheckIn)] + public void ErrorSetSecretTest() + { + SecureString secureSecretValue = SecretValue.ToSecureString(); + keyVaultClientMock.Setup(kv => kv.SetSecret(VaultName, SecretName, secureSecretValue)) + .Throws(new Exception("exception")).Verifiable(); + + cmdlet.Name = SecretName; + cmdlet.SecretValue = secureSecretValue; + cmdlet.ExecuteCmdlet(); + + // Assert + keyVaultClientMock.VerifyAll(); + commandRuntimeMock.Verify(f => f.WriteError(It.IsAny()), Times.Once()); + } + } +} diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault.Test/packages.config b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/packages.config new file mode 100644 index 000000000000..3c30556f0994 --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault.Test/packages.config @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/Commands.KeyVault.csproj b/src/ResourceManager/KeyVault/Commands.KeyVault/Commands.KeyVault.csproj new file mode 100644 index 000000000000..fd935b5fa6f6 --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/Commands.KeyVault.csproj @@ -0,0 +1,162 @@ + + + + + Debug + AnyCPU + {9FFC40CC-A341-4D0C-A25D-DC6B78EF6C94} + Library + Properties + Microsoft.Azure.Commands.KeyVault + Microsoft.Azure.Commands.KeyVault + v4.5 + 512 + + ..\..\..\ + true + + + true + full + false + ..\..\..\Package\Debug\ResourceManager\AzureResourceManager\KeyVault + DEBUG;TRACE + prompt + 4 + true + false + + + true + MSSharedLibKey.snk + true + ..\..\..\Package\Release\ResourceManager\AzureResourceManager\KeyVault + TRACE;SIGN + true + pdbonly + AnyCPU + bin\Release\Microsoft.Azure.Commands.KeyVault.dll.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + MinimumRecommendedRules.ruleset + ;$(ProgramFiles)\Microsoft Visual Studio 12.0\Team Tools\Static Analysis Tools\Rule Sets + ;$(ProgramFiles)\Microsoft Visual Studio 12.0\Team Tools\Static Analysis Tools\FxCop\Rules + true + false + + + + PreserveNewest + + + + Designer + + + + + + + + + + + + + + + + + + + + + + + + + + True + True + Resources.resx + + + + + ..\..\..\packages\Microsoft.KeyVault.Client.1.0.0.20\lib\net45\Microsoft.KeyVault.Client.dll + + + ..\..\..\packages\Microsoft.KeyVault.WebKey.1.0.0.10\lib\net45\Microsoft.KeyVault.WebKey.dll + + + False + ..\..\..\packages\Microsoft.Azure.Management.Resources.2.7.0-preview\lib\net40\Microsoft.Azure.ResourceManager.dll + + + ..\..\..\packages\Microsoft.Data.Edm.5.6.0\lib\net40\Microsoft.Data.Edm.dll + + + ..\..\..\packages\Microsoft.Data.OData.5.6.0\lib\net40\Microsoft.Data.OData.dll + + + ..\..\..\packages\Microsoft.Data.Services.Client.5.6.0\lib\net40\Microsoft.Data.Services.Client.dll + + + False + ..\..\..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll + + + False + ..\..\..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll + + + False + ..\..\..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll + + + False + ..\..\..\packages\Microsoft.WindowsAzure.Common.1.4.0\lib\net45\Microsoft.WindowsAzure.Common.dll + + + False + ..\..\..\packages\Microsoft.WindowsAzure.Common.1.4.0\lib\net45\Microsoft.WindowsAzure.Common.NetFramework.dll + + + False + ..\..\..\packages\Newtonsoft.Json.6.0.4\lib\net45\Newtonsoft.Json.dll + + + + + + ..\..\..\packages\Microsoft.Net.Http.2.2.28\lib\net45\System.Net.Http.Extensions.dll + + + ..\..\..\packages\Microsoft.Net.Http.2.2.28\lib\net45\System.Net.Http.Primitives.dll + + + + + + + + + {5ee72c53-1720-4309-b54b-5fb79703195f} + Commands.Common + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + + + + + + \ No newline at end of file diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/Commands/AddAzureKeyVaultKey.cs b/src/ResourceManager/KeyVault/Commands.KeyVault/Commands/AddAzureKeyVaultKey.cs new file mode 100644 index 000000000000..8004de880891 --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/Commands/AddAzureKeyVaultKey.cs @@ -0,0 +1,264 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using System; +using System.IO; +using System.Security; +using System.Management.Automation; +using Microsoft.Azure.Commands.KeyVault.Models; +using Microsoft.Azure.Commands.KeyVault.Properties; +using Microsoft.KeyVault.WebKey; + + +namespace Microsoft.Azure.Commands.KeyVault +{ + /// + /// Create a new key in key vault. This cmdlet supports the following types of + /// key creation. + /// 1. Create a new HSM or software key with default key attributes + /// 2. Create a new HSM or software key with given key attributes + /// 3. Create a HSM or software key by importing key material with default key + /// attributes + /// 4 .Create a HSM or software key by importing key material with given key + /// attributes + /// + [Cmdlet(VerbsCommon.Add, "AzureKeyVaultKey", + DefaultParameterSetName=CreateParameterSet)] + [OutputType(typeof(KeyBundle))] + public class AddAzureKeyVaultKey : KeyVaultCmdletBase + { + + #region Parameter Set Names + + private const string CreateParameterSet = "Create"; + private const string ImportParameterSet = "Import"; + + #endregion + + #region Input Parameter Definitions + + /// + /// Vault name + /// + [Parameter(Mandatory = true, + ParameterSetName = CreateParameterSet, + Position = 0, + ValueFromPipelineByPropertyName = true, + HelpMessage = "Vault name. Cmdlet constructs the FQDN of a vault based on the name and currently selected environment.")] + [Parameter(Mandatory = true, + ParameterSetName = ImportParameterSet, + Position = 0, + ValueFromPipelineByPropertyName = true, + HelpMessage = "Vault name. Cmdlet constructs the FQDN of a vault based on the name and currently selected environment.")] + [ValidateNotNullOrEmpty] + public string VaultName + { + get; + set; + } + + /// + /// key name + /// + [Parameter(Mandatory = true, + ParameterSetName = CreateParameterSet, + Position = 1, + HelpMessage = "key name")] + [Parameter(Mandatory = true, + ParameterSetName = ImportParameterSet, + Position = 1, + HelpMessage = "key name")] + [ValidateNotNullOrEmpty] + [Alias("KeyName")] + public string Name + { + get; + set; + } + + /// + /// Path to the local file containing to-be-imported key material. + /// The supported suffix are: + /// 1. byok + /// 2. pfx + /// + [Parameter(Mandatory = true, + ParameterSetName = ImportParameterSet, + HelpMessage = "Path to the local file containing to-be-imported key material")] + [ValidateNotNullOrEmpty] + public string KeyFilePath + { + get; + set; + } + + /// + /// Password of the imported file. + /// Required for pfx file + /// + [Parameter(Mandatory = false, + ParameterSetName = ImportParameterSet, + HelpMessage = "Password of the imported key file")] + [ValidateNotNullOrEmpty] + public SecureString KeyFilePassword + { + get; + set; + } + + /// + /// Destination of the key + /// + [Parameter(Mandatory = false, + ParameterSetName = CreateParameterSet, + HelpMessage = "Destination of the key")] + [Parameter(Mandatory = false, + ParameterSetName = ImportParameterSet, + HelpMessage = "Destination of the key")] + [ValidateSetAttribute(new string[] { HsmDestination, SoftwareDestination })] + public string Destination + { + get; + set; + } + + /// + /// Set key in disabled state if present + /// + [Parameter(Mandatory = false, + ParameterSetName = CreateParameterSet, + HelpMessage = "Set key in disabled state if present. If not present, key is enabled.")] + [Parameter(Mandatory = false, + ParameterSetName = ImportParameterSet, + HelpMessage = "Set key in disabled state if present. If not present, key is enabled.")] + public SwitchParameter Disable + { + get; + set; + } + + /// + /// Key operations + /// + [Parameter(Mandatory = false, + ParameterSetName = CreateParameterSet, + ValueFromPipelineByPropertyName = true, + HelpMessage = "The operations that can performs with the key. If not present, all operations can be performed.")] + [Parameter(Mandatory = false, + ParameterSetName = ImportParameterSet, + ValueFromPipelineByPropertyName = true, + HelpMessage = "The operations that can performs with the key. If not present, all operations can be performed.")] + public string[] KeyOps + { + get; + set; + } + + /// + /// Key expires time in UTC time + /// + [Parameter(Mandatory = false, + ParameterSetName = CreateParameterSet, + ValueFromPipelineByPropertyName = true, + HelpMessage = "The expiration time of a key in UTC time. If not present, key will not expire.")] + [Parameter(Mandatory = false, + ParameterSetName = ImportParameterSet, + ValueFromPipelineByPropertyName = true, + HelpMessage = "The expiration time of a key in UTC time. If not present, key will not expire.")] + public DateTime? Expires + { + get; + set; + } + + /// + /// The UTC time before which key can't be used + /// + [Parameter(Mandatory = false, + ParameterSetName = CreateParameterSet, + ValueFromPipelineByPropertyName = true, + HelpMessage = "The UTC time before which key can't be used. If not present, no limitation.")] + [Parameter(Mandatory = false, + ParameterSetName = ImportParameterSet, + ValueFromPipelineByPropertyName = true, + HelpMessage = "The UTC time before which key can't be used. If not present, no limitation.")] + public DateTime? NotBefore + { + get; + set; + } + + #endregion + + public override void ExecuteCmdlet() + { + try + { + KeyBundle keyBundle; + switch (ParameterSetName) + { + case CreateParameterSet: + keyBundle = this.DataServiceClient.CreateKey( + VaultName, Name, + CreateKeyAttributes(false)); + break; + + case ImportParameterSet: + keyBundle = this.DataServiceClient.ImportKey( + VaultName, Name, + CreateKeyAttributes(), + CreateWebKeyFromFile()); + break; + + default: + throw new ArgumentException(Resources.BadParameterSetName); + } + + this.WriteObject(keyBundle); + } + catch (Exception ex) + { + this.WriteErrorDetails(ex); + } + } + + internal KeyCreationAttributes CreateKeyAttributes(bool? hsmDefault=null) + { + bool? isHsm = string.IsNullOrEmpty(Destination) ? hsmDefault : + HsmDestination.Equals(Destination, StringComparison.OrdinalIgnoreCase); + + return new KeyCreationAttributes( + !Disable.IsPresent, + Expires, + NotBefore, + isHsm, + KeyOps); + } + + internal JsonWebKey CreateWebKeyFromFile() + { + FileInfo keyFile = new FileInfo(this.GetUnresolvedProviderPathFromPSPath(this.KeyFilePath)); + if (!keyFile.Exists) + { + throw new FileNotFoundException(string.Format(Resources.KeyFileNotFound, this.KeyFilePath)); + } + + var converterChain = WebKeyConverterFactory.CreateConverterChain(); + return converterChain.ConvertKeyFromFile(keyFile, KeyFilePassword); + } + + private const string HsmDestination = "HSM"; + private const string SoftwareDestination = "Software"; + } +} diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/Commands/GetAzureKeyVaultKey.cs b/src/ResourceManager/KeyVault/Commands.KeyVault/Commands/GetAzureKeyVaultKey.cs new file mode 100644 index 000000000000..3a367197cf7d --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/Commands/GetAzureKeyVaultKey.cs @@ -0,0 +1,105 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using System; +using System.Linq; +using System.Collections.Generic; +using System.Management.Automation; +using Microsoft.Azure.Commands.KeyVault.Models; +using Microsoft.Azure.Commands.KeyVault.Properties; + +namespace Microsoft.Azure.Commands.KeyVault.Cmdlets +{ + [Cmdlet(VerbsCommon.Get, "AzureKeyVaultKey", + DefaultParameterSetName=ByVaultNameParameterSet)] + [OutputType(typeof(List), typeof(KeyBundle))] + public class GetAzureKeyVaultKey : KeyVaultCmdletBase + { + + #region Parameter Set Names + + private const string ByKeyNameParameterSet = "ByKeyName"; + private const string ByVaultNameParameterSet = "ByVaultName"; + + #endregion + + #region Input Parameter Definitions + + /// + /// Vault name + /// + [Parameter(Mandatory = true, + Position = 0, + ValueFromPipelineByPropertyName = true, + ParameterSetName = ByKeyNameParameterSet, + HelpMessage = "Vault name. Cmdlet constructs the FQDN of a vault based on the name and currently selected environment.")] + [Parameter(Mandatory = true, + Position = 0, + ValueFromPipelineByPropertyName = true, + ParameterSetName = ByVaultNameParameterSet, + HelpMessage = "Vault name. Cmdlet constructs the FQDN of a vault based on the name and currently selected environment.")] + + [ValidateNotNullOrEmpty] + public string VaultName + { + get; + set; + } + + /// + /// Key name. + /// + [Parameter(Mandatory = true, + ParameterSetName = ByKeyNameParameterSet, + Position = 1, + ValueFromPipelineByPropertyName = true, + HelpMessage = "key name. Cmdlet constructs the FQDN of a key from vault name, currently selected environment and key name.")] + [ValidateNotNullOrEmpty] + [Alias("KeyName")] + public string Name + { + get; + set; + } + + #endregion + + public override void ExecuteCmdlet() + { + try + { + switch (ParameterSetName) + { + case ByKeyNameParameterSet: + var keyBundle = DataServiceClient.GetKey(VaultName, Name); + WriteObject(keyBundle); + break; + + case ByVaultNameParameterSet: + IEnumerable keyBundles = DataServiceClient.GetKeys(VaultName); + WriteObject(keyBundles, true); + break; + + default: + throw new ArgumentException(Resources.BadParameterSetName); + } + } + catch (Exception ex) + { + this.WriteErrorDetails(ex); + } + } + + } +} diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/Commands/GetAzureKeyVaultSecret.cs b/src/ResourceManager/KeyVault/Commands.KeyVault/Commands/GetAzureKeyVaultSecret.cs new file mode 100644 index 000000000000..7fc077783027 --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/Commands/GetAzureKeyVaultSecret.cs @@ -0,0 +1,102 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using Microsoft.Azure.Commands.KeyVault.Models; +using Microsoft.Azure.Commands.KeyVault.Properties; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Management.Automation; + +namespace Microsoft.Azure.Commands.KeyVault.Cmdlets +{ + [Cmdlet(VerbsCommon.Get, "AzureKeyVaultSecret", + DefaultParameterSetName = ByVaultNameParameterSet)] + [OutputType(typeof(List))] + public class GetAzureKeyVaultSecret : KeyVaultCmdletBase + { + #region Parameter Set Names + + private const string BySecretNameParameterSet = "BySecretName"; + private const string ByVaultNameParameterSet = "ByVaultName"; + + #endregion + + #region Input Parameter Definitions + + /// + /// Vault name + /// + [Parameter(Mandatory = true, + Position = 0, + ValueFromPipelineByPropertyName = true, + ParameterSetName = BySecretNameParameterSet, + HelpMessage = "Vault name. Cmdlet constructs the FQDN of a vault based on the name and currently selected environment.")] + [Parameter(Mandatory = true, + Position = 0, + ValueFromPipelineByPropertyName = true, + ParameterSetName = ByVaultNameParameterSet, + HelpMessage = "Vault name. Cmdlet constructs the FQDN of a vault based on the name and currently selected environment.")] + [ValidateNotNullOrEmpty] + public string VaultName + { + get; + set; + } + + /// + /// Secret name + /// + [Parameter(Mandatory = true, + Position = 1, + ValueFromPipelineByPropertyName = true, + ParameterSetName = BySecretNameParameterSet, + HelpMessage = "Secret name. Cmdlet constructs the FQDN of a secret from vault name, currently selected environment and secret name.")] + [ValidateNotNullOrEmpty] + [Alias("SecretName")] + public string Name + { + get; + set; + } + + #endregion + + public override void ExecuteCmdlet() + { + try + { + switch (ParameterSetName) + { + case BySecretNameParameterSet: + var secret = DataServiceClient.GetSecret(VaultName, Name); + WriteObject(secret); + break; + + case ByVaultNameParameterSet: + var secrets = DataServiceClient.GetSecrets(VaultName); + WriteObject(secrets, true); + break; + + default: + throw new ArgumentException(Resources.BadParameterSetName); + } + } + catch (Exception ex) + { + this.WriteErrorDetails(ex); + } + } + } +} diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/Commands/RemoveAzureKeyVaultKey.cs b/src/ResourceManager/KeyVault/Commands.KeyVault/Commands/RemoveAzureKeyVaultKey.cs new file mode 100644 index 000000000000..c1f90099fd36 --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/Commands/RemoveAzureKeyVaultKey.cs @@ -0,0 +1,95 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using System; +using System.Management.Automation; +using Microsoft.Azure.Commands.KeyVault.Models; +using Microsoft.Azure.Commands.KeyVault.Properties; + +namespace Microsoft.Azure.Commands.KeyVault.Cmdlets +{ + [Cmdlet(VerbsCommon.Remove, "AzureKeyVaultKey", + SupportsShouldProcess = true, + ConfirmImpact = ConfirmImpact.High)] + [OutputType(typeof(KeyBundle))] + public class RemoveAzureKeyVaultKey : KeyVaultCmdletBase + { + #region Input Parameter Definitions + + /// + /// Vault name + /// + [Parameter(Mandatory = true, + Position = 0, + ValueFromPipelineByPropertyName = true, + HelpMessage = "Vault name. Cmdlet constructs the FQDN of a vault based on the name and currently selected environment.")] + [ValidateNotNullOrEmpty] + public string VaultName + { + get; + set; + } + + /// + /// key name + /// + [Parameter(Mandatory = true, + Position = 1, + ValueFromPipelineByPropertyName = true, + HelpMessage = "Key name. Cmdlet constructs the FQDN of a key from vault name, currently selected environment and key name.")] + [ValidateNotNullOrEmpty] + [Alias("KeyName")] + public string Name + { + get; + set; + } + + /// + /// If present, do not ask for confirmation + /// + [Parameter(Mandatory = false, + HelpMessage = "Do not ask for confirmation.")] + public SwitchParameter Force { get; set; } + + [Parameter(Mandatory = false, + HelpMessage = "Cmdlet does not return object by default. If this switch is specified, return a bool to enable pipeline.")] + public SwitchParameter PassThru { get; set; } + + #endregion + public override void ExecuteCmdlet() + { + try + { + KeyBundle keyBundle = null; + ConfirmOperation( + Resources.RemoveKeyWhatIfMessage, + Name, + Resources.RemoveKeyWarning, + Force.IsPresent, + () => { keyBundle = DataServiceClient.DeleteKey(VaultName, Name); }); + + if (PassThru.IsPresent) + { + WriteObject(keyBundle); + } + } + catch (Exception ex) + { + this.WriteErrorDetails(ex); + } + } + + } +} diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/Commands/RemoveAzureKeyVaultSecret.cs b/src/ResourceManager/KeyVault/Commands.KeyVault/Commands/RemoveAzureKeyVaultSecret.cs new file mode 100644 index 000000000000..a173bd673073 --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/Commands/RemoveAzureKeyVaultSecret.cs @@ -0,0 +1,95 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using System; +using System.Management.Automation; +using Microsoft.Azure.Commands.KeyVault.Models; +using Microsoft.Azure.Commands.KeyVault.Properties; + +namespace Microsoft.Azure.Commands.KeyVault.Cmdlets +{ + [Cmdlet(VerbsCommon.Remove, "AzureKeyVaultSecret", + SupportsShouldProcess = true, + ConfirmImpact = ConfirmImpact.High)] + [OutputType(typeof(Secret))] + public class RemoveAzureKeyVaultSecret : KeyVaultCmdletBase + { + #region Input Parameter Definitions + + /// + /// Vault name + /// + [Parameter(Mandatory = true, + Position = 0, + ValueFromPipelineByPropertyName = true, + HelpMessage = "Vault name. Cmdlet constructs the FQDN of a vault based on the name and currently selected environment.")] + [ValidateNotNullOrEmpty] + public string VaultName + { + get; + set; + } + + /// + /// Secret name + /// + [Parameter(Mandatory = true, + Position = 1, + ValueFromPipelineByPropertyName = true, + HelpMessage = "Secret name. Cmdlet constructs the FQDN of a secret from vault name, currently selected environment and secret name.")] + [ValidateNotNullOrEmpty] + [Alias("SecretName")] + public string Name + { + get; + set; + } + + /// + /// If present, do not ask for confirmation + /// + [Parameter(Mandatory = false, + HelpMessage = "Do not ask for confirmation.")] + public SwitchParameter Force { get; set; } + + [Parameter(Mandatory = false, + HelpMessage = "Cmdlet does not return object by default. If this switch is specified, return a bool to enable pipeline.")] + public SwitchParameter PassThru { get; set; } + + #endregion + + public override void ExecuteCmdlet() + { + try + { + Secret secret = null; + ConfirmOperation( + Resources.RemoveSecretWhatIfMessage, + Name, + Resources.RemoveSecretWarning, + Force.IsPresent, + () => { secret = DataServiceClient.DeleteSecret(VaultName, Name); }); + + if (PassThru.IsPresent) + { + WriteObject(secret); + } + } + catch (Exception ex) + { + this.WriteErrorDetails(ex); + } + } + } +} diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/Commands/SetAzureKeyVaultKey.cs b/src/ResourceManager/KeyVault/Commands.KeyVault/Commands/SetAzureKeyVaultKey.cs new file mode 100644 index 000000000000..6ea1ec7a2a74 --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/Commands/SetAzureKeyVaultKey.cs @@ -0,0 +1,118 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using System; +using System.Management.Automation; +using Microsoft.Azure.Commands.KeyVault.Models; + +namespace Microsoft.Azure.Commands.KeyVault.Cmdlets +{ + /// + /// Update attribute of a key vault key. + /// + [Cmdlet(VerbsCommon.Set, "AzureKeyVaultKey")] + [OutputType(typeof(KeyBundle))] + public class SetAzureKeyVaultKey : KeyVaultCmdletBase + { + #region Input Parameter Definitions + + /// + /// Vault name + /// + [Parameter(Mandatory = true, + Position = 0, + ValueFromPipelineByPropertyName = true, + HelpMessage = "Vault name. Cmdlet constructs the FQDN of a vault based on the name and currently selected environment.")] + [ValidateNotNullOrEmpty] + public string VaultName + { + get; + set; + } + + /// + /// key name + /// + [Parameter(Mandatory = true, + Position = 1, + ValueFromPipelineByPropertyName = true, + HelpMessage = "Key name. Cmdlet constructs the FQDN of a key from vault name, currently selected environment and key name.")] + [ValidateNotNullOrEmpty] + [Alias("KeyName")] + public string Name + { + get; + set; + } + + /// + /// If present, enable a key if value is true. + /// Disable a key if value is false. + /// If not present, no change on current key enabled/disabled state. + /// + [Parameter(Mandatory = false, + HelpMessage = "If present, enable a key if value is true. Disable a key if value is false. If not present, no change on current key enabled/disabled state.")] + public bool? Enable + { + get; + set; + } + + /// + /// Key expires time in UTC time + /// + [Parameter(Mandatory = false, + ValueFromPipelineByPropertyName = true, + HelpMessage = "The expiration time of a key in UTC time. If not present, key will not expire.")] + public DateTime? Expires + { + get; + set; + } + + /// + /// The UTC time before which key can't be used + /// + [Parameter(Mandatory = false, + ValueFromPipelineByPropertyName = true, + HelpMessage = "The UTC time before which key can't be used. If not present, no limitation.")] + public DateTime? NotBefore + { + get; + set; + } + + + #endregion + + public override void ExecuteCmdlet() + { + try + { + KeyAttributes attributes = new KeyAttributes + { + Enabled = this.Enable, + Expires = this.Expires, + NotBefore = this.NotBefore + }; + + WriteObject(DataServiceClient.SetKey(VaultName, Name, attributes)); + } + catch (Exception ex) + { + this.WriteErrorDetails(ex); + } + } + } +} diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/Commands/SetAzureKeyVaultSecret.cs b/src/ResourceManager/KeyVault/Commands.KeyVault/Commands/SetAzureKeyVaultSecret.cs new file mode 100644 index 000000000000..048e1b2ba3c7 --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/Commands/SetAzureKeyVaultSecret.cs @@ -0,0 +1,84 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using System; +using System.Security; +using System.Management.Automation; +using Microsoft.Azure.Commands.KeyVault.Models; + +namespace Microsoft.Azure.Commands.KeyVault.Cmdlets +{ + [Cmdlet(VerbsCommon.Set, "AzureKeyVaultSecret")] + [OutputType(typeof(Secret))] + public class SetAzureKeyVaultSecret : KeyVaultCmdletBase + { + #region Input Parameter Definitions + + /// + /// Vault name + /// + [Parameter(Mandatory = true, + Position = 0, + ValueFromPipelineByPropertyName = true, + HelpMessage = "Vault name. Cmdlet constructs the FQDN of a vault based on the name and currently selected environment.")] + [ValidateNotNullOrEmpty] + public string VaultName + { + get; + set; + } + + /// + /// Secret name + /// + [Parameter(Mandatory = true, + Position = 1, + ValueFromPipelineByPropertyName = true, + HelpMessage = "Secret name. Cmdlet constructs the FQDN of a secret from vault name, currently selected environment and secret name.")] + [ValidateNotNullOrEmpty] + [Alias("SecretName")] + public string Name + { + get; + set; + } + + /// + /// Secret value + /// + [Parameter(Mandatory = true, + Position = 2, + HelpMessage = "Secret value")] + public SecureString SecretValue + { + get; + set; + } + + #endregion + + public override void ExecuteCmdlet() + { + try + { + var secret = DataServiceClient.SetSecret(VaultName, Name, SecretValue); + WriteObject(secret); + } + catch (Exception ex) + { + this.WriteErrorDetails(ex); + } + } + } +} diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/MSSharedLibKey.snk b/src/ResourceManager/KeyVault/Commands.KeyVault/MSSharedLibKey.snk new file mode 100644 index 000000000000..695f1b38774e Binary files /dev/null and b/src/ResourceManager/KeyVault/Commands.KeyVault/MSSharedLibKey.snk differ diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/Microsoft.Azure.Commands.KeyVault.format.ps1xml b/src/ResourceManager/KeyVault/Commands.KeyVault/Microsoft.Azure.Commands.KeyVault.format.ps1xml new file mode 100644 index 000000000000..f7f8539950d9 --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/Microsoft.Azure.Commands.KeyVault.format.ps1xml @@ -0,0 +1,107 @@ + + + + + Microsoft.Azure.Commands.KeyVault.Models.KeyBundle + + Microsoft.Azure.Commands.KeyVault.Models.KeyBundle + + + + + + Left + + + + Left + + + + Left + + + + Left + + + + Left + + + + Left + + + + + + + VaultName + + + KeyName + + + $_.Attributes.KeyType + + + $_.Attributes.Enabled + + + Attributes + + + Key + + + + + + + + Microsoft.Azure.Commands.KeyVault.Models.Secret + + Microsoft.Azure.Commands.KeyVault.Models.Secret + + + + + + Left + + + + Left + + + + Left + + + + Left + + + + + + + VaultName + + + SecretName + + + SecretValueText + + + SecretValue + + + + + + + + diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/Models/ByokWebKeyConverter.cs b/src/ResourceManager/KeyVault/Commands.KeyVault/Models/ByokWebKeyConverter.cs new file mode 100644 index 000000000000..cc81b09dbc28 --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/Models/ByokWebKeyConverter.cs @@ -0,0 +1,79 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using System; +using System.Security; +using System.IO; +using Microsoft.Azure.Commands.KeyVault.Properties; +using Microsoft.KeyVault.WebKey; + +namespace Microsoft.Azure.Commands.KeyVault.Models +{ + /// + /// Utility class that creates web key from a BYOK file + /// + internal class ByokWebKeyConverter : IWebKeyConverter + { + public ByokWebKeyConverter(IWebKeyConverter next=null) + { + this.next = next; + } + + public JsonWebKey ConvertKeyFromFile(FileInfo fileInfo, SecureString password) + { + if (CanProcess(fileInfo)) + { + return Convert(fileInfo.FullName); + } + else if (next != null) + { + return next.ConvertKeyFromFile(fileInfo, password); + } + else + { + throw new ArgumentException(string.Format(Resources.UnsupportedFileFormat, fileInfo.Name)); + } + } + + private bool CanProcess(FileInfo fileInfo) + { + if (fileInfo == null || string.IsNullOrEmpty(fileInfo.Extension)) + { + return false; + } + + return ByokFileExtension.Equals(fileInfo.Extension, StringComparison.OrdinalIgnoreCase); + } + + private JsonWebKey Convert(string byokFileName) + { + byte[] byokBlob = File.ReadAllBytes(byokFileName); + + if (byokBlob == null || byokBlob.Length == 0) + { + throw new ArgumentException(string.Format(Resources.InvalidKeyBlob, "BYOK")); + } + + return new JsonWebKey() + { + Kty = JsonWebKeyType.RsaHsm, + T = byokBlob, + }; + } + + private IWebKeyConverter next; + private const string ByokFileExtension = ".byok"; + + } +} diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/Models/DataServiceCredential.cs b/src/ResourceManager/KeyVault/Commands.KeyVault/Models/DataServiceCredential.cs new file mode 100644 index 000000000000..cfffc891f9bd --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/Models/DataServiceCredential.cs @@ -0,0 +1,103 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.WindowsAzure.Commands.Common; +using Microsoft.WindowsAzure.Commands.Common.Models; +using Microsoft.WindowsAzure.Commands.Utilities.Common.Authentication; +using Microsoft.Azure.Commands.KeyVault.Properties; + +namespace Microsoft.Azure.Commands.KeyVault.Models +{ + internal class DataServiceCredential + { + public DataServiceCredential(IAuthenticationFactory authFactory, AzureContext context) + { + if (authFactory == null) + { + throw new ArgumentNullException("authFactory"); + } + if (context == null) + { + throw new ArgumentNullException("context"); + } + + var bundle = GetToken(authFactory, context); + this.token = bundle.Item1; + this.resourceId = bundle.Item2; + } + + /// + /// Authentication callback method required by KeyVaultClient + /// + /// + /// + /// + /// + public string OnAuthentication(string authority, string resource, string scope) + { + // TODO: Add trace to log tokenType, resource, authority, scope etc + string tokenStr = string.Empty; + this.token.AuthorizeRequest((tokenType, tokenValue) => + { + tokenStr = tokenValue; + }); + + return tokenStr; + } + + private Tuple GetToken(IAuthenticationFactory authFactory, AzureContext context) + { + if (context.Subscription == null) + { + throw new ArgumentException(Resources.InvalidCurrentSubscription); + } + if (context.Account == null) + { + throw new ArgumentException(Resources.InvalidSubscriptionState); + } + if (context.Account.Type != AzureAccount.AccountType.User) + { + throw new ArgumentException(string.Format(Resources.UnsupportedAccountType, context.Account.Type)); + } + + var tenant = context.Subscription.GetPropertyAsArray(AzureSubscription.Property.Tenants) + .Intersect(context.Account.GetPropertyAsArray(AzureAccount.Property.Tenants)) + .FirstOrDefault(); + if (tenant == null) + { + throw new ArgumentException(Resources.InvalidSubscriptionState); + } + + try + { + var accesstoken = authFactory.Authenticate(context.Account, context.Environment, tenant, null, ShowDialog.Auto, + ResourceIdEndpoint); + + return Tuple.Create(accesstoken, context.Environment.Endpoints[ResourceIdEndpoint]); + } + catch (Exception ex) + { + throw new ArgumentException(Resources.InvalidSubscriptionState, ex); + } + } + + private IAccessToken token; + private string resourceId; + + private const AzureEnvironment.Endpoint ResourceIdEndpoint = AzureEnvironment.Endpoint.AzureKeyVaultServiceEndpointResourceId; + } +} diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/Models/IKeyVaultDataServiceClient.cs b/src/ResourceManager/KeyVault/Commands.KeyVault/Models/IKeyVaultDataServiceClient.cs new file mode 100644 index 000000000000..441cdc3312b9 --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/Models/IKeyVaultDataServiceClient.cs @@ -0,0 +1,43 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using Microsoft.KeyVault.WebKey; +using System.Collections.Generic; +using System.Security; + +namespace Microsoft.Azure.Commands.KeyVault.Models +{ + public interface IKeyVaultDataServiceClient + { + KeyBundle CreateKey(string vaultName, string keyName, KeyCreationAttributes keyAttributes); + + KeyBundle ImportKey(string vaultName, string keyName, KeyCreationAttributes keyAttributes, JsonWebKey webKey); + + KeyBundle SetKey(string vaultName, string keyName, KeyAttributes keyAttributes); + + KeyBundle GetKey(string vaultName, string keyName); + + IEnumerable GetKeys(string vaultName); + + KeyBundle DeleteKey(string vaultName, string keyName); + + Secret SetSecret(string vaultName, string secretName, SecureString secretValue); + + Secret GetSecret(string vaultName, string secretName); + + IEnumerable GetSecrets(string vaultName); + + Secret DeleteSecret(string vaultName, string secretName); + } +} diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/Models/IWebKeyConverter.cs b/src/ResourceManager/KeyVault/Commands.KeyVault/Models/IWebKeyConverter.cs new file mode 100644 index 000000000000..ee11e701226d --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/Models/IWebKeyConverter.cs @@ -0,0 +1,26 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using System; +using System.IO; +using System.Security; +using Microsoft.KeyVault.WebKey; + +namespace Microsoft.Azure.Commands.KeyVault.Models +{ + internal interface IWebKeyConverter + { + JsonWebKey ConvertKeyFromFile(FileInfo fileInfo, SecureString password); + } +} diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/Models/KeyAttributes.cs b/src/ResourceManager/KeyVault/Commands.KeyVault/Models/KeyAttributes.cs new file mode 100644 index 000000000000..d8265103a3e1 --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/Models/KeyAttributes.cs @@ -0,0 +1,93 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using System; +using System.Collections.ObjectModel; +using Client = Microsoft.KeyVault.Client; + +namespace Microsoft.Azure.Commands.KeyVault.Models +{ + public class KeyAttributes + { + public KeyAttributes() + { } + + internal KeyAttributes(bool? enabled, DateTime? expires, DateTime? notBefore, string keyType, string[] keyOps) + { + this.Enabled = enabled; + this.Expires = expires; + this.NotBefore = notBefore; + this.KeyType = keyType; + this.KeyOps = keyOps; + } + + internal KeyAttributes(bool? enabled, int? expires, int? notBefore, string keyType, string[] keyOps) : + this(enabled, FromUnixTime(expires), FromUnixTime(notBefore), keyType, keyOps) + { } + + public bool? Enabled { get; set; } + + public DateTime? Expires { get; set; } + + public DateTime? NotBefore { get; set; } + + public string KeyType { get; private set; } + + public string[] KeyOps { get; set; } + + public static explicit operator Client.KeyAttributes(KeyAttributes attr) + { + return new Client.KeyAttributes() + { + Enabled = attr.Enabled, + NotBefore = attr.NotBeforeUnixTime, + Expires = attr.ExpiresUnixTime + }; + } + + internal int? ExpiresUnixTime + { + get + { + return ToUnixTime(this.Expires); + } + } + + internal int? NotBeforeUnixTime + { + get + { + return ToUnixTime(this.NotBefore); + } + } + + private static int? ToUnixTime(DateTime? utcTime) + { + if (!utcTime.HasValue) + { + return null; + } + return Client.UnixEpoch.ToUnixTime(utcTime.Value); + } + + private static DateTime? FromUnixTime(int? utcTime) + { + if (!utcTime.HasValue) + { + return null; + } + return Client.UnixEpoch.FromUnixTime(utcTime.Value); + } + } +} diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/Models/KeyBundle.cs b/src/ResourceManager/KeyVault/Commands.KeyVault/Models/KeyBundle.cs new file mode 100644 index 000000000000..969786d79e8a --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/Models/KeyBundle.cs @@ -0,0 +1,64 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using System; +using Microsoft.KeyVault.WebKey; +using Client = Microsoft.KeyVault.Client; +using Microsoft.Azure.Commands.KeyVault.Properties; + +namespace Microsoft.Azure.Commands.KeyVault.Models +{ + public class KeyBundle + { + public KeyBundle() + { } + + internal KeyBundle(Client.KeyBundle clientKeyBundle, VaultUriHelper vaultUriHelper) + { + if (vaultUriHelper == null) + { + throw new ArgumentNullException("vaultUriHelper"); + } + if (clientKeyBundle == null) + { + throw new ArgumentNullException("clientKeyBundle"); + } + if (clientKeyBundle.Key == null || clientKeyBundle.Attributes == null) + { + throw new ArgumentException(Resources.InvalidKeyBundle); + } + + VaultName = vaultUriHelper.GetVaultName(clientKeyBundle.Key.Kid); + KeyName = vaultUriHelper.GetKeyName(clientKeyBundle.Key.Kid); + Key = clientKeyBundle.Key; + Attributes = new KeyAttributes( + clientKeyBundle.Attributes.Enabled, + clientKeyBundle.Attributes.Expires, + clientKeyBundle.Attributes.NotBefore, + clientKeyBundle.Key.Kty, + clientKeyBundle.Key.KeyOps); + + // TODO: trace vaultUriHelper.KeyVaultDnsSuffix; + } + + public string VaultName { get; set; } + + public string KeyName { get; set; } + + public KeyAttributes Attributes { get; set; } + + public JsonWebKey Key { get; set; } + + } +} diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/Models/KeyCreationAttributes.cs b/src/ResourceManager/KeyVault/Commands.KeyVault/Models/KeyCreationAttributes.cs new file mode 100644 index 000000000000..0d0af8d1fa82 --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/Models/KeyCreationAttributes.cs @@ -0,0 +1,30 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using System; +using System.Collections.ObjectModel; + +namespace Microsoft.Azure.Commands.KeyVault.Models +{ + public class KeyCreationAttributes : KeyAttributes + { + public KeyCreationAttributes(bool? enabled, DateTime? expires, DateTime? notBefore, bool? hsm, string[] keyOps) : + base(enabled, expires, notBefore, null, keyOps) + { + this.Hsm = hsm; + } + + public bool? Hsm { get; private set; } + } +} diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/Models/KeyVaultCmdletBase.cs b/src/ResourceManager/KeyVault/Commands.KeyVault/Models/KeyVaultCmdletBase.cs new file mode 100644 index 000000000000..f57f9b34eb23 --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/Models/KeyVaultCmdletBase.cs @@ -0,0 +1,67 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using System; +using System.Net; +using System.Net.Http; +using Microsoft.WindowsAzure.Commands.Utilities.Common; +using Microsoft.WindowsAzure.Commands.Common; + +namespace Microsoft.Azure.Commands.KeyVault.Models +{ + public class KeyVaultCmdletBase : AzurePSCmdlet + { + public KeyVaultCmdletBase() + { + } + protected void WriteErrorDetails(Exception exception) + { + // Call the handler to parse and get ErrorRecord + WriteError(KeyVaultExceptionHandler.RetrieveExceptionDetails(exception)); + } + internal IKeyVaultDataServiceClient DataServiceClient + { + get + { + if (dataServiceClient == null) + { + this.dataServiceClient = new KeyVaultDataServiceClient( + AzureSession.AuthenticationFactory, + AzureSession.CurrentContext, + // TODO: determine HttpClient creation model after fully understand testing framework + new HttpClient()); + } + + return this.dataServiceClient; + } + set + { + this.dataServiceClient = value; + } + } + + protected void ConfirmOperation(string whatIfMessage, string target, string warningMessage, bool force, Action action) + { + if (ShouldProcess(target, whatIfMessage)) + { + if (force || ShouldContinue(string.Format(warningMessage, target),"")) + { + action(); + } + } + } + + private IKeyVaultDataServiceClient dataServiceClient; + } +} diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/Models/KeyVaultDataServiceClient.cs b/src/ResourceManager/KeyVault/Commands.KeyVault/Models/KeyVaultDataServiceClient.cs new file mode 100644 index 000000000000..d0575b7bbfa9 --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/Models/KeyVaultDataServiceClient.cs @@ -0,0 +1,305 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using System; +using System.Text; +using System.Net.Http; +using System.Security; +using System.Collections.Generic; +using System.Threading.Tasks; +using System.Linq; +using Microsoft.WindowsAzure; +using Microsoft.WindowsAzure.Common.Internals; +using Microsoft.WindowsAzure.Commands.Common; +using Microsoft.WindowsAzure.Commands.Common.Models; +using Microsoft.WindowsAzure.Commands.Utilities.Common.Authentication; +using Microsoft.Azure.Commands.KeyVault.Properties; +using Client = Microsoft.KeyVault.Client; +using Microsoft.KeyVault.WebKey; + +namespace Microsoft.Azure.Commands.KeyVault.Models +{ + internal class KeyVaultDataServiceClient : IKeyVaultDataServiceClient + { + public KeyVaultDataServiceClient(IAuthenticationFactory authFactory, AzureContext context, HttpClient httpClient) + { + if (authFactory == null) + { + throw new ArgumentNullException("authFactory"); + } + if (context == null) + { + throw new ArgumentNullException("context"); + } + if (context.Environment == null) + { + throw new ArgumentException(Resources.InvalidAzureEnvironment); + } + if (httpClient == null) + { + throw new ArgumentNullException("httpClient"); + } + + var credential = new DataServiceCredential(authFactory, context); + this.keyVaultClient = new Client.KeyVaultClient( + credential.OnAuthentication, + SendRequestCallback, + ReceiveResponseCallback, + httpClient); + + + this.vaultUriHelper = new VaultUriHelper( + context.Environment.Endpoints[AzureEnvironment.Endpoint.AzureKeyVaultDnsSuffix]); + } + + /// + /// Parameterless constructor for Mocking. + /// + public KeyVaultDataServiceClient() + { + } + + public KeyBundle CreateKey(string vaultName, string keyName, KeyCreationAttributes keyAttributes) + { + if (string.IsNullOrEmpty(vaultName)) + { + throw new ArgumentNullException("vaultName"); + } + if (string.IsNullOrEmpty(keyName)) + { + throw new ArgumentNullException("keyName"); + } + if (keyAttributes == null) + { + throw new ArgumentNullException("keyAttributes"); + } + + string vaultAddress = this.vaultUriHelper.CreateVaultAddress(vaultName); + Client.KeyAttributes clientAttributes = (Client.KeyAttributes)keyAttributes; + clientAttributes.Hsm = keyAttributes.Hsm; + string keyType = JsonWebKeyType.Rsa; + if (keyAttributes.Hsm.HasValue && keyAttributes.Hsm.Value) + { + keyType = JsonWebKeyType.RsaHsm; + } + + Client.KeyBundle clientKeyBundle = this.keyVaultClient.CreateKeyAsync( + vaultAddress, keyName, keyType, keyAttributes.KeyOps, clientAttributes).GetAwaiter().GetResult(); + + return new KeyBundle(clientKeyBundle, this.vaultUriHelper); + } + + public KeyBundle ImportKey(string vaultName, string keyName, KeyCreationAttributes keyAttributes, JsonWebKey webKey) + { + if (string.IsNullOrEmpty(vaultName)) + { + throw new ArgumentNullException("vaultName"); + } + if (string.IsNullOrEmpty(keyName)) + { + throw new ArgumentNullException("keyName"); + } + if (keyAttributes == null) + { + throw new ArgumentNullException("keyAttributes"); + } + if (webKey == null) + { + throw new ArgumentNullException("webKey"); + } + if (keyAttributes.Hsm.HasValue && !keyAttributes.Hsm.Value && + JsonWebKeyType.RsaHsm.Equals(webKey.Kty)) + { + // Importing HSMRSA key blob as RSA key is not allowed + throw new ArgumentException(Resources.InvalidKeyDestination); + } + + string vaultAddress = this.vaultUriHelper.CreateVaultAddress(vaultName); + Client.KeyAttributes clientAttributes = (Client.KeyAttributes)keyAttributes; + clientAttributes.Hsm = keyAttributes.Hsm; + webKey.KeyOps = keyAttributes.KeyOps; + Client.KeyBundle clientKeyBundle = new Client.KeyBundle() + { + Attributes = clientAttributes, + Key = webKey + }; + + clientKeyBundle = this.keyVaultClient.ImportKeyAsync(vaultAddress, keyName, clientKeyBundle).GetAwaiter().GetResult(); + + return new KeyBundle(clientKeyBundle, this.vaultUriHelper); + } + + public KeyBundle SetKey(string vaultName, string keyName, KeyAttributes keyAttributes) + { + if (string.IsNullOrEmpty(vaultName)) + { + throw new ArgumentNullException("vaultName"); + } + if (string.IsNullOrEmpty(keyName)) + { + throw new ArgumentNullException("keyName"); + } + if (keyAttributes == null) + { + throw new ArgumentNullException("keyAttributes"); + } + + string keyId = this.vaultUriHelper.CreateKeyAddress(vaultName, keyName); + Client.KeyAttributes clientAttributes = (Client.KeyAttributes)keyAttributes; + + var clientKeyBundle = this.keyVaultClient.UpdateKeyAsync(keyId, clientAttributes).GetAwaiter().GetResult(); + + return new KeyBundle(clientKeyBundle, this.vaultUriHelper); + } + public KeyBundle GetKey(string vaultName, string keyName) + { + if (string.IsNullOrEmpty(vaultName)) + { + throw new ArgumentNullException("vaultName"); + } + if (string.IsNullOrEmpty(keyName)) + { + throw new ArgumentNullException("keyName"); + } + + string keyId = this.vaultUriHelper.CreateKeyAddress(vaultName, keyName); + + Client.KeyBundle clientKeyBundle = this.keyVaultClient.GetKeyAsync(keyId).GetAwaiter().GetResult(); + + return new KeyBundle(clientKeyBundle, this.vaultUriHelper); + } + + public IEnumerable GetKeys(string vaultName) + { + if (string.IsNullOrEmpty(vaultName)) + { + throw new ArgumentNullException("vaultName"); + } + + string vaultAddress = this.vaultUriHelper.CreateVaultAddress(vaultName); + + return (this.keyVaultClient.GetKeysAsync(vaultAddress).GetAwaiter().GetResult()). + Select( (bundle) => {return new KeyBundle(bundle, this.vaultUriHelper);} ); + } + + public KeyBundle DeleteKey(string vaultName, string keyName) + { + if (string.IsNullOrEmpty(vaultName)) + { + throw new ArgumentNullException("vaultName"); + } + if (string.IsNullOrEmpty(keyName)) + { + throw new ArgumentNullException("keyName"); + } + + string keyId = this.vaultUriHelper.CreateKeyAddress(vaultName, keyName); + + Client.KeyBundle clientKeyBundle = this.keyVaultClient.DeleteKeyAsync(keyId).GetAwaiter().GetResult(); + + return new KeyBundle(clientKeyBundle, this.vaultUriHelper); + } + + public Secret SetSecret(string vaultName, string secretName, SecureString secretValue) + { + if (string.IsNullOrEmpty(vaultName)) + { + throw new ArgumentNullException("vaultName"); + } + if (string.IsNullOrEmpty(secretName)) + { + throw new ArgumentNullException("secretName"); + } + if (secretValue == null) + { + throw new ArgumentNullException("secretValue"); + } + + string vaultAddress = this.vaultUriHelper.CreateVaultAddress(vaultName); + string plainSecretValue = secretValue.ToStringExt(); + + Client.Secret clientSecret = this.keyVaultClient.SetSecretAsync(vaultAddress, secretName, plainSecretValue).GetAwaiter().GetResult(); + + return new Secret(clientSecret, this.vaultUriHelper); + } + + public Secret GetSecret(string vaultName, string secretName) + { + if (string.IsNullOrEmpty(vaultName)) + { + throw new ArgumentNullException("vaultName"); + } + if (string.IsNullOrEmpty(secretName)) + { + throw new ArgumentNullException("secretName"); + } + + string secretAddress = this.vaultUriHelper.CreateSecretAddress(vaultName, secretName); + + Client.Secret clientSecret = this.keyVaultClient.GetSecretAsync(secretAddress).GetAwaiter().GetResult(); + + return new Secret(clientSecret, this.vaultUriHelper); + } + + public IEnumerable GetSecrets(string vaultName) + { + if (string.IsNullOrEmpty(vaultName)) + { + throw new ArgumentNullException("vaultName"); + } + + string vaultAddress = this.vaultUriHelper.CreateVaultAddress(vaultName); + + return (this.keyVaultClient.GetSecretsAsync(vaultAddress).GetAwaiter().GetResult()). + Select((clientSecret) => { return new Secret(clientSecret, this.vaultUriHelper); }); + } + + public Secret DeleteSecret(string vaultName, string secretName) + { + if (string.IsNullOrEmpty(vaultName)) + { + throw new ArgumentNullException("vaultName"); + } + if (string.IsNullOrEmpty(secretName)) + { + throw new ArgumentNullException("secretName"); + } + + string secretAddress = this.vaultUriHelper.CreateSecretAddress(vaultName, secretName); + + Client.Secret clientSecret = this.keyVaultClient.DeleteSecretAsync(secretAddress).GetAwaiter().GetResult(); + + return new Secret(clientSecret, this.vaultUriHelper); + } + + private void SendRequestCallback(string correlationId, HttpRequestMessage request) + { + if (CloudContext.Configuration.Tracing.IsEnabled) + { + Tracing.SendRequest(correlationId, request); + } + } + + private void ReceiveResponseCallback(string correlationId, HttpResponseMessage response) + { + if (CloudContext.Configuration.Tracing.IsEnabled) + { + Tracing.ReceiveResponse(correlationId, response); + } + } + + private VaultUriHelper vaultUriHelper; + private Client.KeyVaultClient keyVaultClient; + } +} diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/Models/KeyVaultExceptionHandler.cs b/src/ResourceManager/KeyVault/Commands.KeyVault/Models/KeyVaultExceptionHandler.cs new file mode 100644 index 000000000000..ecfa8db30bb4 --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/Models/KeyVaultExceptionHandler.cs @@ -0,0 +1,46 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using System; +using System.Management.Automation; + +namespace Microsoft.Azure.Commands.KeyVault.Models +{ + internal static class KeyVaultExceptionHandler + { + /// + /// TODO: refine exception + /// + /// exception to be processed + /// + public static ErrorRecord RetrieveExceptionDetails(Exception exception) + { + if (exception == null) + { + throw new ArgumentNullException("exception"); + } + ErrorRecord errorRecord = null; + + Exception innerException = exception.InnerException; + while (innerException != null) + { + exception = innerException; + innerException = innerException.InnerException; + } + + errorRecord = new ErrorRecord(exception, string.Empty, ErrorCategory.NotSpecified, null); + return errorRecord; + } + } +} diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/Models/PfxWebKeyConverter.cs b/src/ResourceManager/KeyVault/Commands.KeyVault/Models/PfxWebKeyConverter.cs new file mode 100644 index 000000000000..ace802873326 --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/Models/PfxWebKeyConverter.cs @@ -0,0 +1,82 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using System; +using System.Security; +using System.IO; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; +using Microsoft.Azure.Commands.KeyVault.Properties; +using Microsoft.KeyVault.WebKey; + +namespace Microsoft.Azure.Commands.KeyVault.Models +{ + internal class PfxWebKeyConverter : IWebKeyConverter + { + public PfxWebKeyConverter(IWebKeyConverter next = null) + { + this.next = next; + } + + public JsonWebKey ConvertKeyFromFile(FileInfo fileInfo, SecureString password) + { + if (CanProcess(fileInfo, password)) + { + return Convert(fileInfo.FullName, password); + } + else if (next != null) + { + return next.ConvertKeyFromFile(fileInfo, password); + } + else + { + throw new ArgumentException(string.Format(Resources.UnsupportedFileFormat, fileInfo.Name)); + } + } + + private bool CanProcess(FileInfo fileInfo, SecureString password) + { + if (fileInfo == null || + string.IsNullOrEmpty(fileInfo.Extension) || + password == null) + { + return false; + } + + return PfxFileExtension.Equals(fileInfo.Extension, StringComparison.OrdinalIgnoreCase); + } + + private JsonWebKey Convert(string pfxFileName, SecureString pfxPassword) + { + var certificate = new X509Certificate2(pfxFileName, pfxPassword, X509KeyStorageFlags.Exportable); + + if (!certificate.HasPrivateKey) + { + throw new ArgumentException(string.Format(Resources.InvalidKeyBlob, "pfx")); + } + + var key = certificate.PrivateKey as RSA; + + if (key == null) + { + throw new ArgumentException(string.Format(Resources.InvalidKeyBlob, "pfx")); + } + + return new JsonWebKey(key, true); + } + + private IWebKeyConverter next; + private const string PfxFileExtension = ".pfx"; + } +} diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/Models/Secret.cs b/src/ResourceManager/KeyVault/Commands.KeyVault/Models/Secret.cs new file mode 100644 index 000000000000..48cb43c93747 --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/Models/Secret.cs @@ -0,0 +1,79 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using System; +using System.Security; +using Client = Microsoft.KeyVault.Client; + +namespace Microsoft.Azure.Commands.KeyVault.Models +{ + public class Secret + { + public Secret() + { } + + /// + /// Internal constructor used by KeyVaultDataServiceClient + /// + /// secret returned from service + /// helper class + internal Secret(Client.Secret clientSecret, VaultUriHelper vaultUriHelper) + { + if (clientSecret == null) + { + throw new ArgumentNullException("clientSecret"); + } + if (vaultUriHelper == null) + { + throw new ArgumentNullException("vaultUriHelper"); + } + + VaultName = vaultUriHelper.GetVaultName(clientSecret.Id); + SecretName = vaultUriHelper.GetSecretName(clientSecret.Id); + SecretValue = clientSecret.Value.ToSecureString(); + SecretValueText = clientSecret.Value; + // TODO: trace vaultUriHelper.KeyVaultDnsSuffix; + + } + + public string VaultName { get; set; } + + public string SecretName { get; set; } + + public SecureString SecretValue + { + get + { + return secretValue; + } + set + { + secretValue = value; + if (secretValue != null) + { + SecretValueText = secretValue.ToStringExt(); + } + else + { + SecretValueText = null; + } + } + } + private SecureString secretValue; + + public string SecretValueText { get; private set; } + + + } +} diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/Models/SecureStringExtension.cs b/src/ResourceManager/KeyVault/Commands.KeyVault/Models/SecureStringExtension.cs new file mode 100644 index 000000000000..ad21ecfd62be --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/Models/SecureStringExtension.cs @@ -0,0 +1,89 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +namespace Microsoft.Azure.Commands.KeyVault.Models +{ + using System; + using System.Runtime.InteropServices; + using System.Security; + + /// + /// Extends SecureString and string to convert from one to the other + /// + public static class SecureStringExtension + { + + /// + /// Converts a string into a secure string. + /// + /// the string to be converted. + public static SecureString ToSecureString( this string str ) + { + if ( str == null ) + { + throw new ArgumentNullException( "str" ); + } + + SecureString secureString = null; + + try + { + secureString = new SecureString(); + + foreach ( char ch in str ) + { + secureString.AppendChar( ch ); + } + + return secureString; + } + catch ( Exception ) + { + if ( secureString != null ) + { + secureString.Dispose(); + } + + throw; + } + } + + /// + /// Converts the secure string to a string. + /// + /// the secure string to be converted. + public static string ToStringExt( this SecureString secureString ) + { + string str = null; + IntPtr stringPointer = IntPtr.Zero; + + if ( secureString == null ) + { + throw new ArgumentNullException( "secureString" ); + } + + try + { + stringPointer = Marshal.SecureStringToBSTR(secureString); + str = Marshal.PtrToStringBSTR(stringPointer); + } + finally + { + Marshal.ZeroFreeBSTR(stringPointer); + } + + return str; + } + } +} diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/Models/VaultUriHelper.cs b/src/ResourceManager/KeyVault/Commands.KeyVault/Models/VaultUriHelper.cs new file mode 100644 index 000000000000..cae6da443187 --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/Models/VaultUriHelper.cs @@ -0,0 +1,153 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Text; +using System.Linq; +using Microsoft.WindowsAzure.Commands.Common.Models; +using Microsoft.Azure.Commands.KeyVault.Properties; + +namespace Microsoft.Azure.Commands.KeyVault.Models +{ + internal class VaultUriHelper + { + public VaultUriHelper(string keyVaultDnsSuffix) + { + if (string.IsNullOrEmpty(keyVaultDnsSuffix)) + { + throw new ArgumentNullException("keyVaultDnsSuffix"); + } + this.KeyVaultDnsSuffix = keyVaultDnsSuffix; + } + + public string GetVaultName(string vaultAddress) + { + Uri vaultUri = CreateAndValidateVaultUri(vaultAddress); + return vaultUri.Host.Split('.').First(); + } + + public string GetKeyName(string keyAddress) + { + Uri vaultUri = CreateAndValidateVaultUri(keyAddress); + + var keyName = GetValueUnderPath(vaultUri, KeyPathName); + if (string.IsNullOrEmpty(keyName)) + { + throw new ArgumentException(string.Format(Resources.InvalidKeyUri, keyAddress)); + } + + return keyName; + } + + public string GetSecretName(string secretAddress) + { + Uri vaultUri = CreateAndValidateVaultUri(secretAddress); + + var secretName = GetValueUnderPath(vaultUri, SecretPathName); + if (string.IsNullOrEmpty(secretName)) + { + throw new ArgumentException(string.Format(Resources.InvalidSecretUri, secretAddress)); + } + + return secretName; + } + + public String CreateVaultAddress(string vaultName) + { + return CreateVaultUri(vaultName).ToString(); + } + + public string CreateKeyAddress(string vaultName, string keyName) + { + if (string.IsNullOrEmpty(vaultName)) + { + throw new ArgumentNullException("vaultName"); + } + if (string.IsNullOrEmpty(keyName)) + { + throw new ArgumentNullException("keyName"); + } + + return new Uri(CreateVaultUri(vaultName), + string.Format("/{0}/{1}/", KeyPathName, keyName)).ToString(); + } + + public string CreateSecretAddress(string vaultName, string secretName) + { + if (string.IsNullOrEmpty(vaultName)) + { + throw new ArgumentNullException("vaultName"); + } + if (string.IsNullOrEmpty(secretName)) + { + throw new ArgumentNullException("secretName"); + } + + return new Uri(CreateVaultUri(vaultName), + string.Format("/{0}/{1}/", SecretPathName, secretName)).ToString(); + } + + public string KeyVaultDnsSuffix { get; private set; } + private Uri CreateAndValidateVaultUri(string vaultAddress) + { + if (string.IsNullOrEmpty(vaultAddress)) + { + throw new ArgumentNullException("vaultAddress"); + } + + Uri vaultUri; + if (!Uri.TryCreate(vaultAddress, UriKind.Absolute, out vaultUri)) + { + throw new ArgumentException(string.Format(Resources.InvalidVaultUri, vaultAddress, this.KeyVaultDnsSuffix)); + } + + if (vaultUri.HostNameType != UriHostNameType.Dns || + !vaultUri.Host.EndsWith(this.KeyVaultDnsSuffix)) + { + throw new ArgumentException(string.Format(Resources.InvalidVaultUri, vaultAddress, this.KeyVaultDnsSuffix)); + } + + return vaultUri; + } + + private string GetValueUnderPath(Uri vaultUri, string pathName) + { + if (vaultUri.Segments == null || + vaultUri.Segments.Length < 3 || + !string.Equals(vaultUri.Segments[1].TrimEnd('/'), pathName, StringComparison.OrdinalIgnoreCase)) + { + return string.Empty; + } + + return vaultUri.Segments[2].TrimEnd('/'); + } + + private Uri CreateVaultUri(string vaultName) + { + if (string.IsNullOrEmpty(vaultName)) + { + throw new ArgumentNullException("vaultName"); + } + + UriBuilder builder = new UriBuilder("https", vaultName + "." + this.KeyVaultDnsSuffix); + + return builder.Uri; + } + + + private const string KeyPathName = "keys"; + private const string SecretPathName = "secrets"; + } +} diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/Models/WebKeyConverterFactory.cs b/src/ResourceManager/KeyVault/Commands.KeyVault/Models/WebKeyConverterFactory.cs new file mode 100644 index 000000000000..665cb4ce4f5e --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/Models/WebKeyConverterFactory.cs @@ -0,0 +1,26 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using System; + +namespace Microsoft.Azure.Commands.KeyVault.Models +{ + internal static class WebKeyConverterFactory + { + public static IWebKeyConverter CreateConverterChain() + { + return new PfxWebKeyConverter(new ByokWebKeyConverter()); + } + } +} diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/Properties/AssemblyInfo.cs b/src/ResourceManager/KeyVault/Commands.KeyVault/Properties/AssemblyInfo.cs new file mode 100644 index 000000000000..81babef19f02 --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/Properties/AssemblyInfo.cs @@ -0,0 +1,38 @@ +// ---------------------------------------------------------------------------------- +// +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Microsoft Azure Powershell - Key Vault")] +[assembly: AssemblyCompany(Microsoft.WindowsAzure.Commands.Common.AzurePowerShell.AssemblyCompany)] +[assembly: AssemblyProduct(Microsoft.WindowsAzure.Commands.Common.AzurePowerShell.AssemblyProduct)] +[assembly: AssemblyCopyright(Microsoft.WindowsAzure.Commands.Common.AzurePowerShell.AssemblyCopyright)] + +[assembly: ComVisible(false)] +[assembly: CLSCompliant(false)] + +[assembly: Guid("2994548F-69B9-4DC2-8D19-52CC0C0C85BC")] +[assembly: AssemblyVersion(Microsoft.WindowsAzure.Commands.Common.AzurePowerShell.AssemblyVersion)] +[assembly: AssemblyFileVersion(Microsoft.WindowsAzure.Commands.Common.AzurePowerShell.AssemblyFileVersion)] +#if SIGN +[assembly: InternalsVisibleTo("Microsoft.Azure.Commands.KeyVault.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")] +#else +[assembly: InternalsVisibleTo("Microsoft.Azure.Commands.KeyVault.Test")] +#endif diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/Properties/Resources.Designer.cs b/src/ResourceManager/KeyVault/Commands.KeyVault/Properties/Resources.Designer.cs new file mode 100644 index 000000000000..c3e6e41705ad --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/Properties/Resources.Designer.cs @@ -0,0 +1,243 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.34014 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Microsoft.Azure.Commands.KeyVault.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.Azure.Commands.KeyVault.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Bad Parameter Set Name. + /// + internal static string BadParameterSetName { + get { + return ResourceManager.GetString("BadParameterSetName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid AzureEnvironment.. + /// + internal static string InvalidAzureEnvironment { + get { + return ResourceManager.GetString("InvalidAzureEnvironment", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No current subscription has been designated. Use Select-AzureSubscription -Current <subscriptionName> to set the current subscription.. + /// + internal static string InvalidCurrentSubscription { + get { + return ResourceManager.GetString("InvalidCurrentSubscription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid '{0}' key blob.. + /// + internal static string InvalidKeyBlob { + get { + return ResourceManager.GetString("InvalidKeyBlob", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid KeyBundle.. + /// + internal static string InvalidKeyBundle { + get { + return ResourceManager.GetString("InvalidKeyBundle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Can not create given key material in specified destination.. + /// + internal static string InvalidKeyDestination { + get { + return ResourceManager.GetString("InvalidKeyDestination", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid key name.. + /// + internal static string InvalidKeyName { + get { + return ResourceManager.GetString("InvalidKeyName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid key uri '{0}'.. + /// + internal static string InvalidKeyUri { + get { + return ResourceManager.GetString("InvalidKeyUri", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid secret name.. + /// + internal static string InvalidSecretName { + get { + return ResourceManager.GetString("InvalidSecretName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid secret uri '{0}'.. + /// + internal static string InvalidSecretUri { + get { + return ResourceManager.GetString("InvalidSecretUri", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Your Azure credentials have not been set up or have expired, please run Add-AzureAccount to set up your Azure credentials.. + /// + internal static string InvalidSubscriptionState { + get { + return ResourceManager.GetString("InvalidSubscriptionState", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid vault name.. + /// + internal static string InvalidVaultName { + get { + return ResourceManager.GetString("InvalidVaultName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid vault uri '{0}'. Vault uri must contain valid dns host name with domain suffix '{1}'.. + /// + internal static string InvalidVaultUri { + get { + return ResourceManager.GetString("InvalidVaultUri", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Can not find key file '{0}'.. + /// + internal static string KeyFileNotFound { + get { + return ResourceManager.GetString("KeyFileNotFound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Are you sure you want to remove key '{0}'.. + /// + internal static string RemoveKeyWarning { + get { + return ResourceManager.GetString("RemoveKeyWarning", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Remove key. + /// + internal static string RemoveKeyWhatIfMessage { + get { + return ResourceManager.GetString("RemoveKeyWhatIfMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Are you sure you want to remove secret '{0}'. + /// + internal static string RemoveSecretWarning { + get { + return ResourceManager.GetString("RemoveSecretWarning", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Remove secret. + /// + internal static string RemoveSecretWhatIfMessage { + get { + return ResourceManager.GetString("RemoveSecretWhatIfMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Key vault cmdlet does not support account type '{0}'.. + /// + internal static string UnsupportedAccountType { + get { + return ResourceManager.GetString("UnsupportedAccountType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The file format of '{0}' is not supported.. + /// + internal static string UnsupportedFileFormat { + get { + return ResourceManager.GetString("UnsupportedFileFormat", resourceCulture); + } + } + } +} diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/Properties/Resources.resx b/src/ResourceManager/KeyVault/Commands.KeyVault/Properties/Resources.resx new file mode 100644 index 000000000000..ab09e7a48a5b --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/Properties/Resources.resx @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Bad Parameter Set Name + + + Invalid AzureEnvironment. + + + No current subscription has been designated. Use Select-AzureSubscription -Current <subscriptionName> to set the current subscription. + + + Invalid '{0}' key blob. + + + Invalid KeyBundle. + + + Can not create given key material in specified destination. + + + Invalid key name. + + + Invalid key uri '{0}'. + + + Invalid secret name. + + + Invalid secret uri '{0}'. + + + Your Azure credentials have not been set up or have expired, please run Add-AzureAccount to set up your Azure credentials. + + + Invalid vault name. + + + Invalid vault uri '{0}'. Vault uri must contain valid dns host name with domain suffix '{1}'. + + + Can not find key file '{0}'. + + + Are you sure you want to remove key '{0}'. + + + Remove key + + + Are you sure you want to remove secret '{0}' + + + Remove secret + + + Key vault cmdlet does not support account type '{0}'. + + + The file format of '{0}' is not supported. + + \ No newline at end of file diff --git a/src/ResourceManager/KeyVault/Commands.KeyVault/packages.config b/src/ResourceManager/KeyVault/Commands.KeyVault/packages.config new file mode 100644 index 000000000000..c4ac3b61f194 --- /dev/null +++ b/src/ResourceManager/KeyVault/Commands.KeyVault/packages.config @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/ResourceManager/Resources/Commands.Resources/AzureResourceManager.psd1 b/src/ResourceManager/Resources/Commands.Resources/AzureResourceManager.psd1 index f99a82551636..280af494bd98 100644 --- a/src/ResourceManager/Resources/Commands.Resources/AzureResourceManager.psd1 +++ b/src/ResourceManager/Resources/Commands.Resources/AzureResourceManager.psd1 @@ -63,7 +63,8 @@ FormatsToProcess = @( '.\Resources\Microsoft.WindowsAzure.Commands.Profile.format.ps1xml', '.\DataFactories\Microsoft.Azure.Commands.DataFactories.format.ps1xml', '.\RedisCache\Microsoft.Azure.Commands.RedisCache.format.ps1xml', - '.\Batch\Microsoft.Azure.Commands.Batch.format.ps1xml' + '.\Batch\Microsoft.Azure.Commands.Batch.format.ps1xml', + '.\KeyVault\Microsoft.Azure.Commands.KeyVault.format.ps1xml' ) # Modules to import as nested modules of the module specified in ModuleToProcess @@ -74,7 +75,8 @@ NestedModules = @( '.\Sql\Microsoft.Azure.Commands.Sql.dll', '.\DataFactories\Microsoft.Azure.Commands.DataFactories.dll', '.\RedisCache\Microsoft.Azure.Commands.RedisCache.dll', - '.\Batch\Microsoft.Azure.Commands.Batch.dll' + '.\Batch\Microsoft.Azure.Commands.Batch.dll', + '.\KeyVault\Microsoft.Azure.Commands.KeyVault.dll' ) # Functions to export from this module diff --git a/src/ResourceManager/Resources/Commands.Resources/Commands.Resources.csproj b/src/ResourceManager/Resources/Commands.Resources/Commands.Resources.csproj index eebaf66df062..c0547f5600c0 100644 --- a/src/ResourceManager/Resources/Commands.Resources/Commands.Resources.csproj +++ b/src/ResourceManager/Resources/Commands.Resources/Commands.Resources.csproj @@ -222,6 +222,10 @@ {d470e50a-9607-48d6-a924-4f9f86502704} Commands.Batch + + {9ffc40cc-a341-4d0c-a25d-dc6b78ef6c94} + Commands.KeyVault + {c972e3ef-4461-4758-ba31-93e0947b1253} Commands.RedisCache