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

Commit abe87ce

Browse files
Merge pull request #406 from justcoding121/develop
Beta 3.0.393+
2 parents 736b66b + f90e356 commit abe87ce

File tree

7 files changed

+62
-67
lines changed

7 files changed

+62
-67
lines changed

Examples/Titanium.Web.Proxy.Examples.Basic/ProxyTestController.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ public void StartProxy()
7878

7979
//proxyServer.EnableWinAuth = true;
8080

81-
explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000, true)
81+
explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000)
8282
{
8383
//You can set only one of the ExcludedHttpsHostNameRegex and IncludedHttpsHostNameRegex properties, otherwise ArgumentException will be thrown
8484

Titanium.Web.Proxy/Models/ExplicitProxyEndPoint.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ public class ExplicitProxyEndPoint : ProxyEndPoint
1717

1818
internal bool IsSystemHttpsProxy { get; set; }
1919

20+
/// <summary>
21+
/// Enable SSL?
22+
/// </summary>
23+
public bool DecryptSsl { get; }
24+
2025
/// <summary>
2126
/// Generic certificate to use for SSL decryption.
2227
/// </summary>
@@ -40,9 +45,10 @@ public class ExplicitProxyEndPoint : ProxyEndPoint
4045
/// </summary>
4146
/// <param name="ipAddress"></param>
4247
/// <param name="port"></param>
43-
/// <param name="enableSsl"></param>
44-
public ExplicitProxyEndPoint(IPAddress ipAddress, int port, bool enableSsl) : base(ipAddress, port, enableSsl)
48+
/// <param name="decryptSsl"></param>
49+
public ExplicitProxyEndPoint(IPAddress ipAddress, int port, bool decryptSsl = true) : base(ipAddress, port)
4550
{
51+
this.DecryptSsl = decryptSsl;
4652
}
4753

4854
internal async Task InvokeBeforeTunnelConnectRequest(ProxyServer proxyServer, TunnelConnectSessionEventArgs connectArgs, ExceptionHandler exceptionFunc)

Titanium.Web.Proxy/Models/ProxyEndPoint.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,10 @@ public abstract class ProxyEndPoint
1717
/// <param name="ipAddress"></param>
1818
/// <param name="port"></param>
1919
/// <param name="enableSsl"></param>
20-
protected ProxyEndPoint(IPAddress ipAddress, int port, bool enableSsl)
20+
protected ProxyEndPoint(IPAddress ipAddress, int port)
2121
{
2222
IpAddress = ipAddress;
2323
Port = port;
24-
EnableSsl = enableSsl;
2524
}
2625

2726
/// <summary>
@@ -39,10 +38,6 @@ protected ProxyEndPoint(IPAddress ipAddress, int port, bool enableSsl)
3938
/// </summary>
4039
public int Port { get; internal set; }
4140

42-
/// <summary>
43-
/// Enable SSL?
44-
/// </summary>
45-
public bool EnableSsl { get; }
4641

4742
/// <summary>
4843
/// Is IPv6 enabled?

Titanium.Web.Proxy/Models/TransparentProxyEndPoint.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public class TransparentProxyEndPoint : ProxyEndPoint
2020
/// <param name="ipAddress"></param>
2121
/// <param name="port"></param>
2222
/// <param name="enableSsl"></param>
23-
public TransparentProxyEndPoint(IPAddress ipAddress, int port, bool enableSsl) : base(ipAddress, port, enableSsl)
23+
public TransparentProxyEndPoint(IPAddress ipAddress, int port) : base(ipAddress, port)
2424
{
2525
GenericCertificateName = "localhost";
2626
}

Titanium.Web.Proxy/ProxyServer.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -319,10 +319,6 @@ public void SetAsSystemProxy(ExplicitProxyEndPoint endPoint, ProxyProtocolType p
319319

320320
if (isHttps)
321321
{
322-
if (!endPoint.EnableSsl)
323-
{
324-
throw new Exception("Endpoint do not support Https connections");
325-
}
326322

327323
CertificateManager.EnsureRootCertificate();
328324

Titanium.Web.Proxy/RequestHandler.cs

Lines changed: 34 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ private async Task HandleClient(ExplicitProxyEndPoint endPoint, TcpClient tcpCli
7979
await endPoint.InvokeBeforeTunnelConnectRequest(this, connectArgs, ExceptionFunc);
8080

8181
//filter out excluded host names
82-
bool excluded = connectArgs.Excluded;
82+
bool excluded = !endPoint.DecryptSsl || connectArgs.Excluded;
8383

8484
if (await CheckAuthorization(connectArgs) == false)
8585
{
@@ -92,17 +92,15 @@ private async Task HandleClient(ExplicitProxyEndPoint endPoint, TcpClient tcpCli
9292

9393
//write back successfull CONNECT response
9494
var response = ConnectResponse.CreateSuccessfullConnectResponse(version);
95+
// Set ContentLength explicitly to properly handle HTTP 1.0
96+
response.ContentLength = 0;
9597
response.Headers.FixProxyHeaders();
9698
connectArgs.WebSession.Response = response;
9799

98100
await clientStreamWriter.WriteResponseAsync(response);
99101

100-
ClientHelloInfo clientHelloInfo = null;
101-
if (endPoint.EnableSsl)
102-
{
103-
clientHelloInfo = await SslTools.PeekClientHello(clientStream);
104-
}
105-
102+
var clientHelloInfo = await SslTools.PeekClientHello(clientStream);
103+
106104
bool isClientHello = clientHelloInfo != null;
107105
if (isClientHello)
108106
{
@@ -232,48 +230,46 @@ private async Task HandleClient(TransparentProxyEndPoint endPoint, TcpClient tcp
232230

233231
try
234232
{
235-
if (endPoint.EnableSsl)
236-
{
237-
var clientHelloInfo = await SslTools.PeekClientHello(clientStream);
233+
var clientHelloInfo = await SslTools.PeekClientHello(clientStream);
238234

239-
if (clientHelloInfo != null)
240-
{
241-
SslStream sslStream = null;
242-
string sniHostName = null;
235+
var isHttps = clientHelloInfo != null;
236+
string httpsHostName = null;
243237

244-
try
245-
{
246-
sslStream = new SslStream(clientStream);
238+
if (isHttps)
239+
{
240+
SslStream sslStream = null;
241+
242+
try
243+
{
244+
sslStream = new SslStream(clientStream);
247245

248-
sniHostName = clientHelloInfo.GetServerName() ?? endPoint.GenericCertificateName;
246+
httpsHostName = clientHelloInfo.GetServerName() ?? endPoint.GenericCertificateName;
249247

250-
string certName = HttpHelper.GetWildCardDomainName(sniHostName);
251-
var certificate = await CertificateManager.CreateCertificateAsync(certName);
248+
string certName = HttpHelper.GetWildCardDomainName(httpsHostName);
249+
var certificate = await CertificateManager.CreateCertificateAsync(certName);
252250

253-
//Successfully managed to authenticate the client using the fake certificate
254-
await sslStream.AuthenticateAsServerAsync(certificate, false, SslProtocols.Tls, false);
251+
//Successfully managed to authenticate the client using the fake certificate
252+
await sslStream.AuthenticateAsServerAsync(certificate, false, SslProtocols.Tls, false);
255253

256-
//HTTPS server created - we can now decrypt the client's traffic
257-
clientStream = new CustomBufferedStream(sslStream, BufferSize);
254+
//HTTPS server created - we can now decrypt the client's traffic
255+
clientStream = new CustomBufferedStream(sslStream, BufferSize);
258256

259-
clientStreamReader.Dispose();
260-
clientStreamReader = new CustomBinaryReader(clientStream, BufferSize);
261-
clientStreamWriter = new HttpResponseWriter(clientStream, BufferSize);
262-
}
263-
catch (Exception e)
264-
{
265-
ExceptionFunc(new Exception($"Could'nt authenticate client '{sniHostName}' with fake certificate.", e));
266-
sslStream?.Dispose();
267-
return;
268-
}
257+
clientStreamReader.Dispose();
258+
clientStreamReader = new CustomBinaryReader(clientStream, BufferSize);
259+
clientStreamWriter = new HttpResponseWriter(clientStream, BufferSize);
260+
}
261+
catch (Exception e)
262+
{
263+
ExceptionFunc(new Exception($"Could'nt authenticate client '{httpsHostName}' with fake certificate.", e));
264+
sslStream?.Dispose();
265+
return;
269266
}
270-
271-
//HTTPS server created - we can now decrypt the client's traffic
272267
}
273268

269+
//HTTPS server created - we can now decrypt the client's traffic
274270
//Now create the request
275271
await HandleHttpSessionRequest(tcpClient, clientStream, clientStreamReader, clientStreamWriter,
276-
endPoint.EnableSsl ? endPoint.GenericCertificateName : null, endPoint, null, true);
272+
isHttps ? httpsHostName : null, endPoint, null, true);
277273
}
278274
finally
279275
{
@@ -621,7 +617,7 @@ private async Task<TcpConnection> GetServerConnection(SessionEventArgs args, boo
621617
/// <param name="requestHeaders"></param>
622618
private void PrepareRequestHeaders(HeaderCollection requestHeaders)
623619
{
624-
if(requestHeaders.HeaderExists(KnownHeaders.AcceptEncoding))
620+
if (requestHeaders.HeaderExists(KnownHeaders.AcceptEncoding))
625621
{
626622
requestHeaders.SetOrAddHeaderValue(KnownHeaders.AcceptEncoding, "gzip,deflate");
627623
}

Titanium.Web.Proxy/WinAuthHandler.cs

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,21 @@ namespace Titanium.Web.Proxy
1414
public partial class ProxyServer
1515
{
1616
//possible header names
17-
private static readonly List<string> authHeaderNames = new List<string>
17+
private static readonly HashSet<string> authHeaderNames = new HashSet<string>
1818
{
19-
"WWW-Authenticate",
19+
"WWW-Authenticate".ToLower(),
2020
//IIS 6.0 messed up names below
21-
"WWWAuthenticate",
22-
"NTLMAuthorization",
23-
"NegotiateAuthorization",
24-
"KerberosAuthorization"
21+
"WWWAuthenticate".ToLower(),
22+
"NTLMAuthorization".ToLower(),
23+
"NegotiateAuthorization".ToLower(),
24+
"KerberosAuthorization".ToLower()
2525
};
2626

27-
private static readonly List<string> authSchemes = new List<string>
27+
private static readonly HashSet<string> authSchemes = new HashSet<string>
2828
{
29-
"NTLM",
30-
"Negotiate",
31-
"Kerberos"
29+
"NTLM".ToLower(),
30+
"Negotiate".ToLower(),
31+
"Kerberos".ToLower()
3232
};
3333

3434
/// <summary>
@@ -49,7 +49,7 @@ internal async Task Handle401UnAuthorized(SessionEventArgs args)
4949

5050
//check in non-unique headers first
5151
var header = response.Headers.NonUniqueHeaders.FirstOrDefault(
52-
x => authHeaderNames.Any(y => x.Key.Equals(y, StringComparison.OrdinalIgnoreCase)));
52+
x => authHeaderNames.Contains(x.Key.ToLower()));
5353

5454
if (!header.Equals(new KeyValuePair<string, List<HttpHeader>>()))
5555
{
@@ -65,8 +65,10 @@ internal async Task Handle401UnAuthorized(SessionEventArgs args)
6565
//check in unique headers
6666
if (authHeader == null)
6767
{
68+
headerName = null;
69+
6870
//check in non-unique headers first
69-
var uHeader = response.Headers.Headers.FirstOrDefault(x => authHeaderNames.Any(y => x.Key.Equals(y, StringComparison.OrdinalIgnoreCase)));
71+
var uHeader = response.Headers.Headers.FirstOrDefault(x => authHeaderNames.Contains(x.Key.ToLower()));
7072

7173
if (!uHeader.Equals(new KeyValuePair<string, HttpHeader>()))
7274
{
@@ -84,7 +86,7 @@ internal async Task Handle401UnAuthorized(SessionEventArgs args)
8486

8587
if (authHeader != null)
8688
{
87-
string scheme = authSchemes.FirstOrDefault(x => authHeader.Value.Equals(x, StringComparison.OrdinalIgnoreCase));
89+
string scheme = authSchemes.Contains(authHeader.Value.ToLower()) ? authHeader.Value.ToLower() : null;
8890

8991
var expectedAuthState = scheme == null ? State.WinAuthState.INITIAL_TOKEN : State.WinAuthState.UNAUTHORIZED;
9092

@@ -109,7 +111,7 @@ internal async Task Handle401UnAuthorized(SessionEventArgs args)
109111

110112
//replace existing authorization header if any
111113
request.Headers.SetOrAddHeaderValue(KnownHeaders.Authorization, auth);
112-
114+
113115
//don't need to send body for Authorization request
114116
if (request.HasBody)
115117
{
@@ -131,7 +133,7 @@ internal async Task Handle401UnAuthorized(SessionEventArgs args)
131133
request.Headers.SetOrAddHeaderValue(KnownHeaders.Authorization, auth);
132134

133135
//send body for final auth request
134-
if (request.HasBody)
136+
if (request.OriginalHasBody)
135137
{
136138
request.ContentLength = request.Body.Length;
137139
}

0 commit comments

Comments
 (0)