Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
3762ab6
[Feature] Replace test certificates with cert gen module
Sep 26, 2018
2b4e3e2
Use fixed certificate module version
Sep 26, 2018
4f5811b
Use correct version parameter for Save-Module
rjmholt Sep 26, 2018
faea431
Install SelfSignedCertificate rather than save it
rjmholt Sep 26, 2018
32d483e
Generate self-signed certificate for protected certificate test
rjmholt Sep 26, 2018
adf0199
Update certificate-describing documentation
rjmholt Sep 26, 2018
bd9a9f9
Force installation of the self-signed certificate
rjmholt Sep 27, 2018
2478ca2
Fix certificate test breakage
rjmholt Sep 27, 2018
db62e11
Add -AllowClobber to Install-Module
rjmholt Sep 27, 2018
00a1065
Merge branch 'master' of https://github.com/rjmholt/PowerShell into r…
Sep 27, 2018
7b82ff3
Merge branch 'remove-web-cmdlet-test-certs' of https://github.com/rjm…
Sep 27, 2018
4c6b542
Remove hard-coded test passwords
Sep 27, 2018
89e27c7
[Feature] Hide SelfSignedCertificate module name from spell checker
Sep 27, 2018
39abcd9
[Feature] De-verbosify x509 enum parameters used in cert creation
Sep 27, 2018
59d4344
[Feature] Use module-qualified name for cert gen command
Sep 27, 2018
70c01d0
[Feature] Get module name right
Sep 27, 2018
d92d44c
[Feature] Move SelfSignedCert module back to test tools module path
Sep 27, 2018
bf39e17
[Feature] Correct .gitignore of test tools path
Sep 27, 2018
dc41fef
[Feature] Fix module path usage, as asked by @JamesWTruher
Sep 27, 2018
8e8e6d8
[Feature] Put cert gen module in temp dir, revert .gitignore changes
Sep 28, 2018
e539e72
[Feature] Fix module path mangling
Sep 28, 2018
40ac236
[Feature] Address @iSazonov's feedback
Sep 28, 2018
b5cc1ea
[Feature] Change global variable to function-exposed module variable
Oct 1, 2018
2a5722b
[Feature] Prevent use of Get-CertificatePassword before New-Certifica…
Oct 1, 2018
f772d6d
[Feature] Factor New-RandomHexString into test helper module
Oct 1, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion build.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
# On Windows paths is separated by semicolon
$script:TestModulePathSeparator = [System.IO.Path]::PathSeparator

# Path to a directory to store modules we temporarily need to test PowerShell
$script:TestModuleDirPath = Join-Path ([System.IO.Path]::GetTempPath()) 'PwshTestModules'
$null = New-Item -Force -ItemType Directory -Path $script:TestModuleDirPath

$dotnetCLIChannel = "release"
$dotnetCLIRequiredVersion = $(Get-Content $PSScriptRoot/global.json | ConvertFrom-Json).Sdk.Version

Expand Down Expand Up @@ -1035,6 +1039,9 @@ function Publish-PSTestTools {
Pop-Location
}
}

# Get the SelfSignedCertificate module so the web listener can use it
Save-Module -Name SelfSignedCertificate -Path $script:TestModuleDirPath -Repository "PSGallery" -MinimumVersion '0.0.2' -Force -Confirm:$false
}

function Get-ExperimentalFeatureTests {
Expand Down Expand Up @@ -1139,7 +1146,8 @@ function Start-PSPester {
}

# Autoload (in subprocess) temporary modules used in our tests
$command += '$env:PSModulePath = '+"'$TestModulePath$TestModulePathSeparator'" + '+$($env:PSModulePath);'
$newPathFragment = $TestModulePath + $TestModulePathSeparator + $script:TestModuleDirPath + $TestModulePathSeparator
$command += '$env:PSModulePath = '+"'$newPathFragment'" + '+$env:PSModulePath;'

# Windows needs the execution policy adjusted
if ($Environment.IsWindows) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,8 @@ Describe "CmsMessage cmdlets and Get-PfxCertificate basic tests" -Tags "CI" {
}

It "Verify Get-PfxCertificate right password" {
#[SuppressMessage("Microsoft.Security", "CS002:SecretInNextLine", Justification="Test secret.")]
$pass = ConvertTo-SecureString "password" -AsPlainText -Force
$cert = Get-PfxCertificate $protectedCertLocation -Password $pass
$password = Get-CertificatePassword
$cert = Get-PfxCertificate $protectedCertLocation -Password $password
$cert.Subject | Should -Be "CN=localhost"
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,21 @@ OksttXT1kXf+aez9EzDlsgQU4ck78h0WTy01zHLwSKNWK4wFFQM=
return $certLocation
}

Function New-CertificatePassword
{
$script:protectedCertPassword = ConvertTo-SecureString -Force -AsPlainText (New-RandomHexString)
return $script:protectedCertPassword
}

Function Get-CertificatePassword
{
if ($null -eq $script:protectedCertPassword)
{
throw [System.InvalidOperationException] "`$script:protectedCertPassword is not defined. Call New-CertificatePassword first."
}
return $script:protectedCertPassword
}

Function New-ProtectedCertificate
{
<#
Expand All @@ -78,7 +93,15 @@ Function New-ProtectedCertificate
Password: "password"
#>

$certLocation = ".\test\tools\Modules\WebListener\ServerCert.pfx"
$certLocation = Join-Path ([System.IO.Path]::GetTempPath()) 'protectedCert.pfx'

$password = New-CertificatePassword

$null = SelfSignedCertificate\New-SelfSignedCertificate `
-CommonName 'localhost' `
-OutCertPath $certLocation `
-Passphrase $password `
-Force

return $certLocation
}
Expand Down
1 change: 1 addition & 0 deletions test/tools/Modules/HelpersCommon/HelpersCommon.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ FunctionsToExport = @(
'Disable-Testhook'
'Enable-Testhook'
'Get-RandomFileName'
'New-RandomHexString'
'Send-VstsLogFile'
'Set-TesthookResult'
'Start-NativeExecution'
Expand Down
10 changes: 10 additions & 0 deletions test/tools/Modules/HelpersCommon/HelpersCommon.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -313,3 +313,13 @@ function Start-NativeExecution
$script:ErrorActionPreference = $backupEAP
}
}

# Creates a new random hex string for use with things like test certificate passwords
function New-RandomHexString
{
param([int]$Length = 10)

$random = [Random]::new()
return ((1..$Length).ForEach{ '{0:x}' -f $random.Next(0xf) }) -join ''
}

Binary file removed test/tools/Modules/WebListener/ClientCert.pfx
Binary file not shown.
15 changes: 14 additions & 1 deletion test/tools/Modules/WebListener/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
# WebListener Module

A PowerShell module for managing the WebListener App. The included SelF-Signed Certificate `ServerCert.pfx` has the password set to `password` and is issued for the Client and Server Authentication key usages. This certificate is used by the WebListener App for SSL/TLS. The included SelF-Signed Certificate `ClientCert.pfx` has the password set to `password` and has not been issued for any specific key usage. This Certificate is used for Client Certificate Authentication with the WebListener App. The port used for `-HttpsPort` will use TLS 1.2.
A PowerShell module for managing the WebListener App.

When the WebListener is started from this module,
it will automatically generate two fresh certificates,
`ClientCert.pfx` and `ServerCert.pfx` using the `SelfSignedCertificate` module.

The generated Self-Signed Certificate `ServerCert.pfx` has a randomly generated password
and is issued for the Client and Server Authentication key usages.
This certificate is used by the WebListener App for SSL/TLS.

The generated Self-Signed Certificate `ClientCert.pfx` has a randomly generated password
and is not issued for any specific key usage.
This Certificate is used for Client Certificate Authentication with the WebListener App.
The port used for `-HttpsPort` will use TLS 1.2.

# Running WebListener

Expand Down
Binary file removed test/tools/Modules/WebListener/ServerCert.pfx
Binary file not shown.
3 changes: 3 additions & 0 deletions test/tools/Modules/WebListener/WebListener.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
Author = 'Mark Kraus'
Description = 'An HTTP and HTTPS Listener for testing purposes'
RootModule = 'WebListener.psm1'
RequiredModules = @(
'SelfSignedCertificate'
)
FunctionsToExport = @(
'Get-WebListener'
'Get-WebListenerClientCertificate'
Expand Down
75 changes: 71 additions & 4 deletions test/tools/Modules/WebListener/WebListener.psm1
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

Class WebListener
{
[int]$HttpPort
Expand All @@ -18,6 +19,67 @@ Class WebListener

[WebListener]$WebListener

function New-ClientCertificate
{
param([string]$CertificatePath, [string]$Password)

if ($Password)
{
$Passphrase = ConvertTo-SecureString -Force -AsPlainText $Password
}

$distinguishedName = @{
CN = 'adatum.com'
C = 'US'
S = 'Washington'
L = 'Redmond'
O = 'A. Datum Corporation'
OU = 'R&D'
E = 'randd@adatum.com'
}

$certificateParameters = @{
OutCertPath = $CertificatePath
StartDate = [datetime]::Now.Subtract([timespan]::FromDays(30))
Duration = [timespan]::FromDays(365)
Passphrase = $Passphrase
CertificateFormat = 'Pfx'
KeyLength = 4096
ForCertificateAuthority = $true
Force = $true
} + $distinguishedName

SelfSignedCertificate\New-SelfSignedCertificate @certificateParameters
}

function New-ServerCertificate
{
param([string]$CertificatePath, [string]$Password)

if ($Password)
{
$Passphrase = ConvertTo-SecureString -Force -AsPlainText $Password
}

$distinguishedName = @{
CN = 'localhost'
}

$certificateParameters = @{
OutCertPath = $CertificatePath
StartDate = [datetime]::Now.Subtract([timespan]::FromDays(30))
Duration = [timespan]::FromDays(1000)
Passphrase = $Passphrase
KeyUsage = 'DigitalSignature','KeyEncipherment'
EnhancedKeyUsage = 'ServerAuthentication','ClientAuthentication'
CertificateFormat = 'Pfx'
KeyLength = 2048
Force = $true
} + $distinguishedName

SelfSignedCertificate\New-SelfSignedCertificate @certificateParameters
}

function Get-WebListener
{
[CmdletBinding(ConfirmImpact = 'Low')]
Expand Down Expand Up @@ -60,11 +122,17 @@ function Start-WebListener
$initTimeoutSeconds = 15
$appDll = 'WebListener.dll'
$serverPfx = 'ServerCert.pfx'
$serverPfxPassword = 'password'
$serverPfxPassword = New-RandomHexString
$clientPfx = 'ClientCert.pfx'
$initCompleteMessage = 'Now listening on'
$sleepMilliseconds = 100

$serverPfxPath = Join-Path $MyInvocation.MyCommand.Module.ModuleBase $serverPfx
$serverPfxPath = Join-Path ([System.IO.Path]::GetTempPath()) $serverPfx
$Script:ClientPfxPath = Join-Path ([System.IO.Path]::GetTempPath()) $clientPfx
$Script:ClientPfxPassword = New-RandomHexString
New-ServerCertificate -CertificatePath $serverPfxPath -Password $serverPfxPassword
New-ClientCertificate -CertificatePath $Script:ClientPfxPath -Password $Script:ClientPfxPassword

$Job = Start-Job {
$path = Split-Path -parent (get-command WebListener).Path -Verbose
Push-Location $path -Verbose
Expand Down Expand Up @@ -130,8 +198,7 @@ function Get-WebListenerClientCertificate {
[OutputType([System.Security.Cryptography.X509Certificates.X509Certificate2])]
param()
process {
$pfxPath = Join-Path $MyInvocation.MyCommand.Module.ModuleBase 'ClientCert.pfx'
[System.Security.Cryptography.X509Certificates.X509Certificate2]::new($pfxPath,'password')
[System.Security.Cryptography.X509Certificates.X509Certificate2]::new($Script:ClientPfxPath, $Script:ClientPfxPassword)
}
}

Expand Down
4 changes: 4 additions & 0 deletions test/tools/WebListener/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ cd bin
dotnet WebListener.dll ServerCert.pfx password 8083 8084 8085 8086
```

**NOTE**: `ServerCert.pfx` is no longer a static asset
and you will need to create your own certificate for this purpose.
The `SelfSignedCertificate` module in the PowerShell Gallery provides this functionality.

The test site can then be accessed via `http://localhost:8083/`, `https://localhost:8084/`, `https://localhost:8085/`, or `https://localhost:8086/`.

The `WebListener.dll` takes 6 arguments:
Expand Down