Unverified Commit 4640ea36 authored by Jehonathan Thomas's avatar Jehonathan Thomas Committed by GitHub

Merge pull request #331 from justcoding121/develop

Beta 3.0.171+ review
parents 250a081e bfb66f70
...@@ -11,6 +11,7 @@ using Titanium.Web.Proxy.EventArguments; ...@@ -11,6 +11,7 @@ using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Helpers; using Titanium.Web.Proxy.Helpers;
using Titanium.Web.Proxy.Http; using Titanium.Web.Proxy.Http;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Network;
namespace Titanium.Web.Proxy.Examples.Wpf namespace Titanium.Web.Proxy.Examples.Wpf
{ {
...@@ -62,7 +63,9 @@ namespace Titanium.Web.Proxy.Examples.Wpf ...@@ -62,7 +63,9 @@ namespace Titanium.Web.Proxy.Examples.Wpf
public MainWindow() public MainWindow()
{ {
proxyServer = new ProxyServer(); proxyServer = new ProxyServer();
//proxyServer.CertificateEngine = CertificateEngine.BouncyCastle;
proxyServer.TrustRootCertificate = true; proxyServer.TrustRootCertificate = true;
proxyServer.CertificateManager.TrustRootCertificateAsAdministrator();
proxyServer.ForwardToUpstreamGateway = true; proxyServer.ForwardToUpstreamGateway = true;
var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000, true) var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000, true)
......
...@@ -82,14 +82,9 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -82,14 +82,9 @@ namespace Titanium.Web.Proxy.EventArguments
public HttpWebClient WebSession { get; } public HttpWebClient WebSession { get; }
/// <summary> /// <summary>
/// Are we using a custom upstream HTTP proxy? /// Are we using a custom upstream HTTP(S) proxy?
/// </summary> /// </summary>
public ExternalProxy CustomUpStreamHttpProxyUsed { get; internal set; } public ExternalProxy CustomUpStreamProxyUsed { get; internal set; }
/// <summary>
/// Are we using a custom upstream HTTPS proxy?
/// </summary>
public ExternalProxy CustomUpStreamHttpsProxyUsed { get; internal set; }
public event EventHandler<DataEventArgs> DataSent; public event EventHandler<DataEventArgs> DataSent;
...@@ -519,8 +514,7 @@ namespace Titanium.Web.Proxy.EventArguments ...@@ -519,8 +514,7 @@ namespace Titanium.Web.Proxy.EventArguments
public void Dispose() public void Dispose()
{ {
httpResponseHandler = null; httpResponseHandler = null;
CustomUpStreamHttpProxyUsed = null; CustomUpStreamProxyUsed = null;
CustomUpStreamHttpsProxyUsed = null;
WebSession.FinishSession(); WebSession.FinishSession();
} }
......
...@@ -87,7 +87,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -87,7 +87,7 @@ namespace Titanium.Web.Proxy.Http
using (var ms = new MemoryStream()) using (var ms = new MemoryStream())
using (var writer = new HttpRequestWriter(ms, bufferSize)) using (var writer = new HttpRequestWriter(ms, bufferSize))
{ {
var upstreamProxy = ServerConnection.UpStreamHttpProxy; var upstreamProxy = ServerConnection.UpStreamProxy;
bool useUpstreamProxy = upstreamProxy != null && ServerConnection.IsHttps == false; bool useUpstreamProxy = upstreamProxy != null && ServerConnection.IsHttps == false;
......
#if !NET45
using System;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Operators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Prng;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.X509;
using System.Security.Cryptography;
using System.IO;
namespace Titanium.Web.Proxy.Network.Certificate
{
/// <summary>
/// Implements certificate generation operations.
/// </summary>
internal class BCCertificateMaker : ICertificateMaker
{
private const int certificateValidDays = 1825;
private const int certificateGraceDays = 366;
/// <summary>
/// Makes the certificate.
/// </summary>
/// <param name="sSubjectCn">The s subject cn.</param>
/// <param name="isRoot">if set to <c>true</c> [is root].</param>
/// <param name="signingCert">The signing cert.</param>
/// <returns>X509Certificate2 instance.</returns>
public X509Certificate2 MakeCertificate(string sSubjectCn, bool isRoot, X509Certificate2 signingCert = null)
{
return MakeCertificateInternal(sSubjectCn, isRoot, true, signingCert);
}
/// <summary>
/// Generates the certificate.
/// </summary>
/// <param name="subjectName">Name of the subject.</param>
/// <param name="issuerName">Name of the issuer.</param>
/// <param name="validFrom">The valid from.</param>
/// <param name="validTo">The valid to.</param>
/// <param name="keyStrength">The key strength.</param>
/// <param name="signatureAlgorithm">The signature algorithm.</param>
/// <param name="issuerPrivateKey">The issuer private key.</param>
/// <param name="hostName">The host name</param>
/// <returns>X509Certificate2 instance.</returns>
/// <exception cref="PemException">Malformed sequence in RSA private key</exception>
private static X509Certificate2 GenerateCertificate(string hostName,
string subjectName,
string issuerName, DateTime validFrom,
DateTime validTo, int keyStrength = 2048,
string signatureAlgorithm = "SHA256WithRSA",
AsymmetricKeyParameter issuerPrivateKey = null)
{
// Generating Random Numbers
var randomGenerator = new CryptoApiRandomGenerator();
var secureRandom = new SecureRandom(randomGenerator);
// The Certificate Generator
var certificateGenerator = new X509V3CertificateGenerator();
// Serial Number
var serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(long.MaxValue), secureRandom);
certificateGenerator.SetSerialNumber(serialNumber);
// Issuer and Subject Name
var subjectDn = new X509Name(subjectName);
var issuerDn = new X509Name(issuerName);
certificateGenerator.SetIssuerDN(issuerDn);
certificateGenerator.SetSubjectDN(subjectDn);
certificateGenerator.SetNotBefore(validFrom);
certificateGenerator.SetNotAfter(validTo);
if (hostName != null)
{
//add subject alternative names
var subjectAlternativeNames = new Asn1Encodable[] { new GeneralName(GeneralName.DnsName, hostName), };
var subjectAlternativeNamesExtension = new DerSequence(subjectAlternativeNames);
certificateGenerator.AddExtension(X509Extensions.SubjectAlternativeName.Id, false, subjectAlternativeNamesExtension);
}
// Subject Public Key
var keyGenerationParameters = new KeyGenerationParameters(secureRandom, keyStrength);
var keyPairGenerator = new RsaKeyPairGenerator();
keyPairGenerator.Init(keyGenerationParameters);
var subjectKeyPair = keyPairGenerator.GenerateKeyPair();
certificateGenerator.SetPublicKey(subjectKeyPair.Public);
// Set certificate intended purposes to only Server Authentication
certificateGenerator.AddExtension(X509Extensions.ExtendedKeyUsage.Id, false, new ExtendedKeyUsage(KeyPurposeID.IdKPServerAuth));
var signatureFactory = new Asn1SignatureFactory(signatureAlgorithm, issuerPrivateKey ?? subjectKeyPair.Private, secureRandom);
// Self-sign the certificate
var certificate = certificateGenerator.Generate(signatureFactory);
// Corresponding private key
var privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(subjectKeyPair.Private);
var seq = (Asn1Sequence)Asn1Object.FromByteArray(privateKeyInfo.ParsePrivateKey().GetDerEncoded());
if (seq.Count != 9)
{
throw new PemException("Malformed sequence in RSA private key");
}
var rsa = RsaPrivateKeyStructure.GetInstance(seq);
var rsaparams = new RsaPrivateCrtKeyParameters(rsa.Modulus, rsa.PublicExponent, rsa.PrivateExponent, rsa.Prime1, rsa.Prime2, rsa.Exponent1,
rsa.Exponent2, rsa.Coefficient);
var x509Certificate = WithPrivateKey(certificate, rsaparams);
x509Certificate.FriendlyName = subjectName;
return x509Certificate;
}
private static X509Certificate2 WithPrivateKey(Org.BouncyCastle.X509.X509Certificate certificate, AsymmetricKeyParameter privateKey)
{
const string password = "password";
var store = new Pkcs12Store();
var entry = new X509CertificateEntry(certificate);
store.SetCertificateEntry(certificate.SubjectDN.ToString(), entry);
store.SetKeyEntry(certificate.SubjectDN.ToString(), new AsymmetricKeyEntry(privateKey), new[] { entry });
using (var ms = new MemoryStream())
{
store.Save(ms, password.ToCharArray(), new SecureRandom(new CryptoApiRandomGenerator()));
return new X509Certificate2(ms.ToArray(), password, X509KeyStorageFlags.Exportable);
}
}
/// <summary>
/// Makes the certificate internal.
/// </summary>
/// <param name="isRoot">if set to <c>true</c> [is root].</param>
/// <param name="hostName">hostname for certificate</param>
/// <param name="subjectName">The full subject.</param>
/// <param name="validFrom">The valid from.</param>
/// <param name="validTo">The valid to.</param>
/// <param name="signingCertificate">The signing certificate.</param>
/// <returns>X509Certificate2 instance.</returns>
/// <exception cref="System.ArgumentException">You must specify a Signing Certificate if and only if you are not creating a root.</exception>
private X509Certificate2 MakeCertificateInternal(bool isRoot,
string hostName, string subjectName,
DateTime validFrom, DateTime validTo, X509Certificate2 signingCertificate)
{
if (isRoot != (null == signingCertificate))
{
throw new ArgumentException("You must specify a Signing Certificate if and only if you are not creating a root.", nameof(signingCertificate));
}
if (isRoot)
{
return GenerateCertificate(null, subjectName, subjectName, validFrom, validTo);
}
else
{
var rsa = signingCertificate.GetRSAPrivateKey();
var kp = GetRsaKeyPair(rsa.ExportParameters(true));
return GenerateCertificate(hostName, subjectName, signingCertificate.Subject, validFrom, validTo, issuerPrivateKey: kp.Private);
}
}
static AsymmetricCipherKeyPair GetRsaKeyPair(RSAParameters rp)
{
BigInteger modulus = new BigInteger(1, rp.Modulus);
BigInteger pubExp = new BigInteger(1, rp.Exponent);
RsaKeyParameters pubKey = new RsaKeyParameters(
false,
modulus,
pubExp);
RsaPrivateCrtKeyParameters privKey = new RsaPrivateCrtKeyParameters(
modulus,
pubExp,
new BigInteger(1, rp.D),
new BigInteger(1, rp.P),
new BigInteger(1, rp.Q),
new BigInteger(1, rp.DP),
new BigInteger(1, rp.DQ),
new BigInteger(1, rp.InverseQ));
return new AsymmetricCipherKeyPair(pubKey, privKey);
}
/// <summary>
/// Makes the certificate internal.
/// </summary>
/// <param name="subject">The s subject cn.</param>
/// <param name="isRoot">if set to <c>true</c> [is root].</param>
/// <param name="switchToMtaIfNeeded">if set to <c>true</c> [switch to MTA if needed].</param>
/// <param name="signingCert">The signing cert.</param>
/// <param name="cancellationToken">Task cancellation token</param>
/// <returns>X509Certificate2.</returns>
private X509Certificate2 MakeCertificateInternal(string subject, bool isRoot,
bool switchToMtaIfNeeded, X509Certificate2 signingCert = null,
CancellationToken cancellationToken = default(CancellationToken))
{
return MakeCertificateInternal(isRoot, subject, $"CN={subject}", DateTime.UtcNow.AddDays(-certificateGraceDays), DateTime.UtcNow.AddDays(certificateValidDays), isRoot ? null : signingCert);
}
class CryptoApiRandomGenerator : IRandomGenerator
{
readonly RandomNumberGenerator rndProv;
public CryptoApiRandomGenerator()
{
rndProv = RandomNumberGenerator.Create();
}
public void AddSeedMaterial(byte[] seed) { }
public void AddSeedMaterial(long seed) { }
public void NextBytes(byte[] bytes)
{
rndProv.GetBytes(bytes);
}
public void NextBytes(byte[] bytes, int start, int len)
{
if (start < 0)
throw new ArgumentException("Start offset cannot be negative", "start");
if (bytes.Length < (start + len))
throw new ArgumentException("Byte array too small for requested offset and length");
if (bytes.Length == len && start == 0)
{
NextBytes(bytes);
}
else
{
byte[] tmpBuf = new byte[len];
NextBytes(tmpBuf);
Array.Copy(tmpBuf, 0, bytes, start, len);
}
}
}
}
}
#endif
\ No newline at end of file
#if NET45 using System;
using System; using System.IO;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using System.Threading; using System.Threading;
using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1;
...@@ -27,6 +28,10 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -27,6 +28,10 @@ namespace Titanium.Web.Proxy.Network.Certificate
private const int certificateValidDays = 1825; private const int certificateValidDays = 1825;
private const int certificateGraceDays = 366; private const int certificateGraceDays = 366;
// The FriendlyName value cannot be set on Unix.
// Set this flag to true when exception detected to avoid further exceptions
private static bool doNotSetFriendlyName;
/// <summary> /// <summary>
/// Makes the certificate. /// Makes the certificate.
/// </summary> /// </summary>
...@@ -87,6 +92,7 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -87,6 +92,7 @@ namespace Titanium.Web.Proxy.Network.Certificate
var subjectAlternativeNamesExtension = new DerSequence(subjectAlternativeNames); var subjectAlternativeNamesExtension = new DerSequence(subjectAlternativeNames);
certificateGenerator.AddExtension(X509Extensions.SubjectAlternativeName.Id, false, subjectAlternativeNamesExtension); certificateGenerator.AddExtension(X509Extensions.SubjectAlternativeName.Id, false, subjectAlternativeNamesExtension);
} }
// Subject Public Key // Subject Public Key
var keyGenerationParameters = new KeyGenerationParameters(secureRandom, keyStrength); var keyGenerationParameters = new KeyGenerationParameters(secureRandom, keyStrength);
var keyPairGenerator = new RsaKeyPairGenerator(); var keyPairGenerator = new RsaKeyPairGenerator();
...@@ -97,12 +103,15 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -97,12 +103,15 @@ namespace Titanium.Web.Proxy.Network.Certificate
// Set certificate intended purposes to only Server Authentication // Set certificate intended purposes to only Server Authentication
certificateGenerator.AddExtension(X509Extensions.ExtendedKeyUsage.Id, false, new ExtendedKeyUsage(KeyPurposeID.IdKPServerAuth)); certificateGenerator.AddExtension(X509Extensions.ExtendedKeyUsage.Id, false, new ExtendedKeyUsage(KeyPurposeID.IdKPServerAuth));
if (issuerPrivateKey == null)
{
certificateGenerator.AddExtension(X509Extensions.BasicConstraints.Id, true, new BasicConstraints(true));
}
var signatureFactory = new Asn1SignatureFactory(signatureAlgorithm, issuerPrivateKey ?? subjectKeyPair.Private, secureRandom); var signatureFactory = new Asn1SignatureFactory(signatureAlgorithm, issuerPrivateKey ?? subjectKeyPair.Private, secureRandom);
// Self-sign the certificate // Self-sign the certificate
var certificate = certificateGenerator.Generate(signatureFactory); var certificate = certificateGenerator.Generate(signatureFactory);
var x509Certificate = new X509Certificate2(certificate.GetEncoded());
// Corresponding private key // Corresponding private key
var privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(subjectKeyPair.Private); var privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(subjectKeyPair.Private);
...@@ -119,8 +128,20 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -119,8 +128,20 @@ namespace Titanium.Web.Proxy.Network.Certificate
rsa.Exponent2, rsa.Coefficient); rsa.Exponent2, rsa.Coefficient);
// Set private key onto certificate instance // Set private key onto certificate instance
var x509Certificate = new X509Certificate2(certificate.GetEncoded());
x509Certificate.PrivateKey = DotNetUtilities.ToRSA(rsaparams); x509Certificate.PrivateKey = DotNetUtilities.ToRSA(rsaparams);
if (!doNotSetFriendlyName)
{
try
{
x509Certificate.FriendlyName = subjectName; x509Certificate.FriendlyName = subjectName;
}
catch (PlatformNotSupportedException)
{
doNotSetFriendlyName = true;
}
}
return x509Certificate; return x509Certificate;
} }
...@@ -136,18 +157,24 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -136,18 +157,24 @@ namespace Titanium.Web.Proxy.Network.Certificate
/// <param name="signingCertificate">The signing certificate.</param> /// <param name="signingCertificate">The signing certificate.</param>
/// <returns>X509Certificate2 instance.</returns> /// <returns>X509Certificate2 instance.</returns>
/// <exception cref="System.ArgumentException">You must specify a Signing Certificate if and only if you are not creating a root.</exception> /// <exception cref="System.ArgumentException">You must specify a Signing Certificate if and only if you are not creating a root.</exception>
private X509Certificate2 MakeCertificateInternal(bool isRoot, string hostName, string subjectName, DateTime validFrom, DateTime validTo, private X509Certificate2 MakeCertificateInternal(bool isRoot,
X509Certificate2 signingCertificate) string hostName, string subjectName,
DateTime validFrom, DateTime validTo, X509Certificate2 signingCertificate)
{ {
if (isRoot != (null == signingCertificate)) if (isRoot != (null == signingCertificate))
{ {
throw new ArgumentException("You must specify a Signing Certificate if and only if you are not creating a root.", nameof(signingCertificate)); throw new ArgumentException("You must specify a Signing Certificate if and only if you are not creating a root.", nameof(signingCertificate));
} }
return isRoot if (isRoot)
? GenerateCertificate(null, subjectName, subjectName, validFrom, validTo) {
: GenerateCertificate(hostName, subjectName, signingCertificate.Subject, validFrom, validTo, return GenerateCertificate(null, subjectName, subjectName, validFrom, validTo);
issuerPrivateKey: DotNetUtilities.GetKeyPair(signingCertificate.PrivateKey).Private); }
else
{
var kp = DotNetUtilities.GetKeyPair(signingCertificate.PrivateKey);
return GenerateCertificate(hostName, subjectName, signingCertificate.Subject, validFrom, validTo, issuerPrivateKey: kp.Private);
}
} }
/// <summary> /// <summary>
...@@ -163,10 +190,10 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -163,10 +190,10 @@ namespace Titanium.Web.Proxy.Network.Certificate
bool switchToMtaIfNeeded, X509Certificate2 signingCert = null, bool switchToMtaIfNeeded, X509Certificate2 signingCert = null,
CancellationToken cancellationToken = default(CancellationToken)) CancellationToken cancellationToken = default(CancellationToken))
{ {
X509Certificate2 certificate = null; #if NET45
if (switchToMtaIfNeeded && Thread.CurrentThread.GetApartmentState() != ApartmentState.MTA) if (switchToMtaIfNeeded && Thread.CurrentThread.GetApartmentState() != ApartmentState.MTA)
{ {
X509Certificate2 certificate = null;
using (var manualResetEvent = new ManualResetEventSlim(false)) using (var manualResetEvent = new ManualResetEventSlim(false))
{ {
ThreadPool.QueueUserWorkItem(o => ThreadPool.QueueUserWorkItem(o =>
...@@ -184,10 +211,9 @@ namespace Titanium.Web.Proxy.Network.Certificate ...@@ -184,10 +211,9 @@ namespace Titanium.Web.Proxy.Network.Certificate
return certificate; return certificate;
} }
#endif
return MakeCertificateInternal(isRoot, subject, $"CN={subject}", DateTime.UtcNow.AddDays(-certificateGraceDays), return MakeCertificateInternal(isRoot, subject, $"CN={subject}", DateTime.UtcNow.AddDays(-certificateGraceDays), DateTime.UtcNow.AddDays(certificateValidDays), isRoot ? null : signingCert);
DateTime.UtcNow.AddDays(certificateValidDays), isRoot ? null : signingCert);
} }
} }
} }
#endif
\ No newline at end of file
...@@ -12,11 +12,7 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -12,11 +12,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// </summary> /// </summary>
internal class TcpConnection : IDisposable internal class TcpConnection : IDisposable
{ {
internal ExternalProxy UpStreamHttpProxy { get; set; } internal ExternalProxy UpStreamProxy { get; set; }
internal ExternalProxy UpStreamHttpsProxy { get; set; }
internal ExternalProxy UpStreamProxy => UseUpstreamProxy ? IsHttps ? UpStreamHttpsProxy : UpStreamHttpProxy : null;
internal string HostName { get; set; } internal string HostName { get; set; }
......
...@@ -27,15 +27,13 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -27,15 +27,13 @@ namespace Titanium.Web.Proxy.Network.Tcp
/// <param name="isHttps"></param> /// <param name="isHttps"></param>
/// <param name="isConnect"></param> /// <param name="isConnect"></param>
/// <param name="upStreamEndPoint"></param> /// <param name="upStreamEndPoint"></param>
/// <param name="externalHttpProxy"></param> /// <param name="externalProxy"></param>
/// <param name="externalHttpsProxy"></param>
/// <returns></returns> /// <returns></returns>
internal async Task<TcpConnection> CreateClient(ProxyServer server, internal async Task<TcpConnection> CreateClient(ProxyServer server,
string remoteHostName, int remotePort, Version httpVersion, bool isHttps, string remoteHostName, int remotePort, Version httpVersion, bool isHttps,
bool isConnect, IPEndPoint upStreamEndPoint, ExternalProxy externalHttpProxy, ExternalProxy externalHttpsProxy) bool isConnect, IPEndPoint upStreamEndPoint, ExternalProxy externalProxy)
{ {
bool useUpstreamProxy = false; bool useUpstreamProxy = false;
var externalProxy = isHttps ? externalHttpsProxy : externalHttpProxy;
//check if external proxy is set for HTTP/HTTPS //check if external proxy is set for HTTP/HTTPS
if (externalProxy != null && !(externalProxy.HostName == remoteHostName && externalProxy.Port == remotePort)) if (externalProxy != null && !(externalProxy.HostName == remoteHostName && externalProxy.Port == remotePort))
...@@ -129,8 +127,7 @@ namespace Titanium.Web.Proxy.Network.Tcp ...@@ -129,8 +127,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
return new TcpConnection return new TcpConnection
{ {
UpStreamHttpProxy = externalHttpProxy, UpStreamProxy = externalProxy,
UpStreamHttpsProxy = externalHttpsProxy,
UpStreamEndPoint = upStreamEndPoint, UpStreamEndPoint = upStreamEndPoint,
HostName = remoteHostName, HostName = remoteHostName,
Port = remotePort, Port = remotePort,
......
...@@ -273,16 +273,10 @@ namespace Titanium.Web.Proxy ...@@ -273,16 +273,10 @@ namespace Titanium.Web.Proxy
public string ProxyRealm { get; set; } = "TitaniumProxy"; public string ProxyRealm { get; set; } = "TitaniumProxy";
/// <summary> /// <summary>
/// A callback to provide authentication credentials for up stream proxy this proxy is using for HTTP requests /// A callback to provide authentication credentials for up stream proxy this proxy is using for HTTP(S) requests
/// return the ExternalProxy object with valid credentials /// return the ExternalProxy object with valid credentials
/// </summary> /// </summary>
public Func<SessionEventArgs, Task<ExternalProxy>> GetCustomUpStreamHttpProxyFunc { get; set; } public Func<SessionEventArgs, Task<ExternalProxy>> GetCustomUpStreamProxyFunc { get; set; }
/// <summary>
/// A callback to provide authentication credentials for up stream proxy this proxy is using for HTTPS requests
/// return the ExternalProxy object with valid credentials
/// </summary>
public Func<SessionEventArgs, Task<ExternalProxy>> GetCustomUpStreamHttpsProxyFunc { get; set; }
/// <summary> /// <summary>
/// A list of IpAddress and port this proxy is listening to /// A list of IpAddress and port this proxy is listening to
...@@ -571,16 +565,13 @@ namespace Titanium.Web.Proxy ...@@ -571,16 +565,13 @@ namespace Titanium.Web.Proxy
} }
} }
if (ForwardToUpstreamGateway if (ForwardToUpstreamGateway && GetCustomUpStreamProxyFunc == null && systemProxySettingsManager != null)
&& GetCustomUpStreamHttpProxyFunc == null && GetCustomUpStreamHttpsProxyFunc == null
&& systemProxySettingsManager != null)
{ {
// Use WinHttp to handle PAC/WAPD scripts. // Use WinHttp to handle PAC/WAPD scripts.
systemProxyResolver = new WinHttpWebProxyFinder(); systemProxyResolver = new WinHttpWebProxyFinder();
systemProxyResolver.LoadFromIE(); systemProxyResolver.LoadFromIE();
GetCustomUpStreamHttpProxyFunc = GetSystemUpStreamProxy; GetCustomUpStreamProxyFunc = GetSystemUpStreamProxy;
GetCustomUpStreamHttpsProxyFunc = GetSystemUpStreamProxy;
} }
#endif #endif
...@@ -692,13 +683,19 @@ namespace Titanium.Web.Proxy ...@@ -692,13 +683,19 @@ namespace Titanium.Web.Proxy
endPoint.Port = ((IPEndPoint)endPoint.Listener.LocalEndpoint).Port; endPoint.Port = ((IPEndPoint)endPoint.Listener.LocalEndpoint).Port;
while (true) while (proxyRunning)
{
try
{ {
TcpClient tcpClient = await endPoint.Listener.AcceptTcpClientAsync(); TcpClient tcpClient = await endPoint.Listener.AcceptTcpClientAsync();
if (tcpClient != null) if (tcpClient != null)
Task.Run(async () => HandleClient(tcpClient, endPoint)); Task.Run(async () => HandleClient(tcpClient, endPoint));
} }
catch (ObjectDisposedException)
{
// proxy was stopped
}
}
} }
#endif #endif
......
...@@ -23,7 +23,7 @@ namespace Titanium.Web.Proxy ...@@ -23,7 +23,7 @@ namespace Titanium.Web.Proxy
/// </summary> /// </summary>
partial class ProxyServer partial class ProxyServer
{ {
private bool IsWindowsAuthenticationEnabledAndSupported => EnableWinAuth && RunTime.IsWindows && !RunTime.IsRunningOnMono; private bool isWindowsAuthenticationEnabledAndSupported => EnableWinAuth && RunTime.IsWindows && !RunTime.IsRunningOnMono;
/// <summary> /// <summary>
/// This is called when client is aware of proxy /// This is called when client is aware of proxy
...@@ -340,7 +340,7 @@ namespace Titanium.Web.Proxy ...@@ -340,7 +340,7 @@ namespace Titanium.Web.Proxy
//if win auth is enabled //if win auth is enabled
//we need a cache of request body //we need a cache of request body
//so that we can send it after authentication in WinAuthHandler.cs //so that we can send it after authentication in WinAuthHandler.cs
if (IsWindowsAuthenticationEnabledAndSupported && args.WebSession.Request.HasBody) if (isWindowsAuthenticationEnabledAndSupported && args.WebSession.Request.HasBody)
{ {
await args.GetRequestBody(); await args.GetRequestBody();
} }
...@@ -581,35 +581,23 @@ namespace Titanium.Web.Proxy ...@@ -581,35 +581,23 @@ namespace Titanium.Web.Proxy
/// <returns></returns> /// <returns></returns>
private async Task<TcpConnection> GetServerConnection(SessionEventArgs args, bool isConnect) private async Task<TcpConnection> GetServerConnection(SessionEventArgs args, bool isConnect)
{ {
ExternalProxy customUpStreamHttpProxy = null; ExternalProxy customUpStreamProxy = null;
ExternalProxy customUpStreamHttpsProxy = null;
if (args.WebSession.Request.IsHttps) bool isHttps = args.IsHttps;
if (GetCustomUpStreamProxyFunc != null)
{ {
if (GetCustomUpStreamHttpsProxyFunc != null) customUpStreamProxy = await GetCustomUpStreamProxyFunc(args);
{
customUpStreamHttpsProxy = await GetCustomUpStreamHttpsProxyFunc(args);
}
}
else
{
if (GetCustomUpStreamHttpProxyFunc != null)
{
customUpStreamHttpProxy = await GetCustomUpStreamHttpProxyFunc(args);
}
} }
args.CustomUpStreamHttpProxyUsed = customUpStreamHttpProxy; args.CustomUpStreamProxyUsed = customUpStreamProxy;
args.CustomUpStreamHttpsProxyUsed = customUpStreamHttpsProxy;
return await tcpConnectionFactory.CreateClient(this, return await tcpConnectionFactory.CreateClient(this,
args.WebSession.Request.RequestUri.Host, args.WebSession.Request.RequestUri.Host,
args.WebSession.Request.RequestUri.Port, args.WebSession.Request.RequestUri.Port,
args.WebSession.Request.HttpVersion, args.WebSession.Request.HttpVersion,
args.IsHttps, isConnect, isHttps, isConnect,
args.WebSession.UpStreamEndPoint ?? UpStreamEndPoint, args.WebSession.UpStreamEndPoint ?? UpStreamEndPoint,
customUpStreamHttpProxy ?? UpStreamHttpProxy, customUpStreamProxy ?? (isHttps ? UpStreamHttpsProxy : UpStreamHttpProxy));
customUpStreamHttpsProxy ?? UpStreamHttpsProxy);
} }
/// <summary> /// <summary>
......
...@@ -5,7 +5,6 @@ using Titanium.Web.Proxy.Compression; ...@@ -5,7 +5,6 @@ using Titanium.Web.Proxy.Compression;
using Titanium.Web.Proxy.EventArguments; using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Exceptions; using Titanium.Web.Proxy.Exceptions;
using Titanium.Web.Proxy.Extensions; using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Helpers;
namespace Titanium.Web.Proxy namespace Titanium.Web.Proxy
{ {
...@@ -29,7 +28,7 @@ namespace Titanium.Web.Proxy ...@@ -29,7 +28,7 @@ namespace Titanium.Web.Proxy
var response = args.WebSession.Response; var response = args.WebSession.Response;
//check for windows authentication //check for windows authentication
if (IsWindowsAuthenticationEnabledAndSupported && response.StatusCode == (int)HttpStatusCode.Unauthorized) if (isWindowsAuthenticationEnabledAndSupported && response.StatusCode == (int)HttpStatusCode.Unauthorized)
{ {
bool disposed = await Handle401UnAuthorized(args); bool disposed = await Handle401UnAuthorized(args);
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Portable.BouncyCastle" Version="1.8.1.2" /> <PackageReference Include="Portable.BouncyCastle" Version="1.8.1.3" />
<PackageReference Include="StreamExtended" Version="1.0.81" /> <PackageReference Include="StreamExtended" Version="1.0.81" />
</ItemGroup> </ItemGroup>
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
<tags></tags> <tags></tags>
<dependencies> <dependencies>
<dependency id="StreamExtended" version="1.0.81" /> <dependency id="StreamExtended" version="1.0.81" />
<dependency id="Portable.BouncyCastle" version="1.8.1.2" /> <dependency id="Portable.BouncyCastle" version="1.8.1.3" />
</dependencies> </dependencies>
</metadata> </metadata>
<files> <files>
......
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="Portable.BouncyCastle" version="1.8.1.2" targetFramework="net45" /> <package id="Portable.BouncyCastle" version="1.8.1.3" targetFramework="net45" />
<package id="StreamExtended" version="1.0.81" targetFramework="net45" /> <package id="StreamExtended" version="1.0.81" targetFramework="net45" />
</packages> </packages>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment