Skip to content
This repository was archived by the owner on Jul 9, 2023. It is now read-only.

Fix reverse proxy #548

Merged
merged 9 commits into from
Feb 12, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -39,6 +39,8 @@ assembly_info:
# to disable automatic tests
test: on

test_script:
- cmd: test.bat
# skip building commits that add tags (such as release tag)
skip_tags: true

Expand Down
48 changes: 48 additions & 0 deletions docs/api/Titanium.Web.Proxy.Network.CertificateManager.html
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,54 @@ <h5 class="returns">Returns</h5>
</tr>
</tbody>
</table>
<span class="small pull-right mobile-hide">
<span class="divider">|</span>
<a href="https://github.com/justcoding121/Titanium-Web-Proxy/new/master/apiSpec/new?filename=Titanium_Web_Proxy_Network_CertificateManager_CreateServerCertificate_System_String_.md&amp;value=---%0Auid%3A%20Titanium.Web.Proxy.Network.CertificateManager.CreateServerCertificate(System.String)%0Asummary%3A%20'*You%20can%20override%20summary%20for%20the%20API%20here%20using%20*MARKDOWN*%20syntax'%0A---%0A%0A*Please%20type%20below%20more%20information%20about%20this%20API%3A*%0A%0A">Improve this Doc</a>
</span>
<span class="small pull-right mobile-hide">
<a href="https://github.com/justcoding121/Titanium-Web-Proxy/blob/master/src/Titanium.Web.Proxy/Network/CertificateManager.cs/#L439">View Source</a>
</span>
<a id="Titanium_Web_Proxy_Network_CertificateManager_CreateServerCertificate_" data-uid="Titanium.Web.Proxy.Network.CertificateManager.CreateServerCertificate*"></a>
<h4 id="Titanium_Web_Proxy_Network_CertificateManager_CreateServerCertificate_System_String_" data-uid="Titanium.Web.Proxy.Network.CertificateManager.CreateServerCertificate(System.String)">CreateServerCertificate(String)</h4>
<div class="markdown level1 summary"><p>Creates a server certificate signed by the root certificate.</p>
</div>
<div class="markdown level1 conceptual"></div>
<h5 class="decalaration">Declaration</h5>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public Task&lt;X509Certificate2&gt; CreateServerCertificate(string certificateName)</code></pre>
</div>
<h5 class="parameters">Parameters</h5>
<table class="table table-bordered table-striped table-condensed">
<thead>
<tr>
<th>Type</th>
<th>Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.string">String</a></td>
<td><span class="parametername">certificateName</span></td>
<td></td>
</tr>
</tbody>
</table>
<h5 class="returns">Returns</h5>
<table class="table table-bordered table-striped table-condensed">
<thead>
<tr>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><a class="xref" href="https://docs.microsoft.com/dotnet/api/system.threading.tasks.task-1">Task</a>&lt;<a class="xref" href="https://docs.microsoft.com/dotnet/api/system.security.cryptography.x509certificates.x509certificate2">X509Certificate2</a>&gt;</td>
<td></td>
</tr>
</tbody>
</table>
<span class="small pull-right mobile-hide">
<span class="divider">|</span>
<a href="https://github.com/justcoding121/Titanium-Web-Proxy/new/master/apiSpec/new?filename=Titanium_Web_Proxy_Network_CertificateManager_Dispose.md&amp;value=---%0Auid%3A%20Titanium.Web.Proxy.Network.CertificateManager.Dispose%0Asummary%3A%20'*You%20can%20override%20summary%20for%20the%20API%20here%20using%20*MARKDOWN*%20syntax'%0A---%0A%0A*Please%20type%20below%20more%20information%20about%20this%20API%3A*%0A%0A">Improve this Doc</a>
Expand Down
2 changes: 1 addition & 1 deletion docs/index.json

Large diffs are not rendered by default.

13 changes: 13 additions & 0 deletions docs/xrefmap.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
32 changes: 16 additions & 16 deletions src/Titanium.Web.Proxy.sln
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -49,20 +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
{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
{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
Expand All @@ -79,18 +71,26 @@ 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
SolutionGuid = {625C1EB5-44CF-47DE-A85A-B4C8C40ED90A}
EnterpriseLibraryConfigurationToolBinariesPath = .1.505.2\lib\NET35
EndGlobalSection
EndGlobal
2 changes: 1 addition & 1 deletion src/Titanium.Web.Proxy/ExplicitClientHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
4 changes: 2 additions & 2 deletions src/Titanium.Web.Proxy/Network/CertificateManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -432,11 +432,11 @@ internal X509Certificate2 CreateCertificate(string certificateName, bool isRootC
}

/// <summary>
/// Create an SSL certificate async
/// Creates a server certificate signed by the root certificate.
/// </summary>
/// <param name="certificateName"></param>
/// <returns></returns>
internal async Task<X509Certificate2> CreateCertificateAsync(string certificateName)
public async Task<X509Certificate2> CreateServerCertificate(string certificateName)
{
// check in cache first
if (cachedCertificates.TryGetValue(certificateName, out var cached))
Expand Down
29 changes: 3 additions & 26 deletions src/Titanium.Web.Proxy/TransparentClientHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<TcpServerConnection> prefetchConnectionTask = null;
bool closeServerConnection = false;
bool calledRequestHandler = false;

try
{
var clientHelloInfo = await SslTools.PeekClientHello(clientStream, BufferPool, cancellationToken);
Expand All @@ -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
Expand All @@ -82,7 +69,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);
Expand Down Expand Up @@ -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)
Expand Down
5 changes: 5 additions & 0 deletions test.bat
Original file line number Diff line number Diff line change
@@ -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%
54 changes: 54 additions & 0 deletions tests/Titanium.Web.Proxy.IntegrationTests/Helpers/TestHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using System;
using System.Net;
using System.Net.Http;

namespace Titanium.Web.Proxy.IntegrationTests.Helpers
{
public static class TestHelper
{
public static HttpClient GetHttpClient(int localProxyPort)
{
var proxy = new TestProxy($"http://localhost:{localProxyPort}");

var handler = new HttpClientHandler
{
Proxy = proxy,
UseProxy = true
};

return new HttpClient(handler);
}

public static HttpClient GetHttpClient()
{
return new HttpClient(new HttpClientHandler());
}

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;
}

}
}
}
37 changes: 37 additions & 0 deletions tests/Titanium.Web.Proxy.IntegrationTests/HttpsTests.cs
Original file line number Diff line number Diff line change
@@ -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);
}

}
}
Loading