From 360a1227e44b7242c33ab5045b01dd668ca4f4c4 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Tue, 16 May 2017 20:20:55 +0200 Subject: [PATCH] Added X509Certificate2Filename (#27) --- README.md | 3 +- .../Program.cs | 8 ++--- .../Program.cs | 8 +++-- src/WireMock.Net.StandAlone/Program.cs | 8 +++-- src/WireMock.Net/Http/HttpClientHelper.cs | 35 +++++++++++++++++-- .../Request/RequestMessageCompositeMatcher.cs | 17 ++------- src/WireMock.Net/Matchers/XPathMatcher.cs | 12 +++---- src/WireMock.Net/Owin/AspNetCoreSelfHost.cs | 2 +- src/WireMock.Net/Owin/OwinRequestMapper.cs | 7 ++-- src/WireMock.Net/Owin/OwinResponseMapper.cs | 4 +-- src/WireMock.Net/Owin/OwinSelfHost.cs | 2 +- src/WireMock.Net/Owin/WireMockMiddleware.cs | 8 ++--- .../ResponseBuilders/IProxyResponseBuilder.cs | 10 +++++- src/WireMock.Net/ResponseBuilders/Response.cs | 30 +++++++++++++--- src/WireMock.Net/Server/FluentMockServer.cs | 6 ++-- .../Settings/ProxyAndRecordSettings.cs | 5 +++ src/WireMock.Net/WireMock.Net.csproj | 22 ++++++------ 17 files changed, 122 insertions(+), 65 deletions(-) diff --git a/README.md b/README.md index d7db2ee8..d4787c7c 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,8 @@ A C# .NET version based on [mock4net](https://github.com/alexvictoor/mock4net) w ### Frameworks The following frameworks are supported: -- net45 and up +- net 4.5 +- net 4.5.2 and up - netstandard 1.3 ## Stubbing diff --git a/examples/WireMock.Net.Console.Record.NETCoreApp/Program.cs b/examples/WireMock.Net.Console.Record.NETCoreApp/Program.cs index 449ba75a..94943df5 100644 --- a/examples/WireMock.Net.Console.Record.NETCoreApp/Program.cs +++ b/examples/WireMock.Net.Console.Record.NETCoreApp/Program.cs @@ -2,21 +2,19 @@ using WireMock.Server; using WireMock.Settings; -namespace WireMock.Net.Console.NETCoreApp +namespace WireMock.Net.Console.Record.NETCoreApp { static class Program { static void Main(params string[] args) { - string url = "http://localhost:9095/"; - var server = FluentMockServer.Start(new FluentMockServerSettings { - Urls = new[] { url }, + Urls = new[] { "http://localhost:9095/", "https://localhost:9096/" }, StartAdminInterface = true, ProxyAndRecordSettings = new ProxyAndRecordSettings { - Url = "http://www.bbc.com", + Url = "https://www.msn.com", SaveMapping = true } }); diff --git a/src/WireMock.Net.StandAlone.NETCoreApp/Program.cs b/src/WireMock.Net.StandAlone.NETCoreApp/Program.cs index a7323167..5d9d4d0a 100644 --- a/src/WireMock.Net.StandAlone.NETCoreApp/Program.cs +++ b/src/WireMock.Net.StandAlone.NETCoreApp/Program.cs @@ -27,8 +27,11 @@ namespace WireMock.Net.StandAlone.NETCoreApp [ValueArgument(typeof(string), "ProxyURL", Description = "The ProxyURL to use.", Optional = true)] public string ProxyURL { get; set; } - [SwitchArgument("SaveProxyMapping", false, Description = "Save the proxied request and response mapping files in ./__admin/mappings. (default set to false).", Optional = true)] + [SwitchArgument("SaveProxyMapping", true, Description = "Save the proxied request and response mapping files in ./__admin/mappings. (default set to true).", Optional = true)] public bool SaveMapping { get; set; } + + [ValueArgument(typeof(string), "X509Certificate2", Description = "The X509Certificate2 Filename to use.", Optional = true)] + public string X509Certificate2Filename { get; set; } } static void Main(string[] args) @@ -58,7 +61,8 @@ namespace WireMock.Net.StandAlone.NETCoreApp settings.ProxyAndRecordSettings = new ProxyAndRecordSettings { Url = options.ProxyURL, - SaveMapping = options.SaveMapping + SaveMapping = options.SaveMapping, + X509Certificate2Filename = options.X509Certificate2Filename }; } diff --git a/src/WireMock.Net.StandAlone/Program.cs b/src/WireMock.Net.StandAlone/Program.cs index 381896ed..043c88f4 100644 --- a/src/WireMock.Net.StandAlone/Program.cs +++ b/src/WireMock.Net.StandAlone/Program.cs @@ -27,8 +27,11 @@ namespace WireMock.Net.StandAlone [ValueArgument(typeof(string), "ProxyURL", Description = "The ProxyURL to use.", Optional = true)] public string ProxyURL { get; set; } - [SwitchArgument("SaveProxyMapping", false, Description = "Save the proxied request and response mapping files in ./__admin/mappings. (default set to false).", Optional = true)] + [SwitchArgument("SaveProxyMapping", true, Description = "Save the proxied request and response mapping files in ./__admin/mappings. (default set to true).", Optional = true)] public bool SaveMapping { get; set; } + + [ValueArgument(typeof(string), "X509Certificate2", Description = "The X509Certificate2 Filename to use.", Optional = true)] + public string X509Certificate2Filename { get; set; } } static void Main(params string[] args) @@ -58,7 +61,8 @@ namespace WireMock.Net.StandAlone settings.ProxyAndRecordSettings = new ProxyAndRecordSettings { Url = options.ProxyURL, - SaveMapping = options.SaveMapping + SaveMapping = options.SaveMapping, + X509Certificate2Filename = options.X509Certificate2Filename }; } diff --git a/src/WireMock.Net/Http/HttpClientHelper.cs b/src/WireMock.Net/Http/HttpClientHelper.cs index d18d5765..0ca2915b 100644 --- a/src/WireMock.Net/Http/HttpClientHelper.cs +++ b/src/WireMock.Net/Http/HttpClientHelper.cs @@ -7,10 +7,39 @@ namespace WireMock.Http { internal static class HttpClientHelper { - private static HttpClient client = new HttpClient(); - - public static async Task SendAsync(RequestMessage requestMessage, string url) + private static HttpClient CreateHttpClient(string clientX509Certificate2Filename = null) { + if (!string.IsNullOrEmpty(clientX509Certificate2Filename)) + { +#if NETSTANDARD || NET46 + var handler = new HttpClientHandler + { + ClientCertificateOptions = ClientCertificateOption.Manual, + SslProtocols = System.Security.Authentication.SslProtocols.Tls12 | System.Security.Authentication.SslProtocols.Tls11 | System.Security.Authentication.SslProtocols.Tls, + ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true + }; + + handler.ClientCertificates.Add(new System.Security.Cryptography.X509Certificates.X509Certificate2(clientX509Certificate2Filename)); + return new HttpClient(handler); +#else + var handler = new WebRequestHandler + { + ClientCertificateOptions = ClientCertificateOption.Manual, + ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true + }; + + handler.ClientCertificates.Add(new System.Security.Cryptography.X509Certificates.X509Certificate2(clientX509Certificate2Filename)); + return new HttpClient(handler); +#endif + } + + return new HttpClient(); + } + + public static async Task SendAsync(RequestMessage requestMessage, string url, string clientX509Certificate2Filename = null) + { + var client = CreateHttpClient(clientX509Certificate2Filename); + var httpRequestMessage = new HttpRequestMessage(new HttpMethod(requestMessage.Method), url); // Overwrite the host header diff --git a/src/WireMock.Net/Matchers/Request/RequestMessageCompositeMatcher.cs b/src/WireMock.Net/Matchers/Request/RequestMessageCompositeMatcher.cs index 61c4079a..42a36022 100644 --- a/src/WireMock.Net/Matchers/Request/RequestMessageCompositeMatcher.cs +++ b/src/WireMock.Net/Matchers/Request/RequestMessageCompositeMatcher.cs @@ -43,25 +43,12 @@ namespace WireMock.Matchers.Request /// public double GetMatchingScore(RequestMessage requestMessage, RequestMatchResult requestMatchResult) { - var list = new List(); if (_type == CompositeMatcherType.And) { - foreach (var requestMatcher in RequestMatchers) - { - double score = requestMatcher.GetMatchingScore(requestMessage, requestMatchResult); - list.Add(score); - } - - return list.Sum() / list.Count; - } - - foreach (var requestMatcher in RequestMatchers) - { - double score = requestMatcher.GetMatchingScore(requestMessage, requestMatchResult); - list.Add(score); + return RequestMatchers.Average(requestMatcher => requestMatcher.GetMatchingScore(requestMessage, requestMatchResult)); } - return list.Max(); + return RequestMatchers.Max(requestMatcher => requestMatcher.GetMatchingScore(requestMessage, requestMatchResult)); } } } \ No newline at end of file diff --git a/src/WireMock.Net/Matchers/XPathMatcher.cs b/src/WireMock.Net/Matchers/XPathMatcher.cs index a5b92881..560f79d2 100644 --- a/src/WireMock.Net/Matchers/XPathMatcher.cs +++ b/src/WireMock.Net/Matchers/XPathMatcher.cs @@ -3,7 +3,7 @@ using System.Linq; using System.Xml; using JetBrains.Annotations; using WireMock.Validation; -#if NET45 +#if !NETSTANDARD using Wmhelp.XPath2; #endif @@ -41,10 +41,10 @@ namespace WireMock.Matchers try { var nav = new XmlDocument { InnerXml = input }.CreateNavigator(); -#if NET45 - return MatchScores.ToScore(_patterns.Select(p => true.Equals(nav.XPath2Evaluate($"boolean({p})")))); -#else +#if NETSTANDARD return MatchScores.ToScore(_patterns.Select(p => true.Equals(nav.Evaluate($"boolean({p})")))); +#else + return MatchScores.ToScore(_patterns.Select(p => true.Equals(nav.XPath2Evaluate($"boolean({p})")))); #endif } catch (Exception) @@ -65,9 +65,7 @@ namespace WireMock.Matchers /// /// Gets the name. /// - /// - /// Name - /// + /// Name public string GetName() { return "XPathMatcher"; diff --git a/src/WireMock.Net/Owin/AspNetCoreSelfHost.cs b/src/WireMock.Net/Owin/AspNetCoreSelfHost.cs index dee4a42b..abac138a 100644 --- a/src/WireMock.Net/Owin/AspNetCoreSelfHost.cs +++ b/src/WireMock.Net/Owin/AspNetCoreSelfHost.cs @@ -1,4 +1,4 @@ -#if !NET45 +#if NETSTANDARD using System; using System.Collections.Generic; using System.Threading; diff --git a/src/WireMock.Net/Owin/OwinRequestMapper.cs b/src/WireMock.Net/Owin/OwinRequestMapper.cs index 4ef64587..c8e4ba81 100644 --- a/src/WireMock.Net/Owin/OwinRequestMapper.cs +++ b/src/WireMock.Net/Owin/OwinRequestMapper.cs @@ -4,12 +4,11 @@ using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; -#if NET45 +#if !NETSTANDARD using Microsoft.Owin; #else using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Extensions; -using Microsoft.AspNetCore.Http.Features; #endif namespace WireMock.Owin @@ -25,14 +24,14 @@ namespace WireMock.Owin /// /// public async Task MapAsync( -#if NET45 +#if !NETSTANDARD IOwinRequest request #else HttpRequest request #endif ) { -#if NET45 +#if !NETSTANDARD Uri url = request.Uri; #else Uri url = new Uri(request.GetEncodedUrl()); diff --git a/src/WireMock.Net/Owin/OwinResponseMapper.cs b/src/WireMock.Net/Owin/OwinResponseMapper.cs index b0d03be4..d66c9fa4 100644 --- a/src/WireMock.Net/Owin/OwinResponseMapper.cs +++ b/src/WireMock.Net/Owin/OwinResponseMapper.cs @@ -2,7 +2,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -#if NET45 +#if !NETSTANDARD using Microsoft.Owin; #else using Microsoft.AspNetCore.Http; @@ -23,7 +23,7 @@ namespace WireMock.Owin /// /// public async Task MapAsync(ResponseMessage responseMessage -#if NET45 +#if !NETSTANDARD , IOwinResponse response #else , HttpResponse response diff --git a/src/WireMock.Net/Owin/OwinSelfHost.cs b/src/WireMock.Net/Owin/OwinSelfHost.cs index 6c3e285e..eb8588be 100644 --- a/src/WireMock.Net/Owin/OwinSelfHost.cs +++ b/src/WireMock.Net/Owin/OwinSelfHost.cs @@ -1,4 +1,4 @@ -#if NET45 +#if !NETSTANDARD using System; using System.Collections.Generic; using System.Threading; diff --git a/src/WireMock.Net/Owin/WireMockMiddleware.cs b/src/WireMock.Net/Owin/WireMockMiddleware.cs index f6bfc9b6..dc59a4ab 100644 --- a/src/WireMock.Net/Owin/WireMockMiddleware.cs +++ b/src/WireMock.Net/Owin/WireMockMiddleware.cs @@ -4,7 +4,7 @@ using System.Threading.Tasks; using WireMock.Logging; using WireMock.Matchers.Request; using System.Linq; -#if NET45 +#if !NETSTANDARD using Microsoft.Owin; #else using Microsoft.AspNetCore.Http; @@ -12,7 +12,7 @@ using Microsoft.AspNetCore.Http; namespace WireMock.Owin { -#if NET45 +#if !NETSTANDARD internal class WireMockMiddleware : OwinMiddleware #else internal class WireMockMiddleware @@ -24,7 +24,7 @@ namespace WireMock.Owin private readonly OwinRequestMapper _requestMapper = new OwinRequestMapper(); private readonly OwinResponseMapper _responseMapper = new OwinResponseMapper(); -#if NET45 +#if !NETSTANDARD public WireMockMiddleware(OwinMiddleware next, WireMockMiddlewareOptions options) : base(next) { _options = options; @@ -36,7 +36,7 @@ namespace WireMock.Owin } #endif -#if NET45 +#if !NETSTANDARD public override async Task Invoke(IOwinContext ctx) #else public async Task Invoke(HttpContext ctx) diff --git a/src/WireMock.Net/ResponseBuilders/IProxyResponseBuilder.cs b/src/WireMock.Net/ResponseBuilders/IProxyResponseBuilder.cs index 767707ce..820ee030 100644 --- a/src/WireMock.Net/ResponseBuilders/IProxyResponseBuilder.cs +++ b/src/WireMock.Net/ResponseBuilders/IProxyResponseBuilder.cs @@ -8,10 +8,18 @@ namespace WireMock.ResponseBuilders public interface IProxyResponseBuilder : IStatusCodeResponseBuilder { /// - /// From Proxy URL. + /// With Proxy URL. /// /// The proxy url. /// A . IResponseBuilder WithProxy([NotNull] string proxyUrl); + + /// + /// With Proxy URL using X509Certificate2. + /// + /// The proxy url. + /// The X509Certificate2 file to use for client authentication. + /// A . + IResponseBuilder WithProxy([NotNull] string proxyUrl, [CanBeNull] string clientX509Certificate2Filename); } } \ No newline at end of file diff --git a/src/WireMock.Net/ResponseBuilders/Response.cs b/src/WireMock.Net/ResponseBuilders/Response.cs index e7ece5ac..8c752911 100644 --- a/src/WireMock.Net/ResponseBuilders/Response.cs +++ b/src/WireMock.Net/ResponseBuilders/Response.cs @@ -34,6 +34,11 @@ namespace WireMock.ResponseBuilders /// public string ProxyUrl { get; private set; } + /// + /// The client X509Certificate2Filename to use. + /// + public string X509Certificate2Filename { get; private set; } = null; + /// /// Gets the response message. /// @@ -190,7 +195,7 @@ namespace WireMock.ResponseBuilders /// The body asbase64. /// The Encoding. /// A . - public IResponseBuilder WithBodyAsBase64([NotNull] string bodyAsbase64, Encoding encoding = null) + public IResponseBuilder WithBodyAsBase64(string bodyAsbase64, Encoding encoding = null) { Check.NotNull(bodyAsbase64, nameof(bodyAsbase64)); @@ -237,7 +242,7 @@ namespace WireMock.ResponseBuilders } /// - /// From Proxy URL. + /// With Proxy URL. /// /// The proxy url. /// A . @@ -250,6 +255,22 @@ namespace WireMock.ResponseBuilders return this; } + /// + /// With Proxy URL. + /// + /// The proxy url. + /// The X509Certificate2 file to use for client authentication. + /// A . + public IResponseBuilder WithProxy(string proxyUrl, string clientX509Certificate2Filename) + { + Check.NotEmpty(proxyUrl, nameof(proxyUrl)); + Check.NotEmpty(clientX509Certificate2Filename, nameof(clientX509Certificate2Filename)); + + ProxyUrl = proxyUrl; + X509Certificate2Filename = clientX509Certificate2Filename; + return this; + } + /// /// The provide response. /// @@ -264,9 +285,10 @@ namespace WireMock.ResponseBuilders if (ProxyUrl != null) { - return await HttpClientHelper.SendAsync(requestMessage, ProxyUrl); + return await HttpClientHelper.SendAsync(requestMessage, ProxyUrl, X509Certificate2Filename); } - else if (UseTransformer) + + if (UseTransformer) { return ResponseMessageTransformer.Transform(requestMessage, ResponseMessage); } diff --git a/src/WireMock.Net/Server/FluentMockServer.cs b/src/WireMock.Net/Server/FluentMockServer.cs index 122e510b..d535f014 100644 --- a/src/WireMock.Net/Server/FluentMockServer.cs +++ b/src/WireMock.Net/Server/FluentMockServer.cs @@ -164,10 +164,10 @@ namespace WireMock.Server Urls = new[] { (settings.UseSSL == true ? "https" : "http") + "://localhost:" + port + "/" }; } -#if NET45 - _httpServer = new OwinSelfHost(_options, Urls); -#else +#if NETSTANDARD _httpServer = new AspNetCoreSelfHost(_options, Urls); +#else + _httpServer = new OwinSelfHost(_options, Urls); #endif Ports = _httpServer.Ports; diff --git a/src/WireMock.Net/Settings/ProxyAndRecordSettings.cs b/src/WireMock.Net/Settings/ProxyAndRecordSettings.cs index 4d603b8f..b3ed33f1 100644 --- a/src/WireMock.Net/Settings/ProxyAndRecordSettings.cs +++ b/src/WireMock.Net/Settings/ProxyAndRecordSettings.cs @@ -14,5 +14,10 @@ /// Save the mapping for each request/response. /// public bool SaveMapping { get; set; } = true; + + /// + /// The clientCertificateFilename to use. Example : "C:\certificates\cert.pfx" + /// + public string X509Certificate2Filename { get; set; } } } \ No newline at end of file diff --git a/src/WireMock.Net/WireMock.Net.csproj b/src/WireMock.Net/WireMock.Net.csproj index b5f0a4ae..7d347f7a 100644 --- a/src/WireMock.Net/WireMock.Net.csproj +++ b/src/WireMock.Net/WireMock.Net.csproj @@ -5,7 +5,7 @@ WireMock.Net 1.0.2.0 Alexandre Victoor;Stef Heyenrath - net45;netstandard1.3 + net45;net452;net46;netstandard1.3 true WireMock.Net WireMock.Net @@ -26,28 +26,31 @@ NETSTANDARD - - - - All + + - - - - + + + + + + + + + @@ -55,7 +58,6 @@ -