From 9c0031de340bc47d156c16b85d44e1363b568ef0 Mon Sep 17 00:00:00 2001 From: Manoj Ampalam Date: Wed, 10 May 2017 14:47:03 -0700 Subject: [PATCH] E2E tests for ssh key management PowerShell/Win32-OpenSSH#613 --- regress/pesterTests/KeyUtils.Tests.ps1 | 161 +++++++++++++++++++++++++ regress/pesterTests/Keygen.Tests.ps1 | 62 ---------- regress/pesterTests/SSH.Tests.ps1 | 47 ++++---- 3 files changed, 187 insertions(+), 83 deletions(-) create mode 100644 regress/pesterTests/KeyUtils.Tests.ps1 delete mode 100644 regress/pesterTests/Keygen.Tests.ps1 diff --git a/regress/pesterTests/KeyUtils.Tests.ps1 b/regress/pesterTests/KeyUtils.Tests.ps1 new file mode 100644 index 000000000..086069435 --- /dev/null +++ b/regress/pesterTests/KeyUtils.Tests.ps1 @@ -0,0 +1,161 @@ +$tC = 1 +$tI = 0 +$suite = "keyutils" + +Describe "E2E scenarios for ssh key management" -Tags "CI" { + BeforeAll { + if($OpenSSHTestInfo -eq $null) + { + Throw "`$OpenSSHTestInfo is null. Please run Setup-OpenSSHTestEnvironment to setup test environment." + } + + $testDir = "$($OpenSSHTestInfo["TestDataPath"])\$suite" + if( -not (Test-path $testDir -PathType Container)) + { + $null = New-Item $testDir -ItemType directory -Force -ErrorAction SilentlyContinue + } + $keypassphrase = "testpassword" + $keytypes = @("rsa","dsa","ecdsa","ed25519") + #only validate owner and ACE of the file + function ValidKeyFile { + param($Path) + + $currentUser = New-Object System.Security.Principal.NTAccount($($env:USERDOMAIN), $($env:USERNAME)) + $myACL = Get-ACL $Path + $myACL.Owner.Equals($currentUser.Value) | Should Be $true + $myACL.Access | Should Not Be $null + $myACL.Access.Count | Should Be 1 + + $myACL.Access[0].IdentityReference.Equals($currentUser) | Should Be $true + $myACL.Access[0].AccessControlType | Should Be ([System.Security.AccessControl.AccessControlType]::Allow) + $myACL.Access[0].FileSystemRights | Should Be ([System.Security.AccessControl.FileSystemRights]::FullControl) + $myACL.Access[0].IsInherited | Should Be $false + $myACL.Access[0].InheritanceFlags | Should Be ([System.Security.AccessControl.InheritanceFlags]::None) + $myACL.Access[0].PropagationFlags | Should Be ([System.Security.AccessControl.PropagationFlags]::None) + } + } + + BeforeEach { + $tI++; + } + + Context "$tC - ssh-keygen all key types" { + + BeforeAll {$tI=1} + AfterAll{$tC++} + + It "$tC.$tI - Keygen -A" { + $cd = (pwd).Path + cd $testDir + remove-item ssh_host_*_key* -ErrorAction SilentlyContinue + ssh-keygen -A + + Get-ChildItem ssh_host_*_key | % { + ValidKeyFile -Path $_.FullName + } + + Get-ChildItem ssh_host_*_key.pub | % { + ValidKeyFile -Path $_.FullName + } + cd $cd + } + + It "$tC.$tI - Keygen -t -f" { + foreach($type in $keytypes) + { + $keyPath = Join-Path $testDir "id_$type" + remove-item $keyPath -ErrorAction SilentlyContinue + ssh-keygen -t $type -P $keypassphrase -f $keyPath + ValidKeyFile -Path $keyPath + ValidKeyFile -Path "$keyPath.pub" + } + } + } + + # This uses keys generated in above context + Context "$tC - ssh-add test cases" { + BeforeAll {$tI=1} + AfterAll{$tC++} + + # Executing ssh-agent will start agent service + # This is to support typical Unix scenarios where + # running ssh-agent will setup the agent for current session + It "$tC.$tI - ssh-agent starts agent service and sshd depends on ssh-agent" { + if ((Get-Service ssh-agent).Status -eq "Running") { + Stop-Service ssh-agent -Force + } + + (Get-Service ssh-agent).Status | Should Be "Stopped" + (Get-Service sshd).Status | Should Be "Stopped" + + ssh-agent + + (Get-Service ssh-agent).Status | Should Be "Running" + + Stop-Service ssh-agent -Force + + (Get-Service ssh-agent).Status | Should Be "Stopped" + (Get-Service sshd).Status | Should Be "Stopped" + + # this should automatically start both the services + Start-Service sshd + (Get-Service ssh-agent).Status | Should Be "Running" + (Get-Service sshd).Status | Should Be "Running" + } + + It "$tC.$tI - ssh-add - add and remove all key types" { + #set up SSH_ASKPASS + if (-not($env:DISPLAY)) { $env:DISPLAY = 1 } + $env:SSH_ASKPASS="$($env:ComSpec) /c echo $($keypassphrase)" + + $nullFile = join-path $testDir ("$tC.$tI.nullfile") + $null > $nullFile + + foreach($type in $keytypes) + { + $keyPath = Join-Path $testDir "id_$type" + # for ssh-add to consume SSh_ASKPASS, stdin should not be TTY + iex "cmd /c `"ssh-add $keyPath < $nullFile 2> nul `"" + } + + #remove SSH_ASKPASS + if ($env:DISPLAY -eq 1) { Remove-Item env:\DISPLAY } + remove-item "env:SSH_ASKPASS" -ErrorAction SilentlyContinue + + #ensure added keys are listed + $allkeys = ssh-add -L + + foreach($type in $keytypes) + { + $keyPath = Join-Path $testDir "id_$type" + $pubkeyraw = ((Get-Content "$keyPath.pub").Split(' '))[1] + ($allkeys | foreach {$_.Contains($pubkeyraw)}).Contains($true) | Should Be $true + } + + #delete added keys + foreach($type in $keytypes) + { + $keyPath = Join-Path $testDir "id_$type" + iex "cmd /c `"ssh-add -d $keyPath 2> nul `"" + } + + #check keys are deleted + $allkeys = ssh-add -L + + foreach($type in $keytypes) + { + $keyPath = Join-Path $testDir "id_$type" + $pubkeyraw = ((Get-Content "$keyPath.pub").Split(' '))[1] + if ($allkeys.Count -eq 1) { + $allkeys.Contains($pubkeyraw) | Should Be $false + } + else { + ($allkeys | foreach {$_.Contains($pubkeyraw)}).Contains($true) | Should Be $false + } + + } + + } + + } +} diff --git a/regress/pesterTests/Keygen.Tests.ps1 b/regress/pesterTests/Keygen.Tests.ps1 deleted file mode 100644 index da6bb41a7..000000000 --- a/regress/pesterTests/Keygen.Tests.ps1 +++ /dev/null @@ -1,62 +0,0 @@ -Describe "Tests for ssh-keygen" -Tags "CI" { - BeforeAll { - if($OpenSSHTestInfo -eq $null) - { - Throw "`$OpenSSHTestInfo is null. Please run Setup-OpenSSHTestEnvironment to setup test environment." - } - - $testDir = "$($OpenSSHTestInfo["TestDataPath"])\keygen" - if( -not (Test-path $testDir -PathType Container)) - { - $null = New-Item $testDir -ItemType directory -Force -ErrorAction SilentlyContinue - } - #only validate owner and ACE of the file - function ValidKeyFile { - param($Path) - - $currentUser = New-Object System.Security.Principal.NTAccount($($env:USERDOMAIN), $($env:USERNAME)) - $myACL = Get-ACL $Path - $myACL.Owner.Equals($currentUser.Value) | Should Be $true - $myACL.Access | Should Not Be $null - $myACL.Access.Count | Should Be 1 - - $myACL.Access[0].IdentityReference.Equals($currentUser) | Should Be $true - $myACL.Access[0].AccessControlType | Should Be ([System.Security.AccessControl.AccessControlType]::Allow) - $myACL.Access[0].FileSystemRights | Should Be ([System.Security.AccessControl.FileSystemRights]::FullControl) - $myACL.Access[0].IsInherited | Should Be $false - $myACL.Access[0].InheritanceFlags | Should Be ([System.Security.AccessControl.InheritanceFlags]::None) - $myACL.Access[0].PropagationFlags | Should Be ([System.Security.AccessControl.PropagationFlags]::None) - } - } - - Context "Keygen key files" { - BeforeEach { - Remove-Item $testDir\* -Force -ErrorAction ignore - Remove-Item "$PSScriptRoot\ssh_host_*_key*" -Force -ErrorAction ignore - } - - It 'Keygen -A' { - ssh-keygen -A - - Get-ChildItem "$PSScriptRoot\ssh_host_*_key" | % { - ValidKeyFile -Path $_.FullName - } - - Get-ChildItem "$PSScriptRoot\ssh_host_*_key.pub" | % { - ValidKeyFile -Path $_.FullName - } - } - - It 'Keygen -t -f' { - $pwd = "testpassword" - - foreach($type in @("rsa","dsa","ecdsa","ed25519")) - { - $keyPath = Join-Path $testDir "id_$type" - ssh-keygen -t $type -P $pwd -f $keyPath - ValidKeyFile -Path $keyPath - ValidKeyFile -Path "$keyPath.pub" - } - } - } -} diff --git a/regress/pesterTests/SSH.Tests.ps1 b/regress/pesterTests/SSH.Tests.ps1 index 74223bca5..d6c910d09 100644 --- a/regress/pesterTests/SSH.Tests.ps1 +++ b/regress/pesterTests/SSH.Tests.ps1 @@ -1,6 +1,6 @@ #todo: -i -q -v -l -c -C #todo: -S -F -V -e -$tB = 1 +$tC = 1 $tI = 0 Describe "ssh client tests" -Tags "CI" { @@ -73,60 +73,65 @@ Describe "ssh client tests" -Tags "CI" { BeforeEach { $tI++; - $tFile=Join-Path $testDir "$tB.$tI.txt" + $tFile=Join-Path $testDir "$tC.$tI.txt" } - Context "$tB - Basic Scenarios" { + Context "$tC - Basic Scenarios" { BeforeAll {$tI=1} - AfterAll{$tB++} + AfterAll{$tC++} - <# these 2 tests dont work on AppVeyor that sniffs stderr channel - It "$tB.$tI - test version" { - iex "ssh -V 2> $tFile" + It "$tC.$tI - test version" { + iex "cmd /c `"ssh -V 2> $tFile`"" $tFile | Should Contain "OpenSSH_" } - It "$tB.$tI - test help" { - iex "ssh -? 2> $tFile" + It "$tC.$tI - test help" { + iex "cmd /c `"ssh -? 2> $tFile`"" $tFile | Should Contain "usage: ssh" } - #> - - It "$tB.$tI - remote echo command" { + + It "$tC.$tI - remote echo command" { iex "$sshDefaultCmd echo 1234" | Should Be "1234" } + + It "$tC.$tI - exit code" { + ssh -p $port $ssouser@$server exit 0 + $LASTEXITCODE | Should Be 0 + ssh -p $port $ssouser@$server exit 21 + $LASTEXITCODE | Should Be 21 + } } - Context "$tB - Redirection Scenarios" { + Context "$tC - Redirection Scenarios" { BeforeAll {$tI=1} - AfterAll{$tB++} + AfterAll{$tC++} - It "$tB.$tI - stdout to file" { + It "$tC.$tI - stdout to file" { iex "$sshDefaultCmd powershell get-process > $tFile" $tFile | Should Contain "ProcessName" } - It "$tB.$tI - stdout to PS object" { + It "$tC.$tI - stdout to PS object" { $o = iex "$sshDefaultCmd echo 1234" $o | Should Be "1234" } - <#It "$tB.$tI - stdin from PS object" { + <#It "$tC.$tI - stdin from PS object" { #if input redirection doesn't work, this would hang 0 | ssh -p $port $ssouser@$server pause $true | Should Be $true }#> } - Context "$tB - cmdline parameters" { + Context "$tC - cmdline parameters" { BeforeAll {$tI=1} - AfterAll{$tB++} + AfterAll{$tC++} - It "$tB.$tI - verbose to file" { - $logFile = Join-Path $testDir "$tB.$tI.log.txt" + It "$tC.$tI - verbose to file" { + $logFile = Join-Path $testDir "$tC.$tI.log.txt" $o = ssh -p $port -v -E $logFile $ssouser@$server echo 1234 $o | Should Be "1234" #TODO - checks below are very inefficient (time taking).