From dd9e5ea83eb06e135ac4166c2cf5c0c1b3579b8c Mon Sep 17 00:00:00 2001 From: Pooneh Date: Mon, 24 Nov 2014 16:39:38 -0800 Subject: [PATCH 1/3] Key Vault - moving codes into new repo --- .../Commands.KeyVault.Test.csproj | 164 +++++ .../Commands.KeyVault.Test/MSSharedLibKey.snk | Bin 0 -> 160 bytes .../Models/UtilitiesTests.cs | 72 ++ .../Properties/AssemblyInfo.cs | 50 ++ .../Resource.Designer.cs | 73 ++ .../Commands.KeyVault.Test/Resource.resx | 124 ++++ .../Resources/pshtest.pfx | Bin 0 -> 2623 bytes .../Commands.KeyVault.Test/Scripts/Common.ps1 | 264 +++++++ .../Scripts/PSHCommon/Assert.ps1 | 345 +++++++++ .../Scripts/PSHCommon/Common.ps1 | 363 +++++++++ .../Scripts/RunKeyVaultTests.ps1 | 172 +++++ .../Scripts/RunUITests.ps1 | 95 +++ .../Scripts/VaultKeyTests.ps1 | 693 ++++++++++++++++++ .../Scripts/VaultSecretTests.ps1 | 353 +++++++++ .../Scripts/VaultUITests.ps1 | 181 +++++ .../Scripts/bvtdata/byoktest.byok | Bin 0 -> 5510 bytes .../Scripts/bvtdata/pfxtest.pfx | Bin 0 -> 2623 bytes .../Scripts/proddata/byoktest.byok | Bin 0 -> 5260 bytes .../Scripts/proddata/pfxtest.pfx | Bin 0 -> 2623 bytes .../Commands.KeyVault.Test/Scripts/readme.txt | 5 + .../UnitTests/KeyVaultUnitTestBase.cs | 54 ++ .../UnitTests/RemoveKeyVaultKeyTests.cs | 125 ++++ .../UnitTests/RemoveKeyVaultSecretTests.cs | 129 ++++ .../UnitTests/SetKeyVaultKeyTests.cs | 92 +++ .../UnitTests/SetKeyVaultSecretTests.cs | 76 ++ .../Commands.KeyVault.Test/packages.config | 17 + .../Commands.KeyVault.csproj | 162 ++++ .../Commands/AddAzureKeyVaultKey.cs | 264 +++++++ .../Commands/GetAzureKeyVaultKey.cs | 105 +++ .../Commands/GetAzureKeyVaultSecret.cs | 102 +++ .../Commands/RemoveAzureKeyVaultKey.cs | 95 +++ .../Commands/RemoveAzureKeyVaultSecret.cs | 95 +++ .../Commands/SetAzureKeyVaultKey.cs | 118 +++ .../Commands/SetAzureKeyVaultSecret.cs | 84 +++ .../Commands.KeyVault/MSSharedLibKey.snk | Bin 0 -> 160 bytes ...soft.Azure.Commands.KeyVault.format.ps1xml | 107 +++ .../Models/ByokWebKeyConverter.cs | 79 ++ .../Models/DataServiceCredential.cs | 103 +++ .../Models/IKeyVaultDataServiceClient.cs | 43 ++ .../Models/IWebKeyConverter.cs | 26 + .../Commands.KeyVault/Models/KeyAttributes.cs | 93 +++ .../Commands.KeyVault/Models/KeyBundle.cs | 64 ++ .../Models/KeyCreationAttributes.cs | 30 + .../Models/KeyVaultCmdletBase.cs | 67 ++ .../Models/KeyVaultDataServiceClient.cs | 305 ++++++++ .../Models/KeyVaultExceptionHandler.cs | 46 ++ .../Models/PfxWebKeyConverter.cs | 82 +++ .../Commands.KeyVault/Models/Secret.cs | 79 ++ .../Models/SecureStringExtension.cs | 89 +++ .../Models/VaultUriHelper.cs | 153 ++++ .../Models/WebKeyConverterFactory.cs | 26 + .../Properties/AssemblyInfo.cs | 38 + .../Properties/Resources.Designer.cs | 243 ++++++ .../Properties/Resources.resx | 180 +++++ .../Commands.KeyVault/packages.config | 12 + 55 files changed, 6337 insertions(+) create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault.Test/Commands.KeyVault.Test.csproj create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault.Test/MSSharedLibKey.snk create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault.Test/Models/UtilitiesTests.cs create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault.Test/Properties/AssemblyInfo.cs create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault.Test/Resource.Designer.cs create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault.Test/Resource.resx create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault.Test/Resources/pshtest.pfx create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/Common.ps1 create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/PSHCommon/Assert.ps1 create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/PSHCommon/Common.ps1 create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/RunKeyVaultTests.ps1 create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/RunUITests.ps1 create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/VaultKeyTests.ps1 create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/VaultSecretTests.ps1 create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/VaultUITests.ps1 create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/bvtdata/byoktest.byok create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/bvtdata/pfxtest.pfx create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/proddata/byoktest.byok create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/proddata/pfxtest.pfx create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault.Test/Scripts/readme.txt create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault.Test/UnitTests/KeyVaultUnitTestBase.cs create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault.Test/UnitTests/RemoveKeyVaultKeyTests.cs create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault.Test/UnitTests/RemoveKeyVaultSecretTests.cs create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault.Test/UnitTests/SetKeyVaultKeyTests.cs create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault.Test/UnitTests/SetKeyVaultSecretTests.cs create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault.Test/packages.config create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault/Commands.KeyVault.csproj create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault/Commands/AddAzureKeyVaultKey.cs create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault/Commands/GetAzureKeyVaultKey.cs create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault/Commands/GetAzureKeyVaultSecret.cs create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault/Commands/RemoveAzureKeyVaultKey.cs create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault/Commands/RemoveAzureKeyVaultSecret.cs create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault/Commands/SetAzureKeyVaultKey.cs create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault/Commands/SetAzureKeyVaultSecret.cs create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault/MSSharedLibKey.snk create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault/Microsoft.Azure.Commands.KeyVault.format.ps1xml create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault/Models/ByokWebKeyConverter.cs create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault/Models/DataServiceCredential.cs create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault/Models/IKeyVaultDataServiceClient.cs create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault/Models/IWebKeyConverter.cs create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault/Models/KeyAttributes.cs create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault/Models/KeyBundle.cs create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault/Models/KeyCreationAttributes.cs create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault/Models/KeyVaultCmdletBase.cs create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault/Models/KeyVaultDataServiceClient.cs create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault/Models/KeyVaultExceptionHandler.cs create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault/Models/PfxWebKeyConverter.cs create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault/Models/Secret.cs create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault/Models/SecureStringExtension.cs create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault/Models/VaultUriHelper.cs create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault/Models/WebKeyConverterFactory.cs create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault/Properties/AssemblyInfo.cs create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault/Properties/Resources.Designer.cs create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault/Properties/Resources.resx create mode 100644 src/ResourceManager/KeyVault/Commands.KeyVault/packages.config 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 0000000000000000000000000000000000000000..695f1b38774e839e5b90059bfb7f32df1dff4223 GIT binary patch literal 160 zcmV;R0AK$ABme*efB*oL000060ssI2Bme+XQ$aBR1ONa50098C{E+7Ye`kjtcRG*W zi8#m|)B?I?xgZ^2Sw5D;l4TxtPwG;3)3^j?qDHjEteSTF{rM+4WI`v zCD?tsZ^;k+S&r1&HRMb=j738S=;J$tCKNrc$@P|lZ +// 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 0000000000000000000000000000000000000000..fefc03c0d0a0c116ae41f319781df8d564d814bd GIT binary patch literal 2623 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 +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 0000000000000000000000000000000000000000..a8c9ed1493096072a3538aa4f8be188f3ff25ab2 GIT binary patch literal 5510 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 A2mk;8 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..fefc03c0d0a0c116ae41f319781df8d564d814bd GIT binary patch literal 2623 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 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 0000000000000000000000000000000000000000..695f1b38774e839e5b90059bfb7f32df1dff4223 GIT binary patch literal 160 zcmV;R0AK$ABme*efB*oL000060ssI2Bme+XQ$aBR1ONa50098C{E+7Ye`kjtcRG*W zi8#m|)B?I?xgZ^2Sw5D;l4TxtPwG;3)3^j?qDHjEteSTF{rM+4WI`v zCD?tsZ^;k+S&r1&HRMb=j738S=;J$tCKNrc$@P|lZ + + + + 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 From f073cda518505d62ad3d4d45a980e25a5b35c260 Mon Sep 17 00:00:00 2001 From: Pooneh Date: Tue, 25 Nov 2014 13:05:14 -0800 Subject: [PATCH 2/3] Update key vault change requirements to the build and common --- AzurePowershell.Test.targets | 8 ++ build.proj | 2 +- setup/azurecmdfiles.wxi | 78 +++++++++++++++++++ src/AzurePowershell.sln | 13 ++++ .../MockCertificateAuthenticationFactory.cs | 3 +- .../Mocks/MockTokenAuthenticationFactory.cs | 3 +- .../Common/ManagementConstants.cs | 4 + .../Common/RequiredResourceLookup.cs | 3 +- .../Factories/AuthenticationFactory.cs | 18 +++-- .../Interfaces/IAuthenticationFactory.cs | 5 +- .../Models/AzureEnvironment.Methods.cs | 8 +- .../Constants.cs | 2 + src/ResourceManager.sln | 20 +++++ 13 files changed, 152 insertions(+), 15 deletions(-) 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 From ea4f1040d4f0d3cbd02c007961410efb93db5f43 Mon Sep 17 00:00:00 2001 From: Pooneh Date: Tue, 25 Nov 2014 21:10:28 -0800 Subject: [PATCH 3/3] Adding key vault to resource manager module --- .../Resources/Commands.Resources/AzureResourceManager.psd1 | 6 ++++-- .../Resources/Commands.Resources/Commands.Resources.csproj | 4 ++++ 2 files changed, 8 insertions(+), 2 deletions(-) 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