diff --git a/src/WireMock.Net/Http/HttpClientBuilder.cs b/src/WireMock.Net/Http/HttpClientBuilder.cs index 6e9e6a17..1051b503 100644 --- a/src/WireMock.Net/Http/HttpClientBuilder.cs +++ b/src/WireMock.Net/Http/HttpClientBuilder.cs @@ -35,9 +35,14 @@ internal static class HttpClientBuilder { handler.ClientCertificateOptions = ClientCertificateOption.Manual; - var x509Certificate2 = CertificateLoader.LoadCertificate(settings.ClientX509Certificate2ThumbprintOrSubjectName); + var x509Certificate2 = CertificateLoader.LoadCertificate(settings.ClientX509Certificate2ThumbprintOrSubjectName!); handler.ClientCertificates.Add(x509Certificate2); } + else if (settings.Certificate != null) + { + handler.ClientCertificateOptions = ClientCertificateOption.Manual; + handler.ClientCertificates.Add(settings.Certificate); + } handler.AllowAutoRedirect = settings.AllowAutoRedirect == true; diff --git a/src/WireMock.Net/ResponseBuilders/IProxyResponseBuilder.cs b/src/WireMock.Net/ResponseBuilders/IProxyResponseBuilder.cs index 0fd6cd85..716cdd0d 100644 --- a/src/WireMock.Net/ResponseBuilders/IProxyResponseBuilder.cs +++ b/src/WireMock.Net/ResponseBuilders/IProxyResponseBuilder.cs @@ -1,4 +1,4 @@ -using JetBrains.Annotations; +using System.Security.Cryptography.X509Certificates; using WireMock.Settings; namespace WireMock.ResponseBuilders; @@ -17,9 +17,17 @@ public interface IProxyResponseBuilder : IStatusCodeResponseBuilder IResponseBuilder WithProxy(string proxyUrl, string? clientX509Certificate2ThumbprintOrSubjectName = null); /// - /// WithProxy using IProxyAndRecordSettings. + /// WithProxy using . /// - /// The IProxyAndRecordSettings. + /// The ProxyAndRecordSettings. /// A . - IResponseBuilder WithProxy([NotNull] ProxyAndRecordSettings settings); + IResponseBuilder WithProxy(ProxyAndRecordSettings settings); + + /// + /// WithProxy using . + /// + /// The proxy url. + /// The X509Certificate2. + /// A . + IResponseBuilder WithProxy(string proxyUrl, X509Certificate2 certificate); } \ No newline at end of file diff --git a/src/WireMock.Net/ResponseBuilders/Response.WithProxy.cs b/src/WireMock.Net/ResponseBuilders/Response.WithProxy.cs index 51e0fb62..359745eb 100644 --- a/src/WireMock.Net/ResponseBuilders/Response.WithProxy.cs +++ b/src/WireMock.Net/ResponseBuilders/Response.WithProxy.cs @@ -2,6 +2,7 @@ using System.Net.Http; using WireMock.Http; using WireMock.Settings; using Stef.Validation; +using System.Security.Cryptography.X509Certificates; namespace WireMock.ResponseBuilders; @@ -38,4 +39,19 @@ public partial class Response _httpClientForProxy = HttpClientBuilder.Build(settings); return this; } + + /// + public IResponseBuilder WithProxy(string proxyUrl, X509Certificate2 certificate) + { + Guard.NotNullOrEmpty(proxyUrl); + Guard.NotNull(certificate); + + var settings = new ProxyAndRecordSettings + { + Url = proxyUrl, + Certificate = certificate + }; + + return WithProxy(settings); + } } \ No newline at end of file diff --git a/src/WireMock.Net/Settings/HttpClientSettings.cs b/src/WireMock.Net/Settings/HttpClientSettings.cs index 42805c1f..95a9d19a 100644 --- a/src/WireMock.Net/Settings/HttpClientSettings.cs +++ b/src/WireMock.Net/Settings/HttpClientSettings.cs @@ -1,9 +1,11 @@ +using System.Security.Cryptography.X509Certificates; + namespace WireMock.Settings; /// /// HttpClientSettings /// -public class HttpClientSettings +public abstract class HttpClientSettings { /// /// The clientCertificate thumbprint or subject name fragment to use. @@ -20,4 +22,9 @@ public class HttpClientSettings /// Proxy requests should follow redirection (30x). /// public bool? AllowAutoRedirect { get; set; } + + /// + /// The to use. + /// + public X509Certificate2? Certificate { get; set; } } \ No newline at end of file diff --git a/src/WireMock.Net/Settings/WireMockCertificateSettings.cs b/src/WireMock.Net/Settings/WireMockCertificateSettings.cs index c7c60eb9..d7ac4707 100644 --- a/src/WireMock.Net/Settings/WireMockCertificateSettings.cs +++ b/src/WireMock.Net/Settings/WireMockCertificateSettings.cs @@ -1,54 +1,53 @@ using JetBrains.Annotations; -namespace WireMock.Settings +namespace WireMock.Settings; + +/// +/// If https is used, these settings can be used to configure the CertificateSettings in case a custom certificate instead the default .NET certificate should be used. +/// +/// X509StoreName and X509StoreLocation should be defined +/// OR +/// X509CertificateFilePath and X509CertificatePassword should be defined +/// +public class WireMockCertificateSettings { /// - /// If https is used, these settings can be used to configure the CertificateSettings in case a custom certificate instead the default .NET certificate should be used. - /// + /// X509 StoreName (AddressBook, AuthRoot, CertificateAuthority, My, Root, TrustedPeople or TrustedPublisher) + /// + [PublicAPI] + public string? X509StoreName { get; set; } + + /// + /// X509 StoreLocation (CurrentUser or LocalMachine) + /// + [PublicAPI] + public string? X509StoreLocation { get; set; } + + /// + /// X509 Thumbprint or SubjectName (if not defined, the 'host' is used) + /// + [PublicAPI] + public string? X509StoreThumbprintOrSubjectName { get; set; } + + /// + /// X509Certificate FilePath + /// + [PublicAPI] + public string? X509CertificateFilePath { get; set; } + + /// + /// X509Certificate Password + /// + [PublicAPI] + public string? X509CertificatePassword { get; set; } + + /// /// X509StoreName and X509StoreLocation should be defined /// OR /// X509CertificateFilePath and X509CertificatePassword should be defined /// - public class WireMockCertificateSettings - { - /// - /// X509 StoreName (AddressBook, AuthRoot, CertificateAuthority, My, Root, TrustedPeople or TrustedPublisher) - /// - [PublicAPI] - public string? X509StoreName { get; set; } - - /// - /// X509 StoreLocation (CurrentUser or LocalMachine) - /// - [PublicAPI] - public string? X509StoreLocation { get; set; } - - /// - /// X509 Thumbprint or SubjectName (if not defined, the 'host' is used) - /// - [PublicAPI] - public string? X509StoreThumbprintOrSubjectName { get; set; } - - /// - /// X509Certificate FilePath - /// - [PublicAPI] - public string? X509CertificateFilePath { get; set; } - - /// - /// X509Certificate Password - /// - [PublicAPI] - public string? X509CertificatePassword { get; set; } - - /// - /// X509StoreName and X509StoreLocation should be defined - /// OR - /// X509CertificateFilePath and X509CertificatePassword should be defined - /// - [PublicAPI] - public bool IsDefined => - !string.IsNullOrEmpty(X509StoreName) && !string.IsNullOrEmpty(X509StoreLocation) || - !string.IsNullOrEmpty(X509CertificateFilePath); - } + [PublicAPI] + public bool IsDefined => + !string.IsNullOrEmpty(X509StoreName) && !string.IsNullOrEmpty(X509StoreLocation) || + !string.IsNullOrEmpty(X509CertificateFilePath); } \ No newline at end of file diff --git a/test/WireMock.Net.Tests/WireMockServer.Proxy.cs b/test/WireMock.Net.Tests/WireMockServer.Proxy.cs index 667d3ab6..ab43ed1b 100644 --- a/test/WireMock.Net.Tests/WireMockServer.Proxy.cs +++ b/test/WireMock.Net.Tests/WireMockServer.Proxy.cs @@ -1,6 +1,3 @@ -using FluentAssertions; -using Moq; -using NFluent; using System; using System.Linq; using System.Net; @@ -8,6 +5,9 @@ using System.Net.Http; using System.Net.Http.Headers; using System.Text; using System.Threading.Tasks; +using FluentAssertions; +using Moq; +using NFluent; using WireMock.Constants; using WireMock.Handlers; using WireMock.Matchers; @@ -144,9 +144,11 @@ public class WireMockServerProxyTests }; var server = WireMockServer.Start(settings); - server.Given(Request.Create() + server + .Given(Request.Create() .WithPath("/*") - .WithBody(new RegexMatcher(stringBody))) + .WithBody(new RegexMatcher(stringBody)) + ) .WithTitle(title) .WithDescription(description) .AtPriority(WireMockConstants.ProxyPriority)