Fix issue install-sshd.ps1 failed on Nano, update it to match inbox manifest, and add setup and uninstall tests (#305)
1. Fix issue install-sshd.ps1 failed on Nano 2. Update settings of services in install-sshd.ps1 to match windows inbox 3. added setup tests and update the test helper scripts to run setup tests before changing configurations on the machine 4. added uninstallation tests
This commit is contained in:
parent
82aa56fe86
commit
ec3eb7a088
|
@ -16,11 +16,6 @@ after_build:
|
|||
Import-Module $env:APPVEYOR_BUILD_FOLDER\contrib\win32\openssh\AppveyorHelper.psm1
|
||||
Install-OpenSSH
|
||||
|
||||
before_test:
|
||||
- ps: |
|
||||
Import-Module $env:APPVEYOR_BUILD_FOLDER\contrib\win32\openssh\AppveyorHelper.psm1
|
||||
Set-OpenSSHTestEnvironment -Confirm:$false
|
||||
|
||||
test_script:
|
||||
- ps: |
|
||||
Import-Module $env:APPVEYOR_BUILD_FOLDER\contrib\win32\openssh\AppveyorHelper.psm1
|
||||
|
|
|
@ -271,8 +271,10 @@ function Publish-Artifact
|
|||
|
||||
if($Global:OpenSSHTestInfo)
|
||||
{
|
||||
Add-Artifact -artifacts $artifacts -FileToAdd $Global:OpenSSHTestInfo["SetupTestResultsFile"]
|
||||
Add-Artifact -artifacts $artifacts -FileToAdd $Global:OpenSSHTestInfo["UnitTestResultsFile"]
|
||||
Add-Artifact -artifacts $artifacts -FileToAdd $Global:OpenSSHTestInfo["E2ETestResultsFile"]
|
||||
Add-Artifact -artifacts $artifacts -FileToAdd $Global:OpenSSHTestInfo["UninstallTestResultsFile"]
|
||||
Add-Artifact -artifacts $artifacts -FileToAdd $Global:OpenSSHTestInfo["TestSetupLogFile"]
|
||||
}
|
||||
|
||||
|
@ -289,6 +291,27 @@ function Publish-Artifact
|
|||
#>
|
||||
function Invoke-OpenSSHTests
|
||||
{
|
||||
Set-BasicTestInfo -Confirm:$false
|
||||
Invoke-OpenSSHSetupTest
|
||||
if (($OpenSSHTestInfo -eq $null) -or (-not (Test-Path $OpenSSHTestInfo["SetupTestResultsFile"])))
|
||||
{
|
||||
Write-Warning "Test result file $OpenSSHTestInfo["SetupTestResultsFile"] not found after tests."
|
||||
Write-BuildMessage -Message "Test result file $OpenSSHTestInfo["SetupTestResultsFile"] not found after tests." -Category Error
|
||||
Set-BuildVariable TestPassed False
|
||||
Write-Warning "Stop running further tests!"
|
||||
return
|
||||
}
|
||||
$xml = [xml](Get-Content $OpenSSHTestInfo["SetupTestResultsFile"] | out-string)
|
||||
if ([int]$xml.'test-results'.failures -gt 0)
|
||||
{
|
||||
$errorMessage = "$($xml.'test-results'.failures) setup tests in regress\pesterTests failed. Detail test log is at $($OpenSSHTestInfo["SetupTestResultsFile"])."
|
||||
Write-Warning $errorMessage
|
||||
Write-BuildMessage -Message $errorMessage -Category Error
|
||||
Set-BuildVariable TestPassed False
|
||||
Write-Warning "Stop running further tests!"
|
||||
return
|
||||
}
|
||||
|
||||
Write-Host "Start running unit tests"
|
||||
$unitTestFailed = Invoke-OpenSSHUnitTest
|
||||
|
||||
|
@ -303,13 +326,17 @@ function Invoke-OpenSSHTests
|
|||
Write-Host "All Unit tests passed!"
|
||||
Write-BuildMessage -Message "All Unit tests passed!" -Category Information
|
||||
}
|
||||
|
||||
# Run all E2E tests.
|
||||
Set-OpenSSHTestEnvironment -Confirm:$false
|
||||
Invoke-OpenSSHE2ETest
|
||||
if (($OpenSSHTestInfo -eq $null) -or (-not (Test-Path $OpenSSHTestInfo["E2ETestResultsFile"])))
|
||||
{
|
||||
Write-Warning "Test result file $OpenSSHTestInfo["E2ETestResultsFile"] not found after tests."
|
||||
Write-BuildMessage -Message "Test result file $OpenSSHTestInfo["E2ETestResultsFile"] not found after tests." -Category Error
|
||||
Set-BuildVariable TestPassed False
|
||||
Write-Warning "Stop running further tests!"
|
||||
return
|
||||
}
|
||||
$xml = [xml](Get-Content $OpenSSHTestInfo["E2ETestResultsFile"] | out-string)
|
||||
if ([int]$xml.'test-results'.failures -gt 0)
|
||||
|
@ -318,6 +345,26 @@ function Invoke-OpenSSHTests
|
|||
Write-Warning $errorMessage
|
||||
Write-BuildMessage -Message $errorMessage -Category Error
|
||||
Set-BuildVariable TestPassed False
|
||||
Write-Warning "Stop running further tests!"
|
||||
return
|
||||
}
|
||||
|
||||
Invoke-OpenSSHUninstallTest
|
||||
if (($OpenSSHTestInfo -eq $null) -or (-not (Test-Path $OpenSSHTestInfo["UninstallTestResultsFile"])))
|
||||
{
|
||||
Write-Warning "Test result file $OpenSSHTestInfo["UninstallTestResultsFile"] not found after tests."
|
||||
Write-BuildMessage -Message "Test result file $OpenSSHTestInfo["UninstallTestResultsFile"] not found after tests." -Category Error
|
||||
Set-BuildVariable TestPassed False
|
||||
}
|
||||
else {
|
||||
$xml = [xml](Get-Content $OpenSSHTestInfo["UninstallTestResultsFile"] | out-string)
|
||||
if ([int]$xml.'test-results'.failures -gt 0)
|
||||
{
|
||||
$errorMessage = "$($xml.'test-results'.failures) uninstall tests in regress\pesterTests failed. Detail test log is at $($OpenSSHTestInfo["UninstallTestResultsFile"])."
|
||||
Write-Warning $errorMessage
|
||||
Write-BuildMessage -Message $errorMessage -Category Error
|
||||
Set-BuildVariable TestPassed False
|
||||
}
|
||||
}
|
||||
|
||||
# Writing out warning when the $Error.Count is non-zero. Tests Should clean $Error after success.
|
||||
|
@ -335,11 +382,25 @@ function Publish-OpenSSHTestResults
|
|||
{
|
||||
if ($env:APPVEYOR_JOB_ID)
|
||||
{
|
||||
$resultFile = Resolve-Path $Global:OpenSSHTestInfo["E2ETestResultsFile"] -ErrorAction Ignore
|
||||
if( (Test-Path $Global:OpenSSHTestInfo["E2ETestResultsFile"]) -and $resultFile)
|
||||
$setupresultFile = Resolve-Path $Global:OpenSSHTestInfo["SetupTestResultsFile"] -ErrorAction Ignore
|
||||
if( (Test-Path $Global:OpenSSHTestInfo["SetupTestResultsFile"]) -and $setupresultFile)
|
||||
{
|
||||
(New-Object 'System.Net.WebClient').UploadFile("https://ci.appveyor.com/api/testresults/nunit/$($env:APPVEYOR_JOB_ID)", $resultFile)
|
||||
Write-BuildMessage -Message "Test results uploaded!" -Category Information
|
||||
(New-Object 'System.Net.WebClient').UploadFile("https://ci.appveyor.com/api/testresults/nunit/$($env:APPVEYOR_JOB_ID)", $setupresultFile)
|
||||
Write-BuildMessage -Message "Setup test results uploaded!" -Category Information
|
||||
}
|
||||
|
||||
$E2EresultFile = Resolve-Path $Global:OpenSSHTestInfo["E2ETestResultsFile"] -ErrorAction Ignore
|
||||
if( (Test-Path $Global:OpenSSHTestInfo["E2ETestResultsFile"]) -and $E2EresultFile)
|
||||
{
|
||||
(New-Object 'System.Net.WebClient').UploadFile("https://ci.appveyor.com/api/testresults/nunit/$($env:APPVEYOR_JOB_ID)", $E2EresultFile)
|
||||
Write-BuildMessage -Message "E2E test results uploaded!" -Category Information
|
||||
}
|
||||
|
||||
$uninstallResultFile = Resolve-Path $Global:OpenSSHTestInfo["UninstallTestResultsFile"] -ErrorAction Ignore
|
||||
if( (Test-Path $Global:OpenSSHTestInfo["UninstallTestResultsFile"]) -and $uninstallResultFile)
|
||||
{
|
||||
(New-Object 'System.Net.WebClient').UploadFile("https://ci.appveyor.com/api/testresults/nunit/$($env:APPVEYOR_JOB_ID)", $uninstallResultFile)
|
||||
Write-BuildMessage -Message "Uninstall test results uploaded!" -Category Information
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@ Import-Module $PSScriptRoot\OpenSSHUtils -Force
|
|||
|
||||
[System.IO.DirectoryInfo] $repositoryRoot = Get-RepositoryRoot
|
||||
# test environment parameters initialized with defaults
|
||||
$SetupTestResultsFileName = "setupTestResults.xml"
|
||||
$UninstallTestResultsFileName = "UninstallTestResults.xml"
|
||||
$E2ETestResultsFileName = "E2ETestResults.xml"
|
||||
$UnitTestResultsFileName = "UnitTestResults.txt"
|
||||
$TestSetupLogFileName = "TestSetupLog.txt"
|
||||
|
@ -16,6 +18,8 @@ $OpenSSHTestAccounts = $Script:SSOUser, $Script:PubKeyUser, $Script:PasswdUser
|
|||
$OpenSSHConfigPath = Join-Path $env:ProgramData "ssh"
|
||||
|
||||
$Script:TestDataPath = "$env:SystemDrive\OpenSSHTests"
|
||||
$Script:SetupTestResultsFile = Join-Path $TestDataPath $SetupTestResultsFileName
|
||||
$Script:UninstallTestResultsFile = Join-Path $TestDataPath $UninstallTestResultsFileName
|
||||
$Script:E2ETestResultsFile = Join-Path $TestDataPath $E2ETestResultsFileName
|
||||
$Script:UnitTestResultsFile = Join-Path $TestDataPath $UnitTestResultsFileName
|
||||
$Script:TestSetupLogFile = Join-Path $TestDataPath $TestSetupLogFileName
|
||||
|
@ -42,100 +46,43 @@ function Set-OpenSSHTestEnvironment
|
|||
[Switch] $PostmortemDebugging,
|
||||
[Switch] $NoLibreSSL
|
||||
)
|
||||
|
||||
$params = $PSBoundParameters
|
||||
$params.Remove("DebugMode") | Out-Null
|
||||
$params.Remove("NoAppVerifier") | Out-Null
|
||||
$params.Remove("PostmortemDebugging") | Out-Null
|
||||
|
||||
if($PSBoundParameters.ContainsKey("Verbose"))
|
||||
{
|
||||
$verboseInfo = ($PSBoundParameters['Verbose']).IsPresent
|
||||
}
|
||||
|
||||
if($Global:OpenSSHTestInfo -ne $null)
|
||||
{
|
||||
$Global:OpenSSHTestInfo.Clear()
|
||||
$Global:OpenSSHTestInfo = $null
|
||||
}
|
||||
$Script:TestDataPath = $TestDataPath;
|
||||
$Script:E2ETestResultsFile = Join-Path $TestDataPath "E2ETestResults.xml"
|
||||
$Script:UnitTestResultsFile = Join-Path $TestDataPath "UnitTestResults.txt"
|
||||
$Script:TestSetupLogFile = Join-Path $TestDataPath "TestSetupLog.txt"
|
||||
$Script:UnitTestDirectory = Get-UnitTestDirectory
|
||||
|
||||
Set-BasicTestInfo @params
|
||||
|
||||
$Global:OpenSSHTestInfo.Add("Target", "localhost") # test listener name
|
||||
$Global:OpenSSHTestInfo.Add("Port", "47002") # test listener port
|
||||
$Global:OpenSSHTestInfo.Add("SSOUser", $SSOUser) # test user with single sign on capability
|
||||
$Global:OpenSSHTestInfo.Add("PubKeyUser", $PubKeyUser) # test user to be used with explicit key for key auth
|
||||
$Global:OpenSSHTestInfo.Add("PasswdUser", $PasswdUser) # test user to be used for password auth
|
||||
$Global:OpenSSHTestInfo.Add("TestAccountPW", $OpenSSHTestAccountsPassword) # common password for all test accounts
|
||||
$Global:OpenSSHTestInfo.Add("DebugMode", $DebugMode.IsPresent) # run openssh E2E in debug mode
|
||||
|
||||
|
||||
$Script:EnableAppVerifier = -not ($NoAppVerifier.IsPresent)
|
||||
$Script:NoLibreSSL = $NoLibreSSL.IsPresent
|
||||
if($Script:WindowsInBox = $true)
|
||||
{
|
||||
$Script:EnableAppVerifier = $false
|
||||
}
|
||||
$Global:OpenSSHTestInfo.Add("EnableAppVerifier", $Script:EnableAppVerifier)
|
||||
|
||||
if($Script:EnableAppVerifier)
|
||||
{
|
||||
$Script:PostmortemDebugging = $PostmortemDebugging.IsPresent
|
||||
}
|
||||
|
||||
$Global:OpenSSHTestInfo = @{
|
||||
"Target"= "localhost"; # test listener name
|
||||
"Port"= "47002"; # test listener port
|
||||
"SSOUser"= $SSOUser; # test user with single sign on capability
|
||||
"PubKeyUser"= $PubKeyUser; # test user to be used with explicit key for key auth
|
||||
"PasswdUser"= $PasswdUser; # common password for all test accounts
|
||||
"TestAccountPW"= $OpenSSHTestAccountsPassword; # common password for all test accounts
|
||||
"TestDataPath" = $TestDataPath; # openssh tests path
|
||||
"TestSetupLogFile" = $Script:TestSetupLogFile; # openssh test setup log file
|
||||
"E2ETestResultsFile" = $Script:E2ETestResultsFile; # openssh E2E test results file
|
||||
"UnitTestResultsFile" = $Script:UnitTestResultsFile; # openssh unittest test results file
|
||||
"E2ETestDirectory" = $Script:E2ETestDirectory # the directory of E2E tests
|
||||
"UnitTestDirectory" = $Script:UnitTestDirectory # the directory of unit tests
|
||||
"DebugMode" = $DebugMode.IsPresent # run openssh E2E in debug mode
|
||||
"EnableAppVerifier" = $Script:EnableAppVerifier
|
||||
"PostmortemDebugging" = $Script:PostmortemDebugging
|
||||
"NoLibreSSL" = $Script:NoLibreSSL
|
||||
}
|
||||
}
|
||||
$Global:OpenSSHTestInfo.Add("PostmortemDebugging", $Script:PostmortemDebugging)
|
||||
|
||||
#start service if not already started
|
||||
Start-Service -Name sshd
|
||||
|
||||
#if user does not set path, pick it up
|
||||
if([string]::IsNullOrEmpty($OpenSSHBinPath))
|
||||
{
|
||||
$sshcmd = get-command ssh.exe -ErrorAction SilentlyContinue
|
||||
if($sshcmd -eq $null)
|
||||
{
|
||||
Throw "Cannot find ssh.exe. Please specify -OpenSSHBinPath to the OpenSSH installed location."
|
||||
}
|
||||
else
|
||||
{
|
||||
$dirToCheck = split-path $sshcmd.Path
|
||||
$description = "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"
|
||||
if(-not $pscmdlet.ShouldProcess($description, $prompt, $caption))
|
||||
{
|
||||
Write-Host "User decided not to pick up ssh.exe from $dirToCheck. Please specify -OpenSSHBinPath to the OpenSSH installed location."
|
||||
return
|
||||
}
|
||||
$script:OpenSSHBinPath = $dirToCheck
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (-not (Test-Path (Join-Path $OpenSSHBinPath ssh.exe) -PathType Leaf))
|
||||
{
|
||||
Throw "Cannot find OpenSSH binaries under $OpenSSHBinPath. Please specify -OpenSSHBinPath to the OpenSSH installed location"
|
||||
}
|
||||
else
|
||||
{
|
||||
$script:OpenSSHBinPath = $OpenSSHBinPath
|
||||
}
|
||||
}
|
||||
|
||||
$Global:OpenSSHTestInfo.Add("OpenSSHBinPath", $script:OpenSSHBinPath)
|
||||
if (-not ($env:Path.ToLower().Contains($script:OpenSSHBinPath.ToLower())))
|
||||
{
|
||||
$env:Path = "$($script:OpenSSHBinPath);$($env:path)"
|
||||
}
|
||||
|
||||
$acl = get-acl (join-path $script:OpenSSHBinPath "ssh.exe")
|
||||
|
||||
if($acl.Owner -ieq "NT SERVICE\TrustedInstaller")
|
||||
{
|
||||
$Script:WindowsInBox = $true
|
||||
$Global:OpenSSHTestInfo.Add("WindowsInBox", $true)
|
||||
$Global:OpenSSHTestInfo["EnableAppVerifier"] = $false
|
||||
$Script:EnableAppVerifier = $false
|
||||
}
|
||||
|
||||
$description = @"
|
||||
WARNING: Following changes will be made to OpenSSH configuration
|
||||
|
@ -160,12 +107,7 @@ WARNING: Following changes will be made to OpenSSH configuration
|
|||
return
|
||||
}
|
||||
|
||||
Install-OpenSSHTestDependencies
|
||||
|
||||
if(-not (Test-path $TestDataPath -PathType Container))
|
||||
{
|
||||
New-Item -ItemType Directory -Path $TestDataPath -Force -ErrorAction SilentlyContinue | out-null
|
||||
}
|
||||
Install-OpenSSHTestDependencies
|
||||
|
||||
$backupConfigPath = Join-Path $OpenSSHConfigPath sshd_config.ori
|
||||
$targetsshdConfig = Join-Path $OpenSSHConfigPath sshd_config
|
||||
|
@ -194,7 +136,7 @@ WARNING: Following changes will be made to OpenSSH configuration
|
|||
#copy ca private key to test dir
|
||||
$ca_priv_key = (Join-Path $Global:OpenSSHTestInfo["TestDataPath"] sshtest_ca_userkeys)
|
||||
Copy-Item (Join-Path $Script:E2ETestDirectory 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
|
||||
|
||||
Restart-Service sshd -Force
|
||||
|
@ -271,6 +213,98 @@ WARNING: Following changes will be made to OpenSSH configuration
|
|||
|
||||
Backup-OpenSSHTestInfo
|
||||
}
|
||||
|
||||
function Set-BasicTestInfo
|
||||
{
|
||||
[CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact="High")]
|
||||
param
|
||||
(
|
||||
[string] $OpenSSHBinPath,
|
||||
[string] $TestDataPath = "$env:SystemDrive\OpenSSHTests",
|
||||
[Switch] $NoLibreSSL
|
||||
)
|
||||
|
||||
if($Global:OpenSSHTestInfo -ne $null)
|
||||
{
|
||||
$Global:OpenSSHTestInfo.Clear()
|
||||
$Global:OpenSSHTestInfo = $null
|
||||
}
|
||||
$Script:TestDataPath = $TestDataPath;
|
||||
$Script:E2ETestResultsFile = Join-Path $TestDataPath $E2ETestResultsFileName
|
||||
$Script:SetupTestResultsFile = Join-Path $TestDataPath $SetupTestResultsFileName
|
||||
$Script:UninstallTestResultsFile = Join-Path $TestDataPath $UninstallTestResultsFileName
|
||||
$Script:UnitTestResultsFile = Join-Path $TestDataPath $UnitTestResultsFileName
|
||||
$Script:TestSetupLogFile = Join-Path $TestDataPath $TestSetupLogFileName
|
||||
$Script:UnitTestDirectory = Get-UnitTestDirectory
|
||||
$Script:NoLibreSSL = $NoLibreSSL.IsPresent
|
||||
|
||||
$Global:OpenSSHTestInfo = @{
|
||||
"TestDataPath" = $TestDataPath; # openssh tests path
|
||||
"TestSetupLogFile" = $Script:TestSetupLogFile; # openssh test setup log file
|
||||
"E2ETestResultsFile" = $Script:E2ETestResultsFile; # openssh E2E test results file
|
||||
"SetupTestResultsFile" = $Script:SetupTestResultsFile; # openssh setup test test results file
|
||||
"UninstallTestResultsFile" = $Script:UninstallTestResultsFile; # openssh Uninstall test test results file
|
||||
"UnitTestResultsFile" = $Script:UnitTestResultsFile; # openssh unittest test results file
|
||||
"E2ETestDirectory" = $Script:E2ETestDirectory # the directory of E2E tests
|
||||
"UnitTestDirectory" = $Script:UnitTestDirectory # the directory of unit tests
|
||||
"NoLibreSSL" = $Script:NoLibreSSL
|
||||
"WindowsInBox" = $Script:WindowsInBox
|
||||
}
|
||||
#if user does not set path, pick it up
|
||||
if([string]::IsNullOrEmpty($OpenSSHBinPath))
|
||||
{
|
||||
$sshcmd = get-command ssh.exe -ErrorAction SilentlyContinue
|
||||
if($sshcmd -eq $null)
|
||||
{
|
||||
Throw "Cannot find ssh.exe. Please specify -OpenSSHBinPath to the OpenSSH installed location."
|
||||
}
|
||||
else
|
||||
{
|
||||
$dirToCheck = split-path $sshcmd.Path
|
||||
$description = "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"
|
||||
if(-not $pscmdlet.ShouldProcess($description, $prompt, $caption))
|
||||
{
|
||||
Write-Host "User decided not to pick up ssh.exe from $dirToCheck. Please specify -OpenSSHBinPath to the OpenSSH installed location."
|
||||
return
|
||||
}
|
||||
$script:OpenSSHBinPath = $dirToCheck
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (-not (Test-Path (Join-Path $OpenSSHBinPath ssh.exe) -PathType Leaf))
|
||||
{
|
||||
Throw "Cannot find OpenSSH binaries under $OpenSSHBinPath. Please specify -OpenSSHBinPath to the OpenSSH installed location"
|
||||
}
|
||||
else
|
||||
{
|
||||
$script:OpenSSHBinPath = $OpenSSHBinPath
|
||||
}
|
||||
}
|
||||
|
||||
$Global:OpenSSHTestInfo.Add("OpenSSHBinPath", $script:OpenSSHBinPath)
|
||||
if (-not ($env:Path.ToLower().Contains($script:OpenSSHBinPath.ToLower())))
|
||||
{
|
||||
$env:Path = "$($script:OpenSSHBinPath);$($env:path)"
|
||||
}
|
||||
|
||||
$acl = get-acl (join-path $script:OpenSSHBinPath "ssh.exe")
|
||||
|
||||
if($acl.Owner -ieq "NT SERVICE\TrustedInstaller")
|
||||
{
|
||||
$Script:WindowsInBox = $true
|
||||
$Global:OpenSSHTestInfo["WindowsInBox"]= $true
|
||||
}
|
||||
|
||||
Install-OpenSSHTestDependencies -TestHarness
|
||||
if(-not (Test-path $TestDataPath -PathType Container))
|
||||
{
|
||||
New-Item -ItemType Directory -Path $TestDataPath -Force -ErrorAction SilentlyContinue | out-null
|
||||
}
|
||||
}
|
||||
|
||||
#TODO - this is Windows specific. Need to be in PAL
|
||||
function Get-LocalUserProfile
|
||||
{
|
||||
|
@ -299,7 +333,7 @@ function Get-LocalUserProfile
|
|||
function Install-OpenSSHTestDependencies
|
||||
{
|
||||
[CmdletBinding()]
|
||||
param ()
|
||||
param ([Switch] $TestHarness)
|
||||
|
||||
#$isOpenSSHUtilsAvailable = Get-Module 'OpenSSHUtils' -ListAvailable
|
||||
#if (-not ($isOpenSSHUtilsAvailable))
|
||||
|
@ -328,6 +362,11 @@ function Install-OpenSSHTestDependencies
|
|||
choco install Pester --version 3.4.6 -y --force --limitoutput 2>&1 >> $Script:TestSetupLogFile
|
||||
}
|
||||
|
||||
if($TestHarness)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
if($Script:PostmortemDebugging -or (($OpenSSHTestInfo -ne $null) -and ($OpenSSHTestInfo["PostmortemDebugging"])))
|
||||
{
|
||||
$folderName = "x86"
|
||||
|
@ -568,6 +607,36 @@ function Get-UnitTestDirectory
|
|||
$unitTestDir
|
||||
}
|
||||
|
||||
<#
|
||||
.Synopsis
|
||||
Run OpenSSH Setup tests.
|
||||
#>
|
||||
function Invoke-OpenSSHSetupTest
|
||||
{
|
||||
# Discover all CI tests and run them.
|
||||
Import-Module pester -force -global
|
||||
Push-Location $Script:E2ETestDirectory
|
||||
Write-Log -Message "Running OpenSSH Setup tests..."
|
||||
$testFolders = @(Get-ChildItem *.tests.ps1 -Recurse | ForEach-Object{ Split-Path $_.FullName} | Sort-Object -Unique)
|
||||
Invoke-Pester $testFolders -OutputFormat NUnitXml -OutputFile $Script:SetupTestResultsFile -Tag 'Setup' -PassThru
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
<#
|
||||
.Synopsis
|
||||
Run OpenSSH uninstall tests.
|
||||
#>
|
||||
function Invoke-OpenSSHUninstallTest
|
||||
{
|
||||
# Discover all CI tests and run them.
|
||||
Import-Module pester -force -global
|
||||
Push-Location $Script:E2ETestDirectory
|
||||
Write-Log -Message "Running OpenSSH Uninstall tests..."
|
||||
$testFolders = @(Get-ChildItem *.tests.ps1 -Recurse | ForEach-Object{ Split-Path $_.FullName} | Sort-Object -Unique)
|
||||
Invoke-Pester $testFolders -OutputFormat NUnitXml -OutputFile $Script:UninstallTestResultsFile -Tag 'Uninstall' -PassThru
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
<#
|
||||
.Synopsis
|
||||
Run OpenSSH pester tests.
|
||||
|
@ -726,4 +795,4 @@ function Write-Log
|
|||
}
|
||||
}
|
||||
|
||||
Export-ModuleMember -Function Set-OpenSSHTestEnvironment, Clear-OpenSSHTestEnvironment, Invoke-OpenSSHUnitTest, Invoke-OpenSSHE2ETest, Backup-OpenSSHTestInfo, Restore-OpenSSHTestInfo
|
||||
Export-ModuleMember -Function Set-BasicTestInfo, Set-OpenSSHTestEnvironment, Clear-OpenSSHTestEnvironment, Invoke-OpenSSHSetupTest, Invoke-OpenSSHUnitTest, Invoke-OpenSSHE2ETest, Invoke-OpenSSHUninstallTest, Backup-OpenSSHTestInfo, Restore-OpenSSHTestInfo
|
||||
|
|
|
@ -33,14 +33,30 @@ wevtutil um `"$etwman`"
|
|||
[XML]$xml = Get-Content $etwman
|
||||
$xml.instrumentationManifest.instrumentation.events.provider.resourceFileName = $sshagentpath.ToString()
|
||||
$xml.instrumentationManifest.instrumentation.events.provider.messageFileName = $sshagentpath.ToString()
|
||||
$xml.Save($etwman)
|
||||
|
||||
$streamWriter = $null
|
||||
$xmlWriter = $null
|
||||
try {
|
||||
$streamWriter = new-object System.IO.StreamWriter($etwman)
|
||||
$xmlWriter = [System.Xml.XmlWriter]::Create($streamWriter)
|
||||
$xml.Save($xmlWriter)
|
||||
}
|
||||
finally {
|
||||
if($streamWriter) {
|
||||
$streamWriter.Close()
|
||||
}
|
||||
}
|
||||
|
||||
#register etw provider
|
||||
wevtutil im `"$etwman`"
|
||||
|
||||
New-Service -Name ssh-agent -BinaryPathName `"$sshagentpath`" -Description "SSH Agent" -StartupType Manual | Out-Null
|
||||
cmd.exe /c 'sc.exe sdset ssh-agent D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU)(A;;RP;;;AU)'
|
||||
$agentDesc = "Agent to hold private keys used for public key authentication."
|
||||
New-Service -Name ssh-agent -DisplayName "OpenSSH Authentication Agent" -BinaryPathName `"$sshagentpath`" -Description $agentDesc -StartupType Manual | Out-Null
|
||||
sc.exe sdset ssh-agent "D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU)(A;;RP;;;AU)"
|
||||
sc.exe privs ssh-agent SeImpersonatePrivilege
|
||||
|
||||
New-Service -Name sshd -BinaryPathName `"$sshdpath`" -Description "SSH Daemon" -StartupType Manual | Out-Null
|
||||
$sshdDesc = "SSH protocol based service to provide secure encrypted communications between two untrusted hosts over an insecure network."
|
||||
New-Service -Name sshd -DisplayName "OpenSSH SSH Server" -BinaryPathName `"$sshdpath`" -Description $sshdDesc -StartupType Manual | Out-Null
|
||||
sc.exe privs sshd SeAssignPrimaryTokenPrivilege/SeTcbPrivilege/SeBackupPrivilege/SeRestorePrivilege/SeImpersonatePrivilege
|
||||
|
||||
Write-Host -ForegroundColor Green "sshd and ssh-agent services successfully installed"
|
||||
|
|
|
@ -0,0 +1,490 @@
|
|||
If ($PSVersiontable.PSVersion.Major -le 2) {$PSScriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path}
|
||||
Import-Module $PSScriptRoot\CommonUtils.psm1 -Force
|
||||
$suite = "Setup"
|
||||
$tC = 1
|
||||
$tI = 0
|
||||
Describe "Setup Tests" -Tags "Setup" {
|
||||
BeforeAll {
|
||||
if($OpenSSHTestInfo -eq $null)
|
||||
{
|
||||
Throw "`$OpenSSHTestInfo is null. Please run Set-OpenSSHTestEnvironment to set test environments."
|
||||
}
|
||||
|
||||
$windowsInBox = $OpenSSHTestInfo["WindowsInBox"]
|
||||
$binPath = $OpenSSHTestInfo["OpenSSHBinPath"]
|
||||
$dataPath = Join-path $env:ProgramData ssh
|
||||
|
||||
$systemSid = Get-UserSID -WellKnownSidType ([System.Security.Principal.WellKnownSidType]::LocalSystemSid)
|
||||
$adminsSid = Get-UserSID -WellKnownSidType ([System.Security.Principal.WellKnownSidType]::BuiltinAdministratorsSid)
|
||||
$usersSid = Get-UserSID -WellKnownSidType ([System.Security.Principal.WellKnownSidType]::BuiltinUsersSid)
|
||||
$authenticatedUserSid = Get-UserSID -WellKnownSidType ([System.Security.Principal.WellKnownSidType]::AuthenticatedUserSid)
|
||||
$trustedInstallerSid = Get-UserSID -User "NT SERVICE\TrustedInstaller"
|
||||
$allApplicationPackagesSid = Get-UserSID -User "ALL APPLICATION PACKAGES"
|
||||
$allRestrictedApplicationPackagesSid = Get-UserSID -User "ALL RESTRICTED APPLICATION PACKAGES"
|
||||
|
||||
$FSReadAccessPerm = ([System.UInt32] [System.Security.AccessControl.FileSystemRights]::ReadAndExecute.value__) -bor `
|
||||
([System.UInt32] [System.Security.AccessControl.FileSystemRights]::Synchronize.value__)
|
||||
$FSReadWriteAccessPerm = ([System.UInt32] [System.Security.AccessControl.FileSystemRights]::ReadAndExecute.value__) -bor `
|
||||
([System.UInt32] [System.Security.AccessControl.FileSystemRights]::Write.value__) -bor `
|
||||
([System.UInt32] [System.Security.AccessControl.FileSystemRights]::Modify.value__) -bor `
|
||||
([System.UInt32] [System.Security.AccessControl.FileSystemRights]::Synchronize.value__)
|
||||
|
||||
$FSFullControlPerm = [System.UInt32] [System.Security.AccessControl.FileSystemRights]::FullControl.value__
|
||||
$FSReadAndExecutePerm = ([System.UInt32] [System.Security.AccessControl.FileSystemRights]::ReadAndExecute.value__) -bor `
|
||||
([System.UInt32] [System.Security.AccessControl.FileSystemRights]::Synchronize.value__)
|
||||
|
||||
$RegReadKeyPerm = ([System.UInt32] [System.Security.AccessControl.RegistryRights]::ReadKey.value__)
|
||||
$RegFullControlPerm = [System.UInt32] [System.Security.AccessControl.RegistryRights]::FullControl.value__
|
||||
|
||||
#only validate owner and ACEs of the registry
|
||||
function ValidateRegistryACL {
|
||||
param([string]$RegPath, $Ownersid = $adminsSid, $IdAcls)
|
||||
Test-Path -Path $RegPath | Should Be $true
|
||||
$myACL = Get-ACL $RegPath
|
||||
$OwnerSid = Get-UserSid -User $myACL.Owner
|
||||
$OwnerSid.Equals($Ownersid) | Should Be $true
|
||||
$myACL.Access | Should Not Be $null
|
||||
$CAPABILITY_SID = "S-1-15-3-1024-1065365936-1281604716-3511738428-1654721687-432734479-3232135806-4053264122-3456934681"
|
||||
$nonPropagate = $myACL.Access | ? {($_.PropagationFlags -eq ([System.Security.AccessControl.PropagationFlags]::None)) -and ($_.IdentityReference -ine $CAPABILITY_SID)}
|
||||
|
||||
foreach ($a in $nonPropagate) {
|
||||
$findItem = $IdAcls | ? {
|
||||
($a.IdentityReference -eq (Get-UserAccount -UserSid ($_.Identity))) -and `
|
||||
($a.IsInherited -eq $_.IsInherited) -and `
|
||||
($a.AccessControlType -eq ([System.Security.AccessControl.AccessControlType]::Allow)) -and `
|
||||
(([System.Int32]$a.RegistryRights.value__) -eq ($_.RegistryRights))
|
||||
}
|
||||
$findItem | Should Not Be $null
|
||||
}
|
||||
|
||||
foreach ($expected in $IdAcls) {
|
||||
$findItem = $nonPropagate | ? {
|
||||
((Get-UserAccount -UserSid ($expected.Identity)) -eq $_.IdentityReference) -and `
|
||||
($expected.IsInherited -eq $_.IsInherited) -and `
|
||||
($expected.RegistryRights -eq ([System.Int32]$_.RegistryRights.value__))
|
||||
}
|
||||
$findItem | Should Not Be $null
|
||||
}
|
||||
}
|
||||
|
||||
#only validate owner and ACEs of the file
|
||||
function ValidateFileSystem {
|
||||
param(
|
||||
[string]$FilePath,
|
||||
[bool]$IsDirectory = $false,
|
||||
[switch]$IsDataFile,
|
||||
$OwnerSid = $trustedInstallerSid)
|
||||
|
||||
if($IsDirectory)
|
||||
{
|
||||
Test-Path -Path $FilePath -PathType Container | Should Be $true
|
||||
}
|
||||
else
|
||||
{
|
||||
Test-Path -Path $FilePath -PathType Leaf | Should Be $true
|
||||
}
|
||||
|
||||
$myACL = Get-ACL $FilePath
|
||||
$currentOwnerSid = Get-UserSid -User $myACL.Owner
|
||||
if(-not $windowsInBox) {return}
|
||||
$currentOwnerSid.Equals($OwnerSid) | Should Be $true
|
||||
$myACL.Access | Should Not Be $null
|
||||
if($IsDirectory)
|
||||
{
|
||||
$identities = @($systemSid, $adminsSid)
|
||||
}
|
||||
elseif($IsDataFile)
|
||||
{
|
||||
$identities = @($systemSid, $adminsSid, $authenticatedUserSid)
|
||||
}
|
||||
else
|
||||
{
|
||||
$identities = @($systemSid, $adminsSid, $trustedInstallerSid, $allApplicationPackagesSid, $allRestrictedApplicationPackagesSid, $usersSid)
|
||||
}
|
||||
|
||||
$identities | % {
|
||||
(Get-UserAccount -UserSid $_) | Should BeIn $myACL.Access.IdentityReference
|
||||
}
|
||||
|
||||
foreach ($a in $myACL.Access) {
|
||||
$id = Get-UserSid -User $a.IdentityReference
|
||||
if($id -eq $null)
|
||||
{
|
||||
$idRefShortValue = ($a.IdentityReference.Value).split('\')[-1]
|
||||
$id = Get-UserSID -User $idRefShortValue
|
||||
}
|
||||
|
||||
$id | Should BeIn $identities
|
||||
|
||||
switch ($id)
|
||||
{
|
||||
{@($systemSid, $adminsSid) -contains $_}
|
||||
{
|
||||
if($IsDataFile)
|
||||
{
|
||||
([System.UInt32]$a.FileSystemRights.value__) | Should Be $FSFullControlPerm
|
||||
}
|
||||
else
|
||||
{
|
||||
([System.UInt32]$a.FileSystemRights.value__) | Should Be $FSReadAndExecutePerm
|
||||
}
|
||||
break;
|
||||
}
|
||||
{@($usersSid, $allApplicationPackagesSid, $allRestrictedApplicationPackagesSid, $authenticatedUserSid) -contains $_}
|
||||
{
|
||||
([System.UInt32]$a.FileSystemRights.value__) | Should Be $FSReadAndExecutePerm
|
||||
break;
|
||||
}
|
||||
$trustedInstallerSid
|
||||
{
|
||||
([System.UInt32]$a.FileSystemRights.value__) | Should Be $FSFullControlPerm
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$a.AccessControlType | Should Be ([System.Security.AccessControl.AccessControlType]::Allow)
|
||||
if($IsDirectory)
|
||||
{
|
||||
$a.InheritanceFlags | Should Be (([System.Security.AccessControl.InheritanceFlags]::ContainerInherit.value__ -bor `
|
||||
[System.Security.AccessControl.InheritanceFlags]::ObjectInherit.value__))
|
||||
}
|
||||
else
|
||||
{
|
||||
$a.InheritanceFlags | Should Be ([System.Security.AccessControl.InheritanceFlags]::None)
|
||||
}
|
||||
$a.PropagationFlags | Should Be ([System.Security.AccessControl.PropagationFlags]::None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Context "$tC - Validate Openssh binary files" {
|
||||
|
||||
BeforeAll {
|
||||
$tI=1
|
||||
$binaries = @(
|
||||
@{
|
||||
Name = 'sshd.exe'
|
||||
},
|
||||
@{
|
||||
Name = 'ssh.exe'
|
||||
},
|
||||
@{
|
||||
Name = 'ssh-agent.exe'
|
||||
},
|
||||
@{
|
||||
Name = 'ssh-add.exe'
|
||||
},
|
||||
@{
|
||||
Name = 'sftp.exe'
|
||||
},
|
||||
@{
|
||||
Name = 'sftp-server.exe'
|
||||
},
|
||||
@{
|
||||
Name = 'scp.exe'
|
||||
},
|
||||
@{
|
||||
Name = 'ssh-shellhost.exe'
|
||||
},
|
||||
@{
|
||||
Name = 'ssh-agent.exe'
|
||||
},
|
||||
@{
|
||||
Name = 'ssh-keyscan.exe'
|
||||
}
|
||||
)
|
||||
$dataFile = @(
|
||||
@{
|
||||
Name = 'sshd_config_default'
|
||||
},
|
||||
@{
|
||||
Name = 'install-sshd.ps1'
|
||||
},
|
||||
@{
|
||||
Name = 'uninstall-sshd.ps1'
|
||||
},
|
||||
@{
|
||||
Name = 'FixHostFilePermissions.ps1'
|
||||
},
|
||||
@{
|
||||
Name = 'FixUserFilePermissions.ps1'
|
||||
},
|
||||
@{
|
||||
Name = 'OpenSSHUtils.psm1'
|
||||
},
|
||||
@{
|
||||
Name = 'OpenSSHUtils.psd1'
|
||||
},
|
||||
@{
|
||||
Name = 'openssh-events.man'
|
||||
}
|
||||
)
|
||||
|
||||
$dataFile1 = @(
|
||||
@{
|
||||
Name = "sshd_config"
|
||||
}
|
||||
@{
|
||||
Name = "logs"
|
||||
IsDirectory = $true
|
||||
}
|
||||
)
|
||||
}
|
||||
AfterAll{$tC++}
|
||||
AfterEach { $tI++ }
|
||||
|
||||
It "$tC.$tI - Validate Openssh binary files--<Name>" -TestCases:$binaries{
|
||||
param([string]$Name, [boolean]$IsDirectory = $false)
|
||||
ValidateFileSystem -FilePath (join-path $binPath $Name)
|
||||
}
|
||||
It "$tC.$tI - Validate Openssh script files--<Name>" -TestCases:$dataFile {
|
||||
param([string]$Name, [boolean]$IsDirectory = $false)
|
||||
if(-not $WindowsInbox) { ValidateFileSystem -FilePath (join-path $binPath $Name) }
|
||||
}
|
||||
|
||||
It "$tC.$tI - Validate data files--<Name>" -TestCases:$dataFile1 {
|
||||
param([string]$Name, [boolean]$IsDirectory = $false)
|
||||
if(-not (Test-Path $dataPath -PathType Container))
|
||||
{
|
||||
Start-Service sshd
|
||||
}
|
||||
|
||||
ValidateFileSystem -FilePath (join-path $dataPath $Name) -IsDirectory $IsDirectory -OwnerSid $adminsSid -IsDataFile
|
||||
}
|
||||
}
|
||||
|
||||
Context "$tC - Validate Openssh registry entries" {
|
||||
BeforeAll {
|
||||
$tI=1
|
||||
$servicePath = "HKLM:\SYSTEM\ControlSet001\Services"
|
||||
$opensshRegPath = "HKLM:\SOFTWARE\OpenSSH"
|
||||
|
||||
$opensshACLs = @(
|
||||
@{
|
||||
Identity=$systemSid
|
||||
IsInherited = $false
|
||||
RegistryRights = $RegFullControlPerm
|
||||
PropagationFlags = "None"
|
||||
},
|
||||
@{
|
||||
Identity=$adminsSid
|
||||
IsInherited = $false
|
||||
RegistryRights = $RegFullControlPerm
|
||||
PropagationFlags = "None"
|
||||
},
|
||||
@{
|
||||
Identity=$authenticatedUserSid
|
||||
IsInherited = $false
|
||||
RegistryRights = $RegReadKeyPerm -bor ([System.UInt32] [System.Security.AccessControl.RegistryRights]::SetValue.value__)
|
||||
PropagationFlags = "None"
|
||||
}
|
||||
)
|
||||
}
|
||||
AfterAll{$tC++}
|
||||
AfterEach { $tI++ }
|
||||
|
||||
It "$tC.$tI - Validate Registry key ssh-agent\Description" {
|
||||
$p = Get-ItemPropertyValue (Join-Path $servicePath "ssh-agent") -Name "Description"
|
||||
$p | Should Not Be $null
|
||||
}
|
||||
|
||||
It "$tC.$tI - Validate Registry key ssh-agent\ErrorControl" {
|
||||
$p = Get-ItemPropertyValue (Join-Path $servicePath "ssh-agent") -Name "ErrorControl"
|
||||
$p | Should Be 1
|
||||
}
|
||||
|
||||
It "$tC.$tI - Validate Registry key ssh-agent\ImagePath" {
|
||||
$p = Get-ItemPropertyValue (Join-Path $servicePath "ssh-agent") -Name "ImagePath"
|
||||
$imagePath = (Join-Path $binPath "ssh-agent.exe").ToLower()
|
||||
$p | Should Match "[`"]?$($imagePath.Replace("\", "\\"))[`"]?"
|
||||
}
|
||||
|
||||
It "$tC.$tI - Validate Registry key ssh-agent\ObjectName" {
|
||||
$p = Get-ItemPropertyValue (Join-Path $servicePath "ssh-agent") -Name "ObjectName"
|
||||
$p | Should Be "LocalSystem"
|
||||
}
|
||||
|
||||
It "$tC.$tI - Validate Registry key ssh-agent\Start" {
|
||||
$p = Get-ItemPropertyValue (Join-Path $servicePath "ssh-agent") -Name "Start"
|
||||
$p | Should Be 3
|
||||
}
|
||||
|
||||
It "$tC.$tI - Validate Registry key ssh-agent\Type" {
|
||||
$p = Get-ItemPropertyValue (Join-Path $servicePath "ssh-agent") -Name "Type"
|
||||
$p | Should Be 16
|
||||
}
|
||||
|
||||
It "$tC.$tI - Validate Registry key to ssh-agent\Security\Security" {
|
||||
$p = Get-ItemPropertyValue (Join-Path $servicePath "ssh-agent\Security") -Name Security
|
||||
$p.Gettype() | Should Be byte[]
|
||||
}
|
||||
|
||||
It "$tC.$tI - Validate Registry key sshd\Description" {
|
||||
$p = Get-ItemPropertyValue (Join-Path $servicePath "sshd") -Name "Description"
|
||||
$p | Should not Be $null
|
||||
}
|
||||
|
||||
It "$tC.$tI - Validate Registry key sshd\ErrorControl" {
|
||||
$p = Get-ItemPropertyValue (Join-Path $servicePath "sshd") -Name "ErrorControl"
|
||||
$p | Should Be 1
|
||||
}
|
||||
|
||||
It "$tC.$tI - Validate Registry key sshd\ImagePath" {
|
||||
$p = Get-ItemPropertyValue (Join-Path $servicePath "sshd") -Name "ImagePath"
|
||||
$imagePath = (Join-Path $binPath "sshd.exe").ToLower()
|
||||
$p | Should Match "[`"]?$($imagePath.Replace("\", "\\"))[`"]?"
|
||||
}
|
||||
|
||||
It "$tC.$tI - Validate Registry key sshd\ObjectName" {
|
||||
$p = Get-ItemPropertyValue (Join-Path $servicePath "sshd") -Name "ObjectName"
|
||||
$p | Should Be "LocalSystem"
|
||||
}
|
||||
|
||||
It "$tC.$tI - Validate Registry key sshd\Start" {
|
||||
$p = Get-ItemPropertyValue (Join-Path $servicePath "sshd") -Name "Start"
|
||||
$p | Should Be 3
|
||||
}
|
||||
|
||||
It "$tC.$tI - Validate Registry key sshd\Type" {
|
||||
$p = Get-ItemPropertyValue (Join-Path $servicePath "sshd") -Name "Type"
|
||||
$p | Should Be 16
|
||||
}
|
||||
|
||||
It "$tC.$tI - Validate Registry openssh entry" {
|
||||
ValidateRegistryACL -RegPath $opensshRegPath -IdAcls $opensshACLs
|
||||
}
|
||||
It "$tC.$tI - Validate Registry openssh\agent entry" {
|
||||
$agentPath = Join-Path $opensshRegPath "Agent"
|
||||
if(-not (Test-Path $agentPath -PathType Container))
|
||||
{
|
||||
Start-Service ssh-agent
|
||||
}
|
||||
|
||||
ValidateRegistryACL -RegPath $agentPath -IdAcls $opensshACLs
|
||||
}
|
||||
}
|
||||
|
||||
Context "$tC - Validate service settings" {
|
||||
BeforeAll {
|
||||
$tI=1
|
||||
}
|
||||
AfterAll{$tC++}
|
||||
AfterEach { $tI++ }
|
||||
|
||||
It "$tC.$tI - Validate properties of ssh-agent service" {
|
||||
$sshdSvc = Get-service ssh-agent
|
||||
$sshdSvc.StartType | Should Be ([System.ServiceProcess.ServiceStartMode]::Manual)
|
||||
$sshdSvc.ServiceType | Should Be ([System.ServiceProcess.ServiceType]::Win32OwnProcess)
|
||||
$sshdSvc.ServiceName | Should Be "ssh-agent"
|
||||
$sshdSvc.DisplayName | Should BeLike "OpenSSH*"
|
||||
$sshdSvc.Name | Should Be "ssh-agent"
|
||||
($sshdSvc.DependentServices).Count | Should Be 0
|
||||
($sshdSvc.ServicesDependedOn).Count | Should Be 0
|
||||
($sshdSvc.RequiredServices).Count | Should Be 0
|
||||
}
|
||||
|
||||
It "$tC.$tI - Validate properties of sshd service" {
|
||||
$sshdSvc = Get-service sshd
|
||||
$sshdSvc.StartType | Should Be ([System.ServiceProcess.ServiceStartMode]::Manual)
|
||||
$sshdSvc.ServiceType | Should Be ([System.ServiceProcess.ServiceType]::Win32OwnProcess)
|
||||
$sshdSvc.ServiceName | Should Be "sshd"
|
||||
$sshdSvc.DisplayName | Should BeLike "OpenSSH*"
|
||||
$sshdSvc.Name | Should Be "sshd"
|
||||
($sshdSvc.DependentServices).Count | Should Be 0
|
||||
($sshdSvc.ServicesDependedOn).Count | Should Be 0
|
||||
($sshdSvc.RequiredServices).Count | Should Be 0
|
||||
}
|
||||
|
||||
It "$tC.$tI - Validate RequiredPrivileges of ssh-agent" {
|
||||
$a = sc.exe qprivs ssh-agent 256
|
||||
$p = @($a | % { if($_ -match "Se[\w]+Privilege" ) {$start = $_.IndexOf("Se");$_.Substring($start, $_.length-$start)}})
|
||||
$p.count | Should Be 1
|
||||
$p[0] | Should Be "SeImpersonatePrivilege"
|
||||
}
|
||||
|
||||
It "$tC.$tI - Validate RequiredPrivileges of sshd" {
|
||||
$expected = @("SeAssignPrimaryTokenPrivilege", "SeTcbPrivilege", "SeBackupPrivilege", "SeRestorePrivilege", "SeImpersonatePrivilege")
|
||||
$a = sc.exe qprivs sshd 256
|
||||
$p = $a | % { if($_ -match "Se[\w]+Privilege" ) {$start = $_.IndexOf("Se");$_.Substring($start, $_.length-$start)}}
|
||||
$expected | % {
|
||||
$_ | Should BeIn $p
|
||||
}
|
||||
|
||||
$p | % {
|
||||
$_ | Should BeIn $expected
|
||||
}
|
||||
}
|
||||
|
||||
It "$tC.$tI - Validate security access to ssh-agent service" {
|
||||
$a = @(sc.exe sdshow ssh-agent)
|
||||
$b = $a[-1] -split "[D|S]:"
|
||||
|
||||
$expected_dacl_aces = @("(A;;CCLCSWRPWPDTLOCRRC;;;SY)", "(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)", "(A;;CCLCSWLOCRRC;;;IU)", "(A;;CCLCSWLOCRRC;;;SU)", "(A;;RP;;;AU)")
|
||||
$c = @($b | ? { -not [string]::IsNullOrWhiteSpace($_) })
|
||||
$dacl = $c[0]
|
||||
$dacl_aces = $dacl -split "(\([;|\w]+\))"
|
||||
$actual_dacl_aces = $dacl_aces | ? { -not [string]::IsNullOrWhiteSpace($_) }
|
||||
|
||||
$expected_dacl_aces | % {
|
||||
$_ | Should BeIn $actual_dacl_aces
|
||||
}
|
||||
$actual_dacl_aces | % {
|
||||
$_ | Should BeIn $expected_dacl_aces
|
||||
}
|
||||
|
||||
<# ignore sacl for now
|
||||
if($c.Count -gt 1) {
|
||||
$c[1] | Should Be "(AU;FA;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;WD)"
|
||||
}#>
|
||||
}
|
||||
|
||||
It "$tC.$tI - Validate security access to sshd service" {
|
||||
$a = @(sc.exe sdshow sshd)
|
||||
$b = $a[-1] -split "[D|S]:"
|
||||
|
||||
$expected_dacl_aces = @("(A;;CCLCSWRPWPDTLOCRRC;;;SY)", "(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)", "(A;;CCLCSWLOCRRC;;;IU)", "(A;;CCLCSWLOCRRC;;;SU)")
|
||||
$c = @($b | ? { -not [string]::IsNullOrWhiteSpace($_) })
|
||||
$dacl = $c[0]
|
||||
$dacl_aces = $dacl -split "(\([;|\w]+\))"
|
||||
$actual_dacl_aces = $dacl_aces | ? { -not [string]::IsNullOrWhiteSpace($_) }
|
||||
|
||||
$expected_dacl_aces | % {
|
||||
$_ | Should BeIn $actual_dacl_aces
|
||||
}
|
||||
$actual_dacl_aces | % {
|
||||
$_ | Should BeIn $expected_dacl_aces
|
||||
}
|
||||
|
||||
<# ignore sacl for now
|
||||
if($c.Count -gt 1) {
|
||||
$c[1] | Should Be "(AU;FA;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;WD)"
|
||||
}#>
|
||||
}
|
||||
}
|
||||
|
||||
Context "$tC - Validate Firewall settings" {
|
||||
BeforeAll {
|
||||
$firwallRuleName = "OpenSSH-Server-In-TCP"
|
||||
$tI=1
|
||||
}
|
||||
|
||||
AfterAll{$tC++}
|
||||
AfterEach { $tI++ }
|
||||
|
||||
It "$tC.$tI - Validate Firewall settings" -skip:(!$windowsInBox) {
|
||||
$rule = Get-NetFirewallRule -Name $firwallRuleName
|
||||
$rule.Group | Should BeLike "OpenSSH*"
|
||||
$rule.Description | Should BeLike "*OpenSSH*"
|
||||
$rule.DisplayName | Should BeLike "OpenSSH*"
|
||||
$rule.Enabled | Should Be $true
|
||||
$rule.Profile.ToString() | Should Be 'Any'
|
||||
$rule.Direction.ToString() | Should Be 'Inbound'
|
||||
$rule.Action.ToString() | Should Be 'Allow'
|
||||
$rule.StatusCode | Should Be 65536
|
||||
$fwportFilter = $rule | Get-NetFirewallPortFilter
|
||||
$fwportFilter.Protocol | Should Be 'TCP'
|
||||
$fwportFilter.LocalPort | Should Be 22
|
||||
$fwportFilter.RemotePort | Should Be 'Any'
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,196 @@
|
|||
If ($PSVersiontable.PSVersion.Major -le 2) {$PSScriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path}
|
||||
Import-Module $PSScriptRoot\CommonUtils.psm1 -Force
|
||||
$suite = "Uninstall"
|
||||
$tC = 1
|
||||
$tI = 0
|
||||
Describe "Uninstall Tests" -Tags "Uninstall" {
|
||||
BeforeAll {
|
||||
if($OpenSSHTestInfo -eq $null)
|
||||
{
|
||||
Throw "`$OpenSSHTestInfo is null. Please run Set-OpenSSHTestEnvironment to set test environments."
|
||||
}
|
||||
|
||||
$windowsInBox = $OpenSSHTestInfo["WindowsInBox"]
|
||||
$binPath = $OpenSSHTestInfo["OpenSSHBinPath"]
|
||||
$dataPath = Join-path $env:ProgramData ssh
|
||||
|
||||
Stop-Service sshd -ErrorAction SilentlyContinue
|
||||
Stop-Service ssh-agent -ErrorAction SilentlyContinue
|
||||
if(Get-Service sshd -ErrorAction SilentlyContinue)
|
||||
{
|
||||
if($windowsInBox) {
|
||||
Remove-WindowsCapability -online -name OpenSSH.Server~~~~0.0.1.0
|
||||
}
|
||||
else {
|
||||
& (Join-Path $binPath "uninstall-sshd.ps1")
|
||||
}
|
||||
}
|
||||
if(Get-Service ssh-agent -ErrorAction SilentlyContinue)
|
||||
{
|
||||
if($windowsInBox) {
|
||||
Remove-WindowsCapability -online -name OpenSSH.Client~~~~0.0.1.0
|
||||
}
|
||||
else
|
||||
{
|
||||
& (Join-Path $binPath "uninstall-sshd.ps1")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$systemSid = Get-UserSID -WellKnownSidType ([System.Security.Principal.WellKnownSidType]::LocalSystemSid)
|
||||
$adminsSid = Get-UserSID -WellKnownSidType ([System.Security.Principal.WellKnownSidType]::BuiltinAdministratorsSid)
|
||||
$authenticatedUserSid = Get-UserSID -WellKnownSidType ([System.Security.Principal.WellKnownSidType]::AuthenticatedUserSid)
|
||||
|
||||
$RegReadKeyPerm = ([System.UInt32] [System.Security.AccessControl.RegistryRights]::ReadKey.value__)
|
||||
$RegFullControlPerm = [System.UInt32] [System.Security.AccessControl.RegistryRights]::FullControl.value__
|
||||
|
||||
#only validate owner and ACEs of the registry
|
||||
function ValidateRegistryACL {
|
||||
param([string]$RegPath, $Ownersid = $adminsSid, $IdAcls)
|
||||
Test-Path -Path $RegPath | Should Be $true
|
||||
$myACL = Get-ACL $RegPath
|
||||
$OwnerSid = Get-UserSid -User $myACL.Owner
|
||||
$OwnerSid.Equals($Ownersid) | Should Be $true
|
||||
$myACL.Access | Should Not Be $null
|
||||
$CAPABILITY_SID = "S-1-15-3-1024-1065365936-1281604716-3511738428-1654721687-432734479-3232135806-4053264122-3456934681"
|
||||
$nonPropagate = $myACL.Access | ? {($_.PropagationFlags -eq ([System.Security.AccessControl.PropagationFlags]::None)) -and ($_.IdentityReference -ine $CAPABILITY_SID)}
|
||||
|
||||
foreach ($a in $nonPropagate) {
|
||||
$findItem = $IdAcls | ? {
|
||||
($a.IdentityReference -eq (Get-UserAccount -UserSid ($_.Identity))) -and `
|
||||
($a.IsInherited -eq $_.IsInherited) -and `
|
||||
($a.AccessControlType -eq ([System.Security.AccessControl.AccessControlType]::Allow)) -and `
|
||||
($a.PropagationFlags -eq ([System.Security.AccessControl.PropagationFlags]::None) -and `
|
||||
(([System.Int32]$a.RegistryRights.value__) -eq ($_.RegistryRights)))
|
||||
}
|
||||
$findItem | Should Not Be $null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Context "$tC - Validate Openssh binary files" {
|
||||
BeforeAll {
|
||||
if(-not $Windowsbox)
|
||||
{
|
||||
$binaries = $null
|
||||
return
|
||||
}
|
||||
$tI=1
|
||||
$binaries = @(
|
||||
@{
|
||||
Name = 'sshd.exe'
|
||||
},
|
||||
@{
|
||||
Name = 'ssh.exe'
|
||||
},
|
||||
@{
|
||||
Name = 'ssh-agent.exe'
|
||||
},
|
||||
@{
|
||||
Name = 'ssh-add.exe'
|
||||
},
|
||||
@{
|
||||
Name = 'sftp.exe'
|
||||
},
|
||||
@{
|
||||
Name = 'sftp-server.exe'
|
||||
},
|
||||
@{
|
||||
Name = 'scp.exe'
|
||||
},
|
||||
@{
|
||||
Name = 'ssh-shellhost.exe'
|
||||
},
|
||||
@{
|
||||
Name = 'ssh-agent.exe'
|
||||
},
|
||||
@{
|
||||
Name = 'ssh-keyscan.exe'
|
||||
}
|
||||
)
|
||||
}
|
||||
AfterAll{$tC++}
|
||||
AfterEach { $tI++ }
|
||||
|
||||
It "$tC.$tI - Validate Openssh binary files--<Name> is removed" -TestCases:$binaries{
|
||||
param([string]$Name, [boolean]$IsDirectory = $false)
|
||||
if(-not [string]::IsNullOrWhiteSpace($Name)) {
|
||||
(join-path $binPath $Name) | Should Not Exist
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Context "$tC - Validate Openssh registry entries" {
|
||||
BeforeAll {
|
||||
$tI=1
|
||||
$servicePath = "HKLM:\SYSTEM\ControlSet001\Services"
|
||||
$opensshRegPath = "HKLM:\SOFTWARE\OpenSSH"
|
||||
|
||||
$opensshACLs = @(
|
||||
@{
|
||||
Identity=$systemSid
|
||||
IsInherited = $false
|
||||
RegistryRights = $RegFullControlPerm
|
||||
PropagationFlags = "None"
|
||||
},
|
||||
@{
|
||||
Identity=$adminsSid
|
||||
IsInherited = $false
|
||||
RegistryRights = $RegFullControlPerm
|
||||
PropagationFlags = "None"
|
||||
},
|
||||
@{
|
||||
Identity=$authenticatedUserSid
|
||||
IsInherited = $false
|
||||
RegistryRights = $RegReadKeyPerm -bor ([System.UInt32] [System.Security.AccessControl.RegistryRights]::SetValue.value__)
|
||||
PropagationFlags = "None"
|
||||
}
|
||||
)
|
||||
}
|
||||
AfterAll{$tC++}
|
||||
AfterEach { $tI++ }
|
||||
|
||||
It "$tC.$tI - Validate Registry key ssh-agent is removed" {
|
||||
(Join-Path $servicePath "ssh-agent") | Should Not Exist
|
||||
}
|
||||
|
||||
It "$tC.$tI - Validate Registry key sshd is removed" {
|
||||
(Join-Path $servicePath "sshd") | Should Not Exist
|
||||
}
|
||||
|
||||
It "$tC.$tI - Validate Registry openssh entry" {
|
||||
ValidateRegistryACL -RegPath $opensshRegPath -IdAcls $opensshACLs
|
||||
}
|
||||
}
|
||||
|
||||
Context "$tC - Validate service is removed" {
|
||||
BeforeAll {
|
||||
$tI=1
|
||||
}
|
||||
|
||||
AfterAll{$tC++}
|
||||
AfterEach { $tI++ }
|
||||
|
||||
It "$tC.$tI - Validate ssh-agent is removed" {
|
||||
Get-Service ssh-agent -ErrorAction SilentlyContinue | Should Be $null
|
||||
}
|
||||
|
||||
It "$tC.$tI - Validate sshd is removed" {
|
||||
Get-Service sshd -ErrorAction SilentlyContinue | Should Be $null
|
||||
}
|
||||
}
|
||||
|
||||
Context "$tC - Validate Firewall settings" {
|
||||
BeforeAll {
|
||||
$firwallRuleName = "OpenSSH-Server-In-TCP"
|
||||
$tI=1
|
||||
}
|
||||
|
||||
AfterAll{$tC++}
|
||||
AfterEach { $tI++ }
|
||||
|
||||
It "$tC.$tI - Validate Firewall settings" -skip:(!$windowsInBox) {
|
||||
Get-NetFirewallRule -Name $firwallRuleName -ErrorAction SilentlyContinue | Should Be $null
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue