From d92d9639791d95479a21ef605292bc3c17b8efe0 Mon Sep 17 00:00:00 2001 From: Marco Blessing Date: Thu, 4 Apr 2019 17:02:17 +0200 Subject: [PATCH] Publish preview version (#42) * adds certificate store location * add additional certificate store tests * add cert store tests for New-CredentialStoreItem * fix test * add error handling for credential store path * add Import-CSCertificate helper function * Import new certificate if param is given * fix extension filter * add linux error message * fix pester test for linux * update cert helper functions * export helper functions * fix cs cert import * simplify cs cret lookup * remove obsolete functions * fix pester test for linux * fix error type for linux * fix var name * fix pester test * disable travis artifact upload * update cert lookup for item functions * debug build error * use cert instance constructor for linux * disable debug output * remove obsolete exports --- .travis.yml | 7 +- src/Certificate/Get-CSCertificate.ps1 | 81 ++++++++++ src/Certificate/Import-CSCertificate.ps1 | 112 ++++++++++++++ src/Certificate/Test-CSCertificate.ps1 | 86 +++++++++++ src/Item/Get-CredentialStoreItem.ps1 | 19 ++- src/Item/New-CredentialStoreItem.ps1 | 16 +- src/Item/Set-CredentialStoreItem.ps1 | 12 +- src/PSCredentialStore.psd1 | 6 +- src/Store/New-CredentialStore.ps1 | 48 +++++- src/Store/Update-CredentialStore.ps1 | 140 ------------------ .../Item/03_New-CredentialStoreItem.Tests.ps1 | 28 +++- tests/Store/02_New-CredentialStore.Tests.ps1 | 33 ++++- 12 files changed, 422 insertions(+), 166 deletions(-) create mode 100644 src/Certificate/Get-CSCertificate.ps1 create mode 100644 src/Certificate/Import-CSCertificate.ps1 create mode 100644 src/Certificate/Test-CSCertificate.ps1 delete mode 100644 src/Store/Update-CredentialStore.ps1 diff --git a/.travis.yml b/.travis.yml index cf9fb42..2a043d4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,10 +20,9 @@ matrix: fast_finish: true -addons: - artifacts: - #paths: $(ls ./../dist/PowerShellGet.zip | tr "\n" ":") - paths: ./dist/PowerShellGet.zip +#addons: +# artifacts: +# paths: ./dist/PowerShellGet.zip install: diff --git a/src/Certificate/Get-CSCertificate.ps1 b/src/Certificate/Get-CSCertificate.ps1 new file mode 100644 index 0000000..0e2cd6e --- /dev/null +++ b/src/Certificate/Get-CSCertificate.ps1 @@ -0,0 +1,81 @@ +function Get-CSCertificate { + <# + .SYNOPSIS + Returns the certificate object given by thumbprint. + + .DESCRIPTION + You can use this function to get a stored certificate. Search for the object by its unique thumbprint. + + .PARAMETER Thumbprint + Provide one or more thumprints. + + .PARAMETER StoreName + Select the store name in which you want to search the certificates. + + .PARAMETER StoreLocation + Select between the both available locations CurrentUser odr LocalMachine. + + .INPUTS + [string] + + .OUTPUTS + [System.Security.Cryptography.X509Certificates.X509Certificate2[]] + + .EXAMPLE + Get-CSCertificate -Thumbprint '12345678' -StoreName 'My' -StoreLocation 'CurrentUser' + + .NOTES + File Name : Get-CSCertificate.ps1 + Author : Marco Blessing - marco.blessing@googlemail.com + Requires : + + .LINK + https://github.com/OCram85/PSCredentialStore + #> + [CmdletBinding()] + [OutputType([System.Security.Cryptography.X509Certificates.X509Certificate2])] + param( + [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [ValidateNotNullOrEmpty()] + [string[]]$Thumbprint, + + [Parameter(Mandatory = $false)] + [ValidateSet( + 'AddressBook', + 'AuthRoot', + 'CertificateAuthority', + 'Disallowed', + 'My', + 'Root', + 'TrustedPeople', + 'TrustedPublisher' + )] + [string]$StoreName = 'My', + + [Parameter(Mandatory = $false)] + [ValidateSet( + 'CurrentUser', + 'LocalMachine' + )] + [string]$StoreLocation = 'CurrentUser' + ) + + begin { + $Store = [System.Security.Cryptography.X509Certificates.X509Store]::New($StoreName, $StoreLocation) + try { + $Store.Open('ReadOnly') + } + catch { + $_.Exception.Message | Write-Error -ErrorAction Stop + } + } + + process { + foreach ($Thumb in $Thumbprint) { + Write-Output $Store.Certificates | Where-Object { $_.Thumbprint -eq $Thumb } + } + } + end { + $Store.Close() + } +} diff --git a/src/Certificate/Import-CSCertificate.ps1 b/src/Certificate/Import-CSCertificate.ps1 new file mode 100644 index 0000000..6738036 --- /dev/null +++ b/src/Certificate/Import-CSCertificate.ps1 @@ -0,0 +1,112 @@ +function Import-CSCertificate { + <# + .SYNOPSIS + adds a given pfx certificate file to current uerers personal certificate store. + + .DESCRIPTION + This function is used to import existing pfx certificate files. The Import-PFXCertificate cmdle from the + PKI module imports the certficate into a deprecated store. Thus you can't read the private key afterwards or + using it for decrypting data. + + .PARAMETER Path + Path to an existing *.pfx certificate file. + + .PARAMETER StoreName + Additionally you change change the store where you want the certificate into. + + .INPUTS + [None] + + .OUTPUTS + [None] + + .EXAMPLE + Import-CSCertificate -Path (Join-Path -Path $Env:APPDATA -ChildPath '/PSCredentialStore.pfx') + + .NOTES + File Name : Import-CSCertificate.ps1 + Author : Marco Blessing - marco.blessing@googlemail.com + Requires : + + .LINK + https://github.com/OCram85/PSCredentialStore + #> + [CmdletBinding()] + [OutputType()] + param( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [string]$Path, + + [Parameter(Mandatory = $false)] + [ValidateSet( + 'AddressBook', + 'AuthRoot', + 'CertificateAuthority', + 'Disallowed', + 'My', + 'Root', + 'TrustedPeople', + 'TrustedPublisher' + )] + [string]$StoreName = 'My', + + [Parameter(Mandatory = $false)] + [ValidateSet( + 'CurrentUser', + 'LocalMachine' + )] + [string]$StoreLocation = 'CurrentUser', + + [Parameter(Mandatory = $false)] + [ValidateSet( + 'ReadOnly', + 'ReadWrite', + 'MaxAllowed', + 'OpenExistingOnly', + 'InclueArchived' + )] + [string]$OpenFlags = 'ReadWrite' + ) + begin { + $Store = [System.Security.Cryptography.X509Certificates.X509Store]::new($StoreName, $StoreLocation) + try { + $Store.Open($OpenFlags) + } + catch { + $_.Exception.Message | Write-Error -ErrorAction Stop + } + } + process { + try { + $cert = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new( + $Path, + $null, + ( + [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable -bor + [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::PersistKeySet + ) + ) + + if (Test-CSCertificate -Thumbprint $cert.Thumbprint) { + Write-Warning -Message ('The certificate with thumbprint {0} is already present!' -f $cert.Thumbprint) + } + else { + $Store.Add($cert) + } + } + catch { + $_.Exception.Message | Write-Error -ErrorAction Stop + $ErrorParams = @{ + ErrorAction = 'Stop' + Exception = [System.Exception]::new( + 'Could not read or add the pfx certificate!' + ) + } + Write-Error @ErrorParams + } + } + end { + $Store.Close() + } +} diff --git a/src/Certificate/Test-CSCertificate.ps1 b/src/Certificate/Test-CSCertificate.ps1 new file mode 100644 index 0000000..7a6c97f --- /dev/null +++ b/src/Certificate/Test-CSCertificate.ps1 @@ -0,0 +1,86 @@ +function Test-CSCertificate { + <# + .SYNOPSIS + Tests if the given certificate exists in a store. + + .DESCRIPTION + Use this function to ensure if a certificate is already imported into a given store. + + .PARAMETER Thumbprint + Provide one or more thumprints. + + .PARAMETER StoreName + Select the store name in which you want to search the certificates. + + .PARAMETER StoreLocation + Select between the both available locations CurrentUser odr LocalMachine. + + .INPUTS + [None] + + .OUTPUTS + [bool] + + .EXAMPLE + Test-CSCertificate -Thumbprint '12345678' -StoreName 'My' -StoreLocation 'CurrentUser' + + .NOTES + File Name : Test-CSCertificate.ps1 + Author : Marco Blessing - marco.blessing@googlemail.com + Requires : + + .LINK + https://github.com/OCram85/PSCredentialStore + #> + [CmdletBinding()] + [OutputType([bool])] + param( + [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [ValidateNotNullOrEmpty()] + [string]$Thumbprint, + + [Parameter(Mandatory = $false)] + [ValidateSet( + 'AddressBook', + 'AuthRoot', + 'CertificateAuthority', + 'Disallowed', + 'My', + 'Root', + 'TrustedPeople', + 'TrustedPublisher' + )] + [string]$StoreName = 'My', + + [Parameter(Mandatory = $false)] + [ValidateSet( + 'CurrentUser', + 'LocalMachine' + )] + [string]$StoreLocation = 'CurrentUser' + ) + + begin { + $Store = [System.Security.Cryptography.X509Certificates.X509Store]::New($StoreName, $StoreLocation) + try { + $Store.Open('ReadOnly') + } + catch { + $_.Exception.Message | Write-Error -ErrorAction Stop + } + } + + process { + $Cert = $Store.Certificates | Where-Object { $_.Thumbprint -eq $Thumbprint } + + if ($null -eq $Cert) { + return $false + } + else { + return $true + } + } + end { + $Store.Close() + } +} diff --git a/src/Item/Get-CredentialStoreItem.ps1 b/src/Item/Get-CredentialStoreItem.ps1 index dda05b2..f82f581 100644 --- a/src/Item/Get-CredentialStoreItem.ps1 +++ b/src/Item/Get-CredentialStoreItem.ps1 @@ -87,7 +87,24 @@ function Get-CredentialStoreItem { $CSMembers = Get-Member -InputObject $CS # Let's first check if the given remote host exists as object property if (($CSMembers.MemberType -eq "NoteProperty") -and ($CSMembers.Name -contains $CredentialName)) { - $Cert = Get-PfxCertificate -FilePath $CS.PfXCertificate -ErrorAction Stop + try { + if ($null -eq $CS.PfxCertificate) { + $Cert = Get-CSCertificate -Thumbprint $CS.Thumbprint + } + else { + $Cert = Get-PfxCertificate -FilePath $CS.PfxCertificate -ErrorAction Stop + } + } + catch { + $_.Exception.Message | Write-Error + $ErrorParams = @{ + ErrorAction = 'Stop' + Exception = [System.Security.Cryptography.CryptographicException]::new( + 'Could not read the given PFX certificate.' + ) + } + Write-Error @ErrorParams + } $DecryptedKey = $Cert.PrivateKey.Decrypt( [Convert]::FromBase64String($CS.$CredentialName.EncryptedKey), [System.Security.Cryptography.RSAEncryptionPadding]::Pkcs1 diff --git a/src/Item/New-CredentialStoreItem.ps1 b/src/Item/New-CredentialStoreItem.ps1 index 56d23c5..81a3524 100644 --- a/src/Item/New-CredentialStoreItem.ps1 +++ b/src/Item/New-CredentialStoreItem.ps1 @@ -117,7 +117,21 @@ function New-CredentialStoreItem { if ($Credential.UserName) { try { - $Cert = Get-PfxCertificate -FilePath $CSContent.PfxCertificate -ErrorAction Stop + if ($null -eq $CSContent.PfxCertificate) { + $Cert = Get-CSCertificate -Thumbprint $CSContent.Thumbprint + if ($null -eq $Cert) { + $ErrorParams = @{ + ErrorAction = 'Stop' + Exception = [System.Security.Cryptography.X509Certificates.FileNotFoundException]::new( + ('Could not find the linked certificate with thumbprint {0}' -f $CSContent.Thumbprint) + ) + } + Write-Error @ErrorParams + } + } + else { + $Cert = Get-PfxCertificate -FilePath $CSContent.PfxCertificate -ErrorAction Stop + } } catch { $_.Exception.Message | Write-Error diff --git a/src/Item/Set-CredentialStoreItem.ps1 b/src/Item/Set-CredentialStoreItem.ps1 index 9b3418e..313857e 100644 --- a/src/Item/Set-CredentialStoreItem.ps1 +++ b/src/Item/Set-CredentialStoreItem.ps1 @@ -103,14 +103,20 @@ function Set-CredentialStoreItem { if ($Credential.UserName) { try { - $Cert = Get-PfxCertificate -FilePath $CSContent.PfxCertificate -ErrorAction Stop + if ($null -eq $CSContent.PfxCertificate) { + $Cert = Get-CSCertificate -Thumbprint $CSContent.Thumbprint + } + else { + $Cert = Get-PfxCertificate -FilePath $CSContent.PfxCertificate -ErrorAction Stop + } } catch { $_.Exception.Message | Write-Error $ErrorParams = @{ - Message = 'Could not read the given PFX certificate.' ErrorAction = 'Stop' - Exception = [System.Security.Cryptography.CryptographicException]::new() + Exception = [System.Security.Cryptography.CryptographicException]::new( + 'Could not read the given PFX certificate.' + ) } Write-Error @ErrorParams } diff --git a/src/PSCredentialStore.psd1 b/src/PSCredentialStore.psd1 index 6ecd6e6..190a725 100644 --- a/src/PSCredentialStore.psd1 +++ b/src/PSCredentialStore.psd1 @@ -63,8 +63,11 @@ # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. FunctionsToExport = @( # Certificate + 'Get-CSCertificate', + 'Import-CSCertificate', 'New-CRTAttribute', 'New-PfxCertificate', + 'Test-CSCertificate', 'Use-PfxCertificate', # Connection 'Connect-To', @@ -79,8 +82,7 @@ # Store 'Get-CredentialStore', 'New-CredentialStore', - 'Test-CredentialStore', - 'Update-CredentialStore' + 'Test-CredentialStore' ) # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. diff --git a/src/Store/New-CredentialStore.ps1 b/src/Store/New-CredentialStore.ps1 index 9eb773e..b172e28 100644 --- a/src/Store/New-CredentialStore.ps1 +++ b/src/Store/New-CredentialStore.ps1 @@ -59,19 +59,23 @@ function New-CredentialStore { [Parameter(Mandatory = $false, ParameterSetName = "Shared")] [ValidateNotNullOrEmpty()] - [string]$Path, + [System.IO.FileInfo]$Path, [Parameter(Mandatory = $false, ParameterSetName = "Private")] [Parameter(Mandatory = $false, ParameterSetName = "Shared")] - [switch]$Force, + [Switch]$Force, [Parameter(Mandatory = $false, ParameterSetName = "Private")] [Parameter(Mandatory = $false, ParameterSetName = "Shared")] - [switch]$PassThru, + [Switch]$PassThru, [Parameter(Mandatory = $false, ParameterSetName = "Private")] [Parameter(Mandatory = $false, ParameterSetName = "Shared")] - [Switch]$SkipPFXCertCreation + [Switch]$SkipPFXCertCreation, + + [Parameter(Mandatory = $false, ParameterSetName = "Private")] + [Parameter(Mandatory = $false, ParameterSetName = "Shared")] + [Switch]$UseCertStore ) begin { @@ -80,6 +84,28 @@ function New-CredentialStore { # Set latest Credential Store version # Set-Variable -Name "CSVersion" -Value "2.0.0" -Option Constant -Scope + + # test if the path input is a valid file path + if ($PSCmdlet.MyInvocation.BoundParameters.ContainsKey('Path')) { + if ($Path.Attributes -contains 'Directory') { + $ErrorParams = @{ + ErrorAction = 'Stop' + Exception = [System.IO.InvalidDataException]::new( + 'Please provide a full path containing the credential store file name with the .json extension!' + ) + } + Write-Error @ErrorParams + } + elseif ( ($null -eq $Path.Extension) -or ($Path.Extension -ne '.json')) { + $ErrorParams = @{ + ErrorAction = 'Stop' + Exception = [System.IO.InvalidDataException]::new( + 'Your provided path does not conain the required file extension .json !' + ) + } + Write-Error @ErrorParams + } + } } process { @@ -112,8 +138,8 @@ function New-CredentialStore { State = 'PSCredentialStore' City = 'PSCredentialStore' Organization = 'PSCredentialStore' - OrganizationalUnitName = ' ' - CommonName = 'PrivateStore' + OrganizationalUnitName = $PSCmdlet.ParameterSetName + CommonName = 'PSCredentialStore' } $CRTAttribute = New-CRTAttribute @CRTParams @@ -133,6 +159,7 @@ function New-CredentialStore { Confirm = $false } + # test if there is already a cert if ((Test-Path $PfxParams.CertName) -and (! $Force.IsPresent)) { $ErrorParams = @{ Exception = [System.IO.InvalidDataException]::new( @@ -176,8 +203,15 @@ function New-CredentialStore { Type = $null } if (! $SkipPFXCertCreation.IsPresent) { - $ObjProperties.PfXCertificate = $PfxParams.CertName $ObjProperties.Thumbprint = $FreshCert.Thumbprint + + if (!$UseCertStore.IsPresent) { + $ObjProperties.PfxCertificate = $PfxParams.CertName + } + else { + Write-Verbose 'Importing new PFX certificate file...' + Import-CSCertificate -Path $PfxParams.CertName -StoreName My -StoreLocation CurrentUser + } } if ($PSCmdlet.ParameterSetName -eq "Shared") { diff --git a/src/Store/Update-CredentialStore.ps1 b/src/Store/Update-CredentialStore.ps1 deleted file mode 100644 index e85d7e7..0000000 --- a/src/Store/Update-CredentialStore.ps1 +++ /dev/null @@ -1,140 +0,0 @@ -function Update-CredentialStore { - <# - .SYNOPSIS - A brief description of the function or script. - - .DESCRIPTION - Describe the function of the script using a single sentence or more. - - .PARAMETER One - Description of the Parameter (what it does) - - .INPUTS - Describe the script input parameters (if any), otherwise it may also list the word "[None]". - - .OUTPUTS - Describe the script output parameters (if any), otherwise it may also list the word "[None]". - - .EXAMPLE - .\Remove-Some-Script.ps1 -One content - - .NOTES - File Name : Update-CredentialStore.ps1 - Author : Marco Blessing - marco.blessing@googlemail.com - Requires : - - .LINK - https://github.com/OCram85/PSCredentialStore - #> - [CmdletBinding()] - [OutputType()] - param( - [Parameter(Mandatory = $false)] - [ValidateNotNullOrEmpty()] - [Version]$From = '1.2.0', - - [Parameter(Mandatory = $false)] - [ValidateNotNullOrEmpty()] - [Version]$To = '2.0.0', - - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [string]$Path, - - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [string]$PfxCertificate - - ) - begin { - } - process { - if (Test-Path -Path $Path) { - $CSOld = Get-CredentialStore -Shared -Path $Path -ErrorAction Stop - if ($CSOld.Version -ne $From) { - $ErrorParams = @{ - Message = 'Can not migrate CredentialStore from version {0} to {1}' -f $From, $To - ErrorAction = 'Stop' - Exception = [System.Exception]::new() - } - Write-Error @ErrorParams - } - - $CSNew = [PSCustomObject]@{ - PSTypeName = 'PSCredentialStore.Store' - Version = $To - Created = $CurrentDate - PfxCertificate = $null - Thumbprint = $null - Type = $null - } - - if ($PWD -eq (Get-DefaultCredentialStorePath)) { - $CSNew.Type = 'Private' - } - elseif ($PWD -eq (Get-DefaultCredentialStorePath -Shared)) { - $CSNew.Type = 'Shared' - } - else { - $ErrorParams = @{ - Message = 'Can not determine a valid CredentialStore Type!' - ErrorAction = 'Stop' - Exception = [System.Exception]::new() - } - Write-Error @ErrorParams - } - $Cert = Get-PfxCertificate -FilePath $PfxCertificate -ErrorAction Stop - - $CSNew.PfxCertificate = Join-Path -Path $PfxCertificate - $CSNew.Thumbprint = $Cert.Thumbprint - - - $CredentialItems = $CSOld | Get-Member -MemberType NoteProperty | Where-Object { - $_.Definition -like "*.PSCustomObject*" - } | Select-Object -ExpandProperty Name - - # iterate through all existing items - foreach ($Item in $CredentialItems) { - - $CurrentDate = Get-Date -UFormat "%Y-%m-%d %H:%M:%S" - $RSAKey = Get-RandomAESKey - - $CredentialObj = [PSCustomObject]@{ - User = $Item.UserName - Password = $null - Created = $CurrentDate - LastChange = $null - EncryptedKey = [Convert]::ToBase64String( - $Cert.PublicKey.Key.Encrypt( - $RSAKey, - [System.Security.Cryptography.RSAEncryptionPadding]::Pkcs1 - ) - ) - } - if ($CSOld.Type -eq 'Private') { - $CredentialObject.Password = ConvertTo-SecureString -SecureString $Item.Password | ConvertFrom-SecureString -Key $RSAKey - } - elseif ($CSNew.Type -eq 'Shared') { - $ChallengeKey = [io.file]::ReadAllBytes((Join-Path -Path $PWD -ChildPath '/Challenge.bin')) - $CredentialObject.Password = ConvertTo-SecureString -SecureString $Item.Password -Key $ChallengeKey | ConvertFrom-SecureString -Key $RSAKey - } - Add-Member -InputObject $CSNew -Name ( - ($Item | Get-Variable).Name - ) -MemberType NoteProperty -Value $CredentialObj - } - $CSNew | ConvertTo-Json -Depth 5 | Out-File -LiteralPath ( - Join-Path -Path $PWD -ChildPath './CredentialStore.json' - ) -Encoding utf8 -Confirm:$true - } - else { - $ErrorParams = @{ - Message = 'Could not find the given CredentialStore path!' - ErrorAction = 'Stop' - Exception = [System.IO.FileNotFoundException]::new() - } - Write-Error @ErrorParams - } - } - end { - } -} diff --git a/tests/Item/03_New-CredentialStoreItem.Tests.ps1 b/tests/Item/03_New-CredentialStoreItem.Tests.ps1 index 8c1dad6..56ce83b 100644 --- a/tests/Item/03_New-CredentialStoreItem.Tests.ps1 +++ b/tests/Item/03_New-CredentialStoreItem.Tests.ps1 @@ -4,7 +4,7 @@ Describe "New-CredentialStoreItem" { # Creat a fresh CredentialStore first New-CredentialStore -Force - [String]$tmp = (65..90) + (97..122) | Get-Random -Count 5 | % {[char]$_} + [String]$tmp = (65..90) + (97..122) | Get-Random -Count 5 | ForEach-Object { [char]$_ } $tmp = $tmp.Replace(' ', '') $tmpUser = "MyUser" $tmpPwd = "fooobarysdfsfs" | ConvertTo-SecureString -AsPlainText -Force @@ -65,7 +65,7 @@ Describe "New-CredentialStoreItem" { } Context "General Exception handling" { - Mock Test-CredentialStore {return $false} + Mock Test-CredentialStore { return $false } It "Missing CredentialStore should throw" { { New-CredentialStoreItem -Shared -Path 'C:\missingStore.json' -RemoteHost 'notrelevant' } | Should -Throw "Could not add anything" } @@ -81,5 +81,29 @@ Describe "New-CredentialStoreItem" { (Get-CredentialStoreItem -RemoteHost 'PipeHost').UserName | Should -Be 'pipeUser' } } + Context "Testing items with certficiate store" { + It "Create item in new store with cert store link" { + New-CredentialStore -UseCertStore -Force + + $Path = Get-DefaultCredentialStorePath + $StoreHome = Split-Path -Path $Path -Parent + $CertFile = Join-Path -Path $StoreHome -ChildPath 'PSCredentialStore.pfx' + $Cert = Get-PfxCertificate -FilePath $CertFile + + $myStore = [System.Security.Cryptography.X509Certificates.X509Store]::new('My') + $myStore.Open("ReadWrite") + $myStore.Add($Cert) + $MyStore.Close() + + $UserName = 'testuser' + $Password = ConvertTo-SecureString -String "mypasswd" -AsPlainText -Force + + [PSCredential]::new($UserName, $Password) | New-CredentialStoreItem -RemoteHost 'foobarcerts' + + $writtenItem = Get-CredentialStoreItem -RemoteHost 'foobarcerts' + $writtenItem.UserName | Should -Be "testuser" + $writtenItem.GetNetworkCredential().Password | Should -Be 'mypasswd' + } + } } diff --git a/tests/Store/02_New-CredentialStore.Tests.ps1 b/tests/Store/02_New-CredentialStore.Tests.ps1 index f822940..028504d 100644 --- a/tests/Store/02_New-CredentialStore.Tests.ps1 +++ b/tests/Store/02_New-CredentialStore.Tests.ps1 @@ -46,7 +46,7 @@ Describe "New-CredentialStore" { Test-Path -Path $sCS | Should -Be $true } It "Test2: Try to override existing shared CS" { - {New-CredentialStore -Shared -Confirm:$false} | Should -Throw + { New-CredentialStore -Shared -Confirm:$false } | Should -Throw } It "Test3: Reset shared CredentialStore" { $now = Get-Date @@ -59,19 +59,40 @@ Describe "New-CredentialStore" { Context "Custom Shared CS tests" { $cCS = Join-Path -Path (Get-TempDir) -ChildPath "CredentialStore.json" It "Test1: Create new custom shared" { - {New-CredentialStore -Path $cCS -Shared -Confirm:$false} | Should -Not -Throw + { New-CredentialStore -Path $cCS -Shared -Confirm:$false } | Should -Not -Throw } It "Test2: Try to override exiting one" { - {New-CredentialStore -Path $cCS -Shared -Confirm:$false} | Should -Throw + { New-CredentialStore -Path $cCS -Shared -Confirm:$false } | Should -Throw } It "Test3: Reset existing custom CredentialStore" { - {New-CredentialStore -Path $cCS -Shared -Force -Confirm:$false} | Should -Not -Throw + { New-CredentialStore -Path $cCS -Shared -Force -Confirm:$false } | Should -Not -Throw } } Context "Test exception handling" { - Mock Out-File {throw "foobar exception"} + Mock Out-File { throw "foobar exception" } It "JSON Conversion should fail and throw" { - { New-CredentialStore -Path (Join-Path -Path (Get-TempDir) -ChildPath '/dummy.json') -Shared -Confirm:$false} | Should -Throw + { New-CredentialStore -Path (Join-Path -Path (Get-TempDir) -ChildPath '/dummy.json') -Shared -Confirm:$false } | Should -Throw + } + } + Context "Tests for Windows certificate store" { + It "Create new private store and skip certificate linking" { + { New-CredentialStore -UseCertStore -Force } | Should -Not -Throw + $CS = Get-CredentialStore + $CS.PfxCertificate | Should -Be $null + $CS.Thumbprint | Should -Not -Be $null + $res = Test-CSCertificate -Thumbprint $CS.Thumbprint -StoreName My -StoreLocation CurrentUser + #Write-Verbose -Message ('res: {0}' -f $res) -Verbose + $res | Should -Be $true + + } + It "Create new shared store and skipt certificate linking" { + { New-CredentialStore -Shared -UseCertStore -Force } | Should -Not -Throw + $CS = Get-CredentialStore -Shared + $CS.PfxCertificate | Should -Be $null + $CS.Thumbprint | Should -Not -Be $null + $res = Test-CSCertificate -Thumbprint $CS.Thumbprint -StoreName My -StoreLocation CurrentUser + #Write-Verbose -Message ('res: {0}' -f $res) -Verbose + $res | Should -Be $true } } }