private async Task <IExternalProxy> OnGetCustomUpStreamProxyFunc(SessionEventArgsBase arg) { arg.GetState().PipelineInfo.AppendLine(nameof(OnGetCustomUpStreamProxyFunc)); TorInfo torInfo; lock (_syncObj) { torInfo = _tors[_currProxy]; _currProxy++; if (_currProxy >= _tors.Count) { _currProxy = 0; } } WriteToConsole($"using tor proxy: {torInfo.HostName}:{torInfo.Port}"); // this is just to show the functionality, provided values are junk return(new ExternalProxy { BypassLocalhost = false, ProxyType = ExternalProxyType.Socks5, HostName = torInfo.HostName, Port = torInfo.Port, UseDefaultCredentials = false }); }
private async Task HandleProxyRequest(object sender, SessionEventArgsBase eventArgs, bool isTunnel = false) { _logger.LogDebug("ESO: Processing request to " + eventArgs.WebSession.Request.Url); string failReason = null; var data = ""; var request = eventArgs.WebSession.Request; var requestUri = request.RequestUri; var host = requestUri.Host; await _statistician.Update <HTTPProxy>(CalculateObjectSize(request), DataFlowDirections.Out); CheckProxyMode(host, ref failReason); CheckBannedDomain(host, ref failReason); CheckLanProtection(host, ref failReason, ref data); SetUpstreamAddress(ref eventArgs); // Can't redirect SSL requests if (failReason != null && eventArgs is SessionEventArgs) { var castEventArgs = (SessionEventArgs)eventArgs; castEventArgs.Redirect(string.Format(_appConfig.BlockedRedirectUri, failReason, Uri.EscapeDataString(requestUri.ToString()), data)); } }
/// <summary> /// Gets the connection cache key. /// </summary> /// <param name="args">The session event arguments.</param> /// <param name="applicationProtocol"></param> /// <returns></returns> internal async Task <string> GetConnectionCacheKey(ProxyServer server, SessionEventArgsBase args, SslApplicationProtocol applicationProtocol) { List <SslApplicationProtocol> applicationProtocols = null; if (applicationProtocol != default) { applicationProtocols = new List <SslApplicationProtocol> { applicationProtocol }; } ExternalProxy customUpStreamProxy = null; bool isHttps = args.IsHttps; if (server.GetCustomUpStreamProxyFunc != null) { customUpStreamProxy = await server.GetCustomUpStreamProxyFunc(args); } args.CustomUpStreamProxyUsed = customUpStreamProxy; return(GetConnectionCacheKey( args.WebSession.Request.RequestUri.Host, args.WebSession.Request.RequestUri.Port, isHttps, applicationProtocols, server, args.WebSession.UpStreamEndPoint ?? server.UpStreamEndPoint, customUpStreamProxy ?? (isHttps ? server.UpStreamHttpsProxy : server.UpStreamHttpProxy))); }
private static SessionListItem CreateSessionListItem(SessionEventArgsBase e) { lastSessionNumber++; bool isTunnelConnect = e is TunnelConnectSessionEventArgs; var item = new SessionListItem { Number = lastSessionNumber, WebSession = e.WebSession, IsTunnelConnect = isTunnelConnect }; if (isTunnelConnect || e.WebSession.Request.UpgradeToWebSocket) { e.DataReceived += (sender, args) => { var session = (SessionEventArgs)sender; if (sessionDictionary.TryGetValue(session.WebSession, out var li)) { li.ReceivedDataCount += args.Count; } }; e.DataSent += (sender, args) => { var session = (SessionEventArgs)sender; if (sessionDictionary.TryGetValue(session.WebSession, out var li)) { li.SentDataCount += args.Count; } }; } item.Update(); return(item); }
private async Task <bool> authenticateUserBasic(SessionEventArgsBase session, ReadOnlyMemory <char> authenticationType, ReadOnlyMemory <char> credentials, Func <SessionEventArgsBase, string, string, Task <bool> > proxyBasicAuthenticateFunc) { if (!KnownHeaders.ProxyAuthorizationBasic.Equals(authenticationType.Span)) { // Return not authorized session.HttpClient.Response = createAuthentication407Response("Proxy Authentication Invalid"); return(false); } string decoded = Encoding.UTF8.GetString(Convert.FromBase64String(credentials.ToString())); int colonIndex = decoded.IndexOf(':'); if (colonIndex == -1) { // Return not authorized session.HttpClient.Response = createAuthentication407Response("Proxy Authentication Invalid"); return(false); } string username = decoded.Substring(0, colonIndex); string password = decoded.Substring(colonIndex + 1); bool authenticated = await proxyBasicAuthenticateFunc(session, username, password); if (!authenticated) { session.HttpClient.Response = createAuthentication407Response("Proxy Authentication Invalid"); } return(authenticated); }
private async Task <IExternalProxy> OnGetCustomUpStreamProxyFunc(SessionEventArgsBase arg) { arg.GetState().PipelineInfo.AppendLine(nameof(OnGetCustomUpStreamProxyFunc)); //await writeToConsole(arg.WebSession.Request.Headers); if (arg.WebSession.Request.Headers.HeaderExists("x-forwarded-host")) { var host = arg.WebSession.Request.Headers.GetHeaders("x-forwarded-host")[0].Value; var port = Int32.Parse(arg.WebSession.Request.Headers.GetHeaders("x-forwarded-port")[0].Value); return(new ExternalProxy { BypassLocalhost = false, HostName = arg.WebSession.Request.Headers.GetHeaders("x-forwarded-host")[0].Value, Port = Int32.Parse(arg.WebSession.Request.Headers.GetHeaders("x-forwarded-port")[0].Value), Password = "", UserName = "", UseDefaultCredentials = false }); } else { return(new ExternalProxy { BypassLocalhost = false, HostName = "127.0.0.1", Port = 8001, Password = "", UserName = "", UseDefaultCredentials = false }); } }
private async Task <bool> authenticateUserBasic(SessionEventArgsBase session, string[] headerValueParts) { if (!headerValueParts[0].EqualsIgnoreCase(KnownHeaders.ProxyAuthorizationBasic)) { // Return not authorized session.WebSession.Response = createAuthentication407Response("Proxy Authentication Invalid"); return(false); } string decoded = Encoding.UTF8.GetString(Convert.FromBase64String(headerValueParts[1])); int colonIndex = decoded.IndexOf(':'); if (colonIndex == -1) { // Return not authorized session.WebSession.Response = createAuthentication407Response("Proxy Authentication Invalid"); return(false); } string username = decoded.Substring(0, colonIndex); string password = decoded.Substring(colonIndex + 1); bool authenticated = await AuthenticateUserFunc(username, password); if (!authenticated) { session.WebSession.Response = createAuthentication407Response("Proxy Authentication Invalid"); } return(authenticated); }
public override async Task <ProxyAuthenticationContext> Accept(SessionEventArgsBase session, string token) { ClaimsIdentity identity; try { identity = await authenticator.Authenticate(token); } catch (Exception kvex) { Logger.Error(kvex); return(ProxyAuthenticationContext.Failed()); } if (identity == null) { return(new ProxyAuthenticationContext { Result = ProxyAuthenticationResult.ContinuationNeeded }); } session.SetUserData("request.identity", identity); return(new ProxyAuthenticationContext { Result = ProxyAuthenticationResult.Success }); }
/// <summary> /// Gets the connection cache key. /// </summary> /// <param name="server">The server.</param> /// <param name="session">The session event arguments.</param> /// <param name="applicationProtocol">The application protocol.</param> /// <returns></returns> internal async Task <string> GetConnectionCacheKey(ProxyServerBase server, SessionEventArgsBase session, SslApplicationProtocol applicationProtocol) { List <SslApplicationProtocol>?applicationProtocols = null; if (applicationProtocol != default) { applicationProtocols = new List <SslApplicationProtocol> { applicationProtocol }; } IExternalProxy?customUpStreamProxy = null; bool isHttps = session.IsHttps; if (server.GetCustomUpStreamProxyFunc != null) { customUpStreamProxy = await server.GetCustomUpStreamProxyFunc(session); } session.CustomUpStreamProxyUsed = customUpStreamProxy; var uri = session.HttpClient.Request.RequestUri; return(GetConnectionCacheKey( uri.Host, uri.Port, isHttps, applicationProtocols, session.HttpClient.UpStreamEndPoint ?? server.UpStreamEndPoint, customUpStreamProxy ?? (isHttps ? server.UpStreamHttpsProxy : server.UpStreamHttpProxy))); }
/// <summary> /// Gets the connection cache key. /// </summary> /// <param name="args">The session event arguments.</param> /// <param name="applicationProtocol"></param> /// <returns></returns> private async Task <string> getConnectionCacheKey(SessionEventArgsBase args, SslApplicationProtocol applicationProtocol) { List <SslApplicationProtocol> applicationProtocols = null; if (applicationProtocol != default) { applicationProtocols = new List <SslApplicationProtocol> { applicationProtocol }; } ExternalProxy customUpStreamProxy = null; bool isHttps = args.IsHttps; if (GetCustomUpStreamProxyFunc != null) { customUpStreamProxy = await GetCustomUpStreamProxyFunc(args); } args.CustomUpStreamProxyUsed = customUpStreamProxy; return(tcpConnectionFactory.GetConnectionCacheKey( args.WebSession.Request.RequestUri.Host, args.WebSession.Request.RequestUri.Port, isHttps, applicationProtocols, this, args.WebSession.UpStreamEndPoint ?? UpStreamEndPoint, customUpStreamProxy ?? (isHttps ? UpStreamHttpsProxy : UpStreamHttpProxy))); }
/// <summary> /// Callback to authorize clients of this proxy instance. /// </summary> /// <param name="session">The session event arguments.</param> /// <returns>True if authorized.</returns> private async Task <bool> checkAuthorization(SessionEventArgsBase session) { // If we are not authorizing clients return true if (AuthenticateUserFunc == null && AuthenticateSchemeFunc == null) { return(true); } var httpHeaders = session.WebSession.Request.Headers; try { var header = httpHeaders.GetFirstHeader(KnownHeaders.ProxyAuthorization); if (header == null) { session.WebSession.Response = createAuthentication407Response("Proxy Authentication Required"); return(false); } var headerValueParts = header.Value.Split(ProxyConstants.SpaceSplit); if (headerValueParts.Length != 2) { // Return not authorized session.WebSession.Response = createAuthentication407Response("Proxy Authentication Invalid"); return(false); } if (AuthenticateUserFunc != null) { return(await authenticateUserBasic(session, headerValueParts)); } if (AuthenticateSchemeFunc != null) { var result = await AuthenticateSchemeFunc(session, headerValueParts[0], headerValueParts[1]); if (result.Result == ProxyAuthenticationResult.ContinuationNeeded) { session.WebSession.Response = createAuthentication407Response("Proxy Authentication Invalid", result.Continuation); return(false); } return(result.Result == ProxyAuthenticationResult.Success); } return(false); } catch (Exception e) { ExceptionFunc(new ProxyAuthorizationException("Error whilst authorizing request", session, e, httpHeaders)); // Return not authorized session.WebSession.Response = createAuthentication407Response("Proxy Authentication Invalid"); return(false); } }
private async Task <IExternalProxy> onCustomUpStreamProxyFailureFunc(SessionEventArgsBase arg) { // this is just to show the functionality, provided values are junk return(new ExternalProxy() { BypassLocalhost = false, HostName = "127.0.0.10", Port = 9191, Password = "******", UserName = "******", UseDefaultCredentials = false }); }
private SessionListItem AddSession(SessionEventArgsBase e) { var item = CreateSessionListItem(e); Sessions.Add(item); sessionDictionary.Add(e.WebSession, item); return(item); }
/// <summary> /// Callback to authorize clients of this proxy instance. /// </summary> /// <param name="session">The session event arguments.</param> /// <returns>True if authorized.</returns> private async Task <bool> checkAuthorization(SessionEventArgsBase session) { // If we are not authorizing clients return true if (AuthenticateUserFunc == null) { return(true); } var httpHeaders = session.WebSession.Request.Headers; try { var header = httpHeaders.GetFirstHeader(KnownHeaders.ProxyAuthorization); if (header == null) { session.WebSession.Response = createAuthentication407Response("Proxy Authentication Required"); return(false); } var headerValueParts = header.Value.Split(ProxyConstants.SpaceSplit); if (headerValueParts.Length != 2 || !headerValueParts[0].EqualsIgnoreCase(KnownHeaders.ProxyAuthorizationBasic)) { // Return not authorized session.WebSession.Response = createAuthentication407Response("Proxy Authentication Invalid"); return(false); } string decoded = Encoding.UTF8.GetString(Convert.FromBase64String(headerValueParts[1])); int colonIndex = decoded.IndexOf(':'); if (colonIndex == -1) { // Return not authorized session.WebSession.Response = createAuthentication407Response("Proxy Authentication Invalid"); return(false); } string username = decoded.Substring(0, colonIndex); string password = decoded.Substring(colonIndex + 1); bool authenticated = await AuthenticateUserFunc(username, password); if (!authenticated) { session.WebSession.Response = createAuthentication407Response("Proxy Authentication Invalid"); } return(authenticated); } catch (Exception e) { ExceptionFunc(new ProxyAuthorizationException("Error whilst authorizing request", session, e, httpHeaders)); // Return not authorized session.WebSession.Response = createAuthentication407Response("Proxy Authentication Invalid"); return(false); } }
private async Task <IExternalProxy> onGetCustomUpStreamProxyFunc(SessionEventArgsBase arg) { arg.State.Extended().PipelineInfo.AppendLine(nameof(onGetCustomUpStreamProxyFunc)); // this is just to show the functionality, provided values are junk return(new ExternalProxy() { BypassLocalhost = false, HostName = "127.0.0.9", Port = 9090, Password = "******", UserName = "******", UseDefaultCredentials = false }); }
private Task <bool> HandleBasicAuthentication(SessionEventArgsBase session, string username, string password) { if (username == TestSettings.ProxyUsername && password == TestSettings.ProxyPassword) { ProxyAuthenticationSuccessful = true; return(Task.FromResult(true)); } return(Task.FromResult(false)); }
public static T GetUserData <T>(this SessionEventArgsBase e, string name) { var userData = GetOrCreateUserData(e); if (!userData.TryGetValue(name, out object value)) { return(default(T)); } return((T)value); }
private static IDictionary <string, object> GetOrCreateUserData(SessionEventArgsBase e) { if (!(e.UserData is IDictionary <string, object> userData)) { userData = new Dictionary <string, object>(); e.UserData = userData; } return(userData); }
private void SetUpstreamAddress(ref SessionEventArgsBase eventArgs) { var requestedUpstream = Utility.ExtractHeader(eventArgs.WebSession.Request.Headers, "X-SPECTERO-UPSTREAM-IP") .FirstOrDefault(); IPAddress requestedAddress = null; if (requestedUpstream != null) { // Found a request for a specific upstream if (IPAddress.TryParse(requestedUpstream.Value, out requestedAddress)) { _logger.LogDebug($"ES: Proxy request received with upstream request of {requestedAddress}"); // This lookup is possibly slow, TBD. if (_localAddresses.Contains(requestedAddress)) { _logger.LogDebug($"ES: Requested address is valid ({requestedAddress})"); } else { _logger.LogWarning( $"ES: Requested address is NOT valid for this system ({requestedAddress}), silently ignored. Request originated with system default IP."); } } else { _logger.LogWarning("ES: Invalid X-SPECTERO-UPSTREAM-IP header."); } } else { // Default behavior is to set the same endpoint the request came in via as the outgoing address in multi-ip deployment scenarios // This does not trigger for local (127/8, ::1, 0.0.0.0 and such addresses either) var endpoint = eventArgs.LocalEndPoint; if (Utility.CheckIPFilter(endpoint.IpAddress, Utility.IPComparisonReasons.FOR_PROXY_OUTGOING) && _appConfig.RespectEndpointToOutgoingMapping) { requestedAddress = endpoint.IpAddress; _logger.LogDebug( $"ES: No header upstream was requested, using endpoint default of {requestedAddress} as it was determined valid and RespectEndpointToOutgoingMapping is enabled."); } if (requestedAddress != null) { eventArgs.WebSession.UpStreamEndPoint = new IPEndPoint(requestedAddress, 0); } } }
/// <summary> /// Create a server connection. /// </summary> /// <param name="args">The session event arguments.</param> /// <param name="isConnect">Is this a CONNECT request.</param> /// <param name="applicationProtocol"></param> /// <param name="cancellationToken">The cancellation token for this async task.</param> /// <returns></returns> internal Task <TcpServerConnection> GetServerConnection(ProxyServer server, SessionEventArgsBase args, bool isConnect, SslApplicationProtocol applicationProtocol, bool noCache, CancellationToken cancellationToken) { List <SslApplicationProtocol> applicationProtocols = null; if (applicationProtocol != default) { applicationProtocols = new List <SslApplicationProtocol> { applicationProtocol }; } return(GetServerConnection(server, args, isConnect, applicationProtocols, noCache, cancellationToken)); }
/// <summary> /// Create a server connection. /// </summary> /// <param name="args">The session event arguments.</param> /// <param name="isConnect">Is this a CONNECT request.</param> /// <param name="applicationProtocol"></param> /// <param name="cancellationToken">The cancellation token for this async task.</param> /// <returns></returns> private Task <TcpServerConnection> GetServerConnection(SessionEventArgsBase args, bool isConnect, SslApplicationProtocol applicationProtocol, CancellationToken cancellationToken) { List <SslApplicationProtocol> applicationProtocols = null; if (applicationProtocol != default) { applicationProtocols = new List <SslApplicationProtocol> { applicationProtocol }; } return(GetServerConnection(args, isConnect, applicationProtocols, cancellationToken)); }
private async Task <IExternalProxy> OnCustomUpStreamProxyFailureFunc(SessionEventArgsBase arg) { arg.GetState().PipelineInfo.AppendLine(nameof(OnCustomUpStreamProxyFailureFunc)); // this is just to show the functionality, provided values are junk return(new ExternalProxy { BypassLocalhost = false, HostName = "127.0.0.10", Port = 9191, Password = "******", UserName = "******", UseDefaultCredentials = false }); }
public override Task <ProxyAuthenticationContext> Accept(SessionEventArgsBase session, string token) { var phCredential = CredentialHandle; var pInput = new SecBufferDesc(Convert.FromBase64String(token)); var result = AcceptSecurityContext_0( ref phCredential, IntPtr.Zero, ref pInput, Flags, SECURITY_NETWORK_DREP, out SECURITY_HANDLE phNewContext, out SecBufferDesc pOutput, out ContextFlags pfContextAttr, out SECURITY_INTEGER ptsTimeStamp ); if (result < 0) { throw new Win32Exception(result); } if (result == SEC_I_CONTINUE_NEEDED) { return(Task.FromResult(new ProxyAuthenticationContext { Result = ProxyAuthenticationResult.ContinuationNeeded, Continuation = Convert.ToBase64String(pOutput.ReadBytes()) })); } if (result == SEC_E_OK) { return(Task.FromResult(new ProxyAuthenticationContext { Result = ProxyAuthenticationResult.Success })); } return(Task.FromResult(new ProxyAuthenticationContext { Result = ProxyAuthenticationResult.Failure })); }
private async Task <bool> BasicAuthenticate(SessionEventArgsBase session, string username, string password) { if (!_auth) { return(true); } await Task.CompletedTask; if (Authenticates.TryGetValue(username, out var accountInfo)) { if (password.Equals(accountInfo.Password)) { Interlocked.Increment(ref accountInfo.ConnectTime); return(true); } } return(false); }
/// <summary> /// Call back to select client certificate used for mutual authentication /// </summary> /// <param name="sender">The sender.</param> /// <param name="sessionArgs">The http session.</param> /// <param name="targetHost">The remote hostname.</param> /// <param name="localCertificates">Selected local certificates by SslStream.</param> /// <param name="remoteCertificate">The remote certificate of server.</param> /// <param name="acceptableIssuers">The acceptable issues for client certificate as listed by server.</param> /// <returns></returns> internal X509Certificate?SelectClientCertificate(object sender, SessionEventArgsBase sessionArgs, string targetHost, X509CertificateCollection localCertificates, X509Certificate remoteCertificate, string[] acceptableIssuers) { X509Certificate?clientCertificate = null; //fallback to the first client certificate from proxy machine certificate store if (acceptableIssuers != null && acceptableIssuers.Length > 0 && localCertificates != null && localCertificates.Count > 0) { foreach (var certificate in localCertificates) { string issuer = certificate.Issuer; if (Array.IndexOf(acceptableIssuers, issuer) != -1) { clientCertificate = certificate; } } } //fallback to the first client certificate from proxy machine certificate store if (clientCertificate == null && localCertificates != null && localCertificates.Count > 0) { clientCertificate = localCertificates[0]; } // If user call back is registered if (ClientCertificateSelectionCallback != null) { var args = new CertificateSelectionEventArgs(sessionArgs, targetHost, localCertificates, remoteCertificate, acceptableIssuers) { ClientCertificate = clientCertificate }; ClientCertificateSelectionCallback.InvokeAsync(this, args, ExceptionFunc).Wait(); return(args.ClientCertificate); } return(clientCertificate); }
private async Task <bool> BasicAuthenticate(SessionEventArgsBase session, string username, string password) { await Task.CompletedTask; if (Authenticates.TryGetValue(username, out var accountInfo)) { if (password.Equals(accountInfo.Password)) { lock (accountInfo) { accountInfo.ConnectTime++; } return(true); } } Assert.Fail(); return(false); }
private static SessionListItem AddSession(SessionEventArgsBase e) { if (e.WebSession.Request.Url.StartsWith(WebServerUrl)) { return(null); } if (Sessions.Count > 500) { Sessions.Clear(); sessionDictionary.Clear(); } var item = CreateSessionListItem(e); Sessions.Add(item); if (!sessionDictionary.ContainsKey(e.WebSession)) { sessionDictionary.Add(e.WebSession, item); } return(item); }
private Task <ProxyAuthenticationContext> AuthenticateScheme( SessionEventArgsBase session, string scheme, string token ) { Log($"{scheme}: {token}"); switch (scheme.ToLowerInvariant()) { case "kerberos": case "negotiate": return(Negotiate(session, token)); case "ntlm": return(Ntlm(session, token)); } return(Task.FromResult(ProxyAuthenticationContext.Succeeded())); }
/// <summary> /// Call back to override server certificate validation /// </summary> /// <param name="sender">The sender object.</param> /// <param name="sessionArgs">The http session.</param> /// <param name="certificate">The remote certificate.</param> /// <param name="chain">The certificate chain.</param> /// <param name="sslPolicyErrors">Ssl policy errors</param> /// <returns>Return true if valid certificate.</returns> internal bool ValidateServerCertificate(object sender, SessionEventArgsBase sessionArgs, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { // if user callback is registered then do it if (ServerCertificateValidationCallback != null) { var args = new CertificateValidationEventArgs(sessionArgs, certificate, chain, sslPolicyErrors); // why is the sender null? ServerCertificateValidationCallback.InvokeAsync(this, args, ExceptionFunc).Wait(); return(args.IsValid); } if (sslPolicyErrors == SslPolicyErrors.None) { return(true); } // By default // do not allow this client to communicate with unauthenticated servers. return(true); }
//private readonly object syncNtlm = new object(); //private NtlmContext ntlmContext; private Task <ProxyAuthenticationContext> Ntlm(SessionEventArgsBase session, string token) { if (token.StartsWith("TlRMTVNTUA")) { session.SetUserData("request.ntlm", "true"); } return(Task.FromResult(ProxyAuthenticationContext.Succeeded())); //if (ntlmContext == null) //{ // lock (syncNtlm) // { // if (ntlmContext == null) // { // ntlmContext = new NtlmContext(settings.Authentication, Logger); // } // } //} //return await ntlmContext.Accept(session, token); }