From 7d59224855b5aadc139b88f241216c03417419f5 Mon Sep 17 00:00:00 2001 From: markekraus Date: Sat, 19 Aug 2017 13:10:18 -0500 Subject: [PATCH 01/17] [Feature] Add Tests for Web Cmdlet Certificate Authentication PowerShell/PowerShell#4609 --- .../WebCmdlets.Tests.ps1 | 198 ++++++------------ .../ClientCertificateCheck/.dockerignore | 3 + .../ClientCertificateCheck/ClientCert.pfx | Bin 0 -> 4293 bytes .../ClientCertificateCheck.csproj | 18 ++ .../ClientCertificateCheck/Pages/Error.cshtml | 23 ++ .../Pages/Error.cshtml.cs | 21 ++ .../ClientCertificateCheck/Pages/Index.cshtml | 10 + .../Pages/Index.cshtml.cs | 41 ++++ .../Pages/_Layout.cshtml | 1 + .../Pages/_ValidationScriptsPartial.cshtml | 1 + .../Pages/_ViewImports.cshtml | 3 + .../Pages/_ViewStart.cshtml | 3 + .../docker/ClientCertificateCheck/Program.cs | 48 +++++ .../docker/ClientCertificateCheck/README.md | 37 ++++ .../ClientCertificateCheck/ServerCert.pfx | Bin 0 -> 2553 bytes .../docker/ClientCertificateCheck/Startup.cs | 47 +++++ .../appsettings.Development.json | 10 + .../ClientCertificateCheck/appsettings.json | 8 + .../docker/ClientCertificateCheck/dockerfile | 18 ++ 19 files changed, 353 insertions(+), 137 deletions(-) create mode 100644 test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/.dockerignore create mode 100644 test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/ClientCert.pfx create mode 100644 test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/ClientCertificateCheck.csproj create mode 100644 test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/Error.cshtml create mode 100644 test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/Error.cshtml.cs create mode 100644 test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/Index.cshtml create mode 100644 test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/Index.cshtml.cs create mode 100644 test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/_Layout.cshtml create mode 100644 test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/_ValidationScriptsPartial.cshtml create mode 100644 test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/_ViewImports.cshtml create mode 100644 test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/_ViewStart.cshtml create mode 100644 test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Program.cs create mode 100644 test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/README.md create mode 100644 test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/ServerCert.pfx create mode 100644 test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Startup.cs create mode 100644 test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/appsettings.Development.json create mode 100644 test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/appsettings.json create mode 100644 test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/dockerfile diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 index 1ae16e8a685..6aba7410834 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 @@ -296,95 +296,6 @@ function ExecuteWebRequest return $result } -function GetSelfSignedCert { - <# - .NOTES - This certificate is not issued for any specific Key Usage - It cannot be used for any service that requires a specific key usage - It can be used for SSL/TLS Client Authentication - #> - $PfxBase64 = @' -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 -hqPP3QQIlSXpfTECuB4CAggA -'@ - $Bytes = [System.Convert]::FromBase64String($PfxBase64) - [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($Bytes) -} - <# Defines the list of redirect codes to test as well as the expected Method when the redirection is handled. @@ -919,31 +830,6 @@ Describe "Invoke-WebRequest tests" -Tags "Feature" { #endregion SkipHeaderVerification Tests - #region Certificate Authentication Tests - - # Test pending creation of native test solution - # https://github.com/PowerShell/PowerShell/issues/4609 - It "Verifies Invoke-WebRequest Certificate Authentication Fails without -Certificate" -Pending { - $command = 'Invoke-WebRequest https://prod.idrix.eu/secure/' - $result = ExecuteWebCommand -command $command - ValidateResponse -response $result - - $result.Output | Should Match ([regex]::Escape('Error: No SSL client certificate presented')) - } - - # Test pending creation of native test solution - # https://github.com/PowerShell/PowerShell/issues/4609 - It "Verifies Invoke-WebRequest Certificate Authentication Successful with -Certificate" -Pending { - $Certificate = GetSelfSignedCert - $command = 'Invoke-WebRequest https://prod.idrix.eu/secure/ -Certificate $Certificate' - $result = ExecuteWebCommand -command $command - ValidateResponse -response $result - - $result.Output.Content | Should Match ([regex]::Escape('SSL Authentication OK!')) - } - - #endregion Certificate Authentication Tests - #region charset encoding tests Context "BasicHtmlWebResponseObject Encoding tests" { @@ -1740,29 +1626,6 @@ Describe "Invoke-RestMethod tests" -Tags "Feature" { #endregion SkipHeaderVerification tests - #region Certificate Authentication Tests - - # Test pending creation of native test solution - # https://github.com/PowerShell/PowerShell/issues/4609 - It "Verifies Invoke-RestMethod Certificate Authentication Fails without -Certificate" -Pending { - $command = 'Invoke-RestMethod https://prod.idrix.eu/secure/' - $result = ExecuteWebCommand -command $command - - $result.Output | Should Match ([regex]::Escape('Error: No SSL client certificate presented')) - } - - # Test pending creation of native test solution - # https://github.com/PowerShell/PowerShell/issues/4609 - It "Verifies Invoke-RestMethod Certificate Authentication Successful with -Certificate" -Pending { - $Certificate = GetSelfSignedCert - $command = 'Invoke-RestMethod https://prod.idrix.eu/secure/ -Certificate $Certificate' - $result = ExecuteWebCommand -command $command - - $result.Output | Should Match ([regex]::Escape('SSL Authentication OK!')) - } - - #endregion Certificate Authentication Tests - BeforeEach { if ($env:http_proxy) { $savedHttpProxy = $env:http_proxy @@ -1893,3 +1756,64 @@ Describe "Web cmdlets tests using the cmdlet's aliases" -Tags "CI" { $result.Hello | Should Be "world" } } + +Describe -Name "Web cmdlets tests using Client Certificate Authentication" -Tags "Feature","Slow" { + + BeforeAll { + $portNumber = 8443 + $uri = "https://localhost:{0}/" -f $portNumber + $containerName = 'certcheck' + $initTimeoutSeconds = 15 + $containerPath = Join-Path $PSScriptRoot 'assets\docker\ClientCertificateCheck' + $pfxPath = Join-Path $containerPath 'ClientCert.pfx' + $initCompleteMessage = 'Now listening on' + $successMessage = 'Status: OK' + $failedMessage = 'Status: Failed' + + Push-Location $containerPath + $null = docker build -t $containerName . + $timeOut = (get-date).AddSeconds($initTimeoutSeconds) + $null = docker run -d -p ${portNumber}:${portNumber} --name $containerName $containerName $portNumber + # Wait until the container is running or until the initTimeoutSeconds have been reached + do + { + Start-Sleep -Seconds 1 + $containerStatus = docker logs --tail 3 $containerName | Out-String + $isRunning = $containerStatus -match $initCompleteMessage + } + while (-not $isRunning -and (get-date) -lt $timeOut) + + Pop-Location + + if (-not $isRunning) { + throw 'Container did not start before the timeout was reached.' + } + } + + AfterAll { + $null = docker kill $containerName + $null = docker rm $containerName + } + + It "Verifies Invoke-WebRequest Certificate Authentication Fails without -Certificate" { + $result = Invoke-WebRequest -Uri $uri -SkipCertificateCheck + $result.RawContent | Should Match ([regex]::Escape($failedMessage )) + } + + It "Verifies Invoke-WebRequest Certificate Authentication Successful with -Certificate" { + $certificate = Get-PfxCertificate -FilePath $pfxPath + $result = Invoke-WebRequest -Uri $uri -Certificate $certificate -SkipCertificateCheck + $result.RawContent | Should Match ([regex]::Escape($successMessage)) + } + + It "Verifies Invoke-RestMethod Certificate Authentication Fails without -Certificate" { + $result = Invoke-RestMethod -Uri $uri -SkipCertificateCheck + $result | Should Match ([regex]::Escape($failedMessage)) + } + + It "Verifies Invoke-RestMethod Certificate Authentication Successful with -Certificate" { + $certificate = Get-PfxCertificate -FilePath $pfxPath + $result = Invoke-RestMethod -uri $uri -Certificate $Certificate -SkipCertificateCheck + $result | Should Match ([regex]::Escape($successMessage)) + } +} \ No newline at end of file diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/.dockerignore b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/.dockerignore new file mode 100644 index 00000000000..8e104f73303 --- /dev/null +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/.dockerignore @@ -0,0 +1,3 @@ +bin/ +obj/ +node_modules/ \ No newline at end of file diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/ClientCert.pfx b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/ClientCert.pfx new file mode 100644 index 0000000000000000000000000000000000000000..4f21671e0ed271a806f567495b6e9445df5a3658 GIT binary patch literal 4293 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 + + Very simple ASP.NET Core 2.0 app to provide client certificate details if one is supplied in the webrequest. + netcoreapp2.0 + + + + + + + + + + + + + + diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/Error.cshtml b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/Error.cshtml new file mode 100644 index 00000000000..b1f3143a42e --- /dev/null +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/Error.cshtml @@ -0,0 +1,23 @@ +@page +@model ErrorModel +@{ + ViewData["Title"] = "Error"; +} + +

Error.

+

An error occurred while processing your request.

+ +@if (Model.ShowRequestId) +{ +

+ Request ID: @Model.RequestId +

+} + +

Development Mode

+

+ Swapping to Development environment will display more detailed information about the error that occurred. +

+

+ Development environment should not be enabled in deployed applications, as it can result in sensitive information from exceptions being displayed to end users. For local debugging, development environment can be enabled by setting the ASPNETCORE_ENVIRONMENT environment variable to Development, and restarting the application. +

diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/Error.cshtml.cs b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/Error.cshtml.cs new file mode 100644 index 00000000000..c068c103139 --- /dev/null +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/Error.cshtml.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc.RazorPages; + +namespace ClientCertificateCheck.Pages +{ + public class ErrorModel : PageModel + { + public string RequestId { get; set; } + + public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); + + public void OnGet() + { + RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier; + } + } +} diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/Index.cshtml b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/Index.cshtml new file mode 100644 index 00000000000..7448f01e1d9 --- /dev/null +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/Index.cshtml @@ -0,0 +1,10 @@ +@page +@model IndexModel +Status: @Model.Status +Thumbprint: @Model.CertThumbprint +Subject: @Model.CertSubject +Subject Name: @Model.CertSubjectName +Issuer: @Model.CertIssuer +Issuer Name: @Model.CertIssuerName +Not After: @Model.CertNotAfter +Not Before: @Model.CertNotBefore \ No newline at end of file diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/Index.cshtml.cs b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/Index.cshtml.cs new file mode 100644 index 00000000000..d810145b5ad --- /dev/null +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/Index.cshtml.cs @@ -0,0 +1,41 @@ +using System; +using System.Text; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.AspNetCore.Server.Kestrel.Https; + +namespace ClientCertificateCheck.Pages +{ + public class IndexModel : PageModel + { + public string CertSubject; + public string CertNotAfter; + public string CertNotBefore; + public string CertIssuer; + public string CertIssuerName; + public string CertSubjectName; + public string CertThumbprint; + public string Status = "FAILED"; + + public void OnGet() + { + if(null == HttpContext.Connection.ClientCertificate){ + return; + } + CertSubject = HttpContext.Connection.ClientCertificate.Subject; + CertNotAfter = HttpContext.Connection.ClientCertificate.NotAfter.ToString(); + CertNotBefore = HttpContext.Connection.ClientCertificate.NotBefore.ToString(); + CertIssuer = HttpContext.Connection.ClientCertificate.Issuer; + CertIssuerName = HttpContext.Connection.ClientCertificate.IssuerName.Name; + CertSubjectName = HttpContext.Connection.ClientCertificate.SubjectName.Name; + CertThumbprint = HttpContext.Connection.ClientCertificate.Thumbprint; + if (!string.IsNullOrEmpty(CertThumbprint)) + { + Status = "OK"; + } + } + } +} diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/_Layout.cshtml b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/_Layout.cshtml new file mode 100644 index 00000000000..1dfa991769d --- /dev/null +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/_Layout.cshtml @@ -0,0 +1 @@ +@RenderBody() \ No newline at end of file diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/_ValidationScriptsPartial.cshtml b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/_ValidationScriptsPartial.cshtml new file mode 100644 index 00000000000..5f282702bb0 --- /dev/null +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/_ValidationScriptsPartial.cshtml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/_ViewImports.cshtml b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/_ViewImports.cshtml new file mode 100644 index 00000000000..a460a0f7cad --- /dev/null +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/_ViewImports.cshtml @@ -0,0 +1,3 @@ +@using ClientCertificateCheck +@namespace ClientCertificateCheck.Pages +@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/_ViewStart.cshtml b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/_ViewStart.cshtml new file mode 100644 index 00000000000..a5f10045db9 --- /dev/null +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/_ViewStart.cshtml @@ -0,0 +1,3 @@ +@{ + Layout = "_Layout"; +} diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Program.cs b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Program.cs new file mode 100644 index 00000000000..51456c778e3 --- /dev/null +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Program.cs @@ -0,0 +1,48 @@ +using System; +using System.Net; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using Microsoft.AspNetCore.Server.Kestrel.Https; +using System.Security.Authentication; +using System.Security.Cryptography.X509Certificates; + +namespace ClientCertificateCheck +{ + public class Program + { + public static void Main(string[] args) + { + if (args.Count() != 3) + { + System.Console.WriteLine("Required: "); + Environment.Exit(1); + } + BuildWebHost(args).Run(); + } + + public static IWebHost BuildWebHost(string[] args) => + WebHost.CreateDefaultBuilder() + .UseStartup() + .UseKestrel(options => + { + options.Listen(IPAddress.Any, int.Parse(args[2]), listenOptions => + { + var certificate = new X509Certificate2(args[0], args[1]); + HttpsConnectionAdapterOptions httpsOption = new HttpsConnectionAdapterOptions(); + httpsOption.SslProtocols = SslProtocols.Tls12; + httpsOption.ClientCertificateMode = ClientCertificateMode.AllowCertificate; + httpsOption.ClientCertificateValidation = (inCertificate, inChain, inPolicy) => {return true;}; + httpsOption.CheckCertificateRevocation = false; + httpsOption.ServerCertificate = certificate; + listenOptions.UseHttps(httpsOption); + }); + }) + .Build(); + } +} diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/README.md b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/README.md new file mode 100644 index 00000000000..6b5ba131869 --- /dev/null +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/README.md @@ -0,0 +1,37 @@ +# ClientCertificateCheck + +ASP.NET Core 2.0 Docker Container for testing Client Certificate Authentication. +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 Asp.Net Kestrel server for SSL/TLS. The included SelF-Signed Certificate `ClientCert.pfx` has no password and has not been issued for any specific key usage. + +The Kestrel server will bind on the port passed to the `docker run` command. + +``` +docker build -t clientcertificatecheck . +docker run -d -p 8443:8443 --name clientcertificatecheck clientcertificatecheck 8443 +``` + +The test site can then be accessed via `https://localhost:8443/`. The default page will return information about the certificate is one was provided. + +Certificate Provided in request: +``` +Status: OK +Thumbprint: 2DECF1348FF21B780F45D316A039B5EB4C6312F7 +Subject: E=randd@adatum.com, CN=adatum.com, OU=R&D, O=A. Datum Corporation, L=Redmond, S=Washington, C=US +Subject Name: E=randd@adatum.com, CN=adatum.com, OU=R&D, O=A. Datum Corporation, L=Redmond, S=Washington, C=US +Issuer: E=randd@adatum.com, CN=adatum.com, OU=R&D, O=A. Datum Corporation, L=Redmond, S=Washington, C=US +Issuer Name: E=randd@adatum.com, CN=adatum.com, OU=R&D, O=A. Datum Corporation, L=Redmond, S=Washington, C=US +Not After: 12/26/2044 18:16:46 +Not Before: 08/10/2017 18:16:46 +``` + +No certificate provided in request: +``` +Status: FAILED +Thumbprint: +Subject: +Subject Name: +Issuer: +Issuer Name: +Not After: +Not Before: +``` \ No newline at end of file diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/ServerCert.pfx b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/ServerCert.pfx new file mode 100644 index 0000000000000000000000000000000000000000..dd1cf6a9a8152d145ca2c349eb0f427103172ceb GIT binary patch literal 2553 zcmZ`*3piA1A3x{JnK3g4L!#YrPssI*8MjQj42D!|T}oOa#w|;^mWCJ^msqz#DTYGs zmnFnj-xO`3RxT-`rAY1@a!J0UZ@1m=dA{#C&;Pvt|L_0)e((Fd=l#F$LAZnk2*e;< zLN$({&a>cs6aj@mK9`UWa|t;pdZI#dmq#kjCe&L0ssWn$m{1h!LhuhN zWu5a3wC~cFaObOsrf18piiSVdW|*2QtJ8gysCyngEzHWs2Y3tJP+N#@drJ!S&KcIxl2R(R+7t@ZV4($&2a-bm2Q1auVp>Oj=OAn|1qIu0pj%9p}oL7 zr?q^wecUMn7vcN9yehQ%wZgg5Ai;|Fu}}0Cc?~Fw_npLg<|KYxf^sBK&=z>m>Rf77 z=h~gQcODO;tC|)~986MhMZ~Z@Y+PL8AYKZ#^?4aMf4ikMoYdV!epav_;=J4(le!qI z1@;>3dj5eH8aX+!90f(!j$f7CZykqY&gGP>*M#&CCkmT6&a^U zoSBf$-}^F%p;~tBNele8=hP&FV@_f+Qpcv9Ih7UNyW3sbh&d72tayg<V#Q(XXC{W!2uzXIlhb%cLnthq?9gib?(>Ugv$e5#WimmEvY$$067Hvh%~Yjf0N9 z$?(6Lm{o6jF!S_cGc-E556ms+iRZ0qdsWO^Mce;0WLfAHL;Kxp$ANK%^@(fe>eSQ@H>hrQEcRrB2i&F)YuURws zt@frv?}~3uVWA6l#4Lr2Z4S`RSGP)!xHai0KJ3ypoGK~utU7mFW%4&4VibcJx=9ju z*!rVVVs0fn>PME9a&+b85qrH`Z-ig?h&yd>{j9n_t}i^_EMBr0z2vJ31Tqs@=_iOwYTE2FziVu-#)9nHHwO-a@_Yd8aoU zn(Q7`P6^MFA2Hhe0%=ZnP9D*Y+F3IO+tUn>ZVy!KSGqf6DlT@vDxhVGDAIBSpYG{> zwSN27_W6E4uRk1xe%=DHmG_Wzj(6yg?Nfd_oMI_3aC|@9Wxg0SS-a)im;oaB#;ZV) znJ(+$LRC#qX=}VlDdBUdRy_rIulv@Mk3xisOs0thL zwn7$ppm}be2|t)0B6`7H>=!*hzocH4d4zOl zk~My*WFjxbA>m)A@Q=D8yN67C2-U}&HLCoNIO1K#4sBmA_p@{IBsHfTlFKc%6>+w` zUwWMNX+fA1e0U9ePlqvnD&}nP7|#7B+#+Xr>bg?%+sUSNucv13WS1Ja2}H@_t%G#S zvwk(=ed9dV!4i0&(2z(m7b%sCW3i(2SE?*I&%R6xPMZvcYS27!bU@F)%=TyT<) zfj|f%%awG+&bN&7_O?eS4Y@5pMnt|20t#aRM3O3jkZ~A$7(*iX`n$RMdie(iAqvtW zR0G72YN$)4>FOFeZV}U^{squ=X^7+h;c-Ewe+~d*0Sp%u1JL;pAub346)l$nnt!=9 zbGy3-sL_4X^^{FKFuJsMK{icw_Sz2-Hfru(qGA=#BqDtpm}w1FFThkSmLJy%n#&6TV5abMvTylYppD+#rAK+D*DehmK$_+bA6GMZHgn@+Sv} zALXBn>-Lf1nbM4vr$0_A#4#k;o@TY{+m!sFX#UtY@jD;unFd0ZV^SphUiX*<&iR-# z(r@f68+-IVKWLj#-QK6Fk_gX6QmbB;L_%i*Qgu#gt8UFHp|`Alu22zKd71X=P`Xqv zqre%9oZzW=QA7JKF|%b0&2oCLOZjPel*HO^vGsi{n?tm9suY-_X2t8As*p~kuQem}!k z#ro7?w_1#Yx*CPX^lXWErMj58HEyu)X0-;XXo*#$nOtI=ETFi*hzW`3sH|iJG<~Y# zXabGT%vpG&3rX>=7!x7uP#)5#=N;HJ-mvSio9)r@^i-gT*_vRWZSR&wXN}0RxA_mA zJyZOWTS@&+y+DO(`o9ket*`r^AW2n_lLMH5FIt0azz?lo=0+u=tsUA1qAh?JBl3t4 z4yz%Gfxd+$r;0+Ry!VxV-ZY&wp|FE`PxgDiIatz{SYUq7xTy+SH5!$Oo!$4y>Lh97 GC+y!b4Ho49 literal 0 HcmV?d00001 diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Startup.cs b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Startup.cs new file mode 100644 index 00000000000..aaed4a0e887 --- /dev/null +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Startup.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +namespace ClientCertificateCheck +{ + public class Startup + { + public Startup(IConfiguration configuration) + { + Configuration = configuration; + } + + public IConfiguration Configuration { get; } + + public void ConfigureServices(IServiceCollection services) + { + services.AddMvc(); + } + + public void Configure(IApplicationBuilder app, IHostingEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + else + { + app.UseExceptionHandler("/Error"); + } + + app.UseStaticFiles(); + + app.UseMvc(routes => + { + routes.MapRoute( + name: "default", + template: "{controller}/{action=Index}/{id?}"); + }); + } + } +} diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/appsettings.Development.json b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/appsettings.Development.json new file mode 100644 index 00000000000..fa8ce71a97a --- /dev/null +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/appsettings.Development.json @@ -0,0 +1,10 @@ +{ + "Logging": { + "IncludeScopes": false, + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Information" + } + } +} diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/appsettings.json b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/appsettings.json new file mode 100644 index 00000000000..5fff67bacc4 --- /dev/null +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/appsettings.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "IncludeScopes": false, + "LogLevel": { + "Default": "Warning" + } + } +} diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/dockerfile b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/dockerfile new file mode 100644 index 00000000000..ea8c0a0c580 --- /dev/null +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/dockerfile @@ -0,0 +1,18 @@ +# Stage 1: Build the Application +FROM microsoft/aspnetcore-build:2.0.0-jessie AS builder +WORKDIR /source +COPY *.csproj ./ +RUN dotnet restore +COPY . . +RUN dotnet publish --output /app/ --configuration Release + +# Stage 2: Create runtime container +FROM microsoft/aspnetcore:2.0.0-jessie +WORKDIR /app +COPY --from=builder /app . +# ClientCertificateCheck access 3 paramters: +# +# The Certificate is published to /app +ENTRYPOINT ["dotnet", "ClientCertificateCheck.dll", "ServerCert.pfx", "password"] +# Allow for easy override of HTTPS binding Port +CMD ["8443"] \ No newline at end of file From ac8c68e1107fe622135862571195aae29f6959b9 Mon Sep 17 00:00:00 2001 From: markekraus Date: Sun, 20 Aug 2017 05:17:59 -0500 Subject: [PATCH 02/17] [Feature] Add Tests for Web Cmdlet Certificate Authentication PowerShell/PowerShell#4609 --- .../WebCmdlets.Tests.ps1 | 46 +++++++++++------- .../ClientCertificateCheck/.dockerignore | 3 -- .../ClientCertificateCheck/.dockerignore | 3 ++ .../ClientCertificateCheck/ClientCert.pfx | Bin .../ClientCertificateCheck.csproj | 0 .../ClientCertificateCheck/Pages/Error.cshtml | 0 .../Pages/Error.cshtml.cs | 0 .../ClientCertificateCheck/Pages/Index.cshtml | 0 .../Pages/Index.cshtml.cs | 0 .../Pages/_Layout.cshtml | 0 .../Pages/_ValidationScriptsPartial.cshtml | 0 .../Pages/_ViewImports.cshtml | 0 .../Pages/_ViewStart.cshtml | 0 .../ClientCertificateCheck/Program.cs | 0 .../ClientCertificateCheck/README.md | 41 +++++++++++----- .../ClientCertificateCheck/ServerCert.pfx | Bin .../ClientCertificateCheck/Startup.cs | 0 .../appsettings.Development.json | 0 .../ClientCertificateCheck/appsettings.json | 0 .../ClientCertificateCheck/dockerfile | 2 +- 20 files changed, 62 insertions(+), 33 deletions(-) delete mode 100644 test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/.dockerignore create mode 100644 test/tools/ClientCertificateCheck/.dockerignore rename test/{powershell/Modules/Microsoft.PowerShell.Utility/assets/docker => tools}/ClientCertificateCheck/ClientCert.pfx (100%) rename test/{powershell/Modules/Microsoft.PowerShell.Utility/assets/docker => tools}/ClientCertificateCheck/ClientCertificateCheck.csproj (100%) rename test/{powershell/Modules/Microsoft.PowerShell.Utility/assets/docker => tools}/ClientCertificateCheck/Pages/Error.cshtml (100%) rename test/{powershell/Modules/Microsoft.PowerShell.Utility/assets/docker => tools}/ClientCertificateCheck/Pages/Error.cshtml.cs (100%) rename test/{powershell/Modules/Microsoft.PowerShell.Utility/assets/docker => tools}/ClientCertificateCheck/Pages/Index.cshtml (100%) rename test/{powershell/Modules/Microsoft.PowerShell.Utility/assets/docker => tools}/ClientCertificateCheck/Pages/Index.cshtml.cs (100%) rename test/{powershell/Modules/Microsoft.PowerShell.Utility/assets/docker => tools}/ClientCertificateCheck/Pages/_Layout.cshtml (100%) rename test/{powershell/Modules/Microsoft.PowerShell.Utility/assets/docker => tools}/ClientCertificateCheck/Pages/_ValidationScriptsPartial.cshtml (100%) rename test/{powershell/Modules/Microsoft.PowerShell.Utility/assets/docker => tools}/ClientCertificateCheck/Pages/_ViewImports.cshtml (100%) rename test/{powershell/Modules/Microsoft.PowerShell.Utility/assets/docker => tools}/ClientCertificateCheck/Pages/_ViewStart.cshtml (100%) rename test/{powershell/Modules/Microsoft.PowerShell.Utility/assets/docker => tools}/ClientCertificateCheck/Program.cs (100%) rename test/{powershell/Modules/Microsoft.PowerShell.Utility/assets/docker => tools}/ClientCertificateCheck/README.md (65%) rename test/{powershell/Modules/Microsoft.PowerShell.Utility/assets/docker => tools}/ClientCertificateCheck/ServerCert.pfx (100%) rename test/{powershell/Modules/Microsoft.PowerShell.Utility/assets/docker => tools}/ClientCertificateCheck/Startup.cs (100%) rename test/{powershell/Modules/Microsoft.PowerShell.Utility/assets/docker => tools}/ClientCertificateCheck/appsettings.Development.json (100%) rename test/{powershell/Modules/Microsoft.PowerShell.Utility/assets/docker => tools}/ClientCertificateCheck/appsettings.json (100%) rename test/{powershell/Modules/Microsoft.PowerShell.Utility/assets/docker => tools}/ClientCertificateCheck/dockerfile (97%) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 index 6aba7410834..2c3910acd35 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 @@ -1757,33 +1757,44 @@ Describe "Web cmdlets tests using the cmdlet's aliases" -Tags "CI" { } } -Describe -Name "Web cmdlets tests using Client Certificate Authentication" -Tags "Feature","Slow" { +Describe -Name "Web cmdlets tests using Client Certificate Authentication" -Tags "Feature" { BeforeAll { $portNumber = 8443 $uri = "https://localhost:{0}/" -f $portNumber - $containerName = 'certcheck' $initTimeoutSeconds = 15 - $containerPath = Join-Path $PSScriptRoot 'assets\docker\ClientCertificateCheck' - $pfxPath = Join-Path $containerPath 'ClientCert.pfx' + $projectRootPath = Resolve-Path (Join-Path $PSScriptRoot "\..\..\..\..\") + $appSrcPath = Join-Path $projectRootPath 'test\tools\ClientCertificateCheck' + $buildPsm = Join-Path $projectRootPath 'build.psm1' + $appPublishPath = Join-Path $appSrcPath 'bin' + $appDllPath = Join-Path $appPublishPath 'ClientCertificateCheck.dll' + $serverPfxPath = Join-Path $appSrcPath 'ServerCert.pfx' + $serverPfxPassword = 'password' + $clientPfxPath = Join-Path $appSrcPath 'ClientCert.pfx' $initCompleteMessage = 'Now listening on' $successMessage = 'Status: OK' $failedMessage = 'Status: Failed' - Push-Location $containerPath - $null = docker build -t $containerName . + Import-Module $buildPsm + Find-Dotnet + Push-Location $appSrcPath + dotnet restore + dotnet publish --output $appPublishPath --configuration Release $timeOut = (get-date).AddSeconds($initTimeoutSeconds) - $null = docker run -d -p ${portNumber}:${portNumber} --name $containerName $containerName $portNumber - # Wait until the container is running or until the initTimeoutSeconds have been reached + Pop-Location + $Job = Start-Job { + Push-Location $using:appPublishPath + dotnet $using:appDllPath $using:serverPfxPath $using:serverPfxPassword $using:portNumber + } + # Wait until the app is running or until the initTimeoutSeconds have been reached do { Start-Sleep -Seconds 1 - $containerStatus = docker logs --tail 3 $containerName | Out-String + $containerStatus = $Job.ChildJobs[0].Output | Out-String $isRunning = $containerStatus -match $initCompleteMessage } while (-not $isRunning -and (get-date) -lt $timeOut) - - Pop-Location + $Job.ChildJobs[0].Output if (-not $isRunning) { throw 'Container did not start before the timeout was reached.' @@ -1791,8 +1802,7 @@ Describe -Name "Web cmdlets tests using Client Certificate Authentication" -Tags } AfterAll { - $null = docker kill $containerName - $null = docker rm $containerName + $Job | Stop-Job -PassThru | Remove-Job } It "Verifies Invoke-WebRequest Certificate Authentication Fails without -Certificate" { @@ -1801,9 +1811,10 @@ Describe -Name "Web cmdlets tests using Client Certificate Authentication" -Tags } It "Verifies Invoke-WebRequest Certificate Authentication Successful with -Certificate" { - $certificate = Get-PfxCertificate -FilePath $pfxPath + $certificate = Get-PfxCertificate -FilePath $clientPfxPath $result = Invoke-WebRequest -Uri $uri -Certificate $certificate -SkipCertificateCheck $result.RawContent | Should Match ([regex]::Escape($successMessage)) + $result.RawContent | Should Match $certificate.Thumbprint } It "Verifies Invoke-RestMethod Certificate Authentication Fails without -Certificate" { @@ -1812,8 +1823,9 @@ Describe -Name "Web cmdlets tests using Client Certificate Authentication" -Tags } It "Verifies Invoke-RestMethod Certificate Authentication Successful with -Certificate" { - $certificate = Get-PfxCertificate -FilePath $pfxPath - $result = Invoke-RestMethod -uri $uri -Certificate $Certificate -SkipCertificateCheck + $certificate = Get-PfxCertificate -FilePath $clientPfxPath + $result = Invoke-RestMethod -uri $uri -Certificate $certificate -SkipCertificateCheck $result | Should Match ([regex]::Escape($successMessage)) + $result | Should Match $certificate.Thumbprint } -} \ No newline at end of file +} diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/.dockerignore b/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/.dockerignore deleted file mode 100644 index 8e104f73303..00000000000 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/.dockerignore +++ /dev/null @@ -1,3 +0,0 @@ -bin/ -obj/ -node_modules/ \ No newline at end of file diff --git a/test/tools/ClientCertificateCheck/.dockerignore b/test/tools/ClientCertificateCheck/.dockerignore new file mode 100644 index 00000000000..c94194bca83 --- /dev/null +++ b/test/tools/ClientCertificateCheck/.dockerignore @@ -0,0 +1,3 @@ +bin/ +obj/ +node_modules/ diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/ClientCert.pfx b/test/tools/ClientCertificateCheck/ClientCert.pfx similarity index 100% rename from test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/ClientCert.pfx rename to test/tools/ClientCertificateCheck/ClientCert.pfx diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/ClientCertificateCheck.csproj b/test/tools/ClientCertificateCheck/ClientCertificateCheck.csproj similarity index 100% rename from test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/ClientCertificateCheck.csproj rename to test/tools/ClientCertificateCheck/ClientCertificateCheck.csproj diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/Error.cshtml b/test/tools/ClientCertificateCheck/Pages/Error.cshtml similarity index 100% rename from test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/Error.cshtml rename to test/tools/ClientCertificateCheck/Pages/Error.cshtml diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/Error.cshtml.cs b/test/tools/ClientCertificateCheck/Pages/Error.cshtml.cs similarity index 100% rename from test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/Error.cshtml.cs rename to test/tools/ClientCertificateCheck/Pages/Error.cshtml.cs diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/Index.cshtml b/test/tools/ClientCertificateCheck/Pages/Index.cshtml similarity index 100% rename from test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/Index.cshtml rename to test/tools/ClientCertificateCheck/Pages/Index.cshtml diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/Index.cshtml.cs b/test/tools/ClientCertificateCheck/Pages/Index.cshtml.cs similarity index 100% rename from test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/Index.cshtml.cs rename to test/tools/ClientCertificateCheck/Pages/Index.cshtml.cs diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/_Layout.cshtml b/test/tools/ClientCertificateCheck/Pages/_Layout.cshtml similarity index 100% rename from test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/_Layout.cshtml rename to test/tools/ClientCertificateCheck/Pages/_Layout.cshtml diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/_ValidationScriptsPartial.cshtml b/test/tools/ClientCertificateCheck/Pages/_ValidationScriptsPartial.cshtml similarity index 100% rename from test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/_ValidationScriptsPartial.cshtml rename to test/tools/ClientCertificateCheck/Pages/_ValidationScriptsPartial.cshtml diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/_ViewImports.cshtml b/test/tools/ClientCertificateCheck/Pages/_ViewImports.cshtml similarity index 100% rename from test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/_ViewImports.cshtml rename to test/tools/ClientCertificateCheck/Pages/_ViewImports.cshtml diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/_ViewStart.cshtml b/test/tools/ClientCertificateCheck/Pages/_ViewStart.cshtml similarity index 100% rename from test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Pages/_ViewStart.cshtml rename to test/tools/ClientCertificateCheck/Pages/_ViewStart.cshtml diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Program.cs b/test/tools/ClientCertificateCheck/Program.cs similarity index 100% rename from test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Program.cs rename to test/tools/ClientCertificateCheck/Program.cs diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/README.md b/test/tools/ClientCertificateCheck/README.md similarity index 65% rename from test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/README.md rename to test/tools/ClientCertificateCheck/README.md index 6b5ba131869..96a7cc6ae3a 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/README.md +++ b/test/tools/ClientCertificateCheck/README.md @@ -1,16 +1,9 @@ -# ClientCertificateCheck +# Client Certificate Check -ASP.NET Core 2.0 Docker Container for testing Client Certificate Authentication. -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 Asp.Net Kestrel server for SSL/TLS. The included SelF-Signed Certificate `ClientCert.pfx` has no password and has not been issued for any specific key usage. +ASP.NET Core 2.0 app for testing Client Certificate Authentication. +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 Asp.Net Kestrel server for SSL/TLS. The included SelF-Signed Certificate `ClientCert.pfx` has no password and has not been issued for any specific key usage. The app can be run directly with `dotnet` or as a Docker container. -The Kestrel server will bind on the port passed to the `docker run` command. - -``` -docker build -t clientcertificatecheck . -docker run -d -p 8443:8443 --name clientcertificatecheck clientcertificatecheck 8443 -``` - -The test site can then be accessed via `https://localhost:8443/`. The default page will return information about the certificate is one was provided. +The default page will return information about the certificate is one was provided. Certificate Provided in request: ``` @@ -34,4 +27,28 @@ Issuer: Issuer Name: Not After: Not Before: -``` \ No newline at end of file +``` + +# Run with `dotnet` + +``` +dotnet restore +dotnet dotnet publish --output app --configuration Release +cd app +dotnet ClientCertificateCheck.dll ServerCert.pfx password 8443 +``` + +The test site can then be accessed via `https://localhost:8443/`. + +The `ClientCertificateCheck.dll` takes 3 arguments: the path to the Server Certificate, the Server Certificate Password, and the TCP Port to bind on. + +# Run As a Docker Container + +``` +docker build -t clientcertificatecheck . +docker run -d -p 8443:8443 --name clientcertificatecheck clientcertificatecheck 8443 +``` + +The Kestrel server will bind on the port passed to the `docker run` command. + +The test site can then be accessed via `https://localhost:8443/`. diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/ServerCert.pfx b/test/tools/ClientCertificateCheck/ServerCert.pfx similarity index 100% rename from test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/ServerCert.pfx rename to test/tools/ClientCertificateCheck/ServerCert.pfx diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Startup.cs b/test/tools/ClientCertificateCheck/Startup.cs similarity index 100% rename from test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/Startup.cs rename to test/tools/ClientCertificateCheck/Startup.cs diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/appsettings.Development.json b/test/tools/ClientCertificateCheck/appsettings.Development.json similarity index 100% rename from test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/appsettings.Development.json rename to test/tools/ClientCertificateCheck/appsettings.Development.json diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/appsettings.json b/test/tools/ClientCertificateCheck/appsettings.json similarity index 100% rename from test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/appsettings.json rename to test/tools/ClientCertificateCheck/appsettings.json diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/dockerfile b/test/tools/ClientCertificateCheck/dockerfile similarity index 97% rename from test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/dockerfile rename to test/tools/ClientCertificateCheck/dockerfile index ea8c0a0c580..5dfe05b21f6 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/assets/docker/ClientCertificateCheck/dockerfile +++ b/test/tools/ClientCertificateCheck/dockerfile @@ -15,4 +15,4 @@ COPY --from=builder /app . # The Certificate is published to /app ENTRYPOINT ["dotnet", "ClientCertificateCheck.dll", "ServerCert.pfx", "password"] # Allow for easy override of HTTPS binding Port -CMD ["8443"] \ No newline at end of file +CMD ["8443"] From 44731c8a8d58b96d9bea40747fe91c6020b12703 Mon Sep 17 00:00:00 2001 From: markekraus Date: Sun, 20 Aug 2017 08:25:41 -0500 Subject: [PATCH 03/17] [feature] Add new app to Publish-PSTestTools refactor tests also add ASP.NET to .spelling --- .spelling | 1 + build.psm1 | 1 + .../WebCmdlets.Tests.ps1 | 159 ++++++++++-------- 3 files changed, 88 insertions(+), 73 deletions(-) diff --git a/.spelling b/.spelling index 8fbd0529464..b7d7da30656 100644 --- a/.spelling +++ b/.spelling @@ -13,6 +13,7 @@ AppImage AppVeyor artifact artifacts +ASP.NET AssemblyLoadContext behavior behaviors diff --git a/build.psm1 b/build.psm1 index 0ad818f2cea..3d448030916 100644 --- a/build.psm1 +++ b/build.psm1 @@ -778,6 +778,7 @@ function Publish-PSTestTools { $tools = @( @{Path="${PSScriptRoot}/test/tools/TestExe";Output="testexe"} + @{Path="${PSScriptRoot}/test/tools/ClientCertificateCheck";Output="ClientCertificateCheck"} ) if ($null -eq $Options) { diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 index 2c3910acd35..64a01c7e089 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 @@ -296,6 +296,46 @@ function ExecuteWebRequest return $result } +# Starts the ClientCertificateCheck listener +function StartClientCertificateCheck +{ + param([int]$Port) + $initTimeoutSeconds = 15 + $projectRootPath = Resolve-Path (Join-Path $PSScriptRoot "\..\..\..\..\") + $appSrcPath = Join-Path $projectRootPath 'test\tools\ClientCertificateCheck' + $appPublishPath = Join-Path $appSrcPath 'bin' + $appDllPath = Join-Path $appPublishPath 'ClientCertificateCheck.dll' + $serverPfxPath = Join-Path $appSrcPath 'ServerCert.pfx' + $serverPfxPassword = 'password' + $initCompleteMessage = 'Now listening on' + + $timeOut = (get-date).AddSeconds($initTimeoutSeconds) + $Job = Start-Job { + Push-Location $using:appPublishPath + dotnet $using:appDllPath $using:serverPfxPath $using:serverPfxPassword $using:port + } + # Wait until the app is running or until the initTimeoutSeconds have been reached + do + { + Start-Sleep -Seconds 1 + $containerStatus = $Job.ChildJobs[0].Output | Out-String + $isRunning = $containerStatus -match $initCompleteMessage + } + while (-not $isRunning -and (get-date) -lt $timeOut) + + if (-not $isRunning) { + throw 'Container did not start before the timeout was reached.' + } + return $job +} + +# Stops the ClientCertificateCheck listener +function StopClientCertificateCheck +{ + param($Job) + $Job | Stop-Job -PassThru | Remove-Job +} + <# Defines the list of redirect codes to test as well as the expected Method when the redirection is handled. @@ -323,11 +363,13 @@ Describe "Invoke-WebRequest tests" -Tags "Feature" { BeforeAll { $response = Start-HttpListener -Port 8080 + $certificateChecker = StartClientCertificateCheck -Port 8443 } AfterAll { $null = Stop-HttpListener -Port 8080 $response.PowerShell.Dispose() + StopClientCertificateCheck -Job $certificateChecker } # Validate the output of Invoke-WebRequest @@ -1108,6 +1150,27 @@ Describe "Invoke-WebRequest tests" -Tags "Feature" { #endregion Content Header Inclusion + #region Client Certificate Authentication + + It "Verifies Invoke-WebRequest Certificate Authentication Fails without -Certificate" { + $uri = 'https://localhost:8443/' + $result = Invoke-WebRequest -Uri $uri -SkipCertificateCheck + $failedMessage = 'Status: Failed' + $result.RawContent | Should Match ([regex]::Escape($failedMessage )) + } + + It "Verifies Invoke-WebRequest Certificate Authentication Successful with -Certificate" { + $uri = 'https://localhost:8443/' + $clientPfxPath = Resolve-Path (Join-Path $PSScriptRoot "\..\..\..\tools\ClientCertificateCheck\ClientCert.pfx") + $certificate = Get-PfxCertificate -FilePath $clientPfxPath + $result = Invoke-WebRequest -Uri $uri -Certificate $certificate -SkipCertificateCheck + $successMessage = 'Status: OK' + $result.RawContent | Should Match ([regex]::Escape($successMessage)) + $result.RawContent | Should Match $certificate.Thumbprint + } + + #edregion Client Certificate Authentication + BeforeEach { if ($env:http_proxy) { $savedHttpProxy = $env:http_proxy @@ -1139,11 +1202,13 @@ Describe "Invoke-RestMethod tests" -Tags "Feature" { BeforeAll { $response = Start-HttpListener -Port 8081 + $certificateChecker = StartClientCertificateCheck -Port 8443 } AfterAll { $null = Stop-HttpListener -Port 8081 $response.PowerShell.Dispose() + StopClientCertificateCheck -Job $certificateChecker } It "Invoke-RestMethod returns User-Agent" { @@ -1626,6 +1691,27 @@ Describe "Invoke-RestMethod tests" -Tags "Feature" { #endregion SkipHeaderVerification tests + #region Client Certificate Authentication + + It "Verifies Invoke-RestMethod Certificate Authentication Fails without -Certificate" { + $uri = 'https://localhost:8443/' + $result = Invoke-RestMethod -Uri $uri -SkipCertificateCheck + $failedMessage = 'Status: Failed' + $result | Should Match ([regex]::Escape($failedMessage)) + } + + It "Verifies Invoke-RestMethod Certificate Authentication Successful with -Certificate" { + $uri = 'https://localhost:8443/' + $clientPfxPath = Resolve-Path (Join-Path $PSScriptRoot "\..\..\..\tools\ClientCertificateCheck\ClientCert.pfx") + $certificate = Get-PfxCertificate -FilePath $clientPfxPath + $result = Invoke-RestMethod -uri $uri -Certificate $certificate -SkipCertificateCheck + $successMessage = 'Status: OK' + $result | Should Match ([regex]::Escape($successMessage)) + $result | Should Match $certificate.Thumbprint + } + + #edregion Client Certificate Authentication + BeforeEach { if ($env:http_proxy) { $savedHttpProxy = $env:http_proxy @@ -1756,76 +1842,3 @@ Describe "Web cmdlets tests using the cmdlet's aliases" -Tags "CI" { $result.Hello | Should Be "world" } } - -Describe -Name "Web cmdlets tests using Client Certificate Authentication" -Tags "Feature" { - - BeforeAll { - $portNumber = 8443 - $uri = "https://localhost:{0}/" -f $portNumber - $initTimeoutSeconds = 15 - $projectRootPath = Resolve-Path (Join-Path $PSScriptRoot "\..\..\..\..\") - $appSrcPath = Join-Path $projectRootPath 'test\tools\ClientCertificateCheck' - $buildPsm = Join-Path $projectRootPath 'build.psm1' - $appPublishPath = Join-Path $appSrcPath 'bin' - $appDllPath = Join-Path $appPublishPath 'ClientCertificateCheck.dll' - $serverPfxPath = Join-Path $appSrcPath 'ServerCert.pfx' - $serverPfxPassword = 'password' - $clientPfxPath = Join-Path $appSrcPath 'ClientCert.pfx' - $initCompleteMessage = 'Now listening on' - $successMessage = 'Status: OK' - $failedMessage = 'Status: Failed' - - Import-Module $buildPsm - Find-Dotnet - Push-Location $appSrcPath - dotnet restore - dotnet publish --output $appPublishPath --configuration Release - $timeOut = (get-date).AddSeconds($initTimeoutSeconds) - Pop-Location - $Job = Start-Job { - Push-Location $using:appPublishPath - dotnet $using:appDllPath $using:serverPfxPath $using:serverPfxPassword $using:portNumber - } - # Wait until the app is running or until the initTimeoutSeconds have been reached - do - { - Start-Sleep -Seconds 1 - $containerStatus = $Job.ChildJobs[0].Output | Out-String - $isRunning = $containerStatus -match $initCompleteMessage - } - while (-not $isRunning -and (get-date) -lt $timeOut) - $Job.ChildJobs[0].Output - - if (-not $isRunning) { - throw 'Container did not start before the timeout was reached.' - } - } - - AfterAll { - $Job | Stop-Job -PassThru | Remove-Job - } - - It "Verifies Invoke-WebRequest Certificate Authentication Fails without -Certificate" { - $result = Invoke-WebRequest -Uri $uri -SkipCertificateCheck - $result.RawContent | Should Match ([regex]::Escape($failedMessage )) - } - - It "Verifies Invoke-WebRequest Certificate Authentication Successful with -Certificate" { - $certificate = Get-PfxCertificate -FilePath $clientPfxPath - $result = Invoke-WebRequest -Uri $uri -Certificate $certificate -SkipCertificateCheck - $result.RawContent | Should Match ([regex]::Escape($successMessage)) - $result.RawContent | Should Match $certificate.Thumbprint - } - - It "Verifies Invoke-RestMethod Certificate Authentication Fails without -Certificate" { - $result = Invoke-RestMethod -Uri $uri -SkipCertificateCheck - $result | Should Match ([regex]::Escape($failedMessage)) - } - - It "Verifies Invoke-RestMethod Certificate Authentication Successful with -Certificate" { - $certificate = Get-PfxCertificate -FilePath $clientPfxPath - $result = Invoke-RestMethod -uri $uri -Certificate $certificate -SkipCertificateCheck - $result | Should Match ([regex]::Escape($successMessage)) - $result | Should Match $certificate.Thumbprint - } -} From 23194d07cdde64f879fbc6003f1359ad556e34be Mon Sep 17 00:00:00 2001 From: markekraus Date: Sun, 20 Aug 2017 09:37:12 -0500 Subject: [PATCH 04/17] [feature] spelling fix --- test/tools/ClientCertificateCheck/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/tools/ClientCertificateCheck/README.md b/test/tools/ClientCertificateCheck/README.md index 96a7cc6ae3a..0e7a759312e 100644 --- a/test/tools/ClientCertificateCheck/README.md +++ b/test/tools/ClientCertificateCheck/README.md @@ -1,7 +1,7 @@ # Client Certificate Check ASP.NET Core 2.0 app for testing Client Certificate Authentication. -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 Asp.Net Kestrel server for SSL/TLS. The included SelF-Signed Certificate `ClientCert.pfx` has no password and has not been issued for any specific key usage. The app can be run directly with `dotnet` or as a Docker container. +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 ASP.NET Kestrel server for SSL/TLS. The included SelF-Signed Certificate `ClientCert.pfx` has no password and has not been issued for any specific key usage. The app can be run directly with `dotnet` or as a Docker container. The default page will return information about the certificate is one was provided. From 0dcc1f093d4cdfa569b986631cf9b4aaf27bf767 Mon Sep 17 00:00:00 2001 From: markekraus Date: Sun, 20 Aug 2017 11:57:44 -0500 Subject: [PATCH 05/17] [feature] revert badssl changes --- .../WebCmdlets.Tests.ps1 | 95 ++++++++++++++++++- 1 file changed, 91 insertions(+), 4 deletions(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 index 64a01c7e089..bebfdb288a8 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 @@ -336,6 +336,95 @@ function StopClientCertificateCheck $Job | Stop-Job -PassThru | Remove-Job } +function GetSelfSignedCert { + <# + .NOTES + This certificate is not issued for any specific Key Usage + It cannot be used for any service that requires a specific key usage + It can be used for SSL/TLS Client Authentication + #> + $PfxBase64 = @' +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 +hqPP3QQIlSXpfTECuB4CAggA +'@ + $Bytes = [System.Convert]::FromBase64String($PfxBase64) + [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($Bytes) +} + <# Defines the list of redirect codes to test as well as the expected Method when the redirection is handled. @@ -1161,8 +1250,7 @@ Describe "Invoke-WebRequest tests" -Tags "Feature" { It "Verifies Invoke-WebRequest Certificate Authentication Successful with -Certificate" { $uri = 'https://localhost:8443/' - $clientPfxPath = Resolve-Path (Join-Path $PSScriptRoot "\..\..\..\tools\ClientCertificateCheck\ClientCert.pfx") - $certificate = Get-PfxCertificate -FilePath $clientPfxPath + $certificate = GetSelfSignedCert $result = Invoke-WebRequest -Uri $uri -Certificate $certificate -SkipCertificateCheck $successMessage = 'Status: OK' $result.RawContent | Should Match ([regex]::Escape($successMessage)) @@ -1702,8 +1790,7 @@ Describe "Invoke-RestMethod tests" -Tags "Feature" { It "Verifies Invoke-RestMethod Certificate Authentication Successful with -Certificate" { $uri = 'https://localhost:8443/' - $clientPfxPath = Resolve-Path (Join-Path $PSScriptRoot "\..\..\..\tools\ClientCertificateCheck\ClientCert.pfx") - $certificate = Get-PfxCertificate -FilePath $clientPfxPath + $certificate = GetSelfSignedCert $result = Invoke-RestMethod -uri $uri -Certificate $certificate -SkipCertificateCheck $successMessage = 'Status: OK' $result | Should Match ([regex]::Escape($successMessage)) From a393fd7c3c700bd83086d350440f9a07787b616f Mon Sep 17 00:00:00 2001 From: markekraus Date: Sun, 20 Aug 2017 13:58:31 -0500 Subject: [PATCH 06/17] [feature] Impliment suggestions --- .../WebCmdlets.Tests.ps1 | 20 +++++++-------- .../ClientCertificateCheck/.dockerignore | 3 --- .../ClientCertificateCheck/Pages/Index.cshtml | 2 +- .../Pages/_Layout.cshtml | 2 +- .../Pages/_ValidationScriptsPartial.cshtml | 1 - test/tools/ClientCertificateCheck/README.md | 25 ++++++------------- test/tools/ClientCertificateCheck/dockerfile | 18 ------------- 7 files changed, 19 insertions(+), 52 deletions(-) delete mode 100644 test/tools/ClientCertificateCheck/.dockerignore delete mode 100644 test/tools/ClientCertificateCheck/Pages/_ValidationScriptsPartial.cshtml delete mode 100644 test/tools/ClientCertificateCheck/dockerfile diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 index bebfdb288a8..2bd34d0ef3c 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 @@ -299,32 +299,32 @@ function ExecuteWebRequest # Starts the ClientCertificateCheck listener function StartClientCertificateCheck { - param([int]$Port) + param([int]$Port = 8443) $initTimeoutSeconds = 15 - $projectRootPath = Resolve-Path (Join-Path $PSScriptRoot "\..\..\..\..\") - $appSrcPath = Join-Path $projectRootPath 'test\tools\ClientCertificateCheck' - $appPublishPath = Join-Path $appSrcPath 'bin' - $appDllPath = Join-Path $appPublishPath 'ClientCertificateCheck.dll' - $serverPfxPath = Join-Path $appSrcPath 'ServerCert.pfx' + $appDll = 'ClientCertificateCheck.dll' + $serverPfx = 'ServerCert.pfx' $serverPfxPassword = 'password' $initCompleteMessage = 'Now listening on' $timeOut = (get-date).AddSeconds($initTimeoutSeconds) $Job = Start-Job { - Push-Location $using:appPublishPath - dotnet $using:appDllPath $using:serverPfxPath $using:serverPfxPassword $using:port + $path = Split-Path -parent (get-command ClientCertificateCheck).Path + Push-Location $path + dotnet $using:appDll $using:serverPfx $using:serverPfxPassword $using:Port } # Wait until the app is running or until the initTimeoutSeconds have been reached do { - Start-Sleep -Seconds 1 + Start-Sleep -Milliseconds 100 $containerStatus = $Job.ChildJobs[0].Output | Out-String $isRunning = $containerStatus -match $initCompleteMessage } while (-not $isRunning -and (get-date) -lt $timeOut) if (-not $isRunning) { - throw 'Container did not start before the timeout was reached.' + $Job | Stop-Job -PassThru | Receive-Job + $Job | Remove-Job + throw 'Job did not start before the timeout was reached.' } return $job } diff --git a/test/tools/ClientCertificateCheck/.dockerignore b/test/tools/ClientCertificateCheck/.dockerignore deleted file mode 100644 index c94194bca83..00000000000 --- a/test/tools/ClientCertificateCheck/.dockerignore +++ /dev/null @@ -1,3 +0,0 @@ -bin/ -obj/ -node_modules/ diff --git a/test/tools/ClientCertificateCheck/Pages/Index.cshtml b/test/tools/ClientCertificateCheck/Pages/Index.cshtml index 7448f01e1d9..ad89de87673 100644 --- a/test/tools/ClientCertificateCheck/Pages/Index.cshtml +++ b/test/tools/ClientCertificateCheck/Pages/Index.cshtml @@ -7,4 +7,4 @@ Subject Name: @Model.CertSubjectName Issuer: @Model.CertIssuer Issuer Name: @Model.CertIssuerName Not After: @Model.CertNotAfter -Not Before: @Model.CertNotBefore \ No newline at end of file +Not Before: @Model.CertNotBefore diff --git a/test/tools/ClientCertificateCheck/Pages/_Layout.cshtml b/test/tools/ClientCertificateCheck/Pages/_Layout.cshtml index 1dfa991769d..7d460874112 100644 --- a/test/tools/ClientCertificateCheck/Pages/_Layout.cshtml +++ b/test/tools/ClientCertificateCheck/Pages/_Layout.cshtml @@ -1 +1 @@ -@RenderBody() \ No newline at end of file +@RenderBody() diff --git a/test/tools/ClientCertificateCheck/Pages/_ValidationScriptsPartial.cshtml b/test/tools/ClientCertificateCheck/Pages/_ValidationScriptsPartial.cshtml deleted file mode 100644 index 5f282702bb0..00000000000 --- a/test/tools/ClientCertificateCheck/Pages/_ValidationScriptsPartial.cshtml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/test/tools/ClientCertificateCheck/README.md b/test/tools/ClientCertificateCheck/README.md index 0e7a759312e..8a4ff6991cf 100644 --- a/test/tools/ClientCertificateCheck/README.md +++ b/test/tools/ClientCertificateCheck/README.md @@ -1,11 +1,11 @@ # Client Certificate Check ASP.NET Core 2.0 app for testing Client Certificate Authentication. -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 ASP.NET Kestrel server for SSL/TLS. The included SelF-Signed Certificate `ClientCert.pfx` has no password and has not been issued for any specific key usage. The app can be run directly with `dotnet` or as a Docker container. +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 ASP.NET Kestrel server for SSL/TLS. The included SelF-Signed Certificate `ClientCert.pfx` has no password and has not been issued for any specific key usage. The app can be run directly with `dotnet` or as a Docker container. -The default page will return information about the certificate is one was provided. +The default page will return information about the certificate if one was provided. -Certificate Provided in request: +Response when certificate is provided in request: ``` Status: OK Thumbprint: 2DECF1348FF21B780F45D316A039B5EB4C6312F7 @@ -17,7 +17,7 @@ Not After: 12/26/2044 18:16:46 Not Before: 08/10/2017 18:16:46 ``` -No certificate provided in request: +Response when certificate is not provided in request: ``` Status: FAILED Thumbprint: @@ -33,22 +33,11 @@ Not Before: ``` dotnet restore -dotnet dotnet publish --output app --configuration Release -cd app +dotnet publish --output bin --configuration Release +cd bin dotnet ClientCertificateCheck.dll ServerCert.pfx password 8443 ``` The test site can then be accessed via `https://localhost:8443/`. -The `ClientCertificateCheck.dll` takes 3 arguments: the path to the Server Certificate, the Server Certificate Password, and the TCP Port to bind on. - -# Run As a Docker Container - -``` -docker build -t clientcertificatecheck . -docker run -d -p 8443:8443 --name clientcertificatecheck clientcertificatecheck 8443 -``` - -The Kestrel server will bind on the port passed to the `docker run` command. - -The test site can then be accessed via `https://localhost:8443/`. +The `ClientCertificateCheck.dll` takes 3 arguments: the path to the Server Certificate, the Server Certificate Password, and the TCP Port to bind on. \ No newline at end of file diff --git a/test/tools/ClientCertificateCheck/dockerfile b/test/tools/ClientCertificateCheck/dockerfile deleted file mode 100644 index 5dfe05b21f6..00000000000 --- a/test/tools/ClientCertificateCheck/dockerfile +++ /dev/null @@ -1,18 +0,0 @@ -# Stage 1: Build the Application -FROM microsoft/aspnetcore-build:2.0.0-jessie AS builder -WORKDIR /source -COPY *.csproj ./ -RUN dotnet restore -COPY . . -RUN dotnet publish --output /app/ --configuration Release - -# Stage 2: Create runtime container -FROM microsoft/aspnetcore:2.0.0-jessie -WORKDIR /app -COPY --from=builder /app . -# ClientCertificateCheck access 3 paramters: -# -# The Certificate is published to /app -ENTRYPOINT ["dotnet", "ClientCertificateCheck.dll", "ServerCert.pfx", "password"] -# Allow for easy override of HTTPS binding Port -CMD ["8443"] From a95b08789b30b18703280ba094230351ecb818ab Mon Sep 17 00:00:00 2001 From: markekraus Date: Mon, 21 Aug 2017 04:05:57 -0500 Subject: [PATCH 07/17] [feature] Spelling, var rename, port 8443 to 8083 rebase fix conflict --- .../WebCmdlets.Tests.ps1 | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 index 2bd34d0ef3c..dbc8b08945a 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 @@ -299,7 +299,7 @@ function ExecuteWebRequest # Starts the ClientCertificateCheck listener function StartClientCertificateCheck { - param([int]$Port = 8443) + param([int]$Port = 8083) $initTimeoutSeconds = 15 $appDll = 'ClientCertificateCheck.dll' $serverPfx = 'ServerCert.pfx' @@ -316,15 +316,15 @@ function StartClientCertificateCheck do { Start-Sleep -Milliseconds 100 - $containerStatus = $Job.ChildJobs[0].Output | Out-String - $isRunning = $containerStatus -match $initCompleteMessage + $initStatus = $Job.ChildJobs[0].Output | Out-String + $isRunning = $initStatus -match $initCompleteMessage } while (-not $isRunning -and (get-date) -lt $timeOut) if (-not $isRunning) { $Job | Stop-Job -PassThru | Receive-Job $Job | Remove-Job - throw 'Job did not start before the timeout was reached.' + throw 'ClientCertificateCheck did not start before the timeout was reached.' } return $job } @@ -452,7 +452,7 @@ Describe "Invoke-WebRequest tests" -Tags "Feature" { BeforeAll { $response = Start-HttpListener -Port 8080 - $certificateChecker = StartClientCertificateCheck -Port 8443 + $certificateChecker = StartClientCertificateCheck -Port 8083 } AfterAll { @@ -1242,14 +1242,14 @@ Describe "Invoke-WebRequest tests" -Tags "Feature" { #region Client Certificate Authentication It "Verifies Invoke-WebRequest Certificate Authentication Fails without -Certificate" { - $uri = 'https://localhost:8443/' + $uri = 'https://localhost:8083/' $result = Invoke-WebRequest -Uri $uri -SkipCertificateCheck $failedMessage = 'Status: Failed' $result.RawContent | Should Match ([regex]::Escape($failedMessage )) } It "Verifies Invoke-WebRequest Certificate Authentication Successful with -Certificate" { - $uri = 'https://localhost:8443/' + $uri = 'https://localhost:8083/' $certificate = GetSelfSignedCert $result = Invoke-WebRequest -Uri $uri -Certificate $certificate -SkipCertificateCheck $successMessage = 'Status: OK' @@ -1257,7 +1257,7 @@ Describe "Invoke-WebRequest tests" -Tags "Feature" { $result.RawContent | Should Match $certificate.Thumbprint } - #edregion Client Certificate Authentication + #endregion Client Certificate Authentication BeforeEach { if ($env:http_proxy) { @@ -1290,7 +1290,7 @@ Describe "Invoke-RestMethod tests" -Tags "Feature" { BeforeAll { $response = Start-HttpListener -Port 8081 - $certificateChecker = StartClientCertificateCheck -Port 8443 + $certificateChecker = StartClientCertificateCheck -Port 8083 } AfterAll { @@ -1782,14 +1782,14 @@ Describe "Invoke-RestMethod tests" -Tags "Feature" { #region Client Certificate Authentication It "Verifies Invoke-RestMethod Certificate Authentication Fails without -Certificate" { - $uri = 'https://localhost:8443/' + $uri = 'https://localhost:8083/' $result = Invoke-RestMethod -Uri $uri -SkipCertificateCheck $failedMessage = 'Status: Failed' $result | Should Match ([regex]::Escape($failedMessage)) } It "Verifies Invoke-RestMethod Certificate Authentication Successful with -Certificate" { - $uri = 'https://localhost:8443/' + $uri = 'https://localhost:8083/' $certificate = GetSelfSignedCert $result = Invoke-RestMethod -uri $uri -Certificate $certificate -SkipCertificateCheck $successMessage = 'Status: OK' @@ -1797,7 +1797,7 @@ Describe "Invoke-RestMethod tests" -Tags "Feature" { $result | Should Match $certificate.Thumbprint } - #edregion Client Certificate Authentication + #endregion Client Certificate Authentication BeforeEach { if ($env:http_proxy) { From ebadadc2ce655bbf600dba50c442548a9fc8fedf Mon Sep 17 00:00:00 2001 From: markekraus Date: Mon, 21 Aug 2017 17:58:03 -0500 Subject: [PATCH 08/17] [feature] Rename to HttpsListener and Module-ize . --- build.psm1 | 2 +- .../WebCmdlets.Tests.ps1 | 46 +------ .../Pages/_ViewImports.cshtml | 3 - .../ClientCert.pfx | Bin .../HttpsListener.csproj} | 2 +- .../Pages/Error.cshtml | 0 .../Pages/Error.cshtml.cs | 2 +- .../Pages/Index.cshtml | 0 .../Pages/Index.cshtml.cs | 2 +- .../Pages/_Layout.cshtml | 0 .../HttpsListener/Pages/_ViewImports.cshtml | 3 + .../Pages/_ViewStart.cshtml | 0 .../Program.cs | 2 +- .../README.md | 8 +- .../ServerCert.pfx | Bin .../Startup.cs | 2 +- .../appsettings.Development.json | 0 .../appsettings.json | 0 .../Modules/HttpsListener/HttpsListener.psd1 | 10 ++ .../Modules/HttpsListener/HttpsListener.psm1 | 126 ++++++++++++++++++ 20 files changed, 151 insertions(+), 57 deletions(-) delete mode 100644 test/tools/ClientCertificateCheck/Pages/_ViewImports.cshtml rename test/tools/{ClientCertificateCheck => HttpsListener}/ClientCert.pfx (100%) rename test/tools/{ClientCertificateCheck/ClientCertificateCheck.csproj => HttpsListener/HttpsListener.csproj} (81%) rename test/tools/{ClientCertificateCheck => HttpsListener}/Pages/Error.cshtml (100%) rename test/tools/{ClientCertificateCheck => HttpsListener}/Pages/Error.cshtml.cs (92%) rename test/tools/{ClientCertificateCheck => HttpsListener}/Pages/Index.cshtml (100%) rename test/tools/{ClientCertificateCheck => HttpsListener}/Pages/Index.cshtml.cs (97%) rename test/tools/{ClientCertificateCheck => HttpsListener}/Pages/_Layout.cshtml (100%) create mode 100644 test/tools/HttpsListener/Pages/_ViewImports.cshtml rename test/tools/{ClientCertificateCheck => HttpsListener}/Pages/_ViewStart.cshtml (100%) rename test/tools/{ClientCertificateCheck => HttpsListener}/Program.cs (98%) rename test/tools/{ClientCertificateCheck => HttpsListener}/README.md (82%) rename test/tools/{ClientCertificateCheck => HttpsListener}/ServerCert.pfx (100%) rename test/tools/{ClientCertificateCheck => HttpsListener}/Startup.cs (97%) rename test/tools/{ClientCertificateCheck => HttpsListener}/appsettings.Development.json (100%) rename test/tools/{ClientCertificateCheck => HttpsListener}/appsettings.json (100%) create mode 100644 test/tools/Modules/HttpsListener/HttpsListener.psd1 create mode 100644 test/tools/Modules/HttpsListener/HttpsListener.psm1 diff --git a/build.psm1 b/build.psm1 index 3d448030916..dabbb0ac679 100644 --- a/build.psm1 +++ b/build.psm1 @@ -778,7 +778,7 @@ function Publish-PSTestTools { $tools = @( @{Path="${PSScriptRoot}/test/tools/TestExe";Output="testexe"} - @{Path="${PSScriptRoot}/test/tools/ClientCertificateCheck";Output="ClientCertificateCheck"} + @{Path="${PSScriptRoot}/test/tools/HttpsListener";Output="HttpsListener"} ) if ($null -eq $Options) { diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 index dbc8b08945a..1566380cd2d 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 @@ -296,46 +296,6 @@ function ExecuteWebRequest return $result } -# Starts the ClientCertificateCheck listener -function StartClientCertificateCheck -{ - param([int]$Port = 8083) - $initTimeoutSeconds = 15 - $appDll = 'ClientCertificateCheck.dll' - $serverPfx = 'ServerCert.pfx' - $serverPfxPassword = 'password' - $initCompleteMessage = 'Now listening on' - - $timeOut = (get-date).AddSeconds($initTimeoutSeconds) - $Job = Start-Job { - $path = Split-Path -parent (get-command ClientCertificateCheck).Path - Push-Location $path - dotnet $using:appDll $using:serverPfx $using:serverPfxPassword $using:Port - } - # Wait until the app is running or until the initTimeoutSeconds have been reached - do - { - Start-Sleep -Milliseconds 100 - $initStatus = $Job.ChildJobs[0].Output | Out-String - $isRunning = $initStatus -match $initCompleteMessage - } - while (-not $isRunning -and (get-date) -lt $timeOut) - - if (-not $isRunning) { - $Job | Stop-Job -PassThru | Receive-Job - $Job | Remove-Job - throw 'ClientCertificateCheck did not start before the timeout was reached.' - } - return $job -} - -# Stops the ClientCertificateCheck listener -function StopClientCertificateCheck -{ - param($Job) - $Job | Stop-Job -PassThru | Remove-Job -} - function GetSelfSignedCert { <# .NOTES @@ -452,13 +412,12 @@ Describe "Invoke-WebRequest tests" -Tags "Feature" { BeforeAll { $response = Start-HttpListener -Port 8080 - $certificateChecker = StartClientCertificateCheck -Port 8083 + $httpsListener = Start-HttpsListener -Port 8083 } AfterAll { $null = Stop-HttpListener -Port 8080 $response.PowerShell.Dispose() - StopClientCertificateCheck -Job $certificateChecker } # Validate the output of Invoke-WebRequest @@ -1290,13 +1249,12 @@ Describe "Invoke-RestMethod tests" -Tags "Feature" { BeforeAll { $response = Start-HttpListener -Port 8081 - $certificateChecker = StartClientCertificateCheck -Port 8083 + $httpsListener = Start-HttpsListener -Port 8083 } AfterAll { $null = Stop-HttpListener -Port 8081 $response.PowerShell.Dispose() - StopClientCertificateCheck -Job $certificateChecker } It "Invoke-RestMethod returns User-Agent" { diff --git a/test/tools/ClientCertificateCheck/Pages/_ViewImports.cshtml b/test/tools/ClientCertificateCheck/Pages/_ViewImports.cshtml deleted file mode 100644 index a460a0f7cad..00000000000 --- a/test/tools/ClientCertificateCheck/Pages/_ViewImports.cshtml +++ /dev/null @@ -1,3 +0,0 @@ -@using ClientCertificateCheck -@namespace ClientCertificateCheck.Pages -@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers diff --git a/test/tools/ClientCertificateCheck/ClientCert.pfx b/test/tools/HttpsListener/ClientCert.pfx similarity index 100% rename from test/tools/ClientCertificateCheck/ClientCert.pfx rename to test/tools/HttpsListener/ClientCert.pfx diff --git a/test/tools/ClientCertificateCheck/ClientCertificateCheck.csproj b/test/tools/HttpsListener/HttpsListener.csproj similarity index 81% rename from test/tools/ClientCertificateCheck/ClientCertificateCheck.csproj rename to test/tools/HttpsListener/HttpsListener.csproj index 1ff57676377..58d595b0c4f 100644 --- a/test/tools/ClientCertificateCheck/ClientCertificateCheck.csproj +++ b/test/tools/HttpsListener/HttpsListener.csproj @@ -1,6 +1,6 @@ - Very simple ASP.NET Core 2.0 app to provide client certificate details if one is supplied in the webrequest. + Very simple ASP.NET Core 2.0 app to provide an HTTPS server. netcoreapp2.0 diff --git a/test/tools/ClientCertificateCheck/Pages/Error.cshtml b/test/tools/HttpsListener/Pages/Error.cshtml similarity index 100% rename from test/tools/ClientCertificateCheck/Pages/Error.cshtml rename to test/tools/HttpsListener/Pages/Error.cshtml diff --git a/test/tools/ClientCertificateCheck/Pages/Error.cshtml.cs b/test/tools/HttpsListener/Pages/Error.cshtml.cs similarity index 92% rename from test/tools/ClientCertificateCheck/Pages/Error.cshtml.cs rename to test/tools/HttpsListener/Pages/Error.cshtml.cs index c068c103139..e04bd5bc80b 100644 --- a/test/tools/ClientCertificateCheck/Pages/Error.cshtml.cs +++ b/test/tools/HttpsListener/Pages/Error.cshtml.cs @@ -5,7 +5,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc.RazorPages; -namespace ClientCertificateCheck.Pages +namespace HttpsListener.Pages { public class ErrorModel : PageModel { diff --git a/test/tools/ClientCertificateCheck/Pages/Index.cshtml b/test/tools/HttpsListener/Pages/Index.cshtml similarity index 100% rename from test/tools/ClientCertificateCheck/Pages/Index.cshtml rename to test/tools/HttpsListener/Pages/Index.cshtml diff --git a/test/tools/ClientCertificateCheck/Pages/Index.cshtml.cs b/test/tools/HttpsListener/Pages/Index.cshtml.cs similarity index 97% rename from test/tools/ClientCertificateCheck/Pages/Index.cshtml.cs rename to test/tools/HttpsListener/Pages/Index.cshtml.cs index d810145b5ad..ed6442dd716 100644 --- a/test/tools/ClientCertificateCheck/Pages/Index.cshtml.cs +++ b/test/tools/HttpsListener/Pages/Index.cshtml.cs @@ -7,7 +7,7 @@ using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.AspNetCore.Server.Kestrel.Https; -namespace ClientCertificateCheck.Pages +namespace HttpsListener.Pages { public class IndexModel : PageModel { diff --git a/test/tools/ClientCertificateCheck/Pages/_Layout.cshtml b/test/tools/HttpsListener/Pages/_Layout.cshtml similarity index 100% rename from test/tools/ClientCertificateCheck/Pages/_Layout.cshtml rename to test/tools/HttpsListener/Pages/_Layout.cshtml diff --git a/test/tools/HttpsListener/Pages/_ViewImports.cshtml b/test/tools/HttpsListener/Pages/_ViewImports.cshtml new file mode 100644 index 00000000000..04cdd8cb055 --- /dev/null +++ b/test/tools/HttpsListener/Pages/_ViewImports.cshtml @@ -0,0 +1,3 @@ +@using HttpsListener +@namespace HttpsListener.Pages +@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers diff --git a/test/tools/ClientCertificateCheck/Pages/_ViewStart.cshtml b/test/tools/HttpsListener/Pages/_ViewStart.cshtml similarity index 100% rename from test/tools/ClientCertificateCheck/Pages/_ViewStart.cshtml rename to test/tools/HttpsListener/Pages/_ViewStart.cshtml diff --git a/test/tools/ClientCertificateCheck/Program.cs b/test/tools/HttpsListener/Program.cs similarity index 98% rename from test/tools/ClientCertificateCheck/Program.cs rename to test/tools/HttpsListener/Program.cs index 51456c778e3..151beee47fc 100644 --- a/test/tools/ClientCertificateCheck/Program.cs +++ b/test/tools/HttpsListener/Program.cs @@ -12,7 +12,7 @@ using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; -namespace ClientCertificateCheck +namespace HttpsListener { public class Program { diff --git a/test/tools/ClientCertificateCheck/README.md b/test/tools/HttpsListener/README.md similarity index 82% rename from test/tools/ClientCertificateCheck/README.md rename to test/tools/HttpsListener/README.md index 8a4ff6991cf..eb3b9beba67 100644 --- a/test/tools/ClientCertificateCheck/README.md +++ b/test/tools/HttpsListener/README.md @@ -1,6 +1,6 @@ -# Client Certificate Check +# HTTPS Listener -ASP.NET Core 2.0 app for testing Client Certificate Authentication. +ASP.NET Core 2.0 app for testing HTTPS Requests. 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 ASP.NET Kestrel server for SSL/TLS. The included SelF-Signed Certificate `ClientCert.pfx` has no password and has not been issued for any specific key usage. The app can be run directly with `dotnet` or as a Docker container. The default page will return information about the certificate if one was provided. @@ -35,9 +35,9 @@ Not Before: dotnet restore dotnet publish --output bin --configuration Release cd bin -dotnet ClientCertificateCheck.dll ServerCert.pfx password 8443 +dotnet HttpsListener.dll ServerCert.pfx password 8443 ``` The test site can then be accessed via `https://localhost:8443/`. -The `ClientCertificateCheck.dll` takes 3 arguments: the path to the Server Certificate, the Server Certificate Password, and the TCP Port to bind on. \ No newline at end of file +The `HttpsListener.dll` takes 3 arguments: the path to the Server Certificate, the Server Certificate Password, and the TCP Port to bind on. \ No newline at end of file diff --git a/test/tools/ClientCertificateCheck/ServerCert.pfx b/test/tools/HttpsListener/ServerCert.pfx similarity index 100% rename from test/tools/ClientCertificateCheck/ServerCert.pfx rename to test/tools/HttpsListener/ServerCert.pfx diff --git a/test/tools/ClientCertificateCheck/Startup.cs b/test/tools/HttpsListener/Startup.cs similarity index 97% rename from test/tools/ClientCertificateCheck/Startup.cs rename to test/tools/HttpsListener/Startup.cs index aaed4a0e887..31240327418 100644 --- a/test/tools/ClientCertificateCheck/Startup.cs +++ b/test/tools/HttpsListener/Startup.cs @@ -7,7 +7,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -namespace ClientCertificateCheck +namespace HttpsListener { public class Startup { diff --git a/test/tools/ClientCertificateCheck/appsettings.Development.json b/test/tools/HttpsListener/appsettings.Development.json similarity index 100% rename from test/tools/ClientCertificateCheck/appsettings.Development.json rename to test/tools/HttpsListener/appsettings.Development.json diff --git a/test/tools/ClientCertificateCheck/appsettings.json b/test/tools/HttpsListener/appsettings.json similarity index 100% rename from test/tools/ClientCertificateCheck/appsettings.json rename to test/tools/HttpsListener/appsettings.json diff --git a/test/tools/Modules/HttpsListener/HttpsListener.psd1 b/test/tools/Modules/HttpsListener/HttpsListener.psd1 new file mode 100644 index 00000000000..0e0e3081204 --- /dev/null +++ b/test/tools/Modules/HttpsListener/HttpsListener.psd1 @@ -0,0 +1,10 @@ +@{ + ModuleVersion = '1.0.0' + GUID = '90572e25-3f15-49b0-8f25-fb717d3ef46a' + Author = 'Mark Kraus' + CompanyName = '' + Copyright = '' + Description = 'Creates a new HTTPS Listener for testing purposes' + RootModule = 'HttpsListener.psm1' + FunctionsToExport = @('Start-HttpsListener','Stop-HttpsListener', 'Get-HttpsListener') +} diff --git a/test/tools/Modules/HttpsListener/HttpsListener.psm1 b/test/tools/Modules/HttpsListener/HttpsListener.psm1 new file mode 100644 index 00000000000..c62c7fb5cbe --- /dev/null +++ b/test/tools/Modules/HttpsListener/HttpsListener.psm1 @@ -0,0 +1,126 @@ +Class HttpsListener +{ + [int]$Port + [System.Management.Automation.Job]$Job + + HttpsListener () { } + + [string] ToString() { + return ('Port: {0}; Status: {1}' -f $This.Port, $This.JobStateInfo.State) + } +} + +$HttpsListeners = @{} + +function Get-HttpsListener +{ + [CmdletBinding(ConfirmImpact = 'Low')] + [OutputType([HttpsListener])] + param + ( + [ValidateRange(1,65535)] + [int[]]$Port + ) + + process + { + if ($Port) + { + return $Script:HttpsListeners[$port] + } + return [HttpsListener[]]$Script:HttpsListeners.Values + } +} + +function Start-HttpsListener +{ + [CmdletBinding(ConfirmImpact = 'Low')] + [OutputType([HttpsListener])] + param + ( + [ValidateRange(1,65535)] + [int]$Port = 8083 + ) + + process + { + $runningListener = Get-HttpsListener -Port $Port + if ($runningListener) + { + return $runningListener + } + + $initTimeoutSeconds = 15 + $appDll = 'HttpsListener.dll' + $serverPfx = 'ServerCert.pfx' + $serverPfxPassword = 'password' + $initCompleteMessage = 'Now listening on' + + + $timeOut = (get-date).AddSeconds($initTimeoutSeconds) + $Job = Start-Job { + $path = Split-Path -parent (get-command HttpsListener).Path + Push-Location $path + dotnet $using:appDll $using:serverPfx $using:serverPfxPassword $using:Port + } + $httpsListener = [HttpsListener]@{ + Port = $Port + Job = $Job + } + # Wait until the app is running or until the initTimeoutSeconds have been reached + do + { + Start-Sleep -Milliseconds 100 + $initStatus = $Job.ChildJobs[0].Output | Out-String + $isRunning = $initStatus -match $initCompleteMessage + } + while (-not $isRunning -and (get-date) -lt $timeOut) + + if (-not $isRunning) + { + $Job | Stop-Job -PassThru | Receive-Job + $Job | Remove-Job + throw 'ClientCertificateCheck did not start before the timeout was reached.' + } + $Script:HttpsListeners.Add($Port,$httpsListener) + return $httpsListener + } +} + +function Stop-HttpsListener +{ + [CmdletBinding(ConfirmImpact = 'Low')] + [OutputType([Void])] + param + ( + [parameter( + ParameterSetName = 'HttpsListener', + ValueFromPipeline = $true, + Mandatory = $true + )] + [HttpsListener[]] + $InputObject, + + [parameter( + ParameterSetName = 'Port', + Mandatory = $true + )] + [ValidateRange(1,65535)] + [int[]] + $Port + ) + + process + { + if ($PSCmdlet.ParameterSetName -eq 'Port') + { + $InputObject = Get-HttpsListener -Port $Port + } + foreach ($listener in $InputObject) + { + $listener.job | Stop-Job -PassThru | Remove-Job + $null = $Script:HttpsListeners.Remove($listener.Port) + + } + } +} From 91ea4387fc298740e1f3585c593b6304ee4b1a5f Mon Sep 17 00:00:00 2001 From: Mark Kraus Date: Tue, 22 Aug 2017 12:34:35 -0500 Subject: [PATCH 09/17] [feature] password protect ClientCert to fix macOS import issue --- .../WebCmdlets.Tests.ps1 | 93 ++---------------- test/tools/HttpsListener/ClientCert.pfx | Bin 4293 -> 4293 bytes test/tools/HttpsListener/HttpsListener.csproj | 1 + test/tools/HttpsListener/README.md | 2 +- 4 files changed, 12 insertions(+), 84 deletions(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 index 1566380cd2d..8bfbbd9565c 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 @@ -303,86 +303,9 @@ function GetSelfSignedCert { It cannot be used for any service that requires a specific key usage It can be used for SSL/TLS Client Authentication #> - $PfxBase64 = @' -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 -hqPP3QQIlSXpfTECuB4CAggA -'@ - $Bytes = [System.Convert]::FromBase64String($PfxBase64) - [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($Bytes) + $parentPath = Split-Path -parent (get-command HttpsListener).Path + $pfxPath = Join-Path $parentPath 'ClientCert.pfx' + [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($pfxPath,'password') } <# @@ -1206,8 +1129,10 @@ Describe "Invoke-WebRequest tests" -Tags "Feature" { $failedMessage = 'Status: Failed' $result.RawContent | Should Match ([regex]::Escape($failedMessage )) } - - It "Verifies Invoke-WebRequest Certificate Authentication Successful with -Certificate" { + + # Test skipped on macOS pending support for Client Certificate Authentication + # https://github.com/PowerShell/PowerShell/issues/4650 + It "Verifies Invoke-WebRequest Certificate Authentication Successful with -Certificate" -skip:$IsOSX { $uri = 'https://localhost:8083/' $certificate = GetSelfSignedCert $result = Invoke-WebRequest -Uri $uri -Certificate $certificate -SkipCertificateCheck @@ -1746,7 +1671,9 @@ Describe "Invoke-RestMethod tests" -Tags "Feature" { $result | Should Match ([regex]::Escape($failedMessage)) } - It "Verifies Invoke-RestMethod Certificate Authentication Successful with -Certificate" { + # Test skipped on macOS pending support for Client Certificate Authentication + # https://github.com/PowerShell/PowerShell/issues/4650 + It "Verifies Invoke-RestMethod Certificate Authentication Successful with -Certificate" -skip:$IsOSX { $uri = 'https://localhost:8083/' $certificate = GetSelfSignedCert $result = Invoke-RestMethod -uri $uri -Certificate $certificate -SkipCertificateCheck diff --git a/test/tools/HttpsListener/ClientCert.pfx b/test/tools/HttpsListener/ClientCert.pfx index 4f21671e0ed271a806f567495b6e9445df5a3658..3303943fb72d750407be21114b427f82bd77d6d9 100644 GIT binary patch delta 4145 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 + diff --git a/test/tools/HttpsListener/README.md b/test/tools/HttpsListener/README.md index eb3b9beba67..db12b0f647f 100644 --- a/test/tools/HttpsListener/README.md +++ b/test/tools/HttpsListener/README.md @@ -1,7 +1,7 @@ # HTTPS Listener ASP.NET Core 2.0 app for testing HTTPS Requests. -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 ASP.NET Kestrel server for SSL/TLS. The included SelF-Signed Certificate `ClientCert.pfx` has no password and has not been issued for any specific key usage. The app can be run directly with `dotnet` or as a Docker container. +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 ASP.NET Kestrel server 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. The app can be run directly with `dotnet` or as a Docker container. The default page will return information about the certificate if one was provided. From bb4a8530da3069e46545f62ecef560e4ccd8301f Mon Sep 17 00:00:00 2001 From: markekraus Date: Thu, 24 Aug 2017 05:13:00 -0500 Subject: [PATCH 10/17] [feature] Rename to WebListener * Rename HttpsListener to WebListener * Switch Listener from Razor pages to MVC * Address PR feedback * Adjust tests --- build.psm1 | 2 +- .../WebCmdlets.Tests.ps1 | 60 ++++--- .../tools/HttpsListener/Pages/Error.cshtml.cs | 21 --- test/tools/HttpsListener/Pages/Index.cshtml | 10 -- .../tools/HttpsListener/Pages/Index.cshtml.cs | 41 ----- test/tools/HttpsListener/Pages/_Layout.cshtml | 1 - test/tools/HttpsListener/README.md | 43 ----- .../Modules/HttpsListener/HttpsListener.psd1 | 10 -- .../Modules/HttpsListener/HttpsListener.psm1 | 126 --------------- .../Modules/WebListener/WebListener.psd1 | 10 ++ .../Modules/WebListener/WebListener.psm1 | 147 ++++++++++++++++++ .../ClientCert.pfx | Bin .../WebListener/Controllers/CertController.cs | 43 +++++ .../WebListener/Controllers/HomeController.cs | 22 +++ .../WebListener/Models/ErrorViewModel.cs | 11 ++ .../{HttpsListener => WebListener}/Program.cs | 14 +- test/tools/WebListener/README.md | 52 +++++++ .../ServerCert.pfx | Bin .../{HttpsListener => WebListener}/Startup.cs | 10 +- .../tools/WebListener/Views/Home/Index.cshtml | 5 + .../Views/Shared}/Error.cshtml | 3 +- .../WebListener/Views/Shared/_Layout.cshtml | 1 + .../Views}/_ViewImports.cshtml | 4 +- .../Views}/_ViewStart.cshtml | 0 .../WebListener.csproj} | 10 +- .../appsettings.Development.json | 0 .../appsettings.json | 0 27 files changed, 342 insertions(+), 304 deletions(-) delete mode 100644 test/tools/HttpsListener/Pages/Error.cshtml.cs delete mode 100644 test/tools/HttpsListener/Pages/Index.cshtml delete mode 100644 test/tools/HttpsListener/Pages/Index.cshtml.cs delete mode 100644 test/tools/HttpsListener/Pages/_Layout.cshtml delete mode 100644 test/tools/HttpsListener/README.md delete mode 100644 test/tools/Modules/HttpsListener/HttpsListener.psd1 delete mode 100644 test/tools/Modules/HttpsListener/HttpsListener.psm1 create mode 100644 test/tools/Modules/WebListener/WebListener.psd1 create mode 100644 test/tools/Modules/WebListener/WebListener.psm1 rename test/tools/{HttpsListener => WebListener}/ClientCert.pfx (100%) create mode 100644 test/tools/WebListener/Controllers/CertController.cs create mode 100644 test/tools/WebListener/Controllers/HomeController.cs create mode 100644 test/tools/WebListener/Models/ErrorViewModel.cs rename test/tools/{HttpsListener => WebListener}/Program.cs (82%) create mode 100644 test/tools/WebListener/README.md rename test/tools/{HttpsListener => WebListener}/ServerCert.pfx (100%) rename test/tools/{HttpsListener => WebListener}/Startup.cs (73%) create mode 100644 test/tools/WebListener/Views/Home/Index.cshtml rename test/tools/{HttpsListener/Pages => WebListener/Views/Shared}/Error.cshtml (96%) create mode 100644 test/tools/WebListener/Views/Shared/_Layout.cshtml rename test/tools/{HttpsListener/Pages => WebListener/Views}/_ViewImports.cshtml (50%) rename test/tools/{HttpsListener/Pages => WebListener/Views}/_ViewStart.cshtml (100%) rename test/tools/{HttpsListener/HttpsListener.csproj => WebListener/WebListener.csproj} (72%) rename test/tools/{HttpsListener => WebListener}/appsettings.Development.json (100%) rename test/tools/{HttpsListener => WebListener}/appsettings.json (100%) diff --git a/build.psm1 b/build.psm1 index dabbb0ac679..162158c4c8a 100644 --- a/build.psm1 +++ b/build.psm1 @@ -778,7 +778,7 @@ function Publish-PSTestTools { $tools = @( @{Path="${PSScriptRoot}/test/tools/TestExe";Output="testexe"} - @{Path="${PSScriptRoot}/test/tools/HttpsListener";Output="HttpsListener"} + @{Path="${PSScriptRoot}/test/tools/WebListener";Output="WebListener"} ) if ($null -eq $Options) { diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 index 8bfbbd9565c..faf19343abe 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 @@ -296,18 +296,6 @@ function ExecuteWebRequest return $result } -function GetSelfSignedCert { - <# - .NOTES - This certificate is not issued for any specific Key Usage - It cannot be used for any service that requires a specific key usage - It can be used for SSL/TLS Client Authentication - #> - $parentPath = Split-Path -parent (get-command HttpsListener).Path - $pfxPath = Join-Path $parentPath 'ClientCert.pfx' - [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($pfxPath,'password') -} - <# Defines the list of redirect codes to test as well as the expected Method when the redirection is handled. @@ -335,7 +323,7 @@ Describe "Invoke-WebRequest tests" -Tags "Feature" { BeforeAll { $response = Start-HttpListener -Port 8080 - $httpsListener = Start-HttpsListener -Port 8083 + $WebListener = Start-WebListener } AfterAll { @@ -1124,21 +1112,27 @@ Describe "Invoke-WebRequest tests" -Tags "Feature" { #region Client Certificate Authentication It "Verifies Invoke-WebRequest Certificate Authentication Fails without -Certificate" { - $uri = 'https://localhost:8083/' - $result = Invoke-WebRequest -Uri $uri -SkipCertificateCheck - $failedMessage = 'Status: Failed' - $result.RawContent | Should Match ([regex]::Escape($failedMessage )) + $uri = '{0}/Cert/' -f (Get-WebListenerUrl -Https) + $result = Invoke-WebRequest -Uri $uri -SkipCertificateCheck | + Select-Object -ExcludeProperty Content | + ConvertFrom-Json + + $result.Status | Should Be 'FAILED' + $result.Status | Should Not Be 'OK' } # Test skipped on macOS pending support for Client Certificate Authentication # https://github.com/PowerShell/PowerShell/issues/4650 It "Verifies Invoke-WebRequest Certificate Authentication Successful with -Certificate" -skip:$IsOSX { - $uri = 'https://localhost:8083/' - $certificate = GetSelfSignedCert - $result = Invoke-WebRequest -Uri $uri -Certificate $certificate -SkipCertificateCheck - $successMessage = 'Status: OK' - $result.RawContent | Should Match ([regex]::Escape($successMessage)) - $result.RawContent | Should Match $certificate.Thumbprint + $uri = '{0}/Cert/' -f (Get-WebListenerUrl -Https) + $certificate = Get-TestClientCertificate + $result = Invoke-WebRequest -Uri $uri -Certificate $certificate -SkipCertificateCheck | + Select-Object -ExcludeProperty Content | + ConvertFrom-Json + + $result.Status | Should Not Be 'FAILED' + $result.Status | Should Be 'OK' + $result.Thumbprint | Should Be $certificate.Thumbprint } #endregion Client Certificate Authentication @@ -1174,7 +1168,7 @@ Describe "Invoke-RestMethod tests" -Tags "Feature" { BeforeAll { $response = Start-HttpListener -Port 8081 - $httpsListener = Start-HttpsListener -Port 8083 + $WebListener = Start-WebListener } AfterAll { @@ -1665,21 +1659,23 @@ Describe "Invoke-RestMethod tests" -Tags "Feature" { #region Client Certificate Authentication It "Verifies Invoke-RestMethod Certificate Authentication Fails without -Certificate" { - $uri = 'https://localhost:8083/' + $uri = '{0}/Cert/' -f (Get-WebListenerUrl -Https) $result = Invoke-RestMethod -Uri $uri -SkipCertificateCheck - $failedMessage = 'Status: Failed' - $result | Should Match ([regex]::Escape($failedMessage)) + + $result.Status | Should Be 'FAILED' + $result.Status | Should Not Be 'OK' } # Test skipped on macOS pending support for Client Certificate Authentication # https://github.com/PowerShell/PowerShell/issues/4650 It "Verifies Invoke-RestMethod Certificate Authentication Successful with -Certificate" -skip:$IsOSX { - $uri = 'https://localhost:8083/' - $certificate = GetSelfSignedCert + $uri = '{0}/Cert/' -f (Get-WebListenerUrl -Https) + $certificate = Get-TestClientCertificate $result = Invoke-RestMethod -uri $uri -Certificate $certificate -SkipCertificateCheck - $successMessage = 'Status: OK' - $result | Should Match ([regex]::Escape($successMessage)) - $result | Should Match $certificate.Thumbprint + + $result.Status | Should Not Be 'FAILED' + $result.Status | Should Be 'OK' + $result.Thumbprint | Should Be $certificate.Thumbprint } #endregion Client Certificate Authentication diff --git a/test/tools/HttpsListener/Pages/Error.cshtml.cs b/test/tools/HttpsListener/Pages/Error.cshtml.cs deleted file mode 100644 index e04bd5bc80b..00000000000 --- a/test/tools/HttpsListener/Pages/Error.cshtml.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc.RazorPages; - -namespace HttpsListener.Pages -{ - public class ErrorModel : PageModel - { - public string RequestId { get; set; } - - public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); - - public void OnGet() - { - RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier; - } - } -} diff --git a/test/tools/HttpsListener/Pages/Index.cshtml b/test/tools/HttpsListener/Pages/Index.cshtml deleted file mode 100644 index ad89de87673..00000000000 --- a/test/tools/HttpsListener/Pages/Index.cshtml +++ /dev/null @@ -1,10 +0,0 @@ -@page -@model IndexModel -Status: @Model.Status -Thumbprint: @Model.CertThumbprint -Subject: @Model.CertSubject -Subject Name: @Model.CertSubjectName -Issuer: @Model.CertIssuer -Issuer Name: @Model.CertIssuerName -Not After: @Model.CertNotAfter -Not Before: @Model.CertNotBefore diff --git a/test/tools/HttpsListener/Pages/Index.cshtml.cs b/test/tools/HttpsListener/Pages/Index.cshtml.cs deleted file mode 100644 index ed6442dd716..00000000000 --- a/test/tools/HttpsListener/Pages/Index.cshtml.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using System.Text; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.RazorPages; -using Microsoft.AspNetCore.Server.Kestrel.Https; - -namespace HttpsListener.Pages -{ - public class IndexModel : PageModel - { - public string CertSubject; - public string CertNotAfter; - public string CertNotBefore; - public string CertIssuer; - public string CertIssuerName; - public string CertSubjectName; - public string CertThumbprint; - public string Status = "FAILED"; - - public void OnGet() - { - if(null == HttpContext.Connection.ClientCertificate){ - return; - } - CertSubject = HttpContext.Connection.ClientCertificate.Subject; - CertNotAfter = HttpContext.Connection.ClientCertificate.NotAfter.ToString(); - CertNotBefore = HttpContext.Connection.ClientCertificate.NotBefore.ToString(); - CertIssuer = HttpContext.Connection.ClientCertificate.Issuer; - CertIssuerName = HttpContext.Connection.ClientCertificate.IssuerName.Name; - CertSubjectName = HttpContext.Connection.ClientCertificate.SubjectName.Name; - CertThumbprint = HttpContext.Connection.ClientCertificate.Thumbprint; - if (!string.IsNullOrEmpty(CertThumbprint)) - { - Status = "OK"; - } - } - } -} diff --git a/test/tools/HttpsListener/Pages/_Layout.cshtml b/test/tools/HttpsListener/Pages/_Layout.cshtml deleted file mode 100644 index 7d460874112..00000000000 --- a/test/tools/HttpsListener/Pages/_Layout.cshtml +++ /dev/null @@ -1 +0,0 @@ -@RenderBody() diff --git a/test/tools/HttpsListener/README.md b/test/tools/HttpsListener/README.md deleted file mode 100644 index db12b0f647f..00000000000 --- a/test/tools/HttpsListener/README.md +++ /dev/null @@ -1,43 +0,0 @@ -# HTTPS Listener - -ASP.NET Core 2.0 app for testing HTTPS Requests. -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 ASP.NET Kestrel server 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. The app can be run directly with `dotnet` or as a Docker container. - -The default page will return information about the certificate if one was provided. - -Response when certificate is provided in request: -``` -Status: OK -Thumbprint: 2DECF1348FF21B780F45D316A039B5EB4C6312F7 -Subject: E=randd@adatum.com, CN=adatum.com, OU=R&D, O=A. Datum Corporation, L=Redmond, S=Washington, C=US -Subject Name: E=randd@adatum.com, CN=adatum.com, OU=R&D, O=A. Datum Corporation, L=Redmond, S=Washington, C=US -Issuer: E=randd@adatum.com, CN=adatum.com, OU=R&D, O=A. Datum Corporation, L=Redmond, S=Washington, C=US -Issuer Name: E=randd@adatum.com, CN=adatum.com, OU=R&D, O=A. Datum Corporation, L=Redmond, S=Washington, C=US -Not After: 12/26/2044 18:16:46 -Not Before: 08/10/2017 18:16:46 -``` - -Response when certificate is not provided in request: -``` -Status: FAILED -Thumbprint: -Subject: -Subject Name: -Issuer: -Issuer Name: -Not After: -Not Before: -``` - -# Run with `dotnet` - -``` -dotnet restore -dotnet publish --output bin --configuration Release -cd bin -dotnet HttpsListener.dll ServerCert.pfx password 8443 -``` - -The test site can then be accessed via `https://localhost:8443/`. - -The `HttpsListener.dll` takes 3 arguments: the path to the Server Certificate, the Server Certificate Password, and the TCP Port to bind on. \ No newline at end of file diff --git a/test/tools/Modules/HttpsListener/HttpsListener.psd1 b/test/tools/Modules/HttpsListener/HttpsListener.psd1 deleted file mode 100644 index 0e0e3081204..00000000000 --- a/test/tools/Modules/HttpsListener/HttpsListener.psd1 +++ /dev/null @@ -1,10 +0,0 @@ -@{ - ModuleVersion = '1.0.0' - GUID = '90572e25-3f15-49b0-8f25-fb717d3ef46a' - Author = 'Mark Kraus' - CompanyName = '' - Copyright = '' - Description = 'Creates a new HTTPS Listener for testing purposes' - RootModule = 'HttpsListener.psm1' - FunctionsToExport = @('Start-HttpsListener','Stop-HttpsListener', 'Get-HttpsListener') -} diff --git a/test/tools/Modules/HttpsListener/HttpsListener.psm1 b/test/tools/Modules/HttpsListener/HttpsListener.psm1 deleted file mode 100644 index c62c7fb5cbe..00000000000 --- a/test/tools/Modules/HttpsListener/HttpsListener.psm1 +++ /dev/null @@ -1,126 +0,0 @@ -Class HttpsListener -{ - [int]$Port - [System.Management.Automation.Job]$Job - - HttpsListener () { } - - [string] ToString() { - return ('Port: {0}; Status: {1}' -f $This.Port, $This.JobStateInfo.State) - } -} - -$HttpsListeners = @{} - -function Get-HttpsListener -{ - [CmdletBinding(ConfirmImpact = 'Low')] - [OutputType([HttpsListener])] - param - ( - [ValidateRange(1,65535)] - [int[]]$Port - ) - - process - { - if ($Port) - { - return $Script:HttpsListeners[$port] - } - return [HttpsListener[]]$Script:HttpsListeners.Values - } -} - -function Start-HttpsListener -{ - [CmdletBinding(ConfirmImpact = 'Low')] - [OutputType([HttpsListener])] - param - ( - [ValidateRange(1,65535)] - [int]$Port = 8083 - ) - - process - { - $runningListener = Get-HttpsListener -Port $Port - if ($runningListener) - { - return $runningListener - } - - $initTimeoutSeconds = 15 - $appDll = 'HttpsListener.dll' - $serverPfx = 'ServerCert.pfx' - $serverPfxPassword = 'password' - $initCompleteMessage = 'Now listening on' - - - $timeOut = (get-date).AddSeconds($initTimeoutSeconds) - $Job = Start-Job { - $path = Split-Path -parent (get-command HttpsListener).Path - Push-Location $path - dotnet $using:appDll $using:serverPfx $using:serverPfxPassword $using:Port - } - $httpsListener = [HttpsListener]@{ - Port = $Port - Job = $Job - } - # Wait until the app is running or until the initTimeoutSeconds have been reached - do - { - Start-Sleep -Milliseconds 100 - $initStatus = $Job.ChildJobs[0].Output | Out-String - $isRunning = $initStatus -match $initCompleteMessage - } - while (-not $isRunning -and (get-date) -lt $timeOut) - - if (-not $isRunning) - { - $Job | Stop-Job -PassThru | Receive-Job - $Job | Remove-Job - throw 'ClientCertificateCheck did not start before the timeout was reached.' - } - $Script:HttpsListeners.Add($Port,$httpsListener) - return $httpsListener - } -} - -function Stop-HttpsListener -{ - [CmdletBinding(ConfirmImpact = 'Low')] - [OutputType([Void])] - param - ( - [parameter( - ParameterSetName = 'HttpsListener', - ValueFromPipeline = $true, - Mandatory = $true - )] - [HttpsListener[]] - $InputObject, - - [parameter( - ParameterSetName = 'Port', - Mandatory = $true - )] - [ValidateRange(1,65535)] - [int[]] - $Port - ) - - process - { - if ($PSCmdlet.ParameterSetName -eq 'Port') - { - $InputObject = Get-HttpsListener -Port $Port - } - foreach ($listener in $InputObject) - { - $listener.job | Stop-Job -PassThru | Remove-Job - $null = $Script:HttpsListeners.Remove($listener.Port) - - } - } -} diff --git a/test/tools/Modules/WebListener/WebListener.psd1 b/test/tools/Modules/WebListener/WebListener.psd1 new file mode 100644 index 00000000000..48ff13eb5b1 --- /dev/null +++ b/test/tools/Modules/WebListener/WebListener.psd1 @@ -0,0 +1,10 @@ +@{ + ModuleVersion = '1.0.0' + GUID = '90572e25-3f15-49b0-8f25-fb717d3ef46a' + Author = 'Mark Kraus' + CompanyName = '' + Copyright = '' + Description = 'An HTTP and HTTPS Listener for testing purposes' + RootModule = 'WebListener.psm1' + FunctionsToExport = @('Start-WebListener','Stop-WebListener', 'Get-WebListener', 'Get-WebListenerUrl','Get-TestClientCertificate') +} diff --git a/test/tools/Modules/WebListener/WebListener.psm1 b/test/tools/Modules/WebListener/WebListener.psm1 new file mode 100644 index 00000000000..8765ac679e2 --- /dev/null +++ b/test/tools/Modules/WebListener/WebListener.psm1 @@ -0,0 +1,147 @@ +Enum WebListenerProtocol +{ + HTTP + HTTPS +} + +Class WebListener +{ + [int]$HttpPort + [int]$HttpsPort + [System.Management.Automation.Job]$Job + + WebListener () { } + + [string] ToString() + { + return ('Port: {0}; Status: {1}' -f $This.Port, $This.JobStateInfo.State) + } + + [String] GetStatus() + { + return $This.JobStateInfo.State + } + +} + +[WebListener]$WebListener + +function Get-WebListener +{ + [CmdletBinding(ConfirmImpact = 'Low')] + [OutputType([WebListener])] + param () + + process + { + return [WebListener]$Script:WebListener + } +} + +function Start-WebListener +{ + [CmdletBinding(ConfirmImpact = 'Low')] + [OutputType([WebListener])] + param + ( + [ValidateRange(1,65535)] + [int]$HttpPort = 8083, + + [ValidateRange(1,65535)] + [int]$HttpsPort = 8084 + ) + + process + { + $runningListener = Get-WebListener + if ($null -ne $runningListener -and $runningListener.GetStatus() -eq 'Running') + { + return $runningListener + } + + $initTimeoutSeconds = 15 + $appDll = 'WebListener.dll' + $serverPfx = 'ServerCert.pfx' + $serverPfxPassword = 'password' + $initCompleteMessage = 'Now listening on' + + + $timeOut = (get-date).AddSeconds($initTimeoutSeconds) + $Job = Start-Job { + $path = Split-Path -parent (get-command WebListener).Path + Push-Location $path + dotnet $using:appDll $using:serverPfx $using:serverPfxPassword $using:HtttpPort $using:HtttpsPort + } + $Script:WebListener = [WebListener]@{ + HttpPort = $HttpPort + HttpsPort = $HttpsPort + Job = $Job + } + # Wait until the app is running or until the initTimeoutSeconds have been reached + do + { + Start-Sleep -Milliseconds 100 + $initStatus = $Job.ChildJobs[0].Output | Out-String + $isRunning = $initStatus -match $initCompleteMessage + } + while (-not $isRunning -and (get-date) -lt $timeOut) + + if (-not $isRunning) + { + $Job | Stop-Job -PassThru | Receive-Job + $Job | Remove-Job + throw 'WebListener did not start before the timeout was reached.' + } + return $Script:WebListener + } +} + +function Stop-WebListener +{ + [CmdletBinding(ConfirmImpact = 'Low')] + [OutputType([Void])] + param + ( ) + + process + { + $Script:WebListener.job | Stop-Job -PassThru | Remove-Job + $Script:WebListener = $null + } +} + +function Get-TestClientCertificate { + [CmdletBinding(ConfirmImpact = 'Low')] + [OutputType([System.Security.Cryptography.X509Certificates.X509Certificate2])] + param ( ) + process { + $parentPath = Split-Path -parent (get-command WebListener).Path + $pfxPath = Join-Path $parentPath 'ClientCert.pfx' + [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($pfxPath,'password') + } +} + +function Get-WebListenerUrl { + [CmdletBinding()] + [OutputType([Uri])] + param ( + [switch]$Https + ) + process { + $runningListener = Get-WebListener + if ($null -eq $runningListener -or $runningListener.GetStatus() -ne 'Running') + { + return + } + $Uri = [System.UriBuilder]::new() + $Uri.Host = 'localhost' + $Uri.Port = $runningListener.HttpPort + $Uri.Scheme = 'Http' + if ($Https.IsPresent) + { + $Uri.Port = $runningListener.HttpPort + $Uri.Scheme = 'Https' + } + return [Uri]$Uri.ToString() + } +} diff --git a/test/tools/HttpsListener/ClientCert.pfx b/test/tools/WebListener/ClientCert.pfx similarity index 100% rename from test/tools/HttpsListener/ClientCert.pfx rename to test/tools/WebListener/ClientCert.pfx diff --git a/test/tools/WebListener/Controllers/CertController.cs b/test/tools/WebListener/Controllers/CertController.cs new file mode 100644 index 00000000000..e5d1aaafad4 --- /dev/null +++ b/test/tools/WebListener/Controllers/CertController.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using mvc.Models; +using System.Collections; + +namespace mvc.Controllers +{ + public class CertController : Controller + { + public ActionResult Index() + { + // X509Certificate2 objects do not serialize as JSON. Create a HashTable instead + Hashtable output = new Hashtable + { + {"Status", "FAILED"} + }; + if (null != HttpContext.Connection.ClientCertificate) + { + output = new Hashtable + { + {"Status" , "OK"}, + {"Thumbprint" , HttpContext.Connection.ClientCertificate.Thumbprint}, + {"Subject" , HttpContext.Connection.ClientCertificate.Subject}, + {"SubjectName" , HttpContext.Connection.ClientCertificate.SubjectName.Name}, + {"Issuer" , HttpContext.Connection.ClientCertificate.Issuer}, + {"IssuerName" , HttpContext.Connection.ClientCertificate.IssuerName.Name}, + {"NotAfter" , HttpContext.Connection.ClientCertificate.NotAfter}, + {"NotBefore" , HttpContext.Connection.ClientCertificate.NotBefore} + }; + }; + return Json(output); + } + + public IActionResult Error() + { + return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); + } + } +} diff --git a/test/tools/WebListener/Controllers/HomeController.cs b/test/tools/WebListener/Controllers/HomeController.cs new file mode 100644 index 00000000000..2a8a7a3e29a --- /dev/null +++ b/test/tools/WebListener/Controllers/HomeController.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using mvc.Models; + +namespace mvc.Controllers +{ + public class HomeController : Controller + { + public IActionResult Index() + { + return View(); + } + public IActionResult Error() + { + return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); + } + } +} diff --git a/test/tools/WebListener/Models/ErrorViewModel.cs b/test/tools/WebListener/Models/ErrorViewModel.cs new file mode 100644 index 00000000000..3c4066e0ecb --- /dev/null +++ b/test/tools/WebListener/Models/ErrorViewModel.cs @@ -0,0 +1,11 @@ +using System; + +namespace mvc.Models +{ + public class ErrorViewModel + { + public string RequestId { get; set; } + + public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); + } +} diff --git a/test/tools/HttpsListener/Program.cs b/test/tools/WebListener/Program.cs similarity index 82% rename from test/tools/HttpsListener/Program.cs rename to test/tools/WebListener/Program.cs index 151beee47fc..3103f3970b6 100644 --- a/test/tools/HttpsListener/Program.cs +++ b/test/tools/WebListener/Program.cs @@ -9,18 +9,18 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using Microsoft.AspNetCore.Server.Kestrel.Https; -using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; +using System.Security.Authentication; -namespace HttpsListener +namespace mvc { public class Program { public static void Main(string[] args) { - if (args.Count() != 3) + if (args.Count() != 4) { - System.Console.WriteLine("Required: "); + System.Console.WriteLine("Required: "); Environment.Exit(1); } BuildWebHost(args).Run(); @@ -28,10 +28,10 @@ public static void Main(string[] args) public static IWebHost BuildWebHost(string[] args) => WebHost.CreateDefaultBuilder() - .UseStartup() - .UseKestrel(options => + .UseStartup().UseKestrel(options => { - options.Listen(IPAddress.Any, int.Parse(args[2]), listenOptions => + options.Listen(IPAddress.Loopback, int.Parse(args[2])); + options.Listen(IPAddress.Loopback, int.Parse(args[3]), listenOptions => { var certificate = new X509Certificate2(args[0], args[1]); HttpsConnectionAdapterOptions httpsOption = new HttpsConnectionAdapterOptions(); diff --git a/test/tools/WebListener/README.md b/test/tools/WebListener/README.md new file mode 100644 index 00000000000..7ffbcf91d8b --- /dev/null +++ b/test/tools/WebListener/README.md @@ -0,0 +1,52 @@ +# HTTPS Listener + +ASP.NET Core 2.0 app for testing HTTP and HTTPS Requests. +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 ASP.NET Kestrel server 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. + +The default page will return a list of available tests. + +# Run with `dotnet` + +``` +dotnet restore +dotnet publish --output bin --configuration Release +cd bin +dotnet WebListener.dll ServerCert.pfx password 8083 8084 +``` + +The test site can then be accessed via `https://localhost:8084/`. + +The `WebListener.dll` takes 4 arguments: + +* The path to the Server Certificate +* The Server Certificate Password +* The TCP Port to bind on for HTTP +* The TCP Port to bind on for HTTPS + + +# Tests + +## /Cert/ + +Returns a JSON object containing the details of the Client Certificate if one is provided in the request. + +Response when certificate is provided in request: +```json +{ + "Status": "OK", + "IssuerName": "E=randd@adatum.com, CN=adatum.com, OU=R&D, O=A. Datum Corporation, L=Redmond, S=Washington, C=US", + "SubjectName": "E=randd@adatum.com, CN=adatum.com, OU=R&D, O=A. Datum Corporation, L=Redmond, S=Washington, C=US", + "NotAfter": "2044-12-26T12:16:46-06:00", + "Issuer": "E=randd@adatum.com, CN=adatum.com, OU=R&D, O=A. Datum Corporation, L=Redmond, S=Washington, C=US", + "Subject": "E=randd@adatum.com, CN=adatum.com, OU=R&D, O=A. Datum Corporation, L=Redmond, S=Washington, C=US", + "NotBefore": "2017-08-10T13:16:46-05:00", + "Thumbprint": "2DECF1348FF21B780F45D316A039B5EB4C6312F7" +} +``` + +Response when certificate is not provided in request: +```json +{ + "Status": "FAILED" +} +``` diff --git a/test/tools/HttpsListener/ServerCert.pfx b/test/tools/WebListener/ServerCert.pfx similarity index 100% rename from test/tools/HttpsListener/ServerCert.pfx rename to test/tools/WebListener/ServerCert.pfx diff --git a/test/tools/HttpsListener/Startup.cs b/test/tools/WebListener/Startup.cs similarity index 73% rename from test/tools/HttpsListener/Startup.cs rename to test/tools/WebListener/Startup.cs index 31240327418..7e6af5f7737 100644 --- a/test/tools/HttpsListener/Startup.cs +++ b/test/tools/WebListener/Startup.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -7,7 +7,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -namespace HttpsListener +namespace mvc { public class Startup { @@ -18,11 +18,13 @@ public Startup(IConfiguration configuration) public IConfiguration Configuration { get; } + // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddMvc(); } + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) @@ -31,7 +33,7 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env) } else { - app.UseExceptionHandler("/Error"); + app.UseExceptionHandler("/Home/Error"); } app.UseStaticFiles(); @@ -40,7 +42,7 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env) { routes.MapRoute( name: "default", - template: "{controller}/{action=Index}/{id?}"); + template: "{controller=Home}/{action=Index}/{id?}"); }); } } diff --git a/test/tools/WebListener/Views/Home/Index.cshtml b/test/tools/WebListener/Views/Home/Index.cshtml new file mode 100644 index 00000000000..0007857f793 --- /dev/null +++ b/test/tools/WebListener/Views/Home/Index.cshtml @@ -0,0 +1,5 @@ +

Available Tests

+
    +
  • / - This page
  • +
  • /Cert/ - Client Certificate Details
  • +
diff --git a/test/tools/HttpsListener/Pages/Error.cshtml b/test/tools/WebListener/Views/Shared/Error.cshtml similarity index 96% rename from test/tools/HttpsListener/Pages/Error.cshtml rename to test/tools/WebListener/Views/Shared/Error.cshtml index b1f3143a42e..ec2ea6bd038 100644 --- a/test/tools/HttpsListener/Pages/Error.cshtml +++ b/test/tools/WebListener/Views/Shared/Error.cshtml @@ -1,5 +1,4 @@ -@page -@model ErrorModel +@model ErrorViewModel @{ ViewData["Title"] = "Error"; } diff --git a/test/tools/WebListener/Views/Shared/_Layout.cshtml b/test/tools/WebListener/Views/Shared/_Layout.cshtml new file mode 100644 index 00000000000..603b12341f4 --- /dev/null +++ b/test/tools/WebListener/Views/Shared/_Layout.cshtml @@ -0,0 +1 @@ +@RenderBody() diff --git a/test/tools/HttpsListener/Pages/_ViewImports.cshtml b/test/tools/WebListener/Views/_ViewImports.cshtml similarity index 50% rename from test/tools/HttpsListener/Pages/_ViewImports.cshtml rename to test/tools/WebListener/Views/_ViewImports.cshtml index 04cdd8cb055..861be0a31ac 100644 --- a/test/tools/HttpsListener/Pages/_ViewImports.cshtml +++ b/test/tools/WebListener/Views/_ViewImports.cshtml @@ -1,3 +1,3 @@ -@using HttpsListener -@namespace HttpsListener.Pages +@using mvc +@using mvc.Models @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers diff --git a/test/tools/HttpsListener/Pages/_ViewStart.cshtml b/test/tools/WebListener/Views/_ViewStart.cshtml similarity index 100% rename from test/tools/HttpsListener/Pages/_ViewStart.cshtml rename to test/tools/WebListener/Views/_ViewStart.cshtml diff --git a/test/tools/HttpsListener/HttpsListener.csproj b/test/tools/WebListener/WebListener.csproj similarity index 72% rename from test/tools/HttpsListener/HttpsListener.csproj rename to test/tools/WebListener/WebListener.csproj index b08b87589ea..d8142fa513b 100644 --- a/test/tools/HttpsListener/HttpsListener.csproj +++ b/test/tools/WebListener/WebListener.csproj @@ -1,19 +1,21 @@ + - Very simple ASP.NET Core 2.0 app to provide an HTTPS server. + A simple ASP.NET Core 2.0 MVC app to provide an HTTP and HTTPS server for testing. netcoreapp2.0 + + - - - + + diff --git a/test/tools/HttpsListener/appsettings.Development.json b/test/tools/WebListener/appsettings.Development.json similarity index 100% rename from test/tools/HttpsListener/appsettings.Development.json rename to test/tools/WebListener/appsettings.Development.json diff --git a/test/tools/HttpsListener/appsettings.json b/test/tools/WebListener/appsettings.json similarity index 100% rename from test/tools/HttpsListener/appsettings.json rename to test/tools/WebListener/appsettings.json From 9ee5c32cf1d8dfacbbcf20b4346718ca1ba89214 Mon Sep 17 00:00:00 2001 From: Mark Kraus Date: Thu, 24 Aug 2017 07:28:53 -0500 Subject: [PATCH 11/17] [feature] Address PR feedback --- .../Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 | 8 ++------ test/tools/Modules/WebListener/WebListener.psd1 | 10 +++++++--- test/tools/Modules/WebListener/WebListener.psm1 | 11 +++++------ test/tools/WebListener/Controllers/CertController.cs | 8 ++++---- test/tools/WebListener/Program.cs | 10 ++++++---- 5 files changed, 24 insertions(+), 23 deletions(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 index faf19343abe..b72b1809f77 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 @@ -1118,19 +1118,17 @@ Describe "Invoke-WebRequest tests" -Tags "Feature" { ConvertFrom-Json $result.Status | Should Be 'FAILED' - $result.Status | Should Not Be 'OK' } # Test skipped on macOS pending support for Client Certificate Authentication # https://github.com/PowerShell/PowerShell/issues/4650 It "Verifies Invoke-WebRequest Certificate Authentication Successful with -Certificate" -skip:$IsOSX { $uri = '{0}/Cert/' -f (Get-WebListenerUrl -Https) - $certificate = Get-TestClientCertificate + $certificate = Get-WebListenerClientCertificate $result = Invoke-WebRequest -Uri $uri -Certificate $certificate -SkipCertificateCheck | Select-Object -ExcludeProperty Content | ConvertFrom-Json - $result.Status | Should Not Be 'FAILED' $result.Status | Should Be 'OK' $result.Thumbprint | Should Be $certificate.Thumbprint } @@ -1663,17 +1661,15 @@ Describe "Invoke-RestMethod tests" -Tags "Feature" { $result = Invoke-RestMethod -Uri $uri -SkipCertificateCheck $result.Status | Should Be 'FAILED' - $result.Status | Should Not Be 'OK' } # Test skipped on macOS pending support for Client Certificate Authentication # https://github.com/PowerShell/PowerShell/issues/4650 It "Verifies Invoke-RestMethod Certificate Authentication Successful with -Certificate" -skip:$IsOSX { $uri = '{0}/Cert/' -f (Get-WebListenerUrl -Https) - $certificate = Get-TestClientCertificate + $certificate = Get-WebListenerClientCertificate $result = Invoke-RestMethod -uri $uri -Certificate $certificate -SkipCertificateCheck - $result.Status | Should Not Be 'FAILED' $result.Status | Should Be 'OK' $result.Thumbprint | Should Be $certificate.Thumbprint } diff --git a/test/tools/Modules/WebListener/WebListener.psd1 b/test/tools/Modules/WebListener/WebListener.psd1 index 48ff13eb5b1..c554642cfb7 100644 --- a/test/tools/Modules/WebListener/WebListener.psd1 +++ b/test/tools/Modules/WebListener/WebListener.psd1 @@ -2,9 +2,13 @@ ModuleVersion = '1.0.0' GUID = '90572e25-3f15-49b0-8f25-fb717d3ef46a' Author = 'Mark Kraus' - CompanyName = '' - Copyright = '' Description = 'An HTTP and HTTPS Listener for testing purposes' RootModule = 'WebListener.psm1' - FunctionsToExport = @('Start-WebListener','Stop-WebListener', 'Get-WebListener', 'Get-WebListenerUrl','Get-TestClientCertificate') + FunctionsToExport = @( + 'Start-WebListener' + 'Stop-WebListener' + 'Get-WebListener' + 'Get-WebListenerUrl' + 'Get-WebListenerClientCertificate' + ) } diff --git a/test/tools/Modules/WebListener/WebListener.psm1 b/test/tools/Modules/WebListener/WebListener.psm1 index 8765ac679e2..ee4e4b2c919 100644 --- a/test/tools/Modules/WebListener/WebListener.psm1 +++ b/test/tools/Modules/WebListener/WebListener.psm1 @@ -70,7 +70,7 @@ function Start-WebListener $Job = Start-Job { $path = Split-Path -parent (get-command WebListener).Path Push-Location $path - dotnet $using:appDll $using:serverPfx $using:serverPfxPassword $using:HtttpPort $using:HtttpsPort + dotnet $using:appDll $using:serverPfx $using:serverPfxPassword $using:HttpPort $using:HttpsPort } $Script:WebListener = [WebListener]@{ HttpPort = $HttpPort @@ -100,8 +100,7 @@ function Stop-WebListener { [CmdletBinding(ConfirmImpact = 'Low')] [OutputType([Void])] - param - ( ) + param () process { @@ -110,10 +109,10 @@ function Stop-WebListener } } -function Get-TestClientCertificate { +function Get-WebListenerClientCertificate { [CmdletBinding(ConfirmImpact = 'Low')] [OutputType([System.Security.Cryptography.X509Certificates.X509Certificate2])] - param ( ) + param () process { $parentPath = Split-Path -parent (get-command WebListener).Path $pfxPath = Join-Path $parentPath 'ClientCert.pfx' @@ -131,7 +130,7 @@ function Get-WebListenerUrl { $runningListener = Get-WebListener if ($null -eq $runningListener -or $runningListener.GetStatus() -ne 'Running') { - return + return $null } $Uri = [System.UriBuilder]::new() $Uri.Host = 'localhost' diff --git a/test/tools/WebListener/Controllers/CertController.cs b/test/tools/WebListener/Controllers/CertController.cs index e5d1aaafad4..e844efe6084 100644 --- a/test/tools/WebListener/Controllers/CertController.cs +++ b/test/tools/WebListener/Controllers/CertController.cs @@ -1,11 +1,11 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using mvc.Models; -using System.Collections; namespace mvc.Controllers { @@ -17,7 +17,7 @@ public ActionResult Index() Hashtable output = new Hashtable { {"Status", "FAILED"} - }; + } if (null != HttpContext.Connection.ClientCertificate) { output = new Hashtable @@ -30,8 +30,8 @@ public ActionResult Index() {"IssuerName" , HttpContext.Connection.ClientCertificate.IssuerName.Name}, {"NotAfter" , HttpContext.Connection.ClientCertificate.NotAfter}, {"NotBefore" , HttpContext.Connection.ClientCertificate.NotBefore} - }; - }; + } + } return Json(output); } diff --git a/test/tools/WebListener/Program.cs b/test/tools/WebListener/Program.cs index 3103f3970b6..124f28f7e8d 100644 --- a/test/tools/WebListener/Program.cs +++ b/test/tools/WebListener/Program.cs @@ -1,16 +1,18 @@ using System; -using System.Net; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Net; +using System.Security.Authentication; +using System.Security.Cryptography.X509Certificates; using System.Threading.Tasks; using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Server.Kestrel.Https; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; -using Microsoft.AspNetCore.Server.Kestrel.Https; -using System.Security.Cryptography.X509Certificates; -using System.Security.Authentication; + + namespace mvc { From 14053bb52b50ce4accddef7f38caa064e6a17ca5 Mon Sep 17 00:00:00 2001 From: Mark Kraus Date: Thu, 24 Aug 2017 10:43:33 -0500 Subject: [PATCH 12/17] [feature] Replace missing smeicolons --- test/tools/WebListener/Controllers/CertController.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/tools/WebListener/Controllers/CertController.cs b/test/tools/WebListener/Controllers/CertController.cs index e844efe6084..943b044f765 100644 --- a/test/tools/WebListener/Controllers/CertController.cs +++ b/test/tools/WebListener/Controllers/CertController.cs @@ -17,7 +17,7 @@ public ActionResult Index() Hashtable output = new Hashtable { {"Status", "FAILED"} - } + }; if (null != HttpContext.Connection.ClientCertificate) { output = new Hashtable @@ -30,7 +30,7 @@ public ActionResult Index() {"IssuerName" , HttpContext.Connection.ClientCertificate.IssuerName.Name}, {"NotAfter" , HttpContext.Connection.ClientCertificate.NotAfter}, {"NotBefore" , HttpContext.Connection.ClientCertificate.NotBefore} - } + }; } return Json(output); } From 1a2fd9b5e1ff3ab4ebcfafdf17dff7dbb702987a Mon Sep 17 00:00:00 2001 From: Mark Kraus Date: Thu, 24 Aug 2017 10:55:42 -0500 Subject: [PATCH 13/17] [feature] Address PR Feedback --- test/tools/Modules/WebListener/WebListener.psd1 | 6 +++--- test/tools/Modules/WebListener/WebListener.psm1 | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/tools/Modules/WebListener/WebListener.psd1 b/test/tools/Modules/WebListener/WebListener.psd1 index c554642cfb7..91021b45e5b 100644 --- a/test/tools/Modules/WebListener/WebListener.psd1 +++ b/test/tools/Modules/WebListener/WebListener.psd1 @@ -5,10 +5,10 @@ Description = 'An HTTP and HTTPS Listener for testing purposes' RootModule = 'WebListener.psm1' FunctionsToExport = @( - 'Start-WebListener' - 'Stop-WebListener' 'Get-WebListener' - 'Get-WebListenerUrl' 'Get-WebListenerClientCertificate' + 'Get-WebListenerUrl' + 'Start-WebListener' + 'Stop-WebListener' ) } diff --git a/test/tools/Modules/WebListener/WebListener.psm1 b/test/tools/Modules/WebListener/WebListener.psm1 index ee4e4b2c919..38304edb76a 100644 --- a/test/tools/Modules/WebListener/WebListener.psm1 +++ b/test/tools/Modules/WebListener/WebListener.psm1 @@ -30,7 +30,7 @@ function Get-WebListener { [CmdletBinding(ConfirmImpact = 'Low')] [OutputType([WebListener])] - param () + param() process { @@ -100,7 +100,7 @@ function Stop-WebListener { [CmdletBinding(ConfirmImpact = 'Low')] [OutputType([Void])] - param () + param() process { @@ -112,7 +112,7 @@ function Stop-WebListener function Get-WebListenerClientCertificate { [CmdletBinding(ConfirmImpact = 'Low')] [OutputType([System.Security.Cryptography.X509Certificates.X509Certificate2])] - param () + param() process { $parentPath = Split-Path -parent (get-command WebListener).Path $pfxPath = Join-Path $parentPath 'ClientCert.pfx' From d9770bac27e554f66c74be3e1e43dd62cef64e4c Mon Sep 17 00:00:00 2001 From: Mark Kraus Date: Thu, 24 Aug 2017 12:31:35 -0500 Subject: [PATCH 14/17] [feature] Cleanup and minor fix * Enum was not used * GetStatus() was not accessing the correct property chain * Added -Test param to make URL generation smoother in test code and to fix double / issues --- .../WebCmdlets.Tests.ps1 | 8 ++++---- test/tools/Modules/WebListener/WebListener.psm1 | 12 ++++-------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 index b72b1809f77..2752fc79075 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 @@ -1112,7 +1112,7 @@ Describe "Invoke-WebRequest tests" -Tags "Feature" { #region Client Certificate Authentication It "Verifies Invoke-WebRequest Certificate Authentication Fails without -Certificate" { - $uri = '{0}/Cert/' -f (Get-WebListenerUrl -Https) + $uri = Get-WebListenerUrl -Https -Test 'Cert' $result = Invoke-WebRequest -Uri $uri -SkipCertificateCheck | Select-Object -ExcludeProperty Content | ConvertFrom-Json @@ -1123,7 +1123,7 @@ Describe "Invoke-WebRequest tests" -Tags "Feature" { # Test skipped on macOS pending support for Client Certificate Authentication # https://github.com/PowerShell/PowerShell/issues/4650 It "Verifies Invoke-WebRequest Certificate Authentication Successful with -Certificate" -skip:$IsOSX { - $uri = '{0}/Cert/' -f (Get-WebListenerUrl -Https) + $uri = Get-WebListenerUrl -Https -Test 'Cert' $certificate = Get-WebListenerClientCertificate $result = Invoke-WebRequest -Uri $uri -Certificate $certificate -SkipCertificateCheck | Select-Object -ExcludeProperty Content | @@ -1657,7 +1657,7 @@ Describe "Invoke-RestMethod tests" -Tags "Feature" { #region Client Certificate Authentication It "Verifies Invoke-RestMethod Certificate Authentication Fails without -Certificate" { - $uri = '{0}/Cert/' -f (Get-WebListenerUrl -Https) + $uri = Get-WebListenerUrl -Https -Test 'Cert' $result = Invoke-RestMethod -Uri $uri -SkipCertificateCheck $result.Status | Should Be 'FAILED' @@ -1666,7 +1666,7 @@ Describe "Invoke-RestMethod tests" -Tags "Feature" { # Test skipped on macOS pending support for Client Certificate Authentication # https://github.com/PowerShell/PowerShell/issues/4650 It "Verifies Invoke-RestMethod Certificate Authentication Successful with -Certificate" -skip:$IsOSX { - $uri = '{0}/Cert/' -f (Get-WebListenerUrl -Https) + $uri = Get-WebListenerUrl -Https -Test 'Cert' $certificate = Get-WebListenerClientCertificate $result = Invoke-RestMethod -uri $uri -Certificate $certificate -SkipCertificateCheck diff --git a/test/tools/Modules/WebListener/WebListener.psm1 b/test/tools/Modules/WebListener/WebListener.psm1 index 38304edb76a..dd29e332511 100644 --- a/test/tools/Modules/WebListener/WebListener.psm1 +++ b/test/tools/Modules/WebListener/WebListener.psm1 @@ -1,9 +1,3 @@ -Enum WebListenerProtocol -{ - HTTP - HTTPS -} - Class WebListener { [int]$HttpPort @@ -19,7 +13,7 @@ Class WebListener [String] GetStatus() { - return $This.JobStateInfo.State + return $This.Job.JobStateInfo.State } } @@ -124,7 +118,8 @@ function Get-WebListenerUrl { [CmdletBinding()] [OutputType([Uri])] param ( - [switch]$Https + [switch]$Https, + [String]$Test ) process { $runningListener = Get-WebListener @@ -141,6 +136,7 @@ function Get-WebListenerUrl { $Uri.Port = $runningListener.HttpPort $Uri.Scheme = 'Https' } + $Uri.Path = $Test return [Uri]$Uri.ToString() } } From 2c3cbd36c6c80be4b5aaf366c277112b5be5f762 Mon Sep 17 00:00:00 2001 From: Mark Kraus Date: Thu, 24 Aug 2017 13:55:08 -0500 Subject: [PATCH 15/17] [feature] More minor fixes * Https when it matters. * Expand property... not exclude.. * Remove superfluous and outdated ToString() override --- .../Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 | 4 ++-- test/tools/Modules/WebListener/WebListener.psm1 | 7 +------ 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 index 2752fc79075..7be94bf8b00 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/WebCmdlets.Tests.ps1 @@ -1114,7 +1114,7 @@ Describe "Invoke-WebRequest tests" -Tags "Feature" { It "Verifies Invoke-WebRequest Certificate Authentication Fails without -Certificate" { $uri = Get-WebListenerUrl -Https -Test 'Cert' $result = Invoke-WebRequest -Uri $uri -SkipCertificateCheck | - Select-Object -ExcludeProperty Content | + Select-Object -ExpandProperty Content | ConvertFrom-Json $result.Status | Should Be 'FAILED' @@ -1126,7 +1126,7 @@ Describe "Invoke-WebRequest tests" -Tags "Feature" { $uri = Get-WebListenerUrl -Https -Test 'Cert' $certificate = Get-WebListenerClientCertificate $result = Invoke-WebRequest -Uri $uri -Certificate $certificate -SkipCertificateCheck | - Select-Object -ExcludeProperty Content | + Select-Object -ExpandProperty Content | ConvertFrom-Json $result.Status | Should Be 'OK' diff --git a/test/tools/Modules/WebListener/WebListener.psm1 b/test/tools/Modules/WebListener/WebListener.psm1 index dd29e332511..957c1668f8d 100644 --- a/test/tools/Modules/WebListener/WebListener.psm1 +++ b/test/tools/Modules/WebListener/WebListener.psm1 @@ -6,11 +6,6 @@ Class WebListener WebListener () { } - [string] ToString() - { - return ('Port: {0}; Status: {1}' -f $This.Port, $This.JobStateInfo.State) - } - [String] GetStatus() { return $This.Job.JobStateInfo.State @@ -133,7 +128,7 @@ function Get-WebListenerUrl { $Uri.Scheme = 'Http' if ($Https.IsPresent) { - $Uri.Port = $runningListener.HttpPort + $Uri.Port = $runningListener.HttpsPort $Uri.Scheme = 'Https' } $Uri.Path = $Test From ced727c3abfa5e227ae260002bdaaf1cc6914766 Mon Sep 17 00:00:00 2001 From: Mark Kraus Date: Fri, 25 Aug 2017 06:26:19 -0500 Subject: [PATCH 16/17] [Feature] Move ClientCeret.pfx to WebListener Module * Move the cert * Adjust Get-WebListenerClientCertificate * Remove cert from csproj * ActionResult -> JsonResult (was mistakenly left as ActionResult during testing).. --- test/tools/{ => Modules}/WebListener/ClientCert.pfx | Bin test/tools/Modules/WebListener/WebListener.psm1 | 3 +-- .../tools/WebListener/Controllers/CertController.cs | 2 +- test/tools/WebListener/WebListener.csproj | 1 - 4 files changed, 2 insertions(+), 4 deletions(-) rename test/tools/{ => Modules}/WebListener/ClientCert.pfx (100%) diff --git a/test/tools/WebListener/ClientCert.pfx b/test/tools/Modules/WebListener/ClientCert.pfx similarity index 100% rename from test/tools/WebListener/ClientCert.pfx rename to test/tools/Modules/WebListener/ClientCert.pfx diff --git a/test/tools/Modules/WebListener/WebListener.psm1 b/test/tools/Modules/WebListener/WebListener.psm1 index 957c1668f8d..5c5aa4bffb4 100644 --- a/test/tools/Modules/WebListener/WebListener.psm1 +++ b/test/tools/Modules/WebListener/WebListener.psm1 @@ -103,8 +103,7 @@ function Get-WebListenerClientCertificate { [OutputType([System.Security.Cryptography.X509Certificates.X509Certificate2])] param() process { - $parentPath = Split-Path -parent (get-command WebListener).Path - $pfxPath = Join-Path $parentPath 'ClientCert.pfx' + $pfxPath = Join-Path $MyInvocation.MyCommand.Module.ModuleBase 'ClientCert.pfx' [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($pfxPath,'password') } } diff --git a/test/tools/WebListener/Controllers/CertController.cs b/test/tools/WebListener/Controllers/CertController.cs index 943b044f765..1acbf566020 100644 --- a/test/tools/WebListener/Controllers/CertController.cs +++ b/test/tools/WebListener/Controllers/CertController.cs @@ -11,7 +11,7 @@ namespace mvc.Controllers { public class CertController : Controller { - public ActionResult Index() + public JsonResult Index() { // X509Certificate2 objects do not serialize as JSON. Create a HashTable instead Hashtable output = new Hashtable diff --git a/test/tools/WebListener/WebListener.csproj b/test/tools/WebListener/WebListener.csproj index d8142fa513b..8614e5b136e 100644 --- a/test/tools/WebListener/WebListener.csproj +++ b/test/tools/WebListener/WebListener.csproj @@ -15,7 +15,6 @@ - From b93674ef25f7cda719e10a96240956085274438b Mon Sep 17 00:00:00 2001 From: Mark Kraus Date: Fri, 25 Aug 2017 07:57:22 -0500 Subject: [PATCH 17/17] [Feature] Move ServerCert.pfx to Module * Move cert * Upate csproj * Update module * Add/Update README.md's CI Retest. --- .spelling | 1 + test/tools/Modules/WebListener/README.md | 17 +++++++++++++++++ .../{ => Modules}/WebListener/ServerCert.pfx | Bin .../tools/Modules/WebListener/WebListener.psm1 | 5 ++--- test/tools/WebListener/README.md | 16 ++++++++++------ test/tools/WebListener/WebListener.csproj | 4 ---- 6 files changed, 30 insertions(+), 13 deletions(-) create mode 100644 test/tools/Modules/WebListener/README.md rename test/tools/{ => Modules}/WebListener/ServerCert.pfx (100%) diff --git a/.spelling b/.spelling index b7d7da30656..7c80b928e2e 100644 --- a/.spelling +++ b/.spelling @@ -887,6 +887,7 @@ v0.5.0 v0.6.0 v6.0.0 ValidateNotNullOrEmpty +WebListener WebRequest win7-x86 WindowsVersion diff --git a/test/tools/Modules/WebListener/README.md b/test/tools/Modules/WebListener/README.md new file mode 100644 index 00000000000..f66d94b2c16 --- /dev/null +++ b/test/tools/Modules/WebListener/README.md @@ -0,0 +1,17 @@ +# 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. + +# Running WebListener + +```powershell +Import-Module .\build.psm1 +Publish-PSTestTools +$Listener = Start-WebListener -HttpPort 8083 -HttpsPort 8084 +``` + +# Stopping WebListener + +```powershell +Stop-WebListener +``` diff --git a/test/tools/WebListener/ServerCert.pfx b/test/tools/Modules/WebListener/ServerCert.pfx similarity index 100% rename from test/tools/WebListener/ServerCert.pfx rename to test/tools/Modules/WebListener/ServerCert.pfx diff --git a/test/tools/Modules/WebListener/WebListener.psm1 b/test/tools/Modules/WebListener/WebListener.psm1 index 5c5aa4bffb4..a9071547a41 100644 --- a/test/tools/Modules/WebListener/WebListener.psm1 +++ b/test/tools/Modules/WebListener/WebListener.psm1 @@ -10,7 +10,6 @@ Class WebListener { return $This.Job.JobStateInfo.State } - } [WebListener]$WebListener @@ -54,12 +53,12 @@ function Start-WebListener $serverPfxPassword = 'password' $initCompleteMessage = 'Now listening on' - + $serverPfxPath = Join-Path $MyInvocation.MyCommand.Module.ModuleBase $serverPfx $timeOut = (get-date).AddSeconds($initTimeoutSeconds) $Job = Start-Job { $path = Split-Path -parent (get-command WebListener).Path Push-Location $path - dotnet $using:appDll $using:serverPfx $using:serverPfxPassword $using:HttpPort $using:HttpsPort + dotnet $using:appDll $using:serverPfxPath $using:serverPfxPassword $using:HttpPort $using:HttpsPort } $Script:WebListener = [WebListener]@{ HttpPort = $HttpPort diff --git a/test/tools/WebListener/README.md b/test/tools/WebListener/README.md index 7ffbcf91d8b..e931b2c3a5b 100644 --- a/test/tools/WebListener/README.md +++ b/test/tools/WebListener/README.md @@ -1,9 +1,6 @@ -# HTTPS Listener +# WebListener App -ASP.NET Core 2.0 app for testing HTTP and HTTPS Requests. -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 ASP.NET Kestrel server 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. - -The default page will return a list of available tests. +ASP.NET Core 2.0 app for testing HTTP and HTTPS Requests. The default page will return a list of available tests. # Run with `dotnet` @@ -14,7 +11,7 @@ cd bin dotnet WebListener.dll ServerCert.pfx password 8083 8084 ``` -The test site can then be accessed via `https://localhost:8084/`. +The test site can then be accessed via `http://localhost:8083/` or `https://localhost:8084/`. The `WebListener.dll` takes 4 arguments: @@ -23,6 +20,13 @@ The `WebListener.dll` takes 4 arguments: * The TCP Port to bind on for HTTP * The TCP Port to bind on for HTTPS +# Run With WebListener Module + +```powershell +Import-Module .\build.psm1 +Publish-PSTestTools +$Listener = Start-WebListener -HttpPort 8083 -HttpsPort 8084 +``` # Tests diff --git a/test/tools/WebListener/WebListener.csproj b/test/tools/WebListener/WebListener.csproj index 8614e5b136e..d95182c68ce 100644 --- a/test/tools/WebListener/WebListener.csproj +++ b/test/tools/WebListener/WebListener.csproj @@ -13,8 +13,4 @@ - - - -