/// <summary>
        ///     Handle windows NTLM/Kerberos authentication.
        ///     Note: NTLM/Kerberos cannot do a man in middle operation
        ///     we do for HTTPS requests.
        ///     As such we will be sending local credentials of current
        ///     User to server to authenticate requests.
        ///     To disable this set ProxyServer.EnableWinAuth to false.
        /// </summary>
        private async Task handle401UnAuthorized(SessionEventArgs args)
        {
            string     headerName = null;
            HttpHeader authHeader = null;

            var response = args.HttpClient.Response;

            // check in non-unique headers first
            var header = response.Headers.NonUniqueHeaders.FirstOrDefault(x => authHeaderNames.Contains(x.Key));

            if (!header.Equals(new KeyValuePair <string, List <HttpHeader> >()))
            {
                headerName = header.Key;
            }

            if (headerName != null)
            {
                authHeader = response.Headers.NonUniqueHeaders[headerName]
                             .FirstOrDefault(
                    x => authSchemes.Any(y => x.Value.StartsWith(y, StringComparison.OrdinalIgnoreCase)));
            }

            // check in unique headers
            if (authHeader == null)
            {
                headerName = null;

                // check in non-unique headers first
                var uHeader = response.Headers.Headers.FirstOrDefault(x => authHeaderNames.Contains(x.Key));

                if (!uHeader.Equals(new KeyValuePair <string, HttpHeader>()))
                {
                    headerName = uHeader.Key;
                }

                if (headerName != null)
                {
                    authHeader = authSchemes.Any(x => response.Headers.Headers[headerName].Value
                                                 .StartsWith(x, StringComparison.OrdinalIgnoreCase))
                        ? response.Headers.Headers[headerName]
                        : null;
                }
            }

            if (authHeader != null)
            {
                string scheme = authSchemes.Contains(authHeader.Value) ? authHeader.Value : null;

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

                if (!WinAuthEndPoint.ValidateWinAuthState(args.HttpClient.Data, expectedAuthState))
                {
                    // Invalid state, create proper error message to client
                    await rewriteUnauthorizedResponse(args);

                    return;
                }

                var request = args.HttpClient.Request;

                // clear any existing headers to avoid confusing bad servers
                request.Headers.RemoveHeader(KnownHeaders.Authorization);

                // initial value will match exactly any of the schemes
                if (scheme != null)
                {
                    string clientToken = WinAuthHandler.GetInitialAuthToken(request.Host, scheme, args.HttpClient.Data);

                    string auth = string.Concat(scheme, clientToken);

                    // replace existing authorization header if any
                    request.Headers.SetOrAddHeaderValue(KnownHeaders.Authorization, auth);

                    // don't need to send body for Authorization request
                    if (request.HasBody)
                    {
                        request.ContentLength = 0;
                    }
                }
                else
                {
                    // challenge value will start with any of the scheme selected

                    scheme = authSchemes.First(x =>
                                               authHeader.Value.StartsWith(x, StringComparison.OrdinalIgnoreCase) &&
                                               authHeader.Value.Length > x.Length + 1);

                    string serverToken = authHeader.Value.Substring(scheme.Length + 1);
                    string clientToken = WinAuthHandler.GetFinalAuthToken(request.Host, serverToken, args.HttpClient.Data);

                    string auth = string.Concat(scheme, clientToken);

                    // there will be an existing header from initial client request
                    request.Headers.SetOrAddHeaderValue(KnownHeaders.Authorization, auth);

                    // send body for final auth request
                    if (request.OriginalHasBody)
                    {
                        request.ContentLength = request.Body.Length;
                    }

                    args.HttpClient.Connection.IsWinAuthenticated = true;
                }

                // Need to revisit this.
                // Should we cache all Set-Cookie headers from server during auth process
                // and send it to client after auth?

                // Let ResponseHandler send the updated request
                args.ReRequest = true;
            }
        }
        public void Test_Acquire_Client_Token()
        {
            var token = WinAuthHandler.GetInitialAuthToken("mylocalserver.com", "NTLM", Guid.NewGuid());

            Assert.IsTrue(token.Length > 1);
        }
Example #3
0
        /// <summary>
        /// Handle windows NTLM authentication
        /// Can expand this for Kerberos in future
        /// Note: NTLM/Kerberos cannot do a man in middle operation
        /// we do for HTTPS requests.
        /// As such we will be sending local credentials of current
        /// User to server to authenticate requests.
        /// To disable this set ProxyServer.EnableWinAuth to false
        /// </summary>
        internal async Task <bool> Handle401UnAuthorized(SessionEventArgs args)
        {
            string     headerName = null;
            HttpHeader authHeader = null;

            //check in non-unique headers first
            var header = args.WebSession.Response
                         .NonUniqueResponseHeaders
                         .FirstOrDefault(x =>
                                         authHeaderNames.Any(y => x.Key.Equals(y, StringComparison.OrdinalIgnoreCase)));

            if (!header.Equals(new KeyValuePair <string, List <HttpHeader> >()))
            {
                headerName = header.Key;
            }

            if (headerName != null)
            {
                authHeader = args.WebSession.Response
                             .NonUniqueResponseHeaders[headerName]
                             .Where(x => authSchemes.Any(y => x.Value.StartsWith(y, StringComparison.OrdinalIgnoreCase)))
                             .FirstOrDefault();
            }

            //check in unique headers
            if (authHeader == null)
            {
                //check in non-unique headers first
                var uHeader = args.WebSession.Response
                              .ResponseHeaders
                              .FirstOrDefault(x =>
                                              authHeaderNames.Any(y => x.Key.Equals(y, StringComparison.OrdinalIgnoreCase)));

                if (!uHeader.Equals(new KeyValuePair <string, HttpHeader>()))
                {
                    headerName = uHeader.Key;
                }

                if (headerName != null)
                {
                    authHeader = authSchemes.Any(x => args.WebSession.Response
                                                 .ResponseHeaders[headerName].Value.StartsWith(x, StringComparison.OrdinalIgnoreCase)) ?
                                 args.WebSession.Response.ResponseHeaders[headerName] : null;
                }
            }

            if (authHeader != null)
            {
                var scheme = authSchemes.FirstOrDefault(x => authHeader.Value.Equals(x, StringComparison.OrdinalIgnoreCase));

                //initial value will match exactly any of the schemes
                if (scheme != null)
                {
                    var clientToken = WinAuthHandler.GetInitialAuthToken(args.WebSession.Request.Host, scheme, args.Id);
                    args.WebSession.Request.RequestHeaders.Add("Authorization", new HttpHeader("Authorization", string.Concat(scheme, clientToken)));
                }
                //challenge value will start with any of the scheme selected
                else
                {
                    scheme = authSchemes.FirstOrDefault(x => authHeader.Value.StartsWith(x, StringComparison.OrdinalIgnoreCase) &&
                                                        authHeader.Value.Length > x.Length + 1);

                    var serverToken = authHeader.Value.Substring(scheme.Length + 1);
                    var clientToken = WinAuthHandler.GetFinalAuthToken(args.WebSession.Request.Host, serverToken, args.Id);


                    args.WebSession.Request.RequestHeaders["Authorization"]
                        = new HttpHeader("Authorization", string.Concat(scheme, clientToken));
                }

                //clear current response
                await args.ClearResponse();

                var disposed = await HandleHttpSessionRequestInternal(args.WebSession.ServerConnection, args, false);

                return(disposed);
            }

            return(false);
        }
        /// <summary>
        /// Handle windows NTLM authentication
        /// Can expand this for Kerberos in future
        /// Note: NTLM/Kerberos cannot do a man in middle operation
        /// we do for HTTPS requests.
        /// As such we will be sending local credentials of current
        /// User to server to authenticate requests.
        /// To disable this set ProxyServer.EnableWinAuth to false
        /// </summary>
        internal async Task <bool> Handle401UnAuthorized(SessionEventArgs args)
        {
            string     headerName = null;
            HttpHeader authHeader = null;

            //check in non-unique headers first
            var header =
                args.WebSession.Response.ResponseHeaders.NonUniqueHeaders.FirstOrDefault(
                    x => authHeaderNames.Any(y => x.Key.Equals(y, StringComparison.OrdinalIgnoreCase)));

            if (!header.Equals(new KeyValuePair <string, List <HttpHeader> >()))
            {
                headerName = header.Key;
            }

            if (headerName != null)
            {
                authHeader = args.WebSession.Response.ResponseHeaders.NonUniqueHeaders[headerName]
                             .FirstOrDefault(x => authSchemes.Any(y => x.Value.StartsWith(y, StringComparison.OrdinalIgnoreCase)));
            }

            //check in unique headers
            if (authHeader == null)
            {
                //check in non-unique headers first
                var uHeader =
                    args.WebSession.Response.ResponseHeaders.Headers.FirstOrDefault(x => authHeaderNames.Any(y => x.Key.Equals(y, StringComparison.OrdinalIgnoreCase)));

                if (!uHeader.Equals(new KeyValuePair <string, HttpHeader>()))
                {
                    headerName = uHeader.Key;
                }

                if (headerName != null)
                {
                    authHeader = authSchemes.Any(x => args.WebSession.Response.ResponseHeaders.Headers[headerName].Value
                                                 .StartsWith(x, StringComparison.OrdinalIgnoreCase))
                        ? args.WebSession.Response.ResponseHeaders.Headers[headerName]
                        : null;
                }
            }

            if (authHeader != null)
            {
                string scheme = authSchemes.FirstOrDefault(x => authHeader.Value.Equals(x, StringComparison.OrdinalIgnoreCase));

                //clear any existing headers to avoid confusing bad servers
                if (args.WebSession.Request.RequestHeaders.NonUniqueHeaders.ContainsKey("Authorization"))
                {
                    args.WebSession.Request.RequestHeaders.NonUniqueHeaders.Remove("Authorization");
                }

                //initial value will match exactly any of the schemes
                if (scheme != null)
                {
                    string clientToken = WinAuthHandler.GetInitialAuthToken(args.WebSession.Request.Host, scheme, args.Id);

                    var auth = new HttpHeader("Authorization", string.Concat(scheme, clientToken));

                    //replace existing authorization header if any
                    if (args.WebSession.Request.RequestHeaders.Headers.ContainsKey("Authorization"))
                    {
                        args.WebSession.Request.RequestHeaders.Headers["Authorization"] = auth;
                    }
                    else
                    {
                        args.WebSession.Request.RequestHeaders.Headers.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
                else
                {
                    scheme = authSchemes.FirstOrDefault(x => authHeader.Value.StartsWith(x, StringComparison.OrdinalIgnoreCase) &&
                                                        authHeader.Value.Length > x.Length + 1);

                    string serverToken = authHeader.Value.Substring(scheme.Length + 1);
                    string clientToken = WinAuthHandler.GetFinalAuthToken(args.WebSession.Request.Host, serverToken, args.Id);

                    //there will be an existing header from initial client request
                    args.WebSession.Request.RequestHeaders.Headers["Authorization"] = 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;
                    }
                }

                //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();

                //request again with updated authorization header
                //and server cookies
                bool disposed = await HandleHttpSessionRequestInternal(args.WebSession.ServerConnection, args, false);

                return(disposed);
            }

            return(false);
        }
Example #5
0
        public void Test_Acquire_Client_Token()
        {
            string token = WinAuthHandler.GetInitialAuthToken("mylocalserver.com", "NTLM", new InternalDataStore());

            Assert.IsTrue(token.Length > 1);
        }