Add mitigations to HttpsClientCert_GetCertInformation flakiness (#1529)

This commit is contained in:
Justin Kotalik 2018-10-18 08:49:52 -07:00 committed by GitHub
parent 8f99140f30
commit 48d40e0e36
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 83 additions and 61 deletions

View File

@ -14,8 +14,8 @@
"commandLineArgs": "$(IISExpressArguments)", "commandLineArgs": "$(IISExpressArguments)",
"environmentVariables": { "environmentVariables": {
"IIS_SITE_PATH": "$(MSBuildThisFileDirectory)", "IIS_SITE_PATH": "$(MSBuildThisFileDirectory)",
"ANCM_PATH": "$(AncmPath)", "ANCM_PATH": "$(AspNetCoreModuleV1ShimDll)",
"ANCMV2_PATH": "$(AncmV2Path)", "ANCMV2_PATH": "$(AspNetCoreModuleV2ShimDll)",
"ANCM_OUTOFPROCESS_HANDLER": "$(AspNetCoreModuleV2OutOfProcessHandlerDll)", "ANCM_OUTOFPROCESS_HANDLER": "$(AspNetCoreModuleV2OutOfProcessHandlerDll)",
"LAUNCHER_ARGS": "$(TargetPath)", "LAUNCHER_ARGS": "$(TargetPath)",
"ASPNETCORE_ENVIRONMENT": "Development", "ASPNETCORE_ENVIRONMENT": "Development",
@ -29,9 +29,9 @@
"commandLineArgs": "$(IISArguments)", "commandLineArgs": "$(IISArguments)",
"environmentVariables": { "environmentVariables": {
"IIS_SITE_PATH": "$(MSBuildThisFileDirectory)", "IIS_SITE_PATH": "$(MSBuildThisFileDirectory)",
"ANCM_PATH": "$(AncmPath)", "ANCM_PATH": "$(AspNetCoreModuleV1ShimDll)",
"ANCMV2_PATH": "$(AncmV2Path)", "ANCMV2_PATH": "$(AspNetCoreModuleV2ShimDll)",
"ANCM_OUTOFPROCESS_HANDLER": "$(AspNetCoreModuleV2OutOfProcessHandlerDll)", "ASPNETCORE_MODULE_OUTOFPROCESS_HANDLER": "$(AspNetCoreModuleV2OutOfProcessHandlerDll)",
"LAUNCHER_ARGS": "$(TargetPath)", "LAUNCHER_ARGS": "$(TargetPath)",
"ASPNETCORE_ENVIRONMENT": "Development", "ASPNETCORE_ENVIRONMENT": "Development",
"LAUNCHER_PATH": "$(DotNetPath)", "LAUNCHER_PATH": "$(DotNetPath)",

View File

@ -11,68 +11,57 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
public class ClientCertificateFixture : IDisposable public class ClientCertificateFixture : IDisposable
{ {
private X509Certificate2 _certificate; private X509Certificate2 _certificate;
private const string _certIssuerPrefix = "CN=IISIntegrationTest_Root";
public X509Certificate2 Certificate public X509Certificate2 GetOrCreateCertificate()
{ {
get if (_certificate != null)
{ {
if (_certificate != null) return _certificate;
{ }
return _certificate;
}
using (var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine)) using (var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine))
{ {
store.Open(OpenFlags.ReadWrite); store.Open(OpenFlags.ReadWrite);
var parentKey = CreateKeyMaterial(2048);
foreach (var cert in store.Certificates) // Create a cert name with a random guid to avoid name conflicts
{ var parentRequest = new CertificateRequest(
if (cert.Issuer != "CN=IISIntegrationTest_Root") _certIssuerPrefix + Guid.NewGuid().ToString(),
{ parentKey, HashAlgorithmName.SHA256,
continue; RSASignaturePadding.Pkcs1);
}
_certificate = cert;
store.Close();
return cert;
}
var parentKey = CreateKeyMaterial(2048); parentRequest.CertificateExtensions.Add(
new X509BasicConstraintsExtension(
certificateAuthority: true,
hasPathLengthConstraint: false,
pathLengthConstraint: 0,
critical: true));
// On first run of the test, creates the certificate in the trusted root certificate authorities. parentRequest.CertificateExtensions.Add(
var parentRequest = new CertificateRequest("CN=IISIntegrationTest_Root", parentKey, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); new X509KeyUsageExtension(X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.NonRepudiation, critical: true));
parentRequest.CertificateExtensions.Add( parentRequest.CertificateExtensions.Add(
new X509BasicConstraintsExtension( new X509SubjectKeyIdentifierExtension(parentRequest.PublicKey, false));
certificateAuthority: true,
hasPathLengthConstraint: false,
pathLengthConstraint: 0,
critical: true));
parentRequest.CertificateExtensions.Add( var notBefore = DateTimeOffset.Now.AddDays(-1);
new X509KeyUsageExtension(X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.NonRepudiation, critical: true)); var notAfter = DateTimeOffset.Now.AddYears(5);
parentRequest.CertificateExtensions.Add( var parentCert = parentRequest.CreateSelfSigned(notBefore, notAfter);
new X509SubjectKeyIdentifierExtension(parentRequest.PublicKey, false));
var notBefore = DateTimeOffset.Now.AddDays(-1); // Need to export/import the certificate to associate the private key with the cert.
var notAfter = DateTimeOffset.Now.AddYears(5); var imported = parentCert;
var parentCert = parentRequest.CreateSelfSigned(notBefore, notAfter); var export = parentCert.Export(X509ContentType.Pkcs12, "");
imported = new X509Certificate2(export, "", X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
Array.Clear(export, 0, export.Length);
// Need to export/import the certificate to associate the private key with the cert. // Add the cert to the cert store
var imported = parentCert; _certificate = imported;
var export = parentCert.Export(X509ContentType.Pkcs12, ""); store.Add(certificate: imported);
imported = new X509Certificate2(export, "", X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable); store.Close();
Array.Clear(export, 0, export.Length); return imported;
// Add the cert to the cert store
_certificate = imported;
store.Add(certificate: imported);
store.Close();
return imported;
}
} }
} }
@ -86,7 +75,17 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
using (var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine)) using (var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine))
{ {
store.Open(OpenFlags.ReadWrite); store.Open(OpenFlags.ReadWrite);
store.Remove(Certificate); store.Remove(_certificate);
// Remove any extra certs that were left by previous tests.
for (var i = store.Certificates.Count - 1; i >= 0; i--)
{
var cert = store.Certificates[i];
if (cert.Issuer.StartsWith(_certIssuerPrefix))
{
store.Remove(cert);
}
}
store.Close(); store.Close();
} }
} }

View File

@ -1,7 +1,9 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Net.Http; using System.Net.Http;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities; using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities;
using Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests; using Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests;
@ -9,6 +11,7 @@ using Microsoft.AspNetCore.Server.IntegrationTesting;
using Microsoft.AspNetCore.Server.IntegrationTesting.Common; using Microsoft.AspNetCore.Server.IntegrationTesting.Common;
using Microsoft.AspNetCore.Server.IntegrationTesting.IIS; using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
using Microsoft.AspNetCore.Testing.xunit; using Microsoft.AspNetCore.Testing.xunit;
using Microsoft.Extensions.Logging;
using Xunit; using Xunit;
namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
@ -54,31 +57,51 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
deploymentParameters.ApplicationBaseUriHint = $"https://localhost:{port}/"; deploymentParameters.ApplicationBaseUriHint = $"https://localhost:{port}/";
deploymentParameters.AddHttpsToServerConfig(); deploymentParameters.AddHttpsToServerConfig();
var deploymentResult = await DeployAsync(deploymentParameters);
var handler = new HttpClientHandler var handler = new HttpClientHandler
{ {
ServerCertificateCustomValidationCallback = (a, b, c, d) => true, ServerCertificateCustomValidationCallback = (a, b, c, d) => true,
ClientCertificateOptions = ClientCertificateOption.Manual, ClientCertificateOptions = ClientCertificateOption.Manual,
}; };
X509Certificate2 cert = null;
if (sendClientCert) if (sendClientCert)
{ {
Assert.NotNull(_certFixture.Certificate); cert = _certFixture.GetOrCreateCertificate();
handler.ClientCertificates.Add(_certFixture.Certificate); handler.ClientCertificates.Add(cert);
} }
var deploymentResult = await DeployAsync(deploymentParameters);
var client = deploymentResult.CreateClient(handler); var client = deploymentResult.CreateClient(handler);
var response = await client.GetAsync("GetClientCert"); var response = await client.GetAsync("GetClientCert");
var responseText = await response.Content.ReadAsStringAsync(); var responseText = await response.Content.ReadAsStringAsync();
if (sendClientCert) try
{ {
Assert.Equal($"Enabled;{_certFixture.Certificate.GetCertHashString()}", responseText); if (sendClientCert)
{
Assert.Equal($"Enabled;{cert.GetCertHashString()}", responseText);
}
else
{
Assert.Equal("Disabled", responseText);
}
} }
else catch (Exception ex)
{ {
Assert.Equal("Disabled", responseText); Logger.LogError($"Certificate is invalid. Issuer name: {cert.Issuer}");
using (var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine))
{
Logger.LogError($"List of current certificates in root store:");
store.Open(OpenFlags.ReadWrite);
foreach (var otherCert in store.Certificates)
{
Logger.LogError(otherCert.Issuer);
}
store.Close();
}
throw ex;
} }
} }
} }