Commit 8063d024 authored by Jehonathan's avatar Jehonathan Committed by GitHub

Merge pull request #253 from justcoding121/develop

Beta
parents f02a8bfd 813700fe
...@@ -45,6 +45,8 @@ namespace Titanium.Web.Proxy.Examples.Basic ...@@ -45,6 +45,8 @@ namespace Titanium.Web.Proxy.Examples.Basic
proxyServer.ServerCertificateValidationCallback += OnCertificateValidation; proxyServer.ServerCertificateValidationCallback += OnCertificateValidation;
proxyServer.ClientCertificateSelectionCallback += OnCertificateSelection; proxyServer.ClientCertificateSelectionCallback += OnCertificateSelection;
//proxyServer.EnableWinAuth = true;
var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000, true) var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000, true)
{ {
//Exclude Https addresses you don't want to proxy //Exclude Https addresses you don't want to proxy
......
using System; using System;
using System.Linq;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using Titanium.Web.Proxy.Extensions; using Titanium.Web.Proxy.Extensions;
...@@ -306,6 +307,143 @@ namespace Titanium.Web.Proxy.Http ...@@ -306,6 +307,143 @@ namespace Titanium.Web.Proxy.Http
NonUniqueRequestHeaders = new Dictionary<string, List<HttpHeader>>(StringComparer.OrdinalIgnoreCase); NonUniqueRequestHeaders = new Dictionary<string, List<HttpHeader>>(StringComparer.OrdinalIgnoreCase);
} }
/// <summary>
/// True if header exists
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public bool HeaderExists(string name)
{
if (RequestHeaders.ContainsKey(name)
|| NonUniqueRequestHeaders.ContainsKey(name))
{
return true;
}
return false;
}
/// <summary>
/// Returns all headers with given name if exists
/// Returns null if does'nt exist
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public List<HttpHeader> GetHeaders(string name)
{
if (RequestHeaders.ContainsKey(name))
{
return new List<HttpHeader>() { RequestHeaders[name] };
}
else if (NonUniqueRequestHeaders.ContainsKey(name))
{
return new List<HttpHeader>(NonUniqueRequestHeaders[name]);
}
return null;
}
/// <summary>
/// Returns all headers
/// </summary>
/// <returns></returns>
public List<HttpHeader> GetAllHeaders()
{
var result = new List<HttpHeader>();
result.AddRange(RequestHeaders.Select(x => x.Value));
result.AddRange(NonUniqueRequestHeaders.SelectMany(x => x.Value));
return result;
}
/// <summary>
/// Add a new header with given name and value
/// </summary>
/// <param name="name"></param>
/// <param name="value"></param>
public void AddHeader(string name, string value)
{
AddHeader(new HttpHeader(name, value));
}
/// <summary>
/// Adds the given header object to Request
/// </summary>
/// <param name="newHeader"></param>
public void AddHeader(HttpHeader newHeader)
{
if (NonUniqueRequestHeaders.ContainsKey(newHeader.Name))
{
NonUniqueRequestHeaders[newHeader.Name].Add(newHeader);
return;
}
if (RequestHeaders.ContainsKey(newHeader.Name))
{
var existing = RequestHeaders[newHeader.Name];
RequestHeaders.Remove(newHeader.Name);
NonUniqueRequestHeaders.Add(newHeader.Name,
new List<HttpHeader>() { existing, newHeader });
}
else
{
RequestHeaders.Add(newHeader.Name, newHeader);
}
}
/// <summary>
/// removes all headers with given name
/// </summary>
/// <param name="headerName"></param>
/// <returns>True if header was removed
/// False if no header exists with given name</returns>
public bool RemoveHeader(string headerName)
{
if (RequestHeaders.ContainsKey(headerName))
{
RequestHeaders.Remove(headerName);
return true;
}
else if (NonUniqueRequestHeaders.ContainsKey(headerName))
{
NonUniqueRequestHeaders.Remove(headerName);
return true;
}
return false;
}
/// <summary>
/// Removes given header object if it exist
/// </summary>
/// <param name="header">Returns true if header exists and was removed </param>
public bool RemoveHeader(HttpHeader header)
{
if (RequestHeaders.ContainsKey(header.Name))
{
if (RequestHeaders[header.Name].Equals(header))
{
RequestHeaders.Remove(header.Name);
return true;
}
}
else if (NonUniqueRequestHeaders.ContainsKey(header.Name))
{
if (NonUniqueRequestHeaders[header.Name]
.RemoveAll(x => x.Equals(header)) > 0)
{
return true;
}
}
return false;
}
/// <summary> /// <summary>
/// Dispose off /// Dispose off
/// </summary> /// </summary>
...@@ -320,5 +458,7 @@ namespace Titanium.Web.Proxy.Http ...@@ -320,5 +458,7 @@ namespace Titanium.Web.Proxy.Http
RequestBody = null; RequestBody = null;
RequestBody = null; RequestBody = null;
} }
} }
} }
using System; using System;
using System.Linq;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text; using System.Text;
...@@ -242,6 +243,141 @@ namespace Titanium.Web.Proxy.Http ...@@ -242,6 +243,141 @@ namespace Titanium.Web.Proxy.Http
NonUniqueResponseHeaders = new Dictionary<string, List<HttpHeader>>(StringComparer.OrdinalIgnoreCase); NonUniqueResponseHeaders = new Dictionary<string, List<HttpHeader>>(StringComparer.OrdinalIgnoreCase);
} }
/// <summary>
/// True if header exists
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public bool HeaderExists(string name)
{
if(ResponseHeaders.ContainsKey(name)
|| NonUniqueResponseHeaders.ContainsKey(name))
{
return true;
}
return false;
}
/// <summary>
/// Returns all headers with given name if exists
/// Returns null if does'nt exist
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public List<HttpHeader> GetHeaders(string name)
{
if (ResponseHeaders.ContainsKey(name))
{
return new List<HttpHeader>() { ResponseHeaders[name] };
}
else if (NonUniqueResponseHeaders.ContainsKey(name))
{
return new List<HttpHeader>(NonUniqueResponseHeaders[name]);
}
return null;
}
/// <summary>
/// Returns all headers
/// </summary>
/// <returns></returns>
public List<HttpHeader> GetAllHeaders()
{
var result = new List<HttpHeader>();
result.AddRange(ResponseHeaders.Select(x => x.Value));
result.AddRange(NonUniqueResponseHeaders.SelectMany(x => x.Value));
return result;
}
/// <summary>
/// Add a new header with given name and value
/// </summary>
/// <param name="name"></param>
/// <param name="value"></param>
public void AddHeader(string name, string value)
{
AddHeader(new HttpHeader(name, value));
}
/// <summary>
/// Adds the given header object to Response
/// </summary>
/// <param name="newHeader"></param>
public void AddHeader(HttpHeader newHeader)
{
if (NonUniqueResponseHeaders.ContainsKey(newHeader.Name))
{
NonUniqueResponseHeaders[newHeader.Name].Add(newHeader);
return;
}
if (ResponseHeaders.ContainsKey(newHeader.Name))
{
var existing = ResponseHeaders[newHeader.Name];
ResponseHeaders.Remove(newHeader.Name);
NonUniqueResponseHeaders.Add(newHeader.Name,
new List<HttpHeader>() { existing, newHeader });
}
else
{
ResponseHeaders.Add(newHeader.Name, newHeader);
}
}
/// <summary>
/// removes all headers with given name
/// </summary>
/// <param name="headerName"></param>
/// <returns>True if header was removed
/// False if no header exists with given name</returns>
public bool RemoveHeader(string headerName)
{
if(ResponseHeaders.ContainsKey(headerName))
{
ResponseHeaders.Remove(headerName);
return true;
}
else if (NonUniqueResponseHeaders.ContainsKey(headerName))
{
NonUniqueResponseHeaders.Remove(headerName);
return true;
}
return false;
}
/// <summary>
/// Removes given header object if it exist
/// </summary>
/// <param name="header">Returns true if header exists and was removed </param>
public bool RemoveHeader(HttpHeader header)
{
if (ResponseHeaders.ContainsKey(header.Name))
{
if (ResponseHeaders[header.Name].Equals(header))
{
ResponseHeaders.Remove(header.Name);
return true;
}
}
else if (NonUniqueResponseHeaders.ContainsKey(header.Name))
{
if (NonUniqueResponseHeaders[header.Name]
.RemoveAll(x => x.Equals(header)) > 0)
{
return true;
}
}
return false;
}
/// <summary> /// <summary>
/// Dispose off /// Dispose off
/// </summary> /// </summary>
......
...@@ -205,7 +205,7 @@ namespace Titanium.Web.Proxy ...@@ -205,7 +205,7 @@ namespace Titanium.Web.Proxy
/// in middle attack is not currently supported /// in middle attack is not currently supported
/// (which would require windows delegation enabled for this server process) /// (which would require windows delegation enabled for this server process)
/// </summary> /// </summary>
public bool EnableWinAuth { get; set; } = true; public bool EnableWinAuth { get; set; }
/// <summary> /// <summary>
/// Verifies the remote Secure Sockets Layer (SSL) certificate used for authentication /// Verifies the remote Secure Sockets Layer (SSL) certificate used for authentication
......
...@@ -453,27 +453,31 @@ namespace Titanium.Web.Proxy ...@@ -453,27 +453,31 @@ namespace Titanium.Web.Proxy
await args.WebSession.SendRequest(Enable100ContinueBehaviour); await args.WebSession.SendRequest(Enable100ContinueBehaviour);
} }
//If request was modified by user //check if content-length is > 0
if (args.WebSession.Request.RequestBodyRead) if (args.WebSession.Request.ContentLength > 0)
{ {
if (args.WebSession.Request.ContentEncoding != null) //If request was modified by user
if (args.WebSession.Request.RequestBodyRead)
{ {
args.WebSession.Request.RequestBody = await GetCompressedResponseBody(args.WebSession.Request.ContentEncoding, args.WebSession.Request.RequestBody); if (args.WebSession.Request.ContentEncoding != null)
} {
//chunked send is not supported as of now args.WebSession.Request.RequestBody = await GetCompressedResponseBody(args.WebSession.Request.ContentEncoding, args.WebSession.Request.RequestBody);
args.WebSession.Request.ContentLength = args.WebSession.Request.RequestBody.Length; }
//chunked send is not supported as of now
args.WebSession.Request.ContentLength = args.WebSession.Request.RequestBody.Length;
var newStream = args.WebSession.ServerConnection.Stream; var newStream = args.WebSession.ServerConnection.Stream;
await newStream.WriteAsync(args.WebSession.Request.RequestBody, 0, args.WebSession.Request.RequestBody.Length); await newStream.WriteAsync(args.WebSession.Request.RequestBody, 0, args.WebSession.Request.RequestBody.Length);
} }
else else
{
if (!args.WebSession.Request.ExpectationFailed)
{ {
//If its a post/put/patch request, then read the client html body and send it to server if (!args.WebSession.Request.ExpectationFailed)
if (args.WebSession.Request.HasBody)
{ {
await SendClientRequestBody(args); //If its a post/put/patch request, then read the client html body and send it to server
if (args.WebSession.Request.HasBody)
{
await SendClientRequestBody(args);
}
} }
} }
} }
......
...@@ -5,6 +5,8 @@ using System.Threading.Tasks; ...@@ -5,6 +5,8 @@ using System.Threading.Tasks;
using Titanium.Web.Proxy.EventArguments; using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Models; using Titanium.Web.Proxy.Models;
using Titanium.Web.Proxy.Network.WinAuth; using Titanium.Web.Proxy.Network.WinAuth;
using Titanium.Web.Proxy.Extensions;
using Titanium.Web.Proxy.Helpers;
namespace Titanium.Web.Proxy namespace Titanium.Web.Proxy
{ {
...@@ -87,11 +89,35 @@ namespace Titanium.Web.Proxy ...@@ -87,11 +89,35 @@ namespace Titanium.Web.Proxy
{ {
var scheme = authSchemes.FirstOrDefault(x => authHeader.Value.Equals(x, StringComparison.OrdinalIgnoreCase)); var scheme = authSchemes.FirstOrDefault(x => authHeader.Value.Equals(x, StringComparison.OrdinalIgnoreCase));
//clear any existing headers to avoid confusing bad servers
if (args.WebSession.Request.NonUniqueRequestHeaders.ContainsKey("Authorization"))
{
args.WebSession.Request.NonUniqueRequestHeaders.Remove("Authorization");
}
//initial value will match exactly any of the schemes //initial value will match exactly any of the schemes
if (scheme != null) if (scheme != null)
{ {
var clientToken = WinAuthHandler.GetInitialAuthToken(args.WebSession.Request.Host, scheme, args.Id); var clientToken = WinAuthHandler.GetInitialAuthToken(args.WebSession.Request.Host, scheme, args.Id);
args.WebSession.Request.RequestHeaders.Add("Authorization", new HttpHeader("Authorization", string.Concat(scheme, clientToken)));
var auth = new HttpHeader("Authorization", string.Concat(scheme, clientToken));
//replace existing authorization header if any
if (args.WebSession.Request.RequestHeaders.ContainsKey("Authorization"))
{
args.WebSession.Request.RequestHeaders["Authorization"] = auth;
}
else
{
args.WebSession.Request.RequestHeaders.Add("Authorization", auth);
}
//don't need to send body for Authorization request
if(args.WebSession.Request.HasBody)
{
args.WebSession.Request.ContentLength = 0;
}
} }
//challenge value will start with any of the scheme selected //challenge value will start with any of the scheme selected
else else
...@@ -102,13 +128,28 @@ namespace Titanium.Web.Proxy ...@@ -102,13 +128,28 @@ namespace Titanium.Web.Proxy
var serverToken = authHeader.Value.Substring(scheme.Length + 1); var serverToken = authHeader.Value.Substring(scheme.Length + 1);
var clientToken = WinAuthHandler.GetFinalAuthToken(args.WebSession.Request.Host, serverToken, args.Id); var clientToken = WinAuthHandler.GetFinalAuthToken(args.WebSession.Request.Host, serverToken, args.Id);
//there will be an existing header from initial client request
args.WebSession.Request.RequestHeaders["Authorization"] args.WebSession.Request.RequestHeaders["Authorization"]
= new HttpHeader("Authorization", string.Concat(scheme, clientToken)); = new HttpHeader("Authorization", string.Concat(scheme, clientToken));
//send body for final auth request
if (args.WebSession.Request.HasBody)
{
args.WebSession.Request.ContentLength
= args.WebSession.Request.RequestBody.Length;
}
} }
//clear current response //Need to revisit this.
//Should we cache all Set-Cokiee headers from server during auth process
//and send it to client after auth?
//clear current server response
await args.ClearResponse(); await args.ClearResponse();
//request again with updated authorization header
//and server cookies
var disposed = await HandleHttpSessionRequestInternal(args.WebSession.ServerConnection, args, false); var disposed = await HandleHttpSessionRequestInternal(args.WebSession.ServerConnection, args, false);
return disposed; return disposed;
} }
......
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