Add sshd pester tests (#789)

* add sshd tests

* add test for session child processes

* add sleep

* Update regress/pesterTests/SSHD.Tests.ps1

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* update comments in test

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Tess Gauthier 2025-07-21 15:47:19 -04:00 committed by GitHub
parent a2d4e942df
commit c1a8d54998
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 157 additions and 68 deletions

View File

@ -35,13 +35,13 @@ $Script:PostmortemDebugging = $false
<# <#
.Synopsis .Synopsis
Set-OpenSSHTestEnvironment Set-OpenSSHTestEnvironment
TODO - split these steps into client and server side TODO - split these steps into client and server side
#> #>
function Set-OpenSSHTestEnvironment function Set-OpenSSHTestEnvironment
{ {
[CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact="High")] [CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact="High")]
param param
( (
[string] $OpenSSHBinPath, [string] $OpenSSHBinPath,
[string] $TestDataPath = "$env:SystemDrive\OpenSSHTests", [string] $TestDataPath = "$env:SystemDrive\OpenSSHTests",
[Switch] $DebugMode, [Switch] $DebugMode,
@ -54,7 +54,7 @@ function Set-OpenSSHTestEnvironment
$params.Remove("DebugMode") | Out-Null $params.Remove("DebugMode") | Out-Null
$params.Remove("NoAppVerifier") | Out-Null $params.Remove("NoAppVerifier") | Out-Null
$params.Remove("PostmortemDebugging") | Out-Null $params.Remove("PostmortemDebugging") | Out-Null
if($PSBoundParameters.ContainsKey("Verbose")) if($PSBoundParameters.ContainsKey("Verbose"))
{ {
$verboseInfo = ($PSBoundParameters['Verbose']).IsPresent $verboseInfo = ($PSBoundParameters['Verbose']).IsPresent
@ -72,6 +72,7 @@ function Set-OpenSSHTestEnvironment
$Global:OpenSSHTestInfo.Add("TestAccountPW", $OpenSSHTestAccountsPassword) # common password for all test accounts $Global:OpenSSHTestInfo.Add("TestAccountPW", $OpenSSHTestAccountsPassword) # common password for all test accounts
$Global:OpenSSHTestInfo.Add("DebugMode", $DebugMode.IsPresent) # run openssh E2E in debug mode $Global:OpenSSHTestInfo.Add("DebugMode", $DebugMode.IsPresent) # run openssh E2E in debug mode
$Global:OpenSSHTestInfo.Add("DelayTime", 3) # delay between stoppig sshd service and trying to access log files $Global:OpenSSHTestInfo.Add("DelayTime", 3) # delay between stoppig sshd service and trying to access log files
$Global:OpenSSHTestInfo.Add("SshdServiceName", $SSHDTestSvcName) # sshd service name
$Script:EnableAppVerifier = -not ($NoAppVerifier.IsPresent) $Script:EnableAppVerifier = -not ($NoAppVerifier.IsPresent)
if($Script:WindowsInBox = $true) if($Script:WindowsInBox = $true)
@ -83,7 +84,7 @@ function Set-OpenSSHTestEnvironment
if($Script:EnableAppVerifier) if($Script:EnableAppVerifier)
{ {
$Script:PostmortemDebugging = $PostmortemDebugging.IsPresent $Script:PostmortemDebugging = $PostmortemDebugging.IsPresent
} }
$Global:OpenSSHTestInfo.Add("PostmortemDebugging", $Script:PostmortemDebugging) $Global:OpenSSHTestInfo.Add("PostmortemDebugging", $Script:PostmortemDebugging)
$description = @" $description = @"
@ -94,8 +95,8 @@ WARNING: Following changes will be made to OpenSSH configuration
- test accounts - ssouser, pubkeyuser, and passwduser will be added - test accounts - ssouser, pubkeyuser, and passwduser will be added
- Setup single signon for ssouser - Setup single signon for ssouser
- To cleanup - Run Clear-OpenSSHTestEnvironment - To cleanup - Run Clear-OpenSSHTestEnvironment
"@ "@
$prompt = "Are you sure you want to perform the above operations?" $prompt = "Are you sure you want to perform the above operations?"
$caption = $description $caption = $description
if(-not $pscmdlet.ShouldProcess($description, $prompt, $caption)) if(-not $pscmdlet.ShouldProcess($description, $prompt, $caption))
@ -108,7 +109,7 @@ WARNING: Following changes will be made to OpenSSH configuration
##### START: install sshd test service ##### START: install sshd test service
#delete service if exists #delete service if exists
if (Get-Service $SSHDTestSvcName -ErrorAction SilentlyContinue) if (Get-Service $SSHDTestSvcName -ErrorAction SilentlyContinue)
{ {
Stop-Service $SSHDTestSvcName Stop-Service $SSHDTestSvcName
sc.exe delete $SSHDTestSvcName 1>$null sc.exe delete $SSHDTestSvcName 1>$null
@ -119,22 +120,22 @@ WARNING: Following changes will be made to OpenSSH configuration
Remove-Item $testSvcConfigDir -Force -Recurse -ErrorAction SilentlyContinue Remove-Item $testSvcConfigDir -Force -Recurse -ErrorAction SilentlyContinue
New-Item -ItemType Directory -Path $testSvcConfigDir New-Item -ItemType Directory -Path $testSvcConfigDir
$Global:OpenSSHTestInfo["ServiceConfigDir"] = $testSvcConfigDir $Global:OpenSSHTestInfo["ServiceConfigDir"] = $testSvcConfigDir
#copy sshd_config #copy sshd_config
$testSshdConfig = Join-Path $testSvcConfigDir sshd_config $testSshdConfig = Join-Path $testSvcConfigDir sshd_config
Copy-Item (Join-Path $Script:E2ETestDataDirectory sshd_config) $testSshdConfig -Force Copy-Item (Join-Path $Script:E2ETestDataDirectory sshd_config) $testSshdConfig -Force
$con = (Get-Content $testSshdConfig | Out-String).Replace("___TEST_SERVICE_CONFIG_DIR___", $testSvcConfigDir) $con = (Get-Content $testSshdConfig | Out-String).Replace("___TEST_SERVICE_CONFIG_DIR___", $testSvcConfigDir)
Set-Content -Path $testSshdConfig -Value "$con" -Force Set-Content -Path $testSshdConfig -Value "$con" -Force
if($DebugMode) { if($DebugMode) {
$con = (Get-Content $testSshdConfig | Out-String).Replace("#SyslogFacility AUTH","SyslogFacility LOCAL0") $con = (Get-Content $testSshdConfig | Out-String).Replace("#SyslogFacility AUTH","SyslogFacility LOCAL0")
Set-Content -Path $testSshdConfig -Value "$con" -Force Set-Content -Path $testSshdConfig -Value "$con" -Force
} }
#copy sshtest keys #copy sshtest keys
Copy-Item "$($Script:E2ETestDataDirectory)\sshtest*hostkey*" $testSvcConfigDir -Force Copy-Item "$($Script:E2ETestDataDirectory)\sshtest*hostkey*" $testSvcConfigDir -Force
#copy ca pubkey to ssh config path #copy ca pubkey to ssh config path
Copy-Item "$($Script:E2ETestDataDirectory)\sshtest_ca_userkeys.pub" $testSvcConfigDir -Force Copy-Item "$($Script:E2ETestDataDirectory)\sshtest_ca_userkeys.pub" $testSvcConfigDir -Force
$acl = New-Object System.Security.AccessControl.DirectorySecurity $acl = New-Object System.Security.AccessControl.DirectorySecurity
$rule = New-Object System.Security.AccessControl.FileSystemAccessRule("Administrators","FullControl","Allow") $rule = New-Object System.Security.AccessControl.FileSystemAccessRule("Administrators","FullControl","Allow")
@ -156,7 +157,7 @@ WARNING: Following changes will be made to OpenSSH configuration
#copy ca private key to test dir #copy ca private key to test dir
$ca_priv_key = (Join-Path $Global:OpenSSHTestInfo["TestDataPath"] sshtest_ca_userkeys) $ca_priv_key = (Join-Path $Global:OpenSSHTestInfo["TestDataPath"] sshtest_ca_userkeys)
Copy-Item (Join-Path $Script:E2ETestDataDirectory sshtest_ca_userkeys) $ca_priv_key -Force Copy-Item (Join-Path $Script:E2ETestDataDirectory sshtest_ca_userkeys) $ca_priv_key -Force
Repair-UserSshConfigPermission -FilePath $ca_priv_key -confirm:$false Repair-UserSshConfigPermission -FilePath $ca_priv_key -confirm:$false
$Global:OpenSSHTestInfo["CA_Private_Key"] = $ca_priv_key $Global:OpenSSHTestInfo["CA_Private_Key"] = $ca_priv_key
@ -180,16 +181,16 @@ WARNING: Following changes will be made to OpenSSH configuration
} }
$con = Get-Content $knowHostsFilePath $con = Get-Content $knowHostsFilePath
if (($con -eq $null) -or (-not($con.Contains("###OpenSSHE2ETests")))) { if (($con -eq $null) -or (-not($con.Contains("###OpenSSHE2ETests")))) {
Get-Content (Join-Path $Script:E2ETestDataDirectory known_hosts) | Add-Content $knowHostsFilePath Get-Content (Join-Path $Script:E2ETestDataDirectory known_hosts) | Add-Content $knowHostsFilePath
} }
$sshConfigFilePath = Join-Path $dotSshDirectoryPath config $sshConfigFilePath = Join-Path $dotSshDirectoryPath config
if (-not (Test-Path (Join-Path $dotSshDirectoryPath config) -PathType Leaf)) { if (-not (Test-Path (Join-Path $dotSshDirectoryPath config) -PathType Leaf)) {
Copy-Item (Join-Path $Script:E2ETestDataDirectory ssh_config) $sshConfigFilePath -Force Copy-Item (Join-Path $Script:E2ETestDataDirectory ssh_config) $sshConfigFilePath -Force
} }
$con = Get-Content $sshConfigFilePath $con = Get-Content $sshConfigFilePath
if (($con -eq $null) -or (-not($con.Contains("###OpenSSHE2ETests")))) { if (($con -eq $null) -or (-not($con.Contains("###OpenSSHE2ETests")))) {
Get-Content (Join-Path $Script:E2ETestDataDirectory ssh_config) | Add-Content $sshConfigFilePath Get-Content (Join-Path $Script:E2ETestDataDirectory ssh_config) | Add-Content $sshConfigFilePath
} }
Copy-Item (Join-Path $Script:E2ETestDataDirectory ssh_config) $sshConfigFilePath -Force Copy-Item (Join-Path $Script:E2ETestDataDirectory ssh_config) $sshConfigFilePath -Force
@ -206,7 +207,7 @@ WARNING: Following changes will be made to OpenSSH configuration
} }
catch catch
{ {
#only add the local user when it does not exists on the machine #only add the local user when it does not exists on the machine
net user $user $Script:OpenSSHTestAccountsPassword /ADD 2>&1 >> $Script:TestSetupLogFile net user $user $Script:OpenSSHTestAccountsPassword /ADD 2>&1 >> $Script:TestSetupLogFile
} }
} }
@ -231,17 +232,17 @@ WARNING: Following changes will be made to OpenSSH configuration
$authorizedKeyPath = Join-Path $ssouserProfile .ssh\authorized_keys $authorizedKeyPath = Join-Path $ssouserProfile .ssh\authorized_keys
$testPubKeyPath = Join-Path $Script:E2ETestDataDirectory sshtest_userssokey_ed25519.pub $testPubKeyPath = Join-Path $Script:E2ETestDataDirectory sshtest_userssokey_ed25519.pub
Copy-Item $testPubKeyPath $authorizedKeyPath -Force -ErrorAction SilentlyContinue Copy-Item $testPubKeyPath $authorizedKeyPath -Force -ErrorAction SilentlyContinue
Repair-AuthorizedKeyPermission -FilePath $authorizedKeyPath -confirm:$false Repair-AuthorizedKeyPermission -FilePath $authorizedKeyPath -confirm:$false
copy-item (Join-Path $Script:E2ETestDataDirectory sshtest_userssokey_ed25519) $Global:OpenSSHTestInfo["TestDataPath"] copy-item (Join-Path $Script:E2ETestDataDirectory sshtest_userssokey_ed25519) $Global:OpenSSHTestInfo["TestDataPath"]
$testPriKeypath = Join-Path $Global:OpenSSHTestInfo["TestDataPath"] sshtest_userssokey_ed25519 $testPriKeypath = Join-Path $Global:OpenSSHTestInfo["TestDataPath"] sshtest_userssokey_ed25519
cmd /c "ssh-add -D 2>&1 >> $Script:TestSetupLogFile" cmd /c "ssh-add -D 2>&1 >> $Script:TestSetupLogFile"
Repair-UserKeyPermission -FilePath $testPriKeypath -confirm:$false Repair-UserKeyPermission -FilePath $testPriKeypath -confirm:$false
cmd /c "ssh-add $testPriKeypath 2>&1 >> $Script:TestSetupLogFile" cmd /c "ssh-add $testPriKeypath 2>&1 >> $Script:TestSetupLogFile"
#Enable AppVerifier #Enable AppVerifier
if($Script:EnableAppVerifier) if($Script:EnableAppVerifier)
{ {
# clear all applications in application verifier first # clear all applications in application verifier first
& $env:windir\System32\appverif.exe -disable * -for * | out-null & $env:windir\System32\appverif.exe -disable * -for * | out-null
Get-ChildItem "$($script:OpenSSHBinPath)\*.exe" | % { Get-ChildItem "$($script:OpenSSHBinPath)\*.exe" | % {
@ -249,8 +250,8 @@ WARNING: Following changes will be made to OpenSSH configuration
} }
if($Script:PostmortemDebugging -and (Test-path $Script:WindbgPath)) if($Script:PostmortemDebugging -and (Test-path $Script:WindbgPath))
{ {
# enable Postmortem debugger # enable Postmortem debugger
New-ItemProperty "HKLM:Software\Microsoft\Windows NT\CurrentVersion\AeDebug" -Name Debugger -Type String -Value "`"$Script:WindbgPath`" -p %ld -e %ld -g" -Force -ErrorAction SilentlyContinue | Out-Null New-ItemProperty "HKLM:Software\Microsoft\Windows NT\CurrentVersion\AeDebug" -Name Debugger -Type String -Value "`"$Script:WindbgPath`" -p %ld -e %ld -g" -Force -ErrorAction SilentlyContinue | Out-Null
New-ItemProperty "HKLM:Software\Microsoft\Windows NT\CurrentVersion\AeDebug" -Name Auto -Type String -Value "1" -Force -ErrorAction SilentlyContinue | Out-Null New-ItemProperty "HKLM:Software\Microsoft\Windows NT\CurrentVersion\AeDebug" -Name Auto -Type String -Value "1" -Force -ErrorAction SilentlyContinue | Out-Null
} }
@ -261,9 +262,9 @@ function Set-BasicTestInfo
{ {
[CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact="High")] [CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact="High")]
param param
( (
[string] $OpenSSHBinPath, [string] $OpenSSHBinPath,
[string] $TestDataPath = "$env:SystemDrive\OpenSSHTests", [string] $TestDataPath = "$env:SystemDrive\OpenSSHTests",
[Switch] $NoLibreSSL [Switch] $NoLibreSSL
) )
@ -276,7 +277,7 @@ function Set-BasicTestInfo
$Script:E2ETestResultsFile = Join-Path $TestDataPath $E2ETestResultsFileName $Script:E2ETestResultsFile = Join-Path $TestDataPath $E2ETestResultsFileName
$Script:SetupTestResultsFile = Join-Path $TestDataPath $SetupTestResultsFileName $Script:SetupTestResultsFile = Join-Path $TestDataPath $SetupTestResultsFileName
$Script:UninstallTestResultsFile = Join-Path $TestDataPath $UninstallTestResultsFileName $Script:UninstallTestResultsFile = Join-Path $TestDataPath $UninstallTestResultsFileName
$Script:UnitTestResultsFile = Join-Path $TestDataPath $UnitTestResultsFileName $Script:UnitTestResultsFile = Join-Path $TestDataPath $UnitTestResultsFileName
$Script:TestSetupLogFile = Join-Path $TestDataPath $TestSetupLogFileName $Script:TestSetupLogFile = Join-Path $TestDataPath $TestSetupLogFileName
$Script:UnitTestDirectory = Get-UnitTestDirectory $Script:UnitTestDirectory = Get-UnitTestDirectory
$Script:NoLibreSSL = $NoLibreSSL.IsPresent $Script:NoLibreSSL = $NoLibreSSL.IsPresent
@ -296,7 +297,7 @@ function Set-BasicTestInfo
#if user does not set path, pick it up #if user does not set path, pick it up
if([string]::IsNullOrEmpty($OpenSSHBinPath)) if([string]::IsNullOrEmpty($OpenSSHBinPath))
{ {
$sshcmd = get-command ssh.exe -ErrorAction SilentlyContinue $sshcmd = get-command ssh.exe -ErrorAction SilentlyContinue
if($sshcmd -eq $null) if($sshcmd -eq $null)
{ {
Throw "Cannot find ssh.exe. Please specify -OpenSSHBinPath to the OpenSSH installed location." Throw "Cannot find ssh.exe. Please specify -OpenSSHBinPath to the OpenSSH installed location."
@ -305,7 +306,7 @@ function Set-BasicTestInfo
{ {
$dirToCheck = split-path $sshcmd.Path $dirToCheck = split-path $sshcmd.Path
$description = "Pick up ssh.exe from $dirToCheck." $description = "Pick up ssh.exe from $dirToCheck."
$prompt = "Are you sure you want to pick up ssh.exe from $($dirToCheck)?" $prompt = "Are you sure you want to pick up ssh.exe from $($dirToCheck)?"
$caption = "Found ssh.exe from $dirToCheck" $caption = "Found ssh.exe from $dirToCheck"
if(-not $pscmdlet.ShouldProcess($description, $prompt, $caption)) if(-not $pscmdlet.ShouldProcess($description, $prompt, $caption))
{ {
@ -313,7 +314,7 @@ function Set-BasicTestInfo
return return
} }
$script:OpenSSHBinPath = $dirToCheck $script:OpenSSHBinPath = $dirToCheck
} }
} }
else else
{ {
@ -332,7 +333,7 @@ function Set-BasicTestInfo
} }
$acl = get-acl (join-path $script:OpenSSHBinPath "ssh.exe") $acl = get-acl (join-path $script:OpenSSHBinPath "ssh.exe")
if($acl.Owner -ieq "NT SERVICE\TrustedInstaller") if($acl.Owner -ieq "NT SERVICE\TrustedInstaller")
{ {
$Script:WindowsInBox = $true $Script:WindowsInBox = $true
@ -352,7 +353,7 @@ function Get-LocalUserProfile
param([string]$User) param([string]$User)
$sid = Get-UserSID -User $User $sid = Get-UserSID -User $User
$userProfileRegistry = Join-Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList" $sid $userProfileRegistry = Join-Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList" $sid
if (-not (Test-Path $userProfileRegistry) ) { if (-not (Test-Path $userProfileRegistry) ) {
#create profile #create profile
if (-not($env:DISPLAY)) { $env:DISPLAY = 1 } if (-not($env:DISPLAY)) { $env:DISPLAY = 1 }
$askpass_util = Join-Path $Script:E2ETestDirectory "utilities\askpass_util\askpass_util.exe" $askpass_util = Join-Path $Script:E2ETestDirectory "utilities\askpass_util\askpass_util.exe"
@ -364,9 +365,9 @@ function Get-LocalUserProfile
Remove-item "env:SSH_ASKPASS" -ErrorAction SilentlyContinue Remove-item "env:SSH_ASKPASS" -ErrorAction SilentlyContinue
Remove-item "env:ASKPASS_PASSWORD" -ErrorAction SilentlyContinue Remove-item "env:ASKPASS_PASSWORD" -ErrorAction SilentlyContinue
Remove-item "env:SSH_ASKPASS_REQUIRE" -ErrorAction SilentlyContinue Remove-item "env:SSH_ASKPASS_REQUIRE" -ErrorAction SilentlyContinue
} }
(Get-ItemProperty -Path $userProfileRegistry -Name 'ProfileImagePath').ProfileImagePath (Get-ItemProperty -Path $userProfileRegistry -Name 'ProfileImagePath').ProfileImagePath
} }
@ -380,10 +381,10 @@ function Install-OpenSSHTestDependencies
{ {
[CmdletBinding()] [CmdletBinding()]
param ([Switch] $TestHarness) param ([Switch] $TestHarness)
#$isOpenSSHUtilsAvailable = Get-Module 'OpenSSHUtils' -ListAvailable #$isOpenSSHUtilsAvailable = Get-Module 'OpenSSHUtils' -ListAvailable
#if (-not ($isOpenSSHUtilsAvailable)) #if (-not ($isOpenSSHUtilsAvailable))
#{ #{
Write-Log -Message "Installing Module OpenSSHUtils..." Write-Log -Message "Installing Module OpenSSHUtils..."
Install-OpenSSHUtilsModule -SourceDir $PSScriptRoot Install-OpenSSHUtilsModule -SourceDir $PSScriptRoot
#} #}
@ -404,8 +405,8 @@ function Install-OpenSSHTestDependencies
# Pester 5.x is not compatible with tests. # Pester 5.x is not compatible with tests.
$InstalledPesters = Get-Module -Name 'Pester' -ListAvailable | Where-Object { $_.Version -lt '5.0' } $InstalledPesters = Get-Module -Name 'Pester' -ListAvailable | Where-Object { $_.Version -lt '5.0' }
if ($InstalledPesters.Count -eq 0) if ($InstalledPesters.Count -eq 0)
{ {
Write-Log -Message "Installing Pester..." Write-Log -Message "Installing Pester..."
# Install-Module -Name 'Pester' -RequiredVersion 3.4.6 # Install-Module -Name 'Pester' -RequiredVersion 3.4.6
choco install Pester --version 3.4.6 -y --force --limitoutput 2>&1 >> $Script:TestSetupLogFile choco install Pester --version 3.4.6 -y --force --limitoutput 2>&1 >> $Script:TestSetupLogFile
} }
@ -431,8 +432,8 @@ function Install-OpenSSHTestDependencies
if(-not (Test-Path $Script:WindbgPath)) if(-not (Test-Path $Script:WindbgPath))
{ {
choco install windbg -y --force --limitoutput 2>&1 >> $Script:TestSetupLogFile choco install windbg -y --force --limitoutput 2>&1 >> $Script:TestSetupLogFile
} }
} }
} }
if(($Script:EnableAppVerifier -or (($OpenSSHTestInfo -ne $null) -and ($OpenSSHTestInfo["EnableAppVerifier"]))) -and (-not (Test-path $env:windir\System32\appverif.exe))) if(($Script:EnableAppVerifier -or (($OpenSSHTestInfo -ne $null) -and ($OpenSSHTestInfo["EnableAppVerifier"]))) -and (-not (Test-path $env:windir\System32\appverif.exe)))
@ -444,19 +445,19 @@ function Install-OpenSSHTestDependencies
function Install-OpenSSHUtilsModule function Install-OpenSSHUtilsModule
{ {
[CmdletBinding()] [CmdletBinding()]
param( param(
[string]$TargetDir = (Join-Path -Path $env:ProgramFiles -ChildPath "WindowsPowerShell\Modules\OpenSSHUtils"), [string]$TargetDir = (Join-Path -Path $env:ProgramFiles -ChildPath "WindowsPowerShell\Modules\OpenSSHUtils"),
[string]$SourceDir) [string]$SourceDir)
$manifestFile = Join-Path -Path $SourceDir -ChildPath OpenSSHUtils.psd1 $manifestFile = Join-Path -Path $SourceDir -ChildPath OpenSSHUtils.psd1
$moduleFile = Join-Path -Path $SourceDir -ChildPath OpenSSHUtils.psm1 $moduleFile = Join-Path -Path $SourceDir -ChildPath OpenSSHUtils.psm1
$targetDirectory = $TargetDir $targetDirectory = $TargetDir
$manifest = Test-ModuleManifest -Path $manifestFile -WarningAction SilentlyContinue -ErrorAction Stop $manifest = Test-ModuleManifest -Path $manifestFile -WarningAction SilentlyContinue -ErrorAction Stop
if ($PSVersionTable.PSVersion.Major -ge 5) if ($PSVersionTable.PSVersion.Major -ge 5)
{ {
$targetDirectory = Join-Path -Path $targetDir -ChildPath $manifest.Version.ToString() $targetDirectory = Join-Path -Path $targetDir -ChildPath $manifest.Version.ToString()
} }
$modulePath = Join-Path -Path $env:ProgramFiles -ChildPath WindowsPowerShell\Modules $modulePath = Join-Path -Path $env:ProgramFiles -ChildPath WindowsPowerShell\Modules
if(-not (Test-Path "$targetDirectory" -PathType Container)) if(-not (Test-Path "$targetDirectory" -PathType Container))
{ {
@ -464,7 +465,7 @@ function Install-OpenSSHUtilsModule
} }
Copy-item "$manifestFile" -Destination "$targetDirectory" -Force -ErrorAction SilentlyContinue | out-null Copy-item "$manifestFile" -Destination "$targetDirectory" -Force -ErrorAction SilentlyContinue | out-null
Copy-item "$moduleFile" -Destination "$targetDirectory" -Force -ErrorAction SilentlyContinue | out-null Copy-item "$moduleFile" -Destination "$targetDirectory" -Force -ErrorAction SilentlyContinue | out-null
if ($PSVersionTable.PSVersion.Major -lt 4) if ($PSVersionTable.PSVersion.Major -lt 4)
{ {
$modulePaths = [Environment]::GetEnvironmentVariable('PSModulePath', 'Machine') -split ';' $modulePaths = [Environment]::GetEnvironmentVariable('PSModulePath', 'Machine') -split ';'
@ -488,12 +489,12 @@ function Install-OpenSSHUtilsModule
function Uninstall-OpenSSHUtilsModule function Uninstall-OpenSSHUtilsModule
{ {
[CmdletBinding()] [CmdletBinding()]
param([string]$TargetDir = (Join-Path -Path $env:ProgramFiles -ChildPath "WindowsPowerShell\Modules\OpenSSHUtils")) param([string]$TargetDir = (Join-Path -Path $env:ProgramFiles -ChildPath "WindowsPowerShell\Modules\OpenSSHUtils"))
if(Test-Path $TargetDir -PathType Container) if(Test-Path $TargetDir -PathType Container)
{ {
Remove-item $TargetDir -Recurse -Force -ErrorAction SilentlyContinue | out-null Remove-item $TargetDir -Recurse -Force -ErrorAction SilentlyContinue | out-null
} }
} }
<# <#
@ -503,13 +504,13 @@ function Uninstall-OpenSSHUtilsModule
function Get-UserSID function Get-UserSID
{ {
param param
( (
[string]$Domain, [string]$Domain,
[string]$User [string]$User
) )
if([string]::IsNullOrEmpty($Domain)) if([string]::IsNullOrEmpty($Domain))
{ {
$objUser = New-Object System.Security.Principal.NTAccount($User) $objUser = New-Object System.Security.Principal.NTAccount($User)
} }
else else
{ {
@ -533,12 +534,12 @@ function Clear-OpenSSHTestEnvironment
$sshBinPath = $Global:OpenSSHTestInfo["OpenSSHBinPath"] $sshBinPath = $Global:OpenSSHTestInfo["OpenSSHBinPath"]
# .exe - Windows specific. TODO - PAL # .exe - Windows specific. TODO - PAL
if (-not (Test-Path (Join-Path $sshBinPath ssh.exe) -PathType Leaf)) if (-not (Test-Path (Join-Path $sshBinPath ssh.exe) -PathType Leaf))
{ {
Throw "Cannot find OpenSSH binaries under $script:OpenSSHBinPath. " Throw "Cannot find OpenSSH binaries under $script:OpenSSHBinPath. "
} }
if($Global:OpenSSHTestInfo["EnableAppVerifier"] -and (Test-path $env:windir\System32\appverif.exe)) if($Global:OpenSSHTestInfo["EnableAppVerifier"] -and (Test-path $env:windir\System32\appverif.exe))
{ {
# clear all applications in application verifier # clear all applications in application verifier
@ -552,19 +553,19 @@ function Clear-OpenSSHTestEnvironment
} }
#delete service if exists #delete service if exists
if (Get-Service $SSHDTestSvcName -ErrorAction SilentlyContinue) if (Get-Service $SSHDTestSvcName -ErrorAction SilentlyContinue)
{ {
Stop-Service $SSHDTestSvcName Stop-Service $SSHDTestSvcName
sc.exe delete $SSHDTestSvcName 1>$null sc.exe delete $SSHDTestSvcName 1>$null
} }
#Delete accounts #Delete accounts
foreach ($user in $OpenSSHTestAccounts) foreach ($user in $OpenSSHTestAccounts)
{ {
net user $user /delete net user $user /delete
} }
# remove registered keys # remove registered keys
cmd /c "ssh-add -d (Join-Path $Script:E2ETestDataDirectory sshtest_userssokey_ed25519) 2>&1 >> $Script:TestSetupLogFile" cmd /c "ssh-add -d (Join-Path $Script:E2ETestDataDirectory sshtest_userssokey_ed25519) 2>&1 >> $Script:TestSetupLogFile"
if($Global:OpenSSHTestInfo -ne $null) if($Global:OpenSSHTestInfo -ne $null)
@ -572,10 +573,10 @@ function Clear-OpenSSHTestEnvironment
$Global:OpenSSHTestInfo.Clear() $Global:OpenSSHTestInfo.Clear()
$Global:OpenSSHTestInfo = $null $Global:OpenSSHTestInfo = $null
} }
$isOpenSSHUtilsAvailable = Get-Module 'OpenSSHUtils' -ListAvailable $isOpenSSHUtilsAvailable = Get-Module 'OpenSSHUtils' -ListAvailable
if ($isOpenSSHUtilsAvailable) if ($isOpenSSHUtilsAvailable)
{ {
Write-Log -Message "Uninstalling Module OpenSSHUtils..." Write-Log -Message "Uninstalling Module OpenSSHUtils..."
Uninstall-OpenSSHUtilsModule Uninstall-OpenSSHUtilsModule
} }
@ -632,7 +633,7 @@ function Get-UnitTestDirectory
else else
{ {
$RealConfiguration = $Configuration $RealConfiguration = $Configuration
} }
$unitTestdir = Join-Path $repositoryRoot.FullName -ChildPath "bin\$folderName\$RealConfiguration" $unitTestdir = Join-Path $repositoryRoot.FullName -ChildPath "bin\$folderName\$RealConfiguration"
$unitTestDir $unitTestDir
} }
@ -746,7 +747,7 @@ function Invoke-OpenSSHUnitTest
{ {
$Script:UnitTestDirectory = $OpenSSHTestInfo["UnitTestDirectory"] $Script:UnitTestDirectory = $OpenSSHTestInfo["UnitTestDirectory"]
} }
Push-Location $Script:UnitTestDirectory Push-Location $Script:UnitTestDirectory
Write-Log -Message "Running OpenSSH unit tests..." Write-Log -Message "Running OpenSSH unit tests..."
if (Test-Path $Script:UnitTestResultsFile) if (Test-Path $Script:UnitTestResultsFile)
@ -763,7 +764,7 @@ function Invoke-OpenSSHUnitTest
$unittestFile = "$(Split-Path $_ -Leaf).exe" $unittestFile = "$(Split-Path $_ -Leaf).exe"
$unittestFilePath = join-path $_ $unittestFile $unittestFilePath = join-path $_ $unittestFile
if(Test-Path $unittestFilePath -pathtype leaf) if(Test-Path $unittestFilePath -pathtype leaf)
{ {
$pinfo = New-Object System.Diagnostics.ProcessStartInfo $pinfo = New-Object System.Diagnostics.ProcessStartInfo
$pinfo.FileName = "$unittestFilePath" $pinfo.FileName = "$unittestFilePath"
$pinfo.RedirectStandardError = $true $pinfo.RedirectStandardError = $true
@ -790,13 +791,13 @@ function Invoke-OpenSSHUnitTest
{ {
$testfailed = $true $testfailed = $true
$errorMessage = "$unittestFile failed.`nExitCode: $errorCode. Detail test log is at $($Script:UnitTestResultsFile)." $errorMessage = "$unittestFile failed.`nExitCode: $errorCode. Detail test log is at $($Script:UnitTestResultsFile)."
Write-Warning $errorMessage Write-Warning $errorMessage
} }
else else
{ {
Write-Host "$unittestFile passed!" Write-Host "$unittestFile passed!"
} }
} }
} }
} }
Pop-Location Pop-Location
@ -804,7 +805,7 @@ function Invoke-OpenSSHUnitTest
} }
<# <#
Write-Log Write-Log
#> #>
function Write-Log function Write-Log
{ {

View File

@ -243,6 +243,13 @@ Describe "E2E scenarios for ssh client" -Tags "CI" {
$LASTEXITCODE | Should Be 0 $LASTEXITCODE | Should Be 0
$o | Should Be `$env:computername $o | Should Be `$env:computername
} }
It "$tC.$tI - exiting ssh session exits sshd session child processes" -skip:$skip {
$sshdPidCountBefore = (Get-Process -Name sshd* | Select-Object -ExpandProperty Id).Count
ssh test_target "echo '`$env:computername'"
Start-Sleep -Seconds 2
$sshdPidCountAfter = (Get-Process -Name sshd* | Select-Object -ExpandProperty Id).Count
$sshdPidCountAfter | Should Be $sshdPidCountBefore
}
} }
Context "$tC - configure powershell as default shell with admin user" { Context "$tC - configure powershell as default shell with admin user" {
@ -265,7 +272,7 @@ Describe "E2E scenarios for ssh client" -Tags "CI" {
It "$tC.$tI - admin session can write to console" -skip:$skip { It "$tC.$tI - admin session can write to console" -skip:$skip {
$adminusername = $OpenSSHTestInfo['AdminUser'] $adminusername = $OpenSSHTestInfo['AdminUser']
$o = ssh $adminusername@test_target "Get-ComputerInfo" $o = ssh $adminusername@test_target "Get-ComputerInfo"
$LASTEXITCODE | Should Be 0 $LASTEXITCODE | Should Be 0
$o | Select-String -Pattern "WindowsVersion" | Should Match "WindowsVersion" $o | Select-String -Pattern "WindowsVersion" | Should Match "WindowsVersion"
} }
} }

View File

@ -0,0 +1,81 @@
Import-Module $PSScriptRoot\CommonUtils.psm1 -Force
Describe "E2E scenarios for sshd" -Tags "CI" {
BeforeAll {
if($OpenSSHTestInfo -eq $null)
{
Throw "`$OpenSSHTestInfo is null. Please run Set-OpenSSHTestEnvironment to set test environments."
}
$server = $OpenSSHTestInfo["Target"]
$port = $OpenSSHTestInfo["Port"]
$user = $OpenSSHTestInfo["PasswdUser"]
}
Context "SSHD scenarios" {
BeforeAll {
# configure logingracetime to 10 seconds and presrerve the original config
$sshdconfig = Join-Path $Global:OpenSSHTestInfo["ServiceConfigDir"] sshd_config
$sshdconfig_temp = Join-Path $Global:OpenSSHTestInfo["ServiceConfigDir"] sshd_config_temp
if (Test-Path $sshdconfig_temp) {
Remove-Item $sshdconfig_temp -Force
}
Copy-Item $sshdconfig $sshdconfig_temp
$content = Get-Content -Path $sshdconfig
$newContent = $content -replace "#LoginGraceTime 2m", "LoginGraceTime 10"
$newContent | Set-Content -Path $sshdconfig
}
BeforeEach {
Restart-Service -Name $OpenSSHTestInfo["SshdServiceName"] -Force
}
AfterAll {
# restore original config
Copy-Item $sshdconfig_temp $sshdconfig -Force
Restart-Service -Name $OpenSSHTestInfo["SshdServiceName"] -Force
Remove-Item $sshdconfig_temp -Force
}
It "sshd child process ends when LoginGraceTime is exceeded" {
# Get a count of any sshd processes before a connection in case there's another service running on the system
# should be at least 1 sshd process for the test service
$sshdPidCountBefore = (Get-Process -Name sshd* | Select-Object -ExpandProperty Id).Count
# Start ssh process (do not authenticate)
$sshProc = Start-Process -FilePath ssh -ArgumentList "-l $user test_target" -PassThru
Start-Sleep -Seconds 2
$sshdPidsCountWithConn = (Get-Process -Name sshd* | Select-Object -ExpandProperty Id).Count
# Wait for LoginGraceTime to expire
Start-Sleep -Seconds 10
$sshdPidsCountAfter = (Get-Process -Name sshd* | Select-Object -ExpandProperty Id).Count
if ($sshProc -and !$sshProc.HasExited) {
$sshProc | Stop-Process -Force
}
# with a connection, there should be two additional session processes
$sshdPidsCountWithConn | Should Be (2 + $sshdPidCountBefore)
# after LoginGraceTime expires, one of the session processes should exit
$sshdPidsCountAfter | Should Be (1 + $sshdPidCountBefore)
}
It "sshd pre-auth process is spawned under runtime generated virtual account" {
$sshProc = Start-Process -FilePath ssh -ArgumentList "-l $user test_target" -PassThru
Start-Sleep -Seconds 2
$sshdProcessUsers = Get-Process -Name sshd* -IncludeUsername | Select-Object -ExpandProperty UserName
$foundVirtualAccount = $false
foreach ($username in $sshdProcessUsers) {
if ($username -match '^VIRTUAL USERS\\sshd_\d+$') {
$foundVirtualAccount = $true
break
}
}
if ($sshProc -and !$sshProc.HasExited) {
$sshProc | Stop-Process -Force
}
$foundVirtualAccount | Should Be $true
}
}
}