From f8efd8ab196e964152845515c20fc15f0ad156a3 Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Mon, 11 Feb 2019 14:09:35 -0500 Subject: [PATCH 1/8] integration tests using local kestrel server --- src/Titanium.Web.Proxy.sln | 22 +-- .../ExplicitClientHandler.cs | 2 +- .../Network/CertificateManager.cs | 4 +- .../TransparentClientHandler.cs | 2 +- .../InterceptionTests.cs | 83 +++++++++++- .../Properties/AssemblyInfo.cs | 35 ----- .../SslTests.cs | 79 ++++++++++- ...Titanium.Web.Proxy.IntegrationTests.csproj | 125 ++---------------- .../Utilities/TestHelper.cs | 36 ++++- 9 files changed, 213 insertions(+), 175 deletions(-) delete mode 100644 tests/Titanium.Web.Proxy.IntegrationTests/Properties/AssemblyInfo.cs diff --git a/src/Titanium.Web.Proxy.sln b/src/Titanium.Web.Proxy.sln index 34eb45ecc..0d128e76e 100644 --- a/src/Titanium.Web.Proxy.sln +++ b/src/Titanium.Web.Proxy.sln @@ -25,12 +25,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Titanium.Web.Proxy", "Titan EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Titanium.Web.Proxy.UnitTests", "..\tests\Titanium.Web.Proxy.UnitTests\Titanium.Web.Proxy.UnitTests.csproj", "{B517E3D0-D03B-436F-AB03-34BA0D5321AF}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Titanium.Web.Proxy.IntegrationTests", "..\tests\Titanium.Web.Proxy.IntegrationTests\Titanium.Web.Proxy.IntegrationTests.csproj", "{32231301-B0FB-4F9E-98DF-B3E8A88F4C16}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Titanium.Web.Proxy.Examples.Basic", "..\examples\Titanium.Web.Proxy.Examples.Basic\Titanium.Web.Proxy.Examples.Basic.csproj", "{1FAC4205-4445-4F2B-BB8F-618E8A0C15FD}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Titanium.Web.Proxy.Examples.Wpf", "..\examples\Titanium.Web.Proxy.Examples.Wpf\Titanium.Web.Proxy.Examples.Wpf.csproj", "{4406CE17-9A39-4F28-8363-6169A4F799C1}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Titanium.Web.Proxy.IntegrationTests", "..\tests\Titanium.Web.Proxy.IntegrationTests\Titanium.Web.Proxy.IntegrationTests.csproj", "{1D053D72-DCB4-4517-ACDD-D35ADC186950}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -55,14 +55,6 @@ Global {B517E3D0-D03B-436F-AB03-34BA0D5321AF}.Release|Any CPU.Build.0 = Release|Any CPU {B517E3D0-D03B-436F-AB03-34BA0D5321AF}.Release|x64.ActiveCfg = Release|x64 {B517E3D0-D03B-436F-AB03-34BA0D5321AF}.Release|x64.Build.0 = Release|x64 - {32231301-B0FB-4F9E-98DF-B3E8A88F4C16}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {32231301-B0FB-4F9E-98DF-B3E8A88F4C16}.Debug|Any CPU.Build.0 = Debug|Any CPU - {32231301-B0FB-4F9E-98DF-B3E8A88F4C16}.Debug|x64.ActiveCfg = Debug|x64 - {32231301-B0FB-4F9E-98DF-B3E8A88F4C16}.Debug|x64.Build.0 = Debug|x64 - {32231301-B0FB-4F9E-98DF-B3E8A88F4C16}.Release|Any CPU.ActiveCfg = Release|Any CPU - {32231301-B0FB-4F9E-98DF-B3E8A88F4C16}.Release|Any CPU.Build.0 = Release|Any CPU - {32231301-B0FB-4F9E-98DF-B3E8A88F4C16}.Release|x64.ActiveCfg = Release|x64 - {32231301-B0FB-4F9E-98DF-B3E8A88F4C16}.Release|x64.Build.0 = Release|x64 {1FAC4205-4445-4F2B-BB8F-618E8A0C15FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1FAC4205-4445-4F2B-BB8F-618E8A0C15FD}.Debug|Any CPU.Build.0 = Debug|Any CPU {1FAC4205-4445-4F2B-BB8F-618E8A0C15FD}.Debug|x64.ActiveCfg = Debug|x64 @@ -79,15 +71,23 @@ Global {4406CE17-9A39-4F28-8363-6169A4F799C1}.Release|Any CPU.Build.0 = Release|Any CPU {4406CE17-9A39-4F28-8363-6169A4F799C1}.Release|x64.ActiveCfg = Release|x64 {4406CE17-9A39-4F28-8363-6169A4F799C1}.Release|x64.Build.0 = Release|x64 + {1D053D72-DCB4-4517-ACDD-D35ADC186950}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1D053D72-DCB4-4517-ACDD-D35ADC186950}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1D053D72-DCB4-4517-ACDD-D35ADC186950}.Debug|x64.ActiveCfg = Debug|Any CPU + {1D053D72-DCB4-4517-ACDD-D35ADC186950}.Debug|x64.Build.0 = Debug|Any CPU + {1D053D72-DCB4-4517-ACDD-D35ADC186950}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1D053D72-DCB4-4517-ACDD-D35ADC186950}.Release|Any CPU.Build.0 = Release|Any CPU + {1D053D72-DCB4-4517-ACDD-D35ADC186950}.Release|x64.ActiveCfg = Release|Any CPU + {1D053D72-DCB4-4517-ACDD-D35ADC186950}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {B517E3D0-D03B-436F-AB03-34BA0D5321AF} = {BC1E0789-D348-49CF-8B67-5E99D50EDF64} - {32231301-B0FB-4F9E-98DF-B3E8A88F4C16} = {BC1E0789-D348-49CF-8B67-5E99D50EDF64} {1FAC4205-4445-4F2B-BB8F-618E8A0C15FD} = {B6DBABDC-C985-4872-9C38-B4E5079CBC4B} {4406CE17-9A39-4F28-8363-6169A4F799C1} = {B6DBABDC-C985-4872-9C38-B4E5079CBC4B} + {1D053D72-DCB4-4517-ACDD-D35ADC186950} = {BC1E0789-D348-49CF-8B67-5E99D50EDF64} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EnterpriseLibraryConfigurationToolBinariesPath = .1.505.2\lib\NET35 diff --git a/src/Titanium.Web.Proxy/ExplicitClientHandler.cs b/src/Titanium.Web.Proxy/ExplicitClientHandler.cs index 3191fa2db..0fa047686 100644 --- a/src/Titanium.Web.Proxy/ExplicitClientHandler.cs +++ b/src/Titanium.Web.Proxy/ExplicitClientHandler.cs @@ -168,7 +168,7 @@ await clientStreamWriter.WriteResponseAsync(connectArgs.HttpClient.Response, string certName = HttpHelper.GetWildCardDomainName(connectHostname); var certificate = endPoint.GenericCertificate ?? - await CertificateManager.CreateCertificateAsync(certName); + await CertificateManager.CreateServerCertificate(certName); // Successfully managed to authenticate the client using the fake certificate var options = new SslServerAuthenticationOptions(); diff --git a/src/Titanium.Web.Proxy/Network/CertificateManager.cs b/src/Titanium.Web.Proxy/Network/CertificateManager.cs index cf0aee98c..d7b2164c9 100644 --- a/src/Titanium.Web.Proxy/Network/CertificateManager.cs +++ b/src/Titanium.Web.Proxy/Network/CertificateManager.cs @@ -432,11 +432,11 @@ internal X509Certificate2 CreateCertificate(string certificateName, bool isRootC } /// - /// Create an SSL certificate async + /// Creates a server certificate signed by the root certificate. /// /// /// - internal async Task CreateCertificateAsync(string certificateName) + public async Task CreateServerCertificate(string certificateName) { // check in cache first if (cachedCertificates.TryGetValue(certificateName, out var cached)) diff --git a/src/Titanium.Web.Proxy/TransparentClientHandler.cs b/src/Titanium.Web.Proxy/TransparentClientHandler.cs index f5077f5cd..b90d00444 100644 --- a/src/Titanium.Web.Proxy/TransparentClientHandler.cs +++ b/src/Titanium.Web.Proxy/TransparentClientHandler.cs @@ -82,7 +82,7 @@ private async Task handleClient(TransparentProxyEndPoint endPoint, TcpClientConn string certName = HttpHelper.GetWildCardDomainName(httpsHostName); var certificate = endPoint.GenericCertificate ?? - await CertificateManager.CreateCertificateAsync(certName); + await CertificateManager.CreateServerCertificate(certName); // Successfully managed to authenticate the client using the fake certificate await sslStream.AuthenticateAsServerAsync(certificate, false, SslProtocols.Tls, false); diff --git a/tests/Titanium.Web.Proxy.IntegrationTests/InterceptionTests.cs b/tests/Titanium.Web.Proxy.IntegrationTests/InterceptionTests.cs index 7a4ccfcd3..14e25fab6 100644 --- a/tests/Titanium.Web.Proxy.IntegrationTests/InterceptionTests.cs +++ b/tests/Titanium.Web.Proxy.IntegrationTests/InterceptionTests.cs @@ -1,10 +1,17 @@ using System; +using System.Linq; using System.Net; using System.Net.Http; +using System.Security.Cryptography.X509Certificates; using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Hosting.Server.Features; +using Microsoft.AspNetCore.Http; using Microsoft.VisualStudio.TestTools.UnitTesting; using Titanium.Web.Proxy.EventArguments; using Titanium.Web.Proxy.Models; +using Titanium.Web.Proxy.Network; namespace Titanium.Web.Proxy.IntegrationTests { @@ -14,18 +21,24 @@ public class InterceptionTests [TestMethod] public async Task Can_Intercept_Post_Requests() { - string testUrl = "http://interceptthis.com"; + string testHost = "localhost"; using (var proxy = new ProxyTestController()) { - using (var client = TestHelper.CreateHttpClient(testUrl, proxy.ListeningPort)) + var serverCertificate = await proxy.CertificateManager.CreateServerCertificate(testHost); + + using (var server = new Server(serverCertificate)) { - var response = await client.PostAsync(new Uri(testUrl), new StringContent("hello!")); + var testUrl = $"http://{testHost}:{server.HttpListeningPort}"; + using (var client = TestHelper.CreateHttpClient(proxy.ListeningPort)) + { + var response = await client.PostAsync(new Uri(testUrl), new StringContent("hello!")); - Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); + Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); - var body = await response.Content.ReadAsStringAsync(); - Assert.IsTrue(body.Contains("TitaniumWebProxy-Stopped!!")); + var body = await response.Content.ReadAsStringAsync(); + Assert.IsTrue(body.Contains("TitaniumWebProxy-Stopped!!")); + } } } } @@ -34,6 +47,7 @@ private class ProxyTestController : IDisposable { private readonly ProxyServer proxyServer; public int ListeningPort => proxyServer.ProxyEndPoints[0].Port; + public CertificateManager CertificateManager => proxyServer.CertificateManager; public ProxyTestController() { @@ -46,7 +60,7 @@ public ProxyTestController() public async Task OnRequest(object sender, SessionEventArgs e) { - if (e.HttpClient.Request.Url.Contains("interceptthis.com")) + if (e.HttpClient.Request.Url.Contains("localhost")) { if (e.HttpClient.Request.HasBody) { @@ -68,5 +82,60 @@ public void Dispose() } } + private class Server : IDisposable + { + public int HttpListeningPort; + public int HttpsListeningPort; + + private IWebHost host; + public Server(X509Certificate2 serverCertificate) + { + host = new WebHostBuilder() + .UseKestrel(options => + { + options.Listen(IPAddress.Loopback, 0); + options.Listen(IPAddress.Loopback, 0, listenOptions => + { + listenOptions.UseHttps(serverCertificate); + }); + }) + .UseStartup() + .Build(); + + host.Start(); + + string httpAddress = host.ServerFeatures + .Get() + .Addresses + .First(); + + string httpsAddress = host.ServerFeatures + .Get() + .Addresses + .Skip(1) + .First(); + + HttpListeningPort = int.Parse(httpAddress.Split(':')[2]); + HttpsListeningPort = int.Parse(httpsAddress.Split(':')[2]); + } + + public void Dispose() + { + host.Dispose(); + } + + private class Startup + { + public void Configure(IApplicationBuilder app) + { + app.Run(context => + { + return context.Response.WriteAsync("Server received you request."); + }); + + } + } + } + } } \ No newline at end of file diff --git a/tests/Titanium.Web.Proxy.IntegrationTests/Properties/AssemblyInfo.cs b/tests/Titanium.Web.Proxy.IntegrationTests/Properties/AssemblyInfo.cs deleted file mode 100644 index 0e5f845f1..000000000 --- a/tests/Titanium.Web.Proxy.IntegrationTests/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("Titanium.Web.Proxy.IntegrationTests")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Titanium.Web.Proxy.IntegrationTests")] -[assembly: AssemblyCopyright("Copyright © Titanium 2015-2017")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("32231301-b0fb-4f9e-98df-b3e8a88f4c16")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/tests/Titanium.Web.Proxy.IntegrationTests/SslTests.cs b/tests/Titanium.Web.Proxy.IntegrationTests/SslTests.cs index 56441b1bd..70af9c119 100644 --- a/tests/Titanium.Web.Proxy.IntegrationTests/SslTests.cs +++ b/tests/Titanium.Web.Proxy.IntegrationTests/SslTests.cs @@ -1,8 +1,15 @@ using System; +using System.Linq; using System.Net; +using System.Security.Cryptography.X509Certificates; using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Hosting.Server.Features; +using Microsoft.AspNetCore.Http; using Microsoft.VisualStudio.TestTools.UnitTesting; using Titanium.Web.Proxy.Models; +using Titanium.Web.Proxy.Network; namespace Titanium.Web.Proxy.IntegrationTests { @@ -12,13 +19,20 @@ public class SslTests [TestMethod] public async Task TestSsl() { - string testUrl = "https://google.com"; + string testHost = "localhost"; + using (var proxy = new ProxyTestController()) { - using (var client = TestHelper.CreateHttpClient(testUrl, proxy.ListeningPort)) + var serverCertificate = await proxy.CertificateManager.CreateServerCertificate(testHost); + + using (var server = new Server(serverCertificate)) { - var response = await client.GetAsync(new Uri(testUrl)); - Assert.IsNotNull(response); + var testUrl = $"https://{testHost}:{server.HttpsListeningPort}"; + using (var client = TestHelper.CreateHttpClient(proxy.ListeningPort)) + { + var response = await client.GetAsync(new Uri(testUrl)); + Assert.IsNotNull(response); + } } } } @@ -27,6 +41,7 @@ private class ProxyTestController : IDisposable { private readonly ProxyServer proxyServer; public int ListeningPort => proxyServer.ProxyEndPoints[0].Port; + public CertificateManager CertificateManager => proxyServer.CertificateManager; public ProxyTestController() { @@ -42,5 +57,61 @@ public void Dispose() proxyServer.Dispose(); } } + + private class Server : IDisposable + { + public int HttpListeningPort; + public int HttpsListeningPort; + + private IWebHost host; + public Server(X509Certificate2 serverCertificate) + { + host = new WebHostBuilder() + .UseKestrel(options => + { + options.Listen(IPAddress.Loopback, 0); + options.Listen(IPAddress.Loopback, 0, listenOptions => + { + listenOptions.UseHttps(serverCertificate); + }); + }) + .UseStartup() + .Build(); + + host.Start(); + + string httpAddress = host.ServerFeatures + .Get() + .Addresses + .First(); + + string httpsAddress = host.ServerFeatures + .Get() + .Addresses + .Skip(1) + .First(); + + HttpListeningPort = int.Parse(httpAddress.Split(':')[2]); + HttpsListeningPort = int.Parse(httpsAddress.Split(':')[2]); + } + + public void Dispose() + { + host.Dispose(); + } + + private class Startup + { + public void Configure(IApplicationBuilder app) + { + app.Run(context => + { + return context.Response.WriteAsync("Server received you request."); + }); + + } + } + } + } } diff --git a/tests/Titanium.Web.Proxy.IntegrationTests/Titanium.Web.Proxy.IntegrationTests.csproj b/tests/Titanium.Web.Proxy.IntegrationTests/Titanium.Web.Proxy.IntegrationTests.csproj index 05ffdca66..393f56cec 100644 --- a/tests/Titanium.Web.Proxy.IntegrationTests/Titanium.Web.Proxy.IntegrationTests.csproj +++ b/tests/Titanium.Web.Proxy.IntegrationTests/Titanium.Web.Proxy.IntegrationTests.csproj @@ -1,117 +1,20 @@ - - + + - Debug - AnyCPU - {32231301-B0FB-4F9E-98DF-B3E8A88F4C16} - Library - Properties - Titanium.Web.Proxy.IntegrationTests - Titanium.Web.Proxy.IntegrationTests - v4.5.2 - 512 - {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages - False - UnitTest - + netcoreapp2.2 - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - true - bin\x64\Debug\ - DEBUG;TRACE - full - x64 - prompt - MinimumRecommendedRules.ruleset - - - bin\x64\Release\ - TRACE - true - pdbonly - x64 - prompt - MinimumRecommendedRules.ruleset - - - - - - - - - - - - - - - - - - - - - - - + - - {91018b6d-a7a9-45be-9cb3-79cbb8b169a6} - Titanium.Web.Proxy - + + + + + + + - - rootCert.pfx - PreserveNewest - + - - - - - False - - - False - - - False - - - False - - - - - - - - \ No newline at end of file + + diff --git a/tests/Titanium.Web.Proxy.IntegrationTests/Utilities/TestHelper.cs b/tests/Titanium.Web.Proxy.IntegrationTests/Utilities/TestHelper.cs index a763a1d11..134b0db1e 100644 --- a/tests/Titanium.Web.Proxy.IntegrationTests/Utilities/TestHelper.cs +++ b/tests/Titanium.Web.Proxy.IntegrationTests/Utilities/TestHelper.cs @@ -1,19 +1,49 @@ -using System.Net; +using System; +using System.Net; using System.Net.Http; namespace Titanium.Web.Proxy.IntegrationTests { public static class TestHelper { - public static HttpClient CreateHttpClient(string url, int localProxyPort) + public static HttpClient CreateHttpClient(int localProxyPort) { + var proxy = new TestProxy($"http://localhost:{localProxyPort}"); + var handler = new HttpClientHandler { - Proxy = new WebProxy($"http://localhost:{localProxyPort}", false), + Proxy = proxy, UseProxy = true }; return new HttpClient(handler); } + + public class TestProxy : IWebProxy + { + public Uri ProxyUri { get; set; } + public ICredentials Credentials { get; set; } + + public TestProxy(string proxyUri) + : this(new Uri(proxyUri)) + { + } + + public TestProxy(Uri proxyUri) + { + this.ProxyUri = proxyUri; + } + + public Uri GetProxy(Uri destination) + { + return this.ProxyUri; + } + + public bool IsBypassed(Uri host) + { + return false; + } + + } } } From 66be64abaa36603b471fe5440ef1311e3f08c837 Mon Sep 17 00:00:00 2001 From: buildbot121 Date: Mon, 11 Feb 2019 19:12:22 +0000 Subject: [PATCH 2/8] API documentation update by build server --- ....Web.Proxy.Network.CertificateManager.html | 48 +++++++++++++++++++ docs/index.json | 2 +- docs/xrefmap.yml | 13 +++++ 3 files changed, 62 insertions(+), 1 deletion(-) diff --git a/docs/api/Titanium.Web.Proxy.Network.CertificateManager.html b/docs/api/Titanium.Web.Proxy.Network.CertificateManager.html index 3a80595f6..51a3e3206 100644 --- a/docs/api/Titanium.Web.Proxy.Network.CertificateManager.html +++ b/docs/api/Titanium.Web.Proxy.Network.CertificateManager.html @@ -552,6 +552,54 @@
Returns
+ + | + Improve this Doc + + + View Source + + +

CreateServerCertificate(String)

+

Creates a server certificate signed by the root certificate.

+
+
+
Declaration
+
+
public Task<X509Certificate2> CreateServerCertificate(string certificateName)
+
+
Parameters
+ + + + + + + + + + + + + + + +
TypeNameDescription
StringcertificateName
+
Returns
+ + + + + + + + + + + + + +
TypeDescription
Task<X509Certificate2>
| Improve this Doc diff --git a/docs/index.json b/docs/index.json index 688199fdc..59769f0a5 100644 --- a/docs/index.json +++ b/docs/index.json @@ -267,7 +267,7 @@ "api/Titanium.Web.Proxy.Network.CertificateManager.html": { "href": "api/Titanium.Web.Proxy.Network.CertificateManager.html", "title": "Class CertificateManager | Titanium Web Proxy", - "keywords": "Class CertificateManager A class to manage SSL certificates used by this proxy server. Inheritance Object CertificateManager Implements IDisposable Inherited Members Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : Titanium.Web.Proxy.Network Assembly : Titanium.Web.Proxy.dll Syntax public sealed class CertificateManager : IDisposable Properties | Improve this Doc View Source CertificateCacheTimeOutMinutes Minutes certificates should be kept in cache when not used. Declaration public int CertificateCacheTimeOutMinutes { get; set; } Property Value Type Description Int32 | Improve this Doc View Source CertificateEngine Select Certificate Engine. Optionally set to BouncyCastle. Mono only support BouncyCastle and it is the default. Declaration public CertificateEngine CertificateEngine { get; set; } Property Value Type Description CertificateEngine | Improve this Doc View Source CertificateStorage The fake certificate cache storage. The default cache storage implementation saves certificates in folder \"crts\" (will be created in proxy dll directory). Implement ICertificateCache interface and assign concrete class here to customize. Declaration public ICertificateCache CertificateStorage { get; set; } Property Value Type Description ICertificateCache | Improve this Doc View Source OverwritePfxFile Overwrite Root certificate file. true : replace an existing .pfx file if password is incorrect or if RootCertificate = null. Declaration public bool OverwritePfxFile { get; set; } Property Value Type Description Boolean | Improve this Doc View Source PfxFilePath Name(path) of the Root certificate file. Set the name(path) of the .pfx file. If it is string.Empty Root certificate file will be named as \"rootCert.pfx\" (and will be saved in proxy dll directory) Declaration public string PfxFilePath { get; set; } Property Value Type Description String | Improve this Doc View Source PfxPassword Password of the Root certificate file. Set a password for the .pfx file Declaration public string PfxPassword { get; set; } Property Value Type Description String | Improve this Doc View Source RootCertificate The root certificate. Declaration public X509Certificate2 RootCertificate { get; set; } Property Value Type Description X509Certificate2 | Improve this Doc View Source RootCertificateIssuerName Name of the root certificate issuer. (This is valid only when RootCertificate property is not set.) Declaration public string RootCertificateIssuerName { get; set; } Property Value Type Description String | Improve this Doc View Source RootCertificateName Name of the root certificate. (This is valid only when RootCertificate property is not set.) If no certificate is provided then a default Root Certificate will be created and used. The provided root certificate will be stored in proxy exe directory with the private key. Root certificate file will be named as \"rootCert.pfx\". Declaration public string RootCertificateName { get; set; } Property Value Type Description String | Improve this Doc View Source SaveFakeCertificates Save all fake certificates using CertificateStorage . for can load the certificate and not make new certificate every time. Declaration public bool SaveFakeCertificates { get; set; } Property Value Type Description Boolean | Improve this Doc View Source StorageFlag Adjust behaviour when certificates are saved to filesystem. Declaration public X509KeyStorageFlags StorageFlag { get; set; } Property Value Type Description X509KeyStorageFlags Methods | Improve this Doc View Source ClearRootCertificate() Clear the root certificate and cache. Declaration public void ClearRootCertificate() | Improve this Doc View Source CreateRootCertificate(Boolean) Attempts to create a RootCertificate. Declaration public bool CreateRootCertificate(bool persistToFile = true) Parameters Type Name Description Boolean persistToFile if set to true try to load/save the certificate from rootCert.pfx. Returns Type Description Boolean true if succeeded, else false. | Improve this Doc View Source Dispose() Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. Declaration public void Dispose() | Improve this Doc View Source EnsureRootCertificate() Ensure certificates are setup (creates root if required). Also makes root certificate trusted based on initial setup from proxy constructor for user/machine trust. Declaration public void EnsureRootCertificate() | Improve this Doc View Source EnsureRootCertificate(Boolean, Boolean, Boolean) Ensure certificates are setup (creates root if required). Also makes root certificate trusted based on provided parameters. Note:setting machineTrustRootCertificate to true will force userTrustRootCertificate to true. Declaration public void EnsureRootCertificate(bool userTrustRootCertificate, bool machineTrustRootCertificate, bool trustRootCertificateAsAdmin = false) Parameters Type Name Description Boolean userTrustRootCertificate Should fake HTTPS certificate be trusted by this machine's user certificate store? Boolean machineTrustRootCertificate Should fake HTTPS certificate be trusted by this machine's certificate store? Boolean trustRootCertificateAsAdmin Should we attempt to trust certificates with elevated permissions by prompting for UAC if required? | Improve this Doc View Source IsRootCertificateMachineTrusted() Determines whether the root certificate is machine trusted. Declaration public bool IsRootCertificateMachineTrusted() Returns Type Description Boolean | Improve this Doc View Source IsRootCertificateUserTrusted() Determines whether the root certificate is trusted. Declaration public bool IsRootCertificateUserTrusted() Returns Type Description Boolean | Improve this Doc View Source LoadRootCertificate() Loads root certificate from current executing assembly location with expected name rootCert.pfx. Declaration public X509Certificate2 LoadRootCertificate() Returns Type Description X509Certificate2 | Improve this Doc View Source LoadRootCertificate(String, String, Boolean, X509KeyStorageFlags) Manually load a Root certificate file from give path (.pfx file). Declaration public bool LoadRootCertificate(string pfxFilePath, string password, bool overwritePfXFile = true, X509KeyStorageFlags storageFlag = X509KeyStorageFlags.Exportable) Parameters Type Name Description String pfxFilePath Set the name(path) of the .pfx file. If it is string.Empty Root certificate file will be named as \"rootCert.pfx\" (and will be saved in proxy dll directory). String password Set a password for the .pfx file. Boolean overwritePfXFile true : replace an existing .pfx file if password is incorrect or if RootCertificate==null. X509KeyStorageFlags storageFlag Returns Type Description Boolean true if succeeded, else false. | Improve this Doc View Source RemoveTrustedRootCertificate(Boolean) Removes the trusted certificates from user store, optionally also from machine store. To remove from machine store elevated permissions are required (will fail silently otherwise). Declaration public void RemoveTrustedRootCertificate(bool machineTrusted = false) Parameters Type Name Description Boolean machineTrusted Should also remove from machine store? | Improve this Doc View Source RemoveTrustedRootCertificateAsAdmin(Boolean) Removes the trusted certificates from user store, optionally also from machine store Declaration public bool RemoveTrustedRootCertificateAsAdmin(bool machineTrusted = false) Parameters Type Name Description Boolean machineTrusted Returns Type Description Boolean Should also remove from machine store? | Improve this Doc View Source TrustRootCertificate(Boolean) Trusts the root certificate in user store, optionally also in machine store. Machine trust would require elevated permissions (will silently fail otherwise). Declaration public void TrustRootCertificate(bool machineTrusted = false) Parameters Type Name Description Boolean machineTrusted | Improve this Doc View Source TrustRootCertificateAsAdmin(Boolean) Puts the certificate to the user store, optionally also to machine store. Prompts with UAC if elevated permissions are required. Works only on Windows. Declaration public bool TrustRootCertificateAsAdmin(bool machineTrusted = false) Parameters Type Name Description Boolean machineTrusted Returns Type Description Boolean True if success. Implements System.IDisposable" + "keywords": "Class CertificateManager A class to manage SSL certificates used by this proxy server. Inheritance Object CertificateManager Implements IDisposable Inherited Members Object.ToString() Object.Equals(Object) Object.Equals(Object, Object) Object.ReferenceEquals(Object, Object) Object.GetHashCode() Object.GetType() Object.MemberwiseClone() Namespace : Titanium.Web.Proxy.Network Assembly : Titanium.Web.Proxy.dll Syntax public sealed class CertificateManager : IDisposable Properties | Improve this Doc View Source CertificateCacheTimeOutMinutes Minutes certificates should be kept in cache when not used. Declaration public int CertificateCacheTimeOutMinutes { get; set; } Property Value Type Description Int32 | Improve this Doc View Source CertificateEngine Select Certificate Engine. Optionally set to BouncyCastle. Mono only support BouncyCastle and it is the default. Declaration public CertificateEngine CertificateEngine { get; set; } Property Value Type Description CertificateEngine | Improve this Doc View Source CertificateStorage The fake certificate cache storage. The default cache storage implementation saves certificates in folder \"crts\" (will be created in proxy dll directory). Implement ICertificateCache interface and assign concrete class here to customize. Declaration public ICertificateCache CertificateStorage { get; set; } Property Value Type Description ICertificateCache | Improve this Doc View Source OverwritePfxFile Overwrite Root certificate file. true : replace an existing .pfx file if password is incorrect or if RootCertificate = null. Declaration public bool OverwritePfxFile { get; set; } Property Value Type Description Boolean | Improve this Doc View Source PfxFilePath Name(path) of the Root certificate file. Set the name(path) of the .pfx file. If it is string.Empty Root certificate file will be named as \"rootCert.pfx\" (and will be saved in proxy dll directory) Declaration public string PfxFilePath { get; set; } Property Value Type Description String | Improve this Doc View Source PfxPassword Password of the Root certificate file. Set a password for the .pfx file Declaration public string PfxPassword { get; set; } Property Value Type Description String | Improve this Doc View Source RootCertificate The root certificate. Declaration public X509Certificate2 RootCertificate { get; set; } Property Value Type Description X509Certificate2 | Improve this Doc View Source RootCertificateIssuerName Name of the root certificate issuer. (This is valid only when RootCertificate property is not set.) Declaration public string RootCertificateIssuerName { get; set; } Property Value Type Description String | Improve this Doc View Source RootCertificateName Name of the root certificate. (This is valid only when RootCertificate property is not set.) If no certificate is provided then a default Root Certificate will be created and used. The provided root certificate will be stored in proxy exe directory with the private key. Root certificate file will be named as \"rootCert.pfx\". Declaration public string RootCertificateName { get; set; } Property Value Type Description String | Improve this Doc View Source SaveFakeCertificates Save all fake certificates using CertificateStorage . for can load the certificate and not make new certificate every time. Declaration public bool SaveFakeCertificates { get; set; } Property Value Type Description Boolean | Improve this Doc View Source StorageFlag Adjust behaviour when certificates are saved to filesystem. Declaration public X509KeyStorageFlags StorageFlag { get; set; } Property Value Type Description X509KeyStorageFlags Methods | Improve this Doc View Source ClearRootCertificate() Clear the root certificate and cache. Declaration public void ClearRootCertificate() | Improve this Doc View Source CreateRootCertificate(Boolean) Attempts to create a RootCertificate. Declaration public bool CreateRootCertificate(bool persistToFile = true) Parameters Type Name Description Boolean persistToFile if set to true try to load/save the certificate from rootCert.pfx. Returns Type Description Boolean true if succeeded, else false. | Improve this Doc View Source CreateServerCertificate(String) Creates a server certificate signed by the root certificate. Declaration public Task CreateServerCertificate(string certificateName) Parameters Type Name Description String certificateName Returns Type Description Task < X509Certificate2 > | Improve this Doc View Source Dispose() Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. Declaration public void Dispose() | Improve this Doc View Source EnsureRootCertificate() Ensure certificates are setup (creates root if required). Also makes root certificate trusted based on initial setup from proxy constructor for user/machine trust. Declaration public void EnsureRootCertificate() | Improve this Doc View Source EnsureRootCertificate(Boolean, Boolean, Boolean) Ensure certificates are setup (creates root if required). Also makes root certificate trusted based on provided parameters. Note:setting machineTrustRootCertificate to true will force userTrustRootCertificate to true. Declaration public void EnsureRootCertificate(bool userTrustRootCertificate, bool machineTrustRootCertificate, bool trustRootCertificateAsAdmin = false) Parameters Type Name Description Boolean userTrustRootCertificate Should fake HTTPS certificate be trusted by this machine's user certificate store? Boolean machineTrustRootCertificate Should fake HTTPS certificate be trusted by this machine's certificate store? Boolean trustRootCertificateAsAdmin Should we attempt to trust certificates with elevated permissions by prompting for UAC if required? | Improve this Doc View Source IsRootCertificateMachineTrusted() Determines whether the root certificate is machine trusted. Declaration public bool IsRootCertificateMachineTrusted() Returns Type Description Boolean | Improve this Doc View Source IsRootCertificateUserTrusted() Determines whether the root certificate is trusted. Declaration public bool IsRootCertificateUserTrusted() Returns Type Description Boolean | Improve this Doc View Source LoadRootCertificate() Loads root certificate from current executing assembly location with expected name rootCert.pfx. Declaration public X509Certificate2 LoadRootCertificate() Returns Type Description X509Certificate2 | Improve this Doc View Source LoadRootCertificate(String, String, Boolean, X509KeyStorageFlags) Manually load a Root certificate file from give path (.pfx file). Declaration public bool LoadRootCertificate(string pfxFilePath, string password, bool overwritePfXFile = true, X509KeyStorageFlags storageFlag = X509KeyStorageFlags.Exportable) Parameters Type Name Description String pfxFilePath Set the name(path) of the .pfx file. If it is string.Empty Root certificate file will be named as \"rootCert.pfx\" (and will be saved in proxy dll directory). String password Set a password for the .pfx file. Boolean overwritePfXFile true : replace an existing .pfx file if password is incorrect or if RootCertificate==null. X509KeyStorageFlags storageFlag Returns Type Description Boolean true if succeeded, else false. | Improve this Doc View Source RemoveTrustedRootCertificate(Boolean) Removes the trusted certificates from user store, optionally also from machine store. To remove from machine store elevated permissions are required (will fail silently otherwise). Declaration public void RemoveTrustedRootCertificate(bool machineTrusted = false) Parameters Type Name Description Boolean machineTrusted Should also remove from machine store? | Improve this Doc View Source RemoveTrustedRootCertificateAsAdmin(Boolean) Removes the trusted certificates from user store, optionally also from machine store Declaration public bool RemoveTrustedRootCertificateAsAdmin(bool machineTrusted = false) Parameters Type Name Description Boolean machineTrusted Returns Type Description Boolean Should also remove from machine store? | Improve this Doc View Source TrustRootCertificate(Boolean) Trusts the root certificate in user store, optionally also in machine store. Machine trust would require elevated permissions (will silently fail otherwise). Declaration public void TrustRootCertificate(bool machineTrusted = false) Parameters Type Name Description Boolean machineTrusted | Improve this Doc View Source TrustRootCertificateAsAdmin(Boolean) Puts the certificate to the user store, optionally also to machine store. Prompts with UAC if elevated permissions are required. Works only on Windows. Declaration public bool TrustRootCertificateAsAdmin(bool machineTrusted = false) Parameters Type Name Description Boolean machineTrusted Returns Type Description Boolean True if success. Implements System.IDisposable" }, "api/Titanium.Web.Proxy.Network.html": { "href": "api/Titanium.Web.Proxy.Network.html", diff --git a/docs/xrefmap.yml b/docs/xrefmap.yml index ecda8f2ac..17b310164 100644 --- a/docs/xrefmap.yml +++ b/docs/xrefmap.yml @@ -3035,6 +3035,19 @@ references: isSpec: "True" fullName: Titanium.Web.Proxy.Network.CertificateManager.CreateRootCertificate nameWithType: CertificateManager.CreateRootCertificate +- uid: Titanium.Web.Proxy.Network.CertificateManager.CreateServerCertificate(System.String) + name: CreateServerCertificate(String) + href: api/Titanium.Web.Proxy.Network.CertificateManager.html#Titanium_Web_Proxy_Network_CertificateManager_CreateServerCertificate_System_String_ + commentId: M:Titanium.Web.Proxy.Network.CertificateManager.CreateServerCertificate(System.String) + fullName: Titanium.Web.Proxy.Network.CertificateManager.CreateServerCertificate(System.String) + nameWithType: CertificateManager.CreateServerCertificate(String) +- uid: Titanium.Web.Proxy.Network.CertificateManager.CreateServerCertificate* + name: CreateServerCertificate + href: api/Titanium.Web.Proxy.Network.CertificateManager.html#Titanium_Web_Proxy_Network_CertificateManager_CreateServerCertificate_ + commentId: Overload:Titanium.Web.Proxy.Network.CertificateManager.CreateServerCertificate + isSpec: "True" + fullName: Titanium.Web.Proxy.Network.CertificateManager.CreateServerCertificate + nameWithType: CertificateManager.CreateServerCertificate - uid: Titanium.Web.Proxy.Network.CertificateManager.Dispose name: Dispose() href: api/Titanium.Web.Proxy.Network.CertificateManager.html#Titanium_Web_Proxy_Network_CertificateManager_Dispose From 890c62597beee125e19d0c5a5855e487c8313838 Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Mon, 11 Feb 2019 14:13:34 -0500 Subject: [PATCH 3/8] Update Titanium.Web.Proxy.IntegrationTests.csproj --- .../Titanium.Web.Proxy.IntegrationTests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Titanium.Web.Proxy.IntegrationTests/Titanium.Web.Proxy.IntegrationTests.csproj b/tests/Titanium.Web.Proxy.IntegrationTests/Titanium.Web.Proxy.IntegrationTests.csproj index 393f56cec..9e9e6eea9 100644 --- a/tests/Titanium.Web.Proxy.IntegrationTests/Titanium.Web.Proxy.IntegrationTests.csproj +++ b/tests/Titanium.Web.Proxy.IntegrationTests/Titanium.Web.Proxy.IntegrationTests.csproj @@ -1,4 +1,4 @@ - + netcoreapp2.2 From 587bcba7a054a61484c62ce1ca66bcd4ee438344 Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Mon, 11 Feb 2019 14:32:30 -0500 Subject: [PATCH 4/8] Update appveyor.yml --- appveyor.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index 37c305e1f..dc6a7dd1b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -39,6 +39,9 @@ assembly_info: # to disable automatic tests test: on +test_script: + - cmd: dotnet test "[%APPVEYOR_BUILD_FOLDER%\tests\Titanium.Web.Proxy.IntegrationTests\Titanium.Web.Proxy.IntegrationTests.csproj]" -c %CONFIGURATION% + # skip building commits that add tags (such as release tag) skip_tags: true From 58a197e44f56398e8dbcba24ffe1d81f6ad10ae6 Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Mon, 11 Feb 2019 14:35:30 -0500 Subject: [PATCH 5/8] Update appveyor.yml --- appveyor.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index dc6a7dd1b..5f7983afe 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -40,8 +40,7 @@ assembly_info: test: on test_script: - - cmd: dotnet test "[%APPVEYOR_BUILD_FOLDER%\tests\Titanium.Web.Proxy.IntegrationTests\Titanium.Web.Proxy.IntegrationTests.csproj]" -c %CONFIGURATION% - + - cmd: dotnet test "%APPVEYOR_BUILD_FOLDER%\tests\Titanium.Web.Proxy.IntegrationTests\Titanium.Web.Proxy.IntegrationTests.csproj" -c %CONFIGURATION% # skip building commits that add tags (such as release tag) skip_tags: true From 8db82807596cbec06e05d99751a22f57266fb903 Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Mon, 11 Feb 2019 15:20:20 -0500 Subject: [PATCH 6/8] unit test --- appveyor.yml | 4 +- src/Titanium.Web.Proxy.sln | 10 +- test.bat | 5 + ...Titanium.Web.Proxy.IntegrationTests.csproj | 6 + .../Properties/AssemblyInfo.cs | 17 --- .../Titanium.Web.Proxy.UnitTests.csproj | 125 ++---------------- 6 files changed, 31 insertions(+), 136 deletions(-) create mode 100644 test.bat diff --git a/appveyor.yml b/appveyor.yml index 5f7983afe..6189bfc71 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -27,7 +27,7 @@ cache: .build\cleanup-cache.txt # to run your custom scripts instead of automatic MSBuild build_script: - - cmd: build.bat Package + - cmd: build.bat assembly_info: patch: true @@ -40,7 +40,7 @@ assembly_info: test: on test_script: - - cmd: dotnet test "%APPVEYOR_BUILD_FOLDER%\tests\Titanium.Web.Proxy.IntegrationTests\Titanium.Web.Proxy.IntegrationTests.csproj" -c %CONFIGURATION% + - cmd: test.bat # skip building commits that add tags (such as release tag) skip_tags: true diff --git a/src/Titanium.Web.Proxy.sln b/src/Titanium.Web.Proxy.sln index 0d128e76e..982c03221 100644 --- a/src/Titanium.Web.Proxy.sln +++ b/src/Titanium.Web.Proxy.sln @@ -49,12 +49,12 @@ Global {91018B6D-A7A9-45BE-9CB3-79CBB8B169A6}.Release|x64.Build.0 = Release|x64 {B517E3D0-D03B-436F-AB03-34BA0D5321AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B517E3D0-D03B-436F-AB03-34BA0D5321AF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B517E3D0-D03B-436F-AB03-34BA0D5321AF}.Debug|x64.ActiveCfg = Debug|x64 - {B517E3D0-D03B-436F-AB03-34BA0D5321AF}.Debug|x64.Build.0 = Debug|x64 + {B517E3D0-D03B-436F-AB03-34BA0D5321AF}.Debug|x64.ActiveCfg = Debug|Any CPU + {B517E3D0-D03B-436F-AB03-34BA0D5321AF}.Debug|x64.Build.0 = Debug|Any CPU {B517E3D0-D03B-436F-AB03-34BA0D5321AF}.Release|Any CPU.ActiveCfg = Release|Any CPU {B517E3D0-D03B-436F-AB03-34BA0D5321AF}.Release|Any CPU.Build.0 = Release|Any CPU - {B517E3D0-D03B-436F-AB03-34BA0D5321AF}.Release|x64.ActiveCfg = Release|x64 - {B517E3D0-D03B-436F-AB03-34BA0D5321AF}.Release|x64.Build.0 = Release|x64 + {B517E3D0-D03B-436F-AB03-34BA0D5321AF}.Release|x64.ActiveCfg = Release|Any CPU + {B517E3D0-D03B-436F-AB03-34BA0D5321AF}.Release|x64.Build.0 = Release|Any CPU {1FAC4205-4445-4F2B-BB8F-618E8A0C15FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1FAC4205-4445-4F2B-BB8F-618E8A0C15FD}.Debug|Any CPU.Build.0 = Debug|Any CPU {1FAC4205-4445-4F2B-BB8F-618E8A0C15FD}.Debug|x64.ActiveCfg = Debug|x64 @@ -90,7 +90,7 @@ Global {1D053D72-DCB4-4517-ACDD-D35ADC186950} = {BC1E0789-D348-49CF-8B67-5E99D50EDF64} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution - EnterpriseLibraryConfigurationToolBinariesPath = .1.505.2\lib\NET35 SolutionGuid = {625C1EB5-44CF-47DE-A85A-B4C8C40ED90A} + EnterpriseLibraryConfigurationToolBinariesPath = .1.505.2\lib\NET35 EndGlobalSection EndGlobal diff --git a/test.bat b/test.bat new file mode 100644 index 000000000..4e688b0a5 --- /dev/null +++ b/test.bat @@ -0,0 +1,5 @@ +@echo off + +dotnet test "%APPVEYOR_BUILD_FOLDER%\tests\Titanium.Web.Proxy.IntegrationTests\Titanium.Web.Proxy.IntegrationTests.csproj" -c %CONFIGURATION% +dotnet test "%APPVEYOR_BUILD_FOLDER%\tests\Titanium.Web.Proxy.UnitTests\Titanium.Web.Proxy.UnitTests.csproj" -c %CONFIGURATION% +exit /B %errorlevel% \ No newline at end of file diff --git a/tests/Titanium.Web.Proxy.IntegrationTests/Titanium.Web.Proxy.IntegrationTests.csproj b/tests/Titanium.Web.Proxy.IntegrationTests/Titanium.Web.Proxy.IntegrationTests.csproj index 9e9e6eea9..ecfd7220b 100644 --- a/tests/Titanium.Web.Proxy.IntegrationTests/Titanium.Web.Proxy.IntegrationTests.csproj +++ b/tests/Titanium.Web.Proxy.IntegrationTests/Titanium.Web.Proxy.IntegrationTests.csproj @@ -4,6 +4,12 @@ netcoreapp2.2 + + + PreserveNewest + + + diff --git a/tests/Titanium.Web.Proxy.UnitTests/Properties/AssemblyInfo.cs b/tests/Titanium.Web.Proxy.UnitTests/Properties/AssemblyInfo.cs index 88cea1a29..f7f99ff11 100644 --- a/tests/Titanium.Web.Proxy.UnitTests/Properties/AssemblyInfo.cs +++ b/tests/Titanium.Web.Proxy.UnitTests/Properties/AssemblyInfo.cs @@ -4,11 +4,7 @@ // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("Titanium.Web.Proxy.UnitTests")] [assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Titanium.Web.Proxy.UnitTests")] [assembly: AssemblyCopyright("Copyright © Titanium 2015-2017")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -20,16 +16,3 @@ // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("b517e3d0-d03b-436f-ab03-34ba0d5321af")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/tests/Titanium.Web.Proxy.UnitTests/Titanium.Web.Proxy.UnitTests.csproj b/tests/Titanium.Web.Proxy.UnitTests/Titanium.Web.Proxy.UnitTests.csproj index b89d06841..2484f78a6 100644 --- a/tests/Titanium.Web.Proxy.UnitTests/Titanium.Web.Proxy.UnitTests.csproj +++ b/tests/Titanium.Web.Proxy.UnitTests/Titanium.Web.Proxy.UnitTests.csproj @@ -1,122 +1,23 @@ - - - - Debug - AnyCPU - {B517E3D0-D03B-436F-AB03-34BA0D5321AF} - Library - Properties - Titanium.Web.Proxy.UnitTests - Titanium.Web.Proxy.UnitTests - v4.5.2 - 512 - {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages - False - UnitTest - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - true - + + + netcoreapp2.2 true - - StrongNameKey.snk - - true - bin\x64\Debug\ - DEBUG;TRACE - full - x64 - prompt - MinimumRecommendedRules.ruleset - - - bin\x64\Release\ - TRACE - true - true - pdbonly - x64 - prompt - MinimumRecommendedRules.ruleset - - - - - - - - - - - - - - - - + - - - - - + + + + - + + - - {91018b6d-a7a9-45be-9cb3-79cbb8b169a6} - Titanium.Web.Proxy - + - - - - - False - - - False - - - False - - - False - - - - - - - - \ No newline at end of file + + From 27ccf183e0008465542f89eec95fe20130d8bab7 Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Mon, 11 Feb 2019 20:54:14 -0500 Subject: [PATCH 7/8] #543 Fix reverse proxy. add tests. --- .../TransparentClientHandler.cs | 27 +- .../{Utilities => Helpers}/TestHelper.cs | 9 +- .../HttpsTests.cs | 37 +++ .../InterceptionTests.cs | 232 +++++++++++------- .../NestedProxyTests.cs | 39 +++ .../ReverseProxyTests.cs | 130 ++++++++++ .../Setup/TestProxyServer.cs | 51 ++++ .../Setup/TestServer.cs | 98 ++++++++ .../Setup/TestSuite.cs | 56 +++++ .../SslTests.cs | 117 --------- ...Titanium.Web.Proxy.IntegrationTests.csproj | 1 + .../Titanium.Web.Proxy.UnitTests.csproj | 2 +- 12 files changed, 561 insertions(+), 238 deletions(-) rename tests/Titanium.Web.Proxy.IntegrationTests/{Utilities => Helpers}/TestHelper.cs (80%) create mode 100644 tests/Titanium.Web.Proxy.IntegrationTests/HttpsTests.cs create mode 100644 tests/Titanium.Web.Proxy.IntegrationTests/NestedProxyTests.cs create mode 100644 tests/Titanium.Web.Proxy.IntegrationTests/ReverseProxyTests.cs create mode 100644 tests/Titanium.Web.Proxy.IntegrationTests/Setup/TestProxyServer.cs create mode 100644 tests/Titanium.Web.Proxy.IntegrationTests/Setup/TestServer.cs create mode 100644 tests/Titanium.Web.Proxy.IntegrationTests/Setup/TestSuite.cs delete mode 100644 tests/Titanium.Web.Proxy.IntegrationTests/SslTests.cs diff --git a/src/Titanium.Web.Proxy/TransparentClientHandler.cs b/src/Titanium.Web.Proxy/TransparentClientHandler.cs index b90d00444..8d5ffcfdb 100644 --- a/src/Titanium.Web.Proxy/TransparentClientHandler.cs +++ b/src/Titanium.Web.Proxy/TransparentClientHandler.cs @@ -34,10 +34,6 @@ private async Task handleClient(TransparentProxyEndPoint endPoint, TcpClientConn var clientStream = new CustomBufferedStream(clientConnection.GetStream(), BufferPool, BufferSize); var clientStreamWriter = new HttpResponseWriter(clientStream, BufferPool, BufferSize); - Task prefetchConnectionTask = null; - bool closeServerConnection = false; - bool calledRequestHandler = false; - try { var clientHelloInfo = await SslTools.PeekClientHello(clientStream, BufferPool, cancellationToken); @@ -63,16 +59,7 @@ private async Task handleClient(TransparentProxyEndPoint endPoint, TcpClientConn if (endPoint.DecryptSsl && args.DecryptSsl) { - if(EnableTcpServerConnectionPrefetch) - { - //don't pass cancellation token here - //it could cause floating server connections when client exits - prefetchConnectionTask = tcpConnectionFactory.GetServerConnection(httpsHostName, endPoint.Port, - httpVersion: null, isHttps: true, applicationProtocols: null, isConnect: false, - proxyServer: this, session: null, upStreamEndPoint: UpStreamEndPoint, externalProxy: UpStreamHttpsProxy, - noCache: false, cancellationToken: CancellationToken.None); - } - + SslStream sslStream = null; //do client authentication using fake certificate @@ -140,39 +127,29 @@ await TcpHelper.SendRaw(clientStream, serverStream, BufferPool, BufferSize, return; } } - calledRequestHandler = true; // HTTPS server created - we can now decrypt the client's traffic // Now create the request await handleHttpSessionRequest(endPoint, clientConnection, clientStream, clientStreamWriter, - cancellationTokenSource, isHttps ? httpsHostName : null, null, prefetchConnectionTask); + cancellationTokenSource, isHttps ? httpsHostName : null, null, null); } catch (ProxyException e) { - closeServerConnection = true; onException(clientStream, e); } catch (IOException e) { - closeServerConnection = true; onException(clientStream, new Exception("Connection was aborted", e)); } catch (SocketException e) { - closeServerConnection = true; onException(clientStream, new Exception("Could not connect", e)); } catch (Exception e) { - closeServerConnection = true; onException(clientStream, new Exception("Error occured in whilst handling the client", e)); } finally { - if (!calledRequestHandler) - { - await tcpConnectionFactory.Release(prefetchConnectionTask, closeServerConnection); - } - clientStream.Dispose(); if (!cancellationTokenSource.IsCancellationRequested) diff --git a/tests/Titanium.Web.Proxy.IntegrationTests/Utilities/TestHelper.cs b/tests/Titanium.Web.Proxy.IntegrationTests/Helpers/TestHelper.cs similarity index 80% rename from tests/Titanium.Web.Proxy.IntegrationTests/Utilities/TestHelper.cs rename to tests/Titanium.Web.Proxy.IntegrationTests/Helpers/TestHelper.cs index 134b0db1e..928867604 100644 --- a/tests/Titanium.Web.Proxy.IntegrationTests/Utilities/TestHelper.cs +++ b/tests/Titanium.Web.Proxy.IntegrationTests/Helpers/TestHelper.cs @@ -2,11 +2,11 @@ using System.Net; using System.Net.Http; -namespace Titanium.Web.Proxy.IntegrationTests +namespace Titanium.Web.Proxy.IntegrationTests.Helpers { public static class TestHelper { - public static HttpClient CreateHttpClient(int localProxyPort) + public static HttpClient GetHttpClient(int localProxyPort) { var proxy = new TestProxy($"http://localhost:{localProxyPort}"); @@ -19,6 +19,11 @@ public static HttpClient CreateHttpClient(int localProxyPort) return new HttpClient(handler); } + public static HttpClient GetHttpClient() + { + return new HttpClient(new HttpClientHandler()); + } + public class TestProxy : IWebProxy { public Uri ProxyUri { get; set; } diff --git a/tests/Titanium.Web.Proxy.IntegrationTests/HttpsTests.cs b/tests/Titanium.Web.Proxy.IntegrationTests/HttpsTests.cs new file mode 100644 index 000000000..cb1621bef --- /dev/null +++ b/tests/Titanium.Web.Proxy.IntegrationTests/HttpsTests.cs @@ -0,0 +1,37 @@ +using System; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Titanium.Web.Proxy.IntegrationTests +{ + [TestClass] + public class HttpsTests + { + [TestMethod] + public async Task Can_Handle_Https_Request() + { + var testSuite = new TestSuite(); + + var server = testSuite.GetServer(); + server.HandleRequest((context) => + { + return context.Response.WriteAsync("I am server. I received your greetings."); + }); + + var proxy = testSuite.GetProxy(); + var client = testSuite.GetClient(proxy); + + var response = await client.PostAsync(new Uri(server.ListeningHttpsUrl), + new StringContent("hello server. I am a client.")); + + Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); + var body = await response.Content.ReadAsStringAsync(); + + Assert.AreEqual("I am server. I received your greetings.", body); + } + + } +} diff --git a/tests/Titanium.Web.Proxy.IntegrationTests/InterceptionTests.cs b/tests/Titanium.Web.Proxy.IntegrationTests/InterceptionTests.cs index 14e25fab6..574909124 100644 --- a/tests/Titanium.Web.Proxy.IntegrationTests/InterceptionTests.cs +++ b/tests/Titanium.Web.Proxy.IntegrationTests/InterceptionTests.cs @@ -1,17 +1,9 @@ using System; -using System.Linq; using System.Net; using System.Net.Http; -using System.Security.Cryptography.X509Certificates; using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Hosting.Server.Features; using Microsoft.AspNetCore.Http; using Microsoft.VisualStudio.TestTools.UnitTesting; -using Titanium.Web.Proxy.EventArguments; -using Titanium.Web.Proxy.Models; -using Titanium.Web.Proxy.Network; namespace Titanium.Web.Proxy.IntegrationTests { @@ -19,123 +11,177 @@ namespace Titanium.Web.Proxy.IntegrationTests public class InterceptionTests { [TestMethod] - public async Task Can_Intercept_Post_Requests() + public async Task Can_Intercept_Get_Requests() { - string testHost = "localhost"; + var testSuite = new TestSuite(); - using (var proxy = new ProxyTestController()) + var server = testSuite.GetServer(); + server.HandleRequest((context) => { - var serverCertificate = await proxy.CertificateManager.CreateServerCertificate(testHost); + return context.Response.WriteAsync("I am server. I received your greetings."); + }); - using (var server = new Server(serverCertificate)) + var proxy = testSuite.GetProxy(); + proxy.BeforeRequest += async (sender, e) => + { + if (e.HttpClient.Request.Url.Contains("localhost")) { - var testUrl = $"http://{testHost}:{server.HttpListeningPort}"; - using (var client = TestHelper.CreateHttpClient(proxy.ListeningPort)) - { - var response = await client.PostAsync(new Uri(testUrl), new StringContent("hello!")); + e.Ok("TitaniumWebProxy-Stopped!!"); + return; + } + + await Task.FromResult(0); + }; - Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); + var client = testSuite.GetClient(proxy); + + var response = await client.GetAsync(new Uri(server.ListeningHttpUrl)); + + Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); + + var body = await response.Content.ReadAsStringAsync(); + Assert.IsTrue(body.Contains("TitaniumWebProxy-Stopped!!")); - var body = await response.Content.ReadAsStringAsync(); - Assert.IsTrue(body.Contains("TitaniumWebProxy-Stopped!!")); - } - } - } } - private class ProxyTestController : IDisposable + [TestMethod] + public async Task Can_Intercept_Post_Requests() { - private readonly ProxyServer proxyServer; - public int ListeningPort => proxyServer.ProxyEndPoints[0].Port; - public CertificateManager CertificateManager => proxyServer.CertificateManager; + var testSuite = new TestSuite(); - public ProxyTestController() + var server = testSuite.GetServer(); + server.HandleRequest((context) => { - proxyServer = new ProxyServer(); - var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 0, true); - proxyServer.AddEndPoint(explicitEndPoint); - proxyServer.BeforeRequest += OnRequest; - proxyServer.Start(); - } - - public async Task OnRequest(object sender, SessionEventArgs e) + return context.Response.WriteAsync("I am server. I received your greetings."); + }); + + var proxy = testSuite.GetProxy(); + proxy.BeforeRequest += async (sender, e) => { if (e.HttpClient.Request.Url.Contains("localhost")) { - if (e.HttpClient.Request.HasBody) - { - var body = await e.GetRequestBodyAsString(); - } - e.Ok("TitaniumWebProxy-Stopped!!"); return; } await Task.FromResult(0); - } + }; + + var client = testSuite.GetClient(proxy); + + var response = await client.PostAsync(new Uri(server.ListeningHttpUrl), + new StringContent("hello server. I am a client.")); + + Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); + + var body = await response.Content.ReadAsStringAsync(); + Assert.IsTrue(body.Contains("TitaniumWebProxy-Stopped!!")); - public void Dispose() - { - proxyServer.BeforeRequest -= OnRequest; - proxyServer.Stop(); - proxyServer.Dispose(); - } } - private class Server : IDisposable + [TestMethod] + public async Task Can_Intercept_Put_Requests() { - public int HttpListeningPort; - public int HttpsListeningPort; + var testSuite = new TestSuite(); - private IWebHost host; - public Server(X509Certificate2 serverCertificate) - { - host = new WebHostBuilder() - .UseKestrel(options => - { - options.Listen(IPAddress.Loopback, 0); - options.Listen(IPAddress.Loopback, 0, listenOptions => - { - listenOptions.UseHttps(serverCertificate); - }); - }) - .UseStartup() - .Build(); - - host.Start(); - - string httpAddress = host.ServerFeatures - .Get() - .Addresses - .First(); - - string httpsAddress = host.ServerFeatures - .Get() - .Addresses - .Skip(1) - .First(); - - HttpListeningPort = int.Parse(httpAddress.Split(':')[2]); - HttpsListeningPort = int.Parse(httpsAddress.Split(':')[2]); - } - - public void Dispose() + var server = testSuite.GetServer(); + server.HandleRequest((context) => { - host.Dispose(); - } + return context.Response.WriteAsync("I am server. I received your greetings."); + }); - private class Startup + var proxy = testSuite.GetProxy(); + proxy.BeforeRequest += async (sender, e) => { - public void Configure(IApplicationBuilder app) + if (e.HttpClient.Request.Url.Contains("localhost")) { - app.Run(context => - { - return context.Response.WriteAsync("Server received you request."); - }); + e.Ok("TitaniumWebProxy-Stopped!!"); + return; + } + + await Task.FromResult(0); + }; + + var client = testSuite.GetClient(proxy); + + var response = await client.PutAsync(new Uri(server.ListeningHttpUrl), + new StringContent("hello server. I am a client.")); + + Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); + + var body = await response.Content.ReadAsStringAsync(); + Assert.IsTrue(body.Contains("TitaniumWebProxy-Stopped!!")); + + } + + [TestMethod] + public async Task Can_Intercept_Patch_Requests() + { + var testSuite = new TestSuite(); + + var server = testSuite.GetServer(); + server.HandleRequest((context) => + { + return context.Response.WriteAsync("I am server. I received your greetings."); + }); + + var proxy = testSuite.GetProxy(); + proxy.BeforeRequest += async (sender, e) => + { + if (e.HttpClient.Request.Url.Contains("localhost")) + { + e.Ok("TitaniumWebProxy-Stopped!!"); + return; } - } + + await Task.FromResult(0); + }; + + var client = testSuite.GetClient(proxy); + + var response = await client.PatchAsync(new Uri(server.ListeningHttpUrl), + new StringContent("hello server. I am a client.")); + + Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); + + var body = await response.Content.ReadAsStringAsync(); + Assert.IsTrue(body.Contains("TitaniumWebProxy-Stopped!!")); + } + [TestMethod] + public async Task Can_Intercept_Delete_Requests() + { + var testSuite = new TestSuite(); + + var server = testSuite.GetServer(); + server.HandleRequest((context) => + { + return context.Response.WriteAsync("I am server. I received your greetings."); + }); + + var proxy = testSuite.GetProxy(); + proxy.BeforeRequest += async (sender, e) => + { + if (e.HttpClient.Request.Url.Contains("localhost")) + { + e.Ok("TitaniumWebProxy-Stopped!!"); + return; + } + + await Task.FromResult(0); + }; + + var client = testSuite.GetClient(proxy); + + var response = await client.DeleteAsync(new Uri(server.ListeningHttpUrl)); + + Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); + + var body = await response.Content.ReadAsStringAsync(); + Assert.IsTrue(body.Contains("TitaniumWebProxy-Stopped!!")); + + } } } \ No newline at end of file diff --git a/tests/Titanium.Web.Proxy.IntegrationTests/NestedProxyTests.cs b/tests/Titanium.Web.Proxy.IntegrationTests/NestedProxyTests.cs new file mode 100644 index 000000000..a5cc804ce --- /dev/null +++ b/tests/Titanium.Web.Proxy.IntegrationTests/NestedProxyTests.cs @@ -0,0 +1,39 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; + +namespace Titanium.Web.Proxy.IntegrationTests +{ + [TestClass] + public class NestedProxyTests + { + [TestMethod] + public async Task Smoke_Test_Nested_Proxy() + { + var testSuite = new TestSuite(); + + var server = testSuite.GetServer(); + server.HandleRequest((context) => + { + return context.Response.WriteAsync("I am server. I received your greetings."); + }); + + var proxy1 = testSuite.GetProxy(); + var proxy2 = testSuite.GetProxy(proxy1); + + var client = testSuite.GetClient(proxy2); + + var response = await client.PostAsync(new Uri(server.ListeningHttpsUrl), + new StringContent("hello server. I am a client.")); + + Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); + var body = await response.Content.ReadAsStringAsync(); + + Assert.AreEqual("I am server. I received your greetings.", body); + } + + } +} diff --git a/tests/Titanium.Web.Proxy.IntegrationTests/ReverseProxyTests.cs b/tests/Titanium.Web.Proxy.IntegrationTests/ReverseProxyTests.cs new file mode 100644 index 000000000..37a6fb6d9 --- /dev/null +++ b/tests/Titanium.Web.Proxy.IntegrationTests/ReverseProxyTests.cs @@ -0,0 +1,130 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; + +namespace Titanium.Web.Proxy.IntegrationTests +{ + [TestClass] + public class ReverseProxyTests + { + [TestMethod] + public async Task Smoke_Test_Http_To_Http_Reverse_Proxy() + { + var testSuite = new TestSuite(); + + var server = testSuite.GetServer(); + server.HandleRequest((context) => + { + return context.Response.WriteAsync("I am server. I received your greetings."); + }); + + var proxy = testSuite.GetReverseProxy(); + proxy.BeforeRequest += async (sender, e) => + { + e.HttpClient.Request.RequestUri = new Uri(server.ListeningHttpUrl); + await Task.FromResult(0); + }; + + var client = testSuite.GetReverseProxyClient(); + + var response = await client.PostAsync(new Uri($"http://localhost:{proxy.ProxyEndPoints[0].Port}"), + new StringContent("hello server. I am a client.")); + + Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); + var body = await response.Content.ReadAsStringAsync(); + + Assert.AreEqual("I am server. I received your greetings.", body); + } + + [TestMethod] + public async Task Smoke_Test_Https_To_Http_Reverse_Proxy() + { + var testSuite = new TestSuite(); + + var server = testSuite.GetServer(); + server.HandleRequest((context) => + { + return context.Response.WriteAsync("I am server. I received your greetings."); + }); + + var proxy = testSuite.GetReverseProxy(); + proxy.BeforeRequest += async (sender, e) => + { + e.HttpClient.Request.RequestUri = new Uri(server.ListeningHttpUrl); + await Task.FromResult(0); + }; + + var client = testSuite.GetReverseProxyClient(); + + var response = await client.PostAsync(new Uri($"https://localhost:{proxy.ProxyEndPoints[0].Port}"), + new StringContent("hello server. I am a client.")); + + Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); + var body = await response.Content.ReadAsStringAsync(); + + Assert.AreEqual("I am server. I received your greetings.", body); + } + + [TestMethod] + public async Task Smoke_Test_Http_To_Https_Reverse_Proxy() + { + var testSuite = new TestSuite(); + + var server = testSuite.GetServer(); + server.HandleRequest((context) => + { + return context.Response.WriteAsync("I am server. I received your greetings."); + }); + + var proxy = testSuite.GetReverseProxy(); + proxy.BeforeRequest += async (sender, e) => + { + e.HttpClient.Request.RequestUri = new Uri(server.ListeningHttpsUrl); + await Task.FromResult(0); + }; + + var client = testSuite.GetReverseProxyClient(); + + var response = await client.PostAsync(new Uri($"http://localhost:{proxy.ProxyEndPoints[0].Port}"), + new StringContent("hello server. I am a client.")); + + Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); + var body = await response.Content.ReadAsStringAsync(); + + Assert.AreEqual("I am server. I received your greetings.", body); + } + + [TestMethod] + public async Task Smoke_Test_Https_To_Https_Reverse_Proxy() + { + var testSuite = new TestSuite(); + + var server = testSuite.GetServer(); + server.HandleRequest((context) => + { + return context.Response.WriteAsync("I am server. I received your greetings."); + }); + + var proxy = testSuite.GetReverseProxy(); + proxy.BeforeRequest += async (sender, e) => + { + e.HttpClient.Request.RequestUri = new Uri(server.ListeningHttpsUrl); + await Task.FromResult(0); + }; + + var client = testSuite.GetReverseProxyClient(); + + var response = await client.PostAsync(new Uri($"https://localhost:{proxy.ProxyEndPoints[0].Port}"), + new StringContent("hello server. I am a client.")); + + Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); + var body = await response.Content.ReadAsStringAsync(); + + Assert.AreEqual("I am server. I received your greetings.", body); + } + + } +} diff --git a/tests/Titanium.Web.Proxy.IntegrationTests/Setup/TestProxyServer.cs b/tests/Titanium.Web.Proxy.IntegrationTests/Setup/TestProxyServer.cs new file mode 100644 index 000000000..ab868c15c --- /dev/null +++ b/tests/Titanium.Web.Proxy.IntegrationTests/Setup/TestProxyServer.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Text; +using System.Threading.Tasks; +using Titanium.Web.Proxy.EventArguments; +using Titanium.Web.Proxy.Models; +using Titanium.Web.Proxy.Network; + +namespace Titanium.Web.Proxy.IntegrationTests.Setup +{ + public class TestProxyServer : IDisposable + { + public ProxyServer ProxyServer { get; private set; } + public int ListeningPort => ProxyServer.ProxyEndPoints[0].Port; + public CertificateManager CertificateManager => ProxyServer.CertificateManager; + + public TestProxyServer(bool isReverseProxy, ProxyServer upStreamProxy = null) + { + ProxyServer = new ProxyServer(); + ProxyEndPoint explicitEndPoint = isReverseProxy ? + (ProxyEndPoint)new TransparentProxyEndPoint(IPAddress.Any, 0, true) : + new ExplicitProxyEndPoint(IPAddress.Any, 0, true); + + ProxyServer.AddEndPoint(explicitEndPoint); + + if (upStreamProxy != null) + { + ProxyServer.UpStreamHttpProxy = new ExternalProxy() + { + HostName = "localhost", + Port = upStreamProxy.ProxyEndPoints[0].Port + }; + + ProxyServer.UpStreamHttpsProxy = new ExternalProxy() + { + HostName = "localhost", + Port = upStreamProxy.ProxyEndPoints[0].Port + }; + } + + ProxyServer.Start(); + } + + public void Dispose() + { + ProxyServer.Stop(); + ProxyServer.Dispose(); + } + } +} diff --git a/tests/Titanium.Web.Proxy.IntegrationTests/Setup/TestServer.cs b/tests/Titanium.Web.Proxy.IntegrationTests/Setup/TestServer.cs new file mode 100644 index 000000000..1f8dfeec7 --- /dev/null +++ b/tests/Titanium.Web.Proxy.IntegrationTests/Setup/TestServer.cs @@ -0,0 +1,98 @@ +using Microsoft.AspNetCore; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Hosting.Server.Features; +using Microsoft.AspNetCore.Http; +using System; +using Microsoft.Extensions.DependencyInjection; +using System.Linq; +using System.Net; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using System.Threading.Tasks; + +namespace Titanium.Web.Proxy.IntegrationTests.Setup +{ + //set up a kestrel test server + public class TestServer : IDisposable + { + public string ListeningHttpUrl => $"http://localhost:{HttpListeningPort}"; + public string ListeningHttpsUrl => $"https://localhost:{HttpsListeningPort}"; + + public int HttpListeningPort { get; private set; } + public int HttpsListeningPort { get; private set; } + + private IWebHost host; + public TestServer(X509Certificate2 serverCertificate) + { + var startUp = new Startup(() => requestHandler); + + host = WebHost.CreateDefaultBuilder() + .ConfigureServices(s => + { + s.AddSingleton(startUp); + }) + .UseKestrel(options => + { + options.Listen(IPAddress.Loopback, 0); + options.Listen(IPAddress.Loopback, 0, listenOptions => + { + listenOptions.UseHttps(serverCertificate); + }); + }) + .Build(); + + host.Start(); + + var addresses = host.ServerFeatures + .Get() + .Addresses.ToArray(); + + string httpAddress = addresses[0]; + HttpListeningPort = int.Parse(httpAddress.Split(':')[2]); + + string httpsAddress = addresses[1]; + HttpsListeningPort = int.Parse(httpsAddress.Split(':')[2]); + } + + Func requestHandler = null; + public void HandleRequest(Func requestHandler) + { + this.requestHandler = requestHandler; + } + + public void Dispose() + { + host.StopAsync().Wait(); + host.Dispose(); + } + + private class Startup : IStartup + { + Func> requestHandler; + public Startup(Func> requestHandler) + { + this.requestHandler = requestHandler; + } + + public void Configure(IApplicationBuilder app) + { + app.Run(context => + { + if (requestHandler == null) + { + throw new Exception("Test server not configured to handle request."); + } + + return requestHandler()(context); + }); + + } + + public IServiceProvider ConfigureServices(IServiceCollection services) + { + return services.BuildServiceProvider(); + } + } + } +} diff --git a/tests/Titanium.Web.Proxy.IntegrationTests/Setup/TestSuite.cs b/tests/Titanium.Web.Proxy.IntegrationTests/Setup/TestSuite.cs new file mode 100644 index 000000000..0c0b611ec --- /dev/null +++ b/tests/Titanium.Web.Proxy.IntegrationTests/Setup/TestSuite.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Text; +using Titanium.Web.Proxy.IntegrationTests.Helpers; +using Titanium.Web.Proxy.IntegrationTests.Setup; + +namespace Titanium.Web.Proxy.IntegrationTests +{ + public class TestSuite + { + private TestServer server; + + public TestSuite() + { + var dummyProxy = new ProxyServer(); + var serverCertificate = dummyProxy.CertificateManager.CreateServerCertificate("localhost").Result; + server = new TestServer(serverCertificate); + } + + public TestServer GetServer() + { + return server; + } + + public ProxyServer GetProxy(ProxyServer upStreamProxy = null) + { + if (upStreamProxy != null) + { + return new TestProxyServer(false, upStreamProxy).ProxyServer; + } + + return new TestProxyServer(false).ProxyServer; + } + + public ProxyServer GetReverseProxy(ProxyServer upStreamProxy = null) + { + if (upStreamProxy != null) + { + return new TestProxyServer(true, upStreamProxy).ProxyServer; + } + + return new TestProxyServer(true).ProxyServer; + } + + public HttpClient GetClient(ProxyServer proxyServer) + { + return TestHelper.GetHttpClient(proxyServer.ProxyEndPoints[0].Port); + } + + public HttpClient GetReverseProxyClient() + { + return TestHelper.GetHttpClient(); + } + } +} diff --git a/tests/Titanium.Web.Proxy.IntegrationTests/SslTests.cs b/tests/Titanium.Web.Proxy.IntegrationTests/SslTests.cs deleted file mode 100644 index 70af9c119..000000000 --- a/tests/Titanium.Web.Proxy.IntegrationTests/SslTests.cs +++ /dev/null @@ -1,117 +0,0 @@ -using System; -using System.Linq; -using System.Net; -using System.Security.Cryptography.X509Certificates; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Hosting.Server.Features; -using Microsoft.AspNetCore.Http; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Titanium.Web.Proxy.Models; -using Titanium.Web.Proxy.Network; - -namespace Titanium.Web.Proxy.IntegrationTests -{ - [TestClass] - public class SslTests - { - [TestMethod] - public async Task TestSsl() - { - string testHost = "localhost"; - - using (var proxy = new ProxyTestController()) - { - var serverCertificate = await proxy.CertificateManager.CreateServerCertificate(testHost); - - using (var server = new Server(serverCertificate)) - { - var testUrl = $"https://{testHost}:{server.HttpsListeningPort}"; - using (var client = TestHelper.CreateHttpClient(proxy.ListeningPort)) - { - var response = await client.GetAsync(new Uri(testUrl)); - Assert.IsNotNull(response); - } - } - } - } - - private class ProxyTestController : IDisposable - { - private readonly ProxyServer proxyServer; - public int ListeningPort => proxyServer.ProxyEndPoints[0].Port; - public CertificateManager CertificateManager => proxyServer.CertificateManager; - - public ProxyTestController() - { - proxyServer = new ProxyServer(); - var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 0, true); - proxyServer.AddEndPoint(explicitEndPoint); - proxyServer.Start(); - } - - public void Dispose() - { - proxyServer.Stop(); - proxyServer.Dispose(); - } - } - - private class Server : IDisposable - { - public int HttpListeningPort; - public int HttpsListeningPort; - - private IWebHost host; - public Server(X509Certificate2 serverCertificate) - { - host = new WebHostBuilder() - .UseKestrel(options => - { - options.Listen(IPAddress.Loopback, 0); - options.Listen(IPAddress.Loopback, 0, listenOptions => - { - listenOptions.UseHttps(serverCertificate); - }); - }) - .UseStartup() - .Build(); - - host.Start(); - - string httpAddress = host.ServerFeatures - .Get() - .Addresses - .First(); - - string httpsAddress = host.ServerFeatures - .Get() - .Addresses - .Skip(1) - .First(); - - HttpListeningPort = int.Parse(httpAddress.Split(':')[2]); - HttpsListeningPort = int.Parse(httpsAddress.Split(':')[2]); - } - - public void Dispose() - { - host.Dispose(); - } - - private class Startup - { - public void Configure(IApplicationBuilder app) - { - app.Run(context => - { - return context.Response.WriteAsync("Server received you request."); - }); - - } - } - } - - } -} diff --git a/tests/Titanium.Web.Proxy.IntegrationTests/Titanium.Web.Proxy.IntegrationTests.csproj b/tests/Titanium.Web.Proxy.IntegrationTests/Titanium.Web.Proxy.IntegrationTests.csproj index ecfd7220b..fadb82120 100644 --- a/tests/Titanium.Web.Proxy.IntegrationTests/Titanium.Web.Proxy.IntegrationTests.csproj +++ b/tests/Titanium.Web.Proxy.IntegrationTests/Titanium.Web.Proxy.IntegrationTests.csproj @@ -14,6 +14,7 @@ + diff --git a/tests/Titanium.Web.Proxy.UnitTests/Titanium.Web.Proxy.UnitTests.csproj b/tests/Titanium.Web.Proxy.UnitTests/Titanium.Web.Proxy.UnitTests.csproj index 2484f78a6..dff5cb58c 100644 --- a/tests/Titanium.Web.Proxy.UnitTests/Titanium.Web.Proxy.UnitTests.csproj +++ b/tests/Titanium.Web.Proxy.UnitTests/Titanium.Web.Proxy.UnitTests.csproj @@ -1,7 +1,7 @@  - netcoreapp2.2 + net45 true StrongNameKey.snk From e08721c446718b17848f6178922da40c05941098 Mon Sep 17 00:00:00 2001 From: justcoding121 Date: Mon, 11 Feb 2019 20:58:38 -0500 Subject: [PATCH 8/8] uncomment problamatic test --- tests/Titanium.Web.Proxy.UnitTests/CertificateManagerTests.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/Titanium.Web.Proxy.UnitTests/CertificateManagerTests.cs b/tests/Titanium.Web.Proxy.UnitTests/CertificateManagerTests.cs index 15a464683..a97b5a3de 100644 --- a/tests/Titanium.Web.Proxy.UnitTests/CertificateManagerTests.cs +++ b/tests/Titanium.Web.Proxy.UnitTests/CertificateManagerTests.cs @@ -45,10 +45,9 @@ public async Task Simple_BC_Create_Certificate_Test() } // uncomment this to compare WinCert maker performance with BC (BC takes more time for same test above) - [TestMethod] + //[TestMethod] public async Task Simple_Create_Win_Certificate_Test() { - var tasks = new List(); var mgr = new CertificateManager(null, null, false, false, false, new Lazy(() => (e =>