mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-04-24 09:18:27 +02:00
Add client certificate support (#862)
* Add client certificate support * Add missing test certificate file * Review fixes * Review fixes * Review fixes * Review fixes
This commit is contained in:
@@ -96,4 +96,16 @@ public class SettingsModel
|
|||||||
/// Default value = "All".
|
/// Default value = "All".
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public QueryParameterMultipleValueSupport? QueryParameterMultipleValueSupport { get; set; }
|
public QueryParameterMultipleValueSupport? QueryParameterMultipleValueSupport { get; set; }
|
||||||
|
|
||||||
|
#if NETSTANDARD1_3_OR_GREATER || NET461
|
||||||
|
/// <summary>
|
||||||
|
/// Server client certificate mode
|
||||||
|
/// </summary>
|
||||||
|
public ClientCertificateMode ClientCertificateMode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether to accept any client certificate
|
||||||
|
/// </summary>
|
||||||
|
public bool AcceptAnyClientCertificate { get; set; }
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
#if NETSTANDARD1_3_OR_GREATER || NET461
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
#endif
|
||||||
using WireMock.Types;
|
using WireMock.Types;
|
||||||
using WireMock.Util;
|
using WireMock.Util;
|
||||||
|
|
||||||
@@ -134,4 +137,11 @@ public interface IRequestMessage
|
|||||||
/// Gets the origin
|
/// Gets the origin
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string Origin { get; }
|
string Origin { get; }
|
||||||
|
|
||||||
|
#if NETSTANDARD1_3_OR_GREATER || NET461
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the connection's client certificate
|
||||||
|
/// </summary>
|
||||||
|
X509Certificate2? ClientCertificate { get; }
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
31
src/WireMock.Net.Abstractions/Types/ClientCertificateMode.cs
Normal file
31
src/WireMock.Net.Abstractions/Types/ClientCertificateMode.cs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
namespace WireMock.Types;
|
||||||
|
|
||||||
|
#if NETSTANDARD1_3_OR_GREATER || NET461
|
||||||
|
/// <summary>
|
||||||
|
/// Describes the client certificate requirements for a HTTPS connection.
|
||||||
|
/// This enum is the same as https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.server.kestrel.https.clientcertificatemode
|
||||||
|
/// </summary>
|
||||||
|
public enum ClientCertificateMode
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A client certificate is not required and will not be requested from clients.
|
||||||
|
/// </summary>
|
||||||
|
NoCertificate,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A client certificate will be requested; however, authentication will not fail if a certificate is not provided by the client.
|
||||||
|
/// </summary>
|
||||||
|
AllowCertificate,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A client certificate will be requested, and the client must provide a valid certificate for authentication to succeed.
|
||||||
|
/// </summary>
|
||||||
|
RequireCertificate,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A client certificate is not required and will not be requested from clients at the start of the connection.
|
||||||
|
/// It may be requested by the application later.
|
||||||
|
/// </summary>
|
||||||
|
DelayCertificate,
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
<Description>Commonly used models, enumerations and types.</Description>
|
<Description>Commonly used models, enumerations and types.</Description>
|
||||||
<AssemblyTitle>WireMock.Net.Abstractions</AssemblyTitle>
|
<AssemblyTitle>WireMock.Net.Abstractions</AssemblyTitle>
|
||||||
<Authors>Stef Heyenrath</Authors>
|
<Authors>Stef Heyenrath</Authors>
|
||||||
<TargetFrameworks>net45;net451;netstandard1.0;netstandard2.0;netstandard2.1</TargetFrameworks>
|
<TargetFrameworks>net45;net451;net461;netstandard1.0;netstandard1.3;netstandard2.0;netstandard2.1</TargetFrameworks>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<NoWarn>$(NoWarn);1591;8603</NoWarn>
|
<NoWarn>$(NoWarn);1591;8603</NoWarn>
|
||||||
<AssemblyName>WireMock.Net.Abstractions</AssemblyName>
|
<AssemblyName>WireMock.Net.Abstractions</AssemblyName>
|
||||||
@@ -41,6 +41,16 @@
|
|||||||
</PackageReference>
|
</PackageReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup Condition="$(TargetFramework.StartsWith('netstandard')) and '$(TargetFramework)' != 'netstandard1.0'">
|
||||||
|
<PackageReference Include="System.Security.Cryptography.X509Certificates" Version="4.3.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup Condition="'$(TargetFramework)' == 'net461'">
|
||||||
|
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies.net46" Version="1.0.2">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
</ItemGroup>
|
||||||
<!--<ItemGroup Condition="'$(TargetFramework)' == 'net45'">
|
<!--<ItemGroup Condition="'$(TargetFramework)' == 'net45'">
|
||||||
<PackageReference Include="Nullable" Version="1.2.1">
|
<PackageReference Include="Nullable" Version="1.2.1">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
|||||||
@@ -2,9 +2,10 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
||||||
|
using Microsoft.AspNetCore.Server.Kestrel.Https;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using WireMock.HttpsCertificate;
|
using CertificateLoader = WireMock.HttpsCertificate.CertificateLoader;
|
||||||
|
|
||||||
namespace WireMock.Owin
|
namespace WireMock.Owin
|
||||||
{
|
{
|
||||||
@@ -26,21 +27,25 @@ namespace WireMock.Owin
|
|||||||
{
|
{
|
||||||
kestrelOptions.ListenAnyIP(urlDetail.Port, listenOptions =>
|
kestrelOptions.ListenAnyIP(urlDetail.Port, listenOptions =>
|
||||||
{
|
{
|
||||||
if (wireMockMiddlewareOptions.CustomCertificateDefined)
|
listenOptions.UseHttps(options =>
|
||||||
{
|
{
|
||||||
listenOptions.UseHttps(CertificateLoader.LoadCertificate(
|
if (wireMockMiddlewareOptions.CustomCertificateDefined)
|
||||||
wireMockMiddlewareOptions.X509StoreName,
|
{
|
||||||
wireMockMiddlewareOptions.X509StoreLocation,
|
options.ServerCertificate = CertificateLoader.LoadCertificate(
|
||||||
wireMockMiddlewareOptions.X509ThumbprintOrSubjectName,
|
wireMockMiddlewareOptions.X509StoreName,
|
||||||
wireMockMiddlewareOptions.X509CertificateFilePath,
|
wireMockMiddlewareOptions.X509StoreLocation,
|
||||||
wireMockMiddlewareOptions.X509CertificatePassword,
|
wireMockMiddlewareOptions.X509ThumbprintOrSubjectName,
|
||||||
urlDetail.Host)
|
wireMockMiddlewareOptions.X509CertificateFilePath,
|
||||||
);
|
wireMockMiddlewareOptions.X509CertificatePassword,
|
||||||
}
|
urlDetail.Host);
|
||||||
else
|
}
|
||||||
{
|
|
||||||
listenOptions.UseHttps();
|
options.ClientCertificateMode = (ClientCertificateMode) wireMockMiddlewareOptions.ClientCertificateMode;
|
||||||
}
|
if (wireMockMiddlewareOptions.AcceptAnyClientCertificate)
|
||||||
|
{
|
||||||
|
options.ClientCertificateValidation = (_, _, _) => true;
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel;
|
using Microsoft.AspNetCore.Server.Kestrel;
|
||||||
|
using Microsoft.AspNetCore.Server.Kestrel.Https;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using WireMock.HttpsCertificate;
|
using WireMock.HttpsCertificate;
|
||||||
@@ -23,21 +24,22 @@ internal partial class AspNetCoreSelfHost
|
|||||||
{
|
{
|
||||||
if (urlDetail.IsHttps)
|
if (urlDetail.IsHttps)
|
||||||
{
|
{
|
||||||
if (wireMockMiddlewareOptions.CustomCertificateDefined)
|
options.UseHttps(new HttpsConnectionFilterOptions
|
||||||
{
|
{
|
||||||
options.UseHttps(CertificateLoader.LoadCertificate(
|
ServerCertificate = wireMockMiddlewareOptions.CustomCertificateDefined
|
||||||
wireMockMiddlewareOptions.X509StoreName,
|
? CertificateLoader.LoadCertificate(
|
||||||
wireMockMiddlewareOptions.X509StoreLocation,
|
wireMockMiddlewareOptions.X509StoreName,
|
||||||
wireMockMiddlewareOptions.X509ThumbprintOrSubjectName,
|
wireMockMiddlewareOptions.X509StoreLocation,
|
||||||
wireMockMiddlewareOptions.X509CertificateFilePath,
|
wireMockMiddlewareOptions.X509ThumbprintOrSubjectName,
|
||||||
wireMockMiddlewareOptions.X509CertificatePassword,
|
wireMockMiddlewareOptions.X509CertificateFilePath,
|
||||||
urlDetail.Host)
|
wireMockMiddlewareOptions.X509CertificatePassword,
|
||||||
);
|
urlDetail.Host)
|
||||||
}
|
: PublicCertificateHelper.GetX509Certificate2(),
|
||||||
else
|
ClientCertificateMode = (ClientCertificateMode) wireMockMiddlewareOptions.ClientCertificateMode,
|
||||||
{
|
ClientCertificateValidation = wireMockMiddlewareOptions.AcceptAnyClientCertificate
|
||||||
options.UseHttps(PublicCertificateHelper.GetX509Certificate2());
|
? (_, _, _) => true
|
||||||
}
|
: null,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,10 @@ internal interface IWireMockMiddlewareOptions
|
|||||||
Action<IServiceCollection>? AdditionalServiceRegistration { get; set; }
|
Action<IServiceCollection>? AdditionalServiceRegistration { get; set; }
|
||||||
|
|
||||||
CorsPolicyOptions? CorsPolicyOptions { get; set; }
|
CorsPolicyOptions? CorsPolicyOptions { get; set; }
|
||||||
|
|
||||||
|
ClientCertificateMode ClientCertificateMode { get; set; }
|
||||||
|
|
||||||
|
bool AcceptAnyClientCertificate { get; set; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
IFileSystemHandler? FileSystemHandler { get; set; }
|
IFileSystemHandler? FileSystemHandler { get; set; }
|
||||||
|
|||||||
@@ -68,7 +68,21 @@ namespace WireMock.Owin.Mappers
|
|||||||
body = await BodyParser.ParseAsync(bodyParserSettings).ConfigureAwait(false);
|
body = await BodyParser.ParseAsync(bodyParserSettings).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new RequestMessage(options, urlDetails, method, clientIP, body, headers, cookies) { DateTime = DateTime.UtcNow };
|
return new RequestMessage(
|
||||||
|
options,
|
||||||
|
urlDetails,
|
||||||
|
method,
|
||||||
|
clientIP,
|
||||||
|
body,
|
||||||
|
headers,
|
||||||
|
cookies
|
||||||
|
#if USE_ASPNETCORE
|
||||||
|
, await request.HttpContext.Connection.GetClientCertificateAsync()
|
||||||
|
#endif
|
||||||
|
)
|
||||||
|
{
|
||||||
|
DateTime = DateTime.UtcNow
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static (UrlDetails UrlDetails, string ClientIP) ParseRequest(IRequest request)
|
private static (UrlDetails UrlDetails, string ClientIP) ParseRequest(IRequest request)
|
||||||
|
|||||||
@@ -42,6 +42,11 @@ internal class WireMockMiddlewareOptions : IWireMockMiddlewareOptions
|
|||||||
public Action<IServiceCollection>? AdditionalServiceRegistration { get; set; }
|
public Action<IServiceCollection>? AdditionalServiceRegistration { get; set; }
|
||||||
|
|
||||||
public CorsPolicyOptions? CorsPolicyOptions { get; set; }
|
public CorsPolicyOptions? CorsPolicyOptions { get; set; }
|
||||||
|
|
||||||
|
public ClientCertificateMode ClientCertificateMode { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool AcceptAnyClientCertificate { get; set; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// <inheritdoc cref="IWireMockMiddlewareOptions.FileSystemHandler"/>
|
/// <inheritdoc cref="IWireMockMiddlewareOptions.FileSystemHandler"/>
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
#if USE_ASPNETCORE
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
#endif
|
||||||
using Stef.Validation;
|
using Stef.Validation;
|
||||||
using WireMock.Models;
|
using WireMock.Models;
|
||||||
using WireMock.Owin;
|
using WireMock.Owin;
|
||||||
@@ -92,6 +95,11 @@ public class RequestMessage : IRequestMessage
|
|||||||
/// <inheritdoc cref="IRequestMessage.Origin" />
|
/// <inheritdoc cref="IRequestMessage.Origin" />
|
||||||
public string Origin { get; }
|
public string Origin { get; }
|
||||||
|
|
||||||
|
#if USE_ASPNETCORE
|
||||||
|
/// <inheritdoc cref="IRequestMessage.ClientCertificate" />
|
||||||
|
public X509Certificate2? ClientCertificate { get; }
|
||||||
|
#endif
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Used for Unit Testing
|
/// Used for Unit Testing
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -115,13 +123,20 @@ public class RequestMessage : IRequestMessage
|
|||||||
/// <param name="bodyData">The BodyData.</param>
|
/// <param name="bodyData">The BodyData.</param>
|
||||||
/// <param name="headers">The headers.</param>
|
/// <param name="headers">The headers.</param>
|
||||||
/// <param name="cookies">The cookies.</param>
|
/// <param name="cookies">The cookies.</param>
|
||||||
|
#if USE_ASPNETCORE
|
||||||
|
/// <param name="clientCertificate">The client certificate</param>
|
||||||
|
#endif
|
||||||
internal RequestMessage(
|
internal RequestMessage(
|
||||||
IWireMockMiddlewareOptions? options,
|
IWireMockMiddlewareOptions? options,
|
||||||
UrlDetails urlDetails, string method,
|
UrlDetails urlDetails, string method,
|
||||||
string clientIP,
|
string clientIP,
|
||||||
IBodyData? bodyData = null,
|
IBodyData? bodyData = null,
|
||||||
IDictionary<string, string[]>? headers = null,
|
IDictionary<string, string[]>? headers = null,
|
||||||
IDictionary<string, string>? cookies = null)
|
IDictionary<string, string>? cookies = null
|
||||||
|
#if USE_ASPNETCORE
|
||||||
|
, X509Certificate2? clientCertificate = null
|
||||||
|
#endif
|
||||||
|
)
|
||||||
{
|
{
|
||||||
Guard.NotNull(urlDetails, nameof(urlDetails));
|
Guard.NotNull(urlDetails, nameof(urlDetails));
|
||||||
Guard.NotNull(method, nameof(method));
|
Guard.NotNull(method, nameof(method));
|
||||||
@@ -156,6 +171,9 @@ public class RequestMessage : IRequestMessage
|
|||||||
Cookies = cookies;
|
Cookies = cookies;
|
||||||
RawQuery = urlDetails.Url.Query;
|
RawQuery = urlDetails.Url.Query;
|
||||||
Query = QueryStringParser.Parse(RawQuery, options?.QueryParameterMultipleValueSupport);
|
Query = QueryStringParser.Parse(RawQuery, options?.QueryParameterMultipleValueSupport);
|
||||||
|
#if USE_ASPNETCORE
|
||||||
|
ClientCertificate = clientCertificate;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -226,7 +226,9 @@ public partial class WireMockServer
|
|||||||
QueryParameterMultipleValueSupport = _settings.QueryParameterMultipleValueSupport,
|
QueryParameterMultipleValueSupport = _settings.QueryParameterMultipleValueSupport,
|
||||||
|
|
||||||
#if USE_ASPNETCORE
|
#if USE_ASPNETCORE
|
||||||
CorsPolicyOptions = _settings.CorsPolicyOptions?.ToString()
|
CorsPolicyOptions = _settings.CorsPolicyOptions?.ToString(),
|
||||||
|
ClientCertificateMode = _settings.ClientCertificateMode,
|
||||||
|
AcceptAnyClientCertificate = _settings.AcceptAnyClientCertificate
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -275,6 +277,9 @@ public partial class WireMockServer
|
|||||||
_settings.CorsPolicyOptions = corsPolicyOptions;
|
_settings.CorsPolicyOptions = corsPolicyOptions;
|
||||||
_options.CorsPolicyOptions = corsPolicyOptions;
|
_options.CorsPolicyOptions = corsPolicyOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_options.ClientCertificateMode = _settings.ClientCertificateMode;
|
||||||
|
_options.AcceptAnyClientCertificate = _settings.AcceptAnyClientCertificate;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return ResponseMessageBuilder.Create("Settings updated");
|
return ResponseMessageBuilder.Create("Settings updated");
|
||||||
|
|||||||
@@ -331,6 +331,8 @@ public partial class WireMockServer : IWireMockServer
|
|||||||
#if USE_ASPNETCORE
|
#if USE_ASPNETCORE
|
||||||
_options.AdditionalServiceRegistration = _settings.AdditionalServiceRegistration;
|
_options.AdditionalServiceRegistration = _settings.AdditionalServiceRegistration;
|
||||||
_options.CorsPolicyOptions = _settings.CorsPolicyOptions;
|
_options.CorsPolicyOptions = _settings.CorsPolicyOptions;
|
||||||
|
_options.ClientCertificateMode = _settings.ClientCertificateMode;
|
||||||
|
_options.AcceptAnyClientCertificate = _settings.AcceptAnyClientCertificate;
|
||||||
|
|
||||||
_httpServer = new AspNetCoreSelfHost(_options, urlOptions);
|
_httpServer = new AspNetCoreSelfHost(_options, urlOptions);
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -235,6 +235,19 @@ public class WireMockServerSettings
|
|||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public bool CustomCertificateDefined => CertificateSettings?.IsDefined == true;
|
public bool CustomCertificateDefined => CertificateSettings?.IsDefined == true;
|
||||||
|
|
||||||
|
#if USE_ASPNETCORE
|
||||||
|
/// <summary>
|
||||||
|
/// Client certificate mode for the server
|
||||||
|
/// </summary>
|
||||||
|
[PublicAPI]
|
||||||
|
public ClientCertificateMode ClientCertificateMode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether to accept any client certificate
|
||||||
|
/// </summary>
|
||||||
|
public bool AcceptAnyClientCertificate { get; set; }
|
||||||
|
#endif
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines the global IWebhookSettings to use.
|
/// Defines the global IWebhookSettings to use.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -64,6 +64,8 @@ public static class WireMockServerSettingsParser
|
|||||||
|
|
||||||
#if USE_ASPNETCORE
|
#if USE_ASPNETCORE
|
||||||
settings.CorsPolicyOptions = parser.GetEnumValue(nameof(WireMockServerSettings.CorsPolicyOptions), CorsPolicyOptions.None);
|
settings.CorsPolicyOptions = parser.GetEnumValue(nameof(WireMockServerSettings.CorsPolicyOptions), CorsPolicyOptions.None);
|
||||||
|
settings.ClientCertificateMode = parser.GetEnumValue(nameof(WireMockServerSettings.ClientCertificateMode), ClientCertificateMode.NoCertificate);
|
||||||
|
settings.AcceptAnyClientCertificate = parser.GetBoolValue(nameof(WireMockServerSettings.AcceptAnyClientCertificate));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
var loggerType = parser.GetStringValue("WireMockLogger");
|
var loggerType = parser.GetStringValue("WireMockLogger");
|
||||||
|
|||||||
7
test/WireMock.Net.Tests/README.md
Normal file
7
test/WireMock.Net.Tests/README.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
## Creating a client certificate like client_cert.pfx
|
||||||
|
|
||||||
|
Follow the instructions to [create a root certificate](https://learn.microsoft.com/en-us/aspnet/core/security/authentication/certauth?view=aspnetcore-7.0#create-root-ca),
|
||||||
|
then [trust it](https://learn.microsoft.com/en-us/aspnet/core/security/authentication/certauth?view=aspnetcore-7.0#install-in-the-trusted-root)
|
||||||
|
and [create a child certificate from it](https://learn.microsoft.com/en-us/aspnet/core/security/authentication/certauth?view=aspnetcore-7.0#create-child-certificate-from-root-certificate).
|
||||||
|
|
||||||
|
Since the root certificate of `client_cert.pfx` is obviously not trusted automatically by cloning this repo, the tests in `WireMockServerTests.ClientCertificate.cs` set `WireMockServerSettings.AcceptAnyClientCertificate` to `true` so that tests pass even if the device hasn't trusted the root of `client_cert.pfx`.
|
||||||
@@ -96,6 +96,10 @@
|
|||||||
<None Update="__admin\mappings\subdirectory\*.xml">
|
<None Update="__admin\mappings\subdirectory\*.xml">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
|
<None Update="client_cert.pfx">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
<DependentUpon>WireMockServerTests.ClientCertificate.cs</DependentUpon>
|
||||||
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
#if !NET451 && !NET452
|
||||||
|
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using FluentAssertions;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
using WireMock.RequestBuilders;
|
||||||
|
using WireMock.ResponseBuilders;
|
||||||
|
using WireMock.Server;
|
||||||
|
using WireMock.Settings;
|
||||||
|
using WireMock.Types;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace WireMock.Net.Tests;
|
||||||
|
|
||||||
|
public partial class WireMockServerTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public async Task WireMockServer_WithRequiredClientCertificates_Should_Work_Correct()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var settings = new WireMockServerSettings
|
||||||
|
{
|
||||||
|
ClientCertificateMode = ClientCertificateMode.RequireCertificate,
|
||||||
|
AcceptAnyClientCertificate = true,
|
||||||
|
UseSSL = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
using var server = WireMockServer.Start(settings);
|
||||||
|
|
||||||
|
server.Given(Request.Create().WithPath("/*"))
|
||||||
|
.RespondWith(Response.Create().WithCallback(message => new ResponseMessage
|
||||||
|
{
|
||||||
|
StatusCode = message.ClientCertificate?.Thumbprint == "2E32E3528C87046A95B8B0BA172A1597C3AF3A9D"
|
||||||
|
? 200
|
||||||
|
: 403
|
||||||
|
}));
|
||||||
|
|
||||||
|
var certificates = new X509Certificate2Collection();
|
||||||
|
certificates.Import("client_cert.pfx", "1234", X509KeyStorageFlags.Exportable);
|
||||||
|
|
||||||
|
var httpMessageHandler = new HttpClientHandler
|
||||||
|
{
|
||||||
|
ServerCertificateCustomValidationCallback = (_, _, _, _) => true,
|
||||||
|
};
|
||||||
|
httpMessageHandler.ClientCertificates.AddRange(certificates);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await new HttpClient(httpMessageHandler)
|
||||||
|
.GetAsync("https://localhost:" + server.Ports[0] + "/foo")
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
BIN
test/WireMock.Net.Tests/client_cert.pfx
Normal file
BIN
test/WireMock.Net.Tests/client_cert.pfx
Normal file
Binary file not shown.
Reference in New Issue
Block a user