Tests/SecretManagementVault.Tests.ps1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#requires -modules @{ModuleName="Pester"; ModuleVersion="5.1.0"}
Describe 'SecretManagement.Keepass' {
    BeforeAll {
        Remove-Module SecretManagement.Keepass,SecretManagement.KeePass.Extension -ErrorAction SilentlyContinue

        #Fetch helper function
        . $PSScriptRoot/../SecretManagement.KeePass.Extension/Private/Unlock-SecureString.ps1

        #Would use TestDrive but the PoshKeePass Module doesn't understand it for purposes of new-keepassdatabase
        $SCRIPT:VaultName = 'SecretManagement.Tests'
        $SCRIPT:VaultExtensionName = 'SecretManagement.KeePass'
        $SCRIPT:VaultPath = Join-Path $TestDrive.FullName 'KeepassTestVault.kdbx'
        $SCRIPT:VaultKey = [PSCredential]::new('vaultkey',(ConvertTo-SecureString -AsPlainText -Force 'ThisIsATestVaultYouShouldNotUseIt'))

        #BUG: For some reason there's an issue with using the nested module exported commands in Pester, this is workaround
        Import-Module "$PSScriptRoot/../SecretManagement.KeePass.psd1" -Force
        & (Get-Module SecretManagement.Keepass) {
            Import-Module "$PSScriptRoot/../PoshKeePass/PoShKeePass.psd1"
            
            #Create three variations of databases: Master Key only, keyfile, and both
            $VaultKeyFilePath = Join-Path $TestDrive.FullName 'KeepassTestKeyFileVault.key'
            $VaultKeyDBPath = $VaultPath -replace 'Vault','KeyVault'
            $VaultKeyPWDBPath = $VaultPath -replace 'Vault','KeyPWVault'
            [KeePassLib.Keys.KcpKeyFile]::Create($VaultKeyFilePath, $null)
            New-KeePassDatabase -DatabasePath $VaultPath -MasterKey $VaultKey
            New-KeePassDatabase -DatabasePath $VaultKeyDBPath -KeyPath $VaultKeyFilePath
            New-KeePassDatabase -DatabasePath $VaultKeyPWDBPath -KeyPath $VaultKeyFilePath -MasterKey $VaultKey

            Remove-Module PoshKeePass
        }

        $SCRIPT:RegisterSecretVaultParams = @{
            Name            = $VaultName
            ModuleName      = (Get-Module $VaultExtensionName).Path
            PassThru        = $true
            VaultParameters = @{
                Path = $VaultPath
            }
        }
        try {
            $SCRIPT:TestVault = Register-SecretVault @RegisterSecretVaultParams
        } catch [InvalidOperationException] {
            if ($PSItem -match 'Provided Name for vault is already being used') {
                Unregister-SecretVault -Name $RegisterSecretVaultParams.Name
                $SCRIPT:TestVault = Register-SecretVault @RegisterSecretVaultParams
            } else {
                $PSCmdlet.ThrowTerminatingError($PSItem)
            }
        }

        Mock -Verifiable Get-Credential {return $VaultKey}
    }

    AfterAll {
        $SCRIPT:TestVault | Unregister-SecretVault
        Get-Item $VaultPath -ErrorAction SilentlyContinue | Remove-Item
    }

    BeforeEach {
        $secretName = "tests/$((New-Guid).Guid)"
    }

    Context 'Unlock' {
        It 'Vault prompts for Master Key' {
            Test-SecretVault -Name $TestVault.Name | Out-Null
            Should -InvokeVerifiable
        }
    }

    Context 'SecretManagement' {
        BeforeAll {
            #Unlock the vault
            Test-SecretVault -Name $TestVault.Name
        }

        It 'Get-SecretVault' {
            Get-SecretVault -Name $TestVault.Name | Should -Not -BeNullOrEmpty
        }
        It 'Test-SecretVault' {
            Test-SecretVault -Name $TestVault.Name | Should -Be $true
        }

        It 'Get/Set/Remove String' {
            $secretText = 'This is my string secret'
            Set-Secret -Name $secretName -Vault $VaultName -Secret $secretText
            $secretInfo = Get-SecretInfo -Name $secretName -Vault $VaultName
            $secretInfo.Name | Should -BeExactly $secretName
            $secretInfo.VaultName | Should -BeExactly $VaultName
            $secret = Get-Secret -Name $secretName -Vault $VaultName
            $secret | Should -Be 'System.Security.SecureString'
            Unlock-SecureString $secret | Should -BeExactly $secretText
            
            Remove-Secret -Name $secretName -Vault $VaultName
            {
                Get-Secret -Name $secretName -Vault $VaultName -ErrorAction Stop 
            } | Should -Throw -ErrorId 'GetSecretNotFound,Microsoft.PowerShell.SecretManagement.GetSecretCommand'
        }

        It 'Get/Set/Remove SecureString' {
            $secretText = 'This is my securestring secret'
            Set-Secret -Name $secretName -Vault $VaultName -Secret ($secretText | ConvertTo-SecureString -AsPlainText -Force)

            $secretInfo = Get-SecretInfo -Name $secretName -Vault $VaultName
            $secretInfo.Name | Should -BeExactly $secretName
            $secretInfo.VaultName | Should -BeExactly $VaultName

            $secret = Get-Secret -Name $secretName -AsPlainText -Vault $VaultName
            $secret | Should -BeExactly $secretText
    
            Remove-Secret -Name $secretName -Vault $VaultName
            { Get-Secret -Name $secretName -Vault $VaultName -ErrorAction Stop } | Should -Throw -ErrorId 'GetSecretNotFound,Microsoft.PowerShell.SecretManagement.GetSecretCommand'
        }

        It 'Get/Set/Remove PSCredential' {
            $secretPassword = 'PesterPassword'
            $secret = [PSCredential]::new('PesterUser',($secretPassword | ConvertTo-SecureString -AsPlainText -Force))
            Set-Secret -Name $secretName -Vault $VaultName -Secret $secret
            $secretInfo = Get-SecretInfo -Name $secretName -Vault $VaultName
            $secretInfo.Name | Should -BeLike $secretName
            $secretInfo.VaultName | Should -BeExactly $VaultName
            $storedSecret = Get-Secret -Name $secretName -Vault $VaultName
            $storedSecret | Should -BeOfType [PSCredential]
            $storedSecret.GetNetworkCredential().Password | Should -BeExactly $secretPassword
            $storedSecret.Username | Should -BeExactly $secret.UserName
            Remove-Secret -Name $secretName -Vault $VaultName
            {
                Get-Secret -Name $secretName -Vault $VaultName -ErrorAction Stop
            } | Should -Throw -ErrorId 'GetSecretNotFound,Microsoft.PowerShell.SecretManagement.GetSecretCommand'
        }

        It 'Register-SecretVault -AllowClobber' {
            $RegisterSecretVaultParams.VaultParameters.Pester = $true
            $RegisterSecretVaultParams.AllowClobber = $true
            $newVault = Register-SecretVault @RegisterSecretVaultParams
            $newVault.VaultParameters.Pester | Should -BeTrue
        }
    }
}