internal void DetachBlob(RequestContextBase memoryBlob)
 {
     if ((memoryBlob != null) && (memoryBlob == this.m_MemoryBlob))
     {
         this.m_MemoryBlob = null;
     }
 }
 // Use this to save the blob from dispose if this object was never used (never given to a user) and is about to be
 // disposed.
 internal void DetachBlob(RequestContextBase memoryBlob)
 {
     if (memoryBlob != null && (object)memoryBlob == (object)_memoryBlob !)
     {
         _memoryBlob = null;
     }
 }
Пример #3
0
        internal HttpListenerRequest(HttpListenerContext httpContext, RequestContextBase memoryBlob)
        {
            if (NetEventSource.IsEnabled)
            {
                NetEventSource.Info(this, $"httpContext:${httpContext} memoryBlob {((IntPtr)memoryBlob.RequestBlob)}");
                NetEventSource.Associate(this, httpContext);
            }
            _httpContext  = httpContext;
            _memoryBlob   = memoryBlob;
            _boundaryType = BoundaryType.None;

            // Set up some of these now to avoid refcounting on memory blob later.
            _requestId    = memoryBlob.RequestBlob->RequestId;
            _connectionId = memoryBlob.RequestBlob->ConnectionId;
            _sslStatus    = memoryBlob.RequestBlob->pSslInfo == null ? SslStatus.Insecure :
                            memoryBlob.RequestBlob->pSslInfo->SslClientCertNegotiated == 0 ? SslStatus.NoClientCert :
                            SslStatus.ClientCert;
            if (memoryBlob.RequestBlob->pRawUrl != null && memoryBlob.RequestBlob->RawUrlLength > 0)
            {
                _rawUrl = Marshal.PtrToStringAnsi((IntPtr)memoryBlob.RequestBlob->pRawUrl, memoryBlob.RequestBlob->RawUrlLength);
            }

            Interop.HttpApi.HTTP_COOKED_URL cookedUrl = memoryBlob.RequestBlob->CookedUrl;
            if (cookedUrl.pHost != null && cookedUrl.HostLength > 0)
            {
                _cookedUrlHost = Marshal.PtrToStringUni((IntPtr)cookedUrl.pHost, cookedUrl.HostLength / 2);
            }
            if (cookedUrl.pAbsPath != null && cookedUrl.AbsPathLength > 0)
            {
                _cookedUrlPath = Marshal.PtrToStringUni((IntPtr)cookedUrl.pAbsPath, cookedUrl.AbsPathLength / 2);
            }
            if (cookedUrl.pQueryString != null && cookedUrl.QueryStringLength > 0)
            {
                _cookedUrlQuery = Marshal.PtrToStringUni((IntPtr)cookedUrl.pQueryString, cookedUrl.QueryStringLength / 2);
            }
            _version         = new Version(memoryBlob.RequestBlob->Version.MajorVersion, memoryBlob.RequestBlob->Version.MinorVersion);
            _clientCertState = ListenerClientCertState.NotInitialized;
            _keepAlive       = null;
            if (NetEventSource.IsEnabled)
            {
                NetEventSource.Info(this, $"RequestId:{RequestId} ConnectionId:{_connectionId} RawConnectionId:{memoryBlob.RequestBlob->RawConnectionId} UrlContext:{memoryBlob.RequestBlob->UrlContext} RawUrl:{_rawUrl} Version:{_version} Secure:{_sslStatus}");
                NetEventSource.Info(this, $"httpContext:${httpContext} RequestUri:{RequestUri} Content-Length:{ContentLength64} HTTP Method:{HttpMethod}");
            }
            // Log headers
            if (NetEventSource.IsEnabled)
            {
                StringBuilder sb = new StringBuilder("HttpListenerRequest Headers:\n");
                for (int i = 0; i < Headers.Count; i++)
                {
                    sb.Append("\t");
                    sb.Append(Headers.GetKey(i));
                    sb.Append(" : ");
                    sb.Append(Headers.Get(i));
                    sb.Append("\n");
                }
                NetEventSource.Info(this, sb.ToString());
            }
        }
Пример #4
0
        internal HttpListenerRequest(HttpListenerContext httpContext, RequestContextBase memoryBlob)
        {
            if (NetEventSource.IsEnabled)
            {
                NetEventSource.Info(this, $"httpContext:${httpContext} memoryBlob {((IntPtr)memoryBlob.RequestBlob)}");
                NetEventSource.Associate(this, httpContext);
            }
            _httpContext = httpContext;
            _memoryBlob = memoryBlob;
            _boundaryType = BoundaryType.None;

            // Set up some of these now to avoid refcounting on memory blob later.
            _requestId = memoryBlob.RequestBlob->RequestId;
            _connectionId = memoryBlob.RequestBlob->ConnectionId;
            _sslStatus = memoryBlob.RequestBlob->pSslInfo == null ? SslStatus.Insecure :
                memoryBlob.RequestBlob->pSslInfo->SslClientCertNegotiated == 0 ? SslStatus.NoClientCert :
                SslStatus.ClientCert;
            if (memoryBlob.RequestBlob->pRawUrl != null && memoryBlob.RequestBlob->RawUrlLength > 0)
            {
                _rawUrl = Marshal.PtrToStringAnsi((IntPtr)memoryBlob.RequestBlob->pRawUrl, memoryBlob.RequestBlob->RawUrlLength);
            }

            Interop.HttpApi.HTTP_COOKED_URL cookedUrl = memoryBlob.RequestBlob->CookedUrl;
            if (cookedUrl.pHost != null && cookedUrl.HostLength > 0)
            {
                _cookedUrlHost = Marshal.PtrToStringUni((IntPtr)cookedUrl.pHost, cookedUrl.HostLength / 2);
            }
            if (cookedUrl.pAbsPath != null && cookedUrl.AbsPathLength > 0)
            {
                _cookedUrlPath = Marshal.PtrToStringUni((IntPtr)cookedUrl.pAbsPath, cookedUrl.AbsPathLength / 2);
            }
            if (cookedUrl.pQueryString != null && cookedUrl.QueryStringLength > 0)
            {
                _cookedUrlQuery = Marshal.PtrToStringUni((IntPtr)cookedUrl.pQueryString, cookedUrl.QueryStringLength / 2);
            }
            _version = new Version(memoryBlob.RequestBlob->Version.MajorVersion, memoryBlob.RequestBlob->Version.MinorVersion);
            _clientCertState = ListenerClientCertState.NotInitialized;
            _keepAlive = null;
            if (NetEventSource.IsEnabled)
            {
                NetEventSource.Info(this, $"RequestId:{RequestId} ConnectionId:{_connectionId} RawConnectionId:{memoryBlob.RequestBlob->RawConnectionId} UrlContext:{memoryBlob.RequestBlob->UrlContext} RawUrl:{_rawUrl} Version:{_version} Secure:{_sslStatus}");
                NetEventSource.Info(this, $"httpContext:${httpContext} RequestUri:{RequestUri} Content-Length:{ContentLength64} HTTP Method:{HttpMethod}");
            }
            // Log headers
            if (NetEventSource.IsEnabled)
            {
                StringBuilder sb = new StringBuilder("HttpListenerRequest Headers:\n");
                for (int i = 0; i < Headers.Count; i++)
                {
                    sb.Append("\t");
                    sb.Append(Headers.GetKey(i));
                    sb.Append(" : ");
                    sb.Append(Headers.Get(i));
                    sb.Append("\n");
                }
                NetEventSource.Info(this, sb.ToString());
            }
        }
 internal HttpListenerContext(HttpListener httpListener, RequestContextBase memoryBlob)
 {
     if (Logging.On) Logging.PrintInfo(Logging.HttpListener, this, ".ctor", "httpListener#" + ValidationHelper.HashString(httpListener) + " requestBlob=" + ValidationHelper.HashString((IntPtr) memoryBlob.RequestBlob));
     m_Listener = httpListener;
     m_Request = new HttpListenerRequest(this, memoryBlob);
     m_AuthenticationSchemes = httpListener.AuthenticationSchemes;
     m_ExtendedProtectionPolicy = httpListener.ExtendedProtectionPolicy;
     GlobalLog.Print("HttpListenerContext#" + ValidationHelper.HashString(this) + "::.ctor() HttpListener#" + ValidationHelper.HashString(m_Listener) + " HttpListenerRequest#" + ValidationHelper.HashString(m_Request));
 }
 internal unsafe HttpListenerContext(HttpListener httpListener, RequestContextBase memoryBlob)
 {
     if (Logging.On)
     {
         Logging.PrintInfo(Logging.HttpListener, this, ".ctor", "httpListener#" + ValidationHelper.HashString(httpListener) + " requestBlob=" + ValidationHelper.HashString((IntPtr) memoryBlob.RequestBlob));
     }
     this.m_Listener = httpListener;
     this.m_Request = new HttpListenerRequest(this, memoryBlob);
 }
Пример #7
0
 internal HttpListenerContext(HttpListener httpListener, RequestContextBase memoryBlob)
 {
     if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"httpListener {httpListener} requestBlob={((IntPtr)memoryBlob.RequestBlob)}");
     _listener = httpListener;
     Request = new HttpListenerRequest(this, memoryBlob);
     AuthenticationSchemes = httpListener.AuthenticationSchemes;
     ExtendedProtectionPolicy = httpListener.ExtendedProtectionPolicy;
     if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"HttpListener: {_listener} HttpListenerRequest: {Request}");
 }
Пример #8
0
 internal unsafe HttpListenerContext(HttpListener httpListener, RequestContextBase memoryBlob)
 {
     if (Logging.On)
     {
         Logging.PrintInfo(Logging.HttpListener, this, ".ctor", "httpListener#" + ValidationHelper.HashString(httpListener) + " requestBlob=" + ValidationHelper.HashString((IntPtr)memoryBlob.RequestBlob));
     }
     this.m_Listener = httpListener;
     this.m_Request  = new HttpListenerRequest(this, memoryBlob);
 }
 internal unsafe HttpListenerRequest(System.Net.HttpListenerContext httpContext, RequestContextBase memoryBlob)
 {
     if (Logging.On)
     {
         Logging.PrintInfo(Logging.HttpListener, this, ".ctor", "httpContext#" + ValidationHelper.HashString(httpContext) + " memoryBlob# " + ValidationHelper.HashString((IntPtr)memoryBlob.RequestBlob));
     }
     if (Logging.On)
     {
         Logging.Associate(Logging.HttpListener, this, httpContext);
     }
     this.m_HttpContext  = httpContext;
     this.m_MemoryBlob   = memoryBlob;
     this.m_BoundaryType = BoundaryType.None;
     this.m_RequestId    = memoryBlob.RequestBlob.RequestId;
     this.m_ConnectionId = memoryBlob.RequestBlob.ConnectionId;
     this.m_SslStatus    = (memoryBlob.RequestBlob.pSslInfo == null) ? SslStatus.Insecure : ((memoryBlob.RequestBlob.pSslInfo.SslClientCertNegotiated == 0) ? SslStatus.NoClientCert : SslStatus.ClientCert);
     if ((memoryBlob.RequestBlob.pRawUrl != null) && (memoryBlob.RequestBlob.RawUrlLength > 0))
     {
         this.m_RawUrl = Marshal.PtrToStringAnsi((IntPtr)memoryBlob.RequestBlob.pRawUrl, memoryBlob.RequestBlob.RawUrlLength);
     }
     UnsafeNclNativeMethods.HttpApi.HTTP_COOKED_URL cookedUrl = memoryBlob.RequestBlob.CookedUrl;
     if ((cookedUrl.pHost != null) && (cookedUrl.HostLength > 0))
     {
         this.m_CookedUrlHost = Marshal.PtrToStringUni((IntPtr)cookedUrl.pHost, cookedUrl.HostLength / 2);
     }
     if ((cookedUrl.pAbsPath != null) && (cookedUrl.AbsPathLength > 0))
     {
         this.m_CookedUrlPath = Marshal.PtrToStringUni((IntPtr)cookedUrl.pAbsPath, cookedUrl.AbsPathLength / 2);
     }
     if ((cookedUrl.pQueryString != null) && (cookedUrl.QueryStringLength > 0))
     {
         this.m_CookedUrlQuery = Marshal.PtrToStringUni((IntPtr)cookedUrl.pQueryString, cookedUrl.QueryStringLength / 2);
     }
     this.m_Version         = new Version(memoryBlob.RequestBlob.Version.MajorVersion, memoryBlob.RequestBlob.Version.MinorVersion);
     this.m_ClientCertState = ListenerClientCertState.NotInitialized;
     this.m_KeepAlive       = TriState.Unspecified;
     if (Logging.On)
     {
         Logging.PrintInfo(Logging.HttpListener, this, ".ctor", "httpContext#" + ValidationHelper.HashString(httpContext) + " RequestUri:" + ValidationHelper.ToString(this.RequestUri) + " Content-Length:" + ValidationHelper.ToString(this.ContentLength64) + " HTTP Method:" + ValidationHelper.ToString(this.HttpMethod));
     }
     if (Logging.On)
     {
         StringBuilder builder = new StringBuilder("HttpListenerRequest Headers:\n");
         for (int i = 0; i < this.Headers.Count; i++)
         {
             builder.Append("\t");
             builder.Append(this.Headers.GetKey(i));
             builder.Append(" : ");
             builder.Append(this.Headers.Get(i));
             builder.Append("\n");
         }
         Logging.PrintInfo(Logging.HttpListener, this, ".ctor", builder.ToString());
     }
 }
 internal unsafe HttpListenerRequest(System.Net.HttpListenerContext httpContext, RequestContextBase memoryBlob)
 {
     if (Logging.On)
     {
         Logging.PrintInfo(Logging.HttpListener, this, ".ctor", "httpContext#" + ValidationHelper.HashString(httpContext) + " memoryBlob# " + ValidationHelper.HashString((IntPtr) memoryBlob.RequestBlob));
     }
     if (Logging.On)
     {
         Logging.Associate(Logging.HttpListener, this, httpContext);
     }
     this.m_HttpContext = httpContext;
     this.m_MemoryBlob = memoryBlob;
     this.m_BoundaryType = BoundaryType.None;
     this.m_RequestId = memoryBlob.RequestBlob.RequestId;
     this.m_ConnectionId = memoryBlob.RequestBlob.ConnectionId;
     this.m_SslStatus = (memoryBlob.RequestBlob.pSslInfo == null) ? SslStatus.Insecure : ((memoryBlob.RequestBlob.pSslInfo.SslClientCertNegotiated == 0) ? SslStatus.NoClientCert : SslStatus.ClientCert);
     if ((memoryBlob.RequestBlob.pRawUrl != null) && (memoryBlob.RequestBlob.RawUrlLength > 0))
     {
         this.m_RawUrl = Marshal.PtrToStringAnsi((IntPtr) memoryBlob.RequestBlob.pRawUrl, memoryBlob.RequestBlob.RawUrlLength);
     }
     UnsafeNclNativeMethods.HttpApi.HTTP_COOKED_URL cookedUrl = memoryBlob.RequestBlob.CookedUrl;
     if ((cookedUrl.pHost != null) && (cookedUrl.HostLength > 0))
     {
         this.m_CookedUrlHost = Marshal.PtrToStringUni((IntPtr) cookedUrl.pHost, cookedUrl.HostLength / 2);
     }
     if ((cookedUrl.pAbsPath != null) && (cookedUrl.AbsPathLength > 0))
     {
         this.m_CookedUrlPath = Marshal.PtrToStringUni((IntPtr) cookedUrl.pAbsPath, cookedUrl.AbsPathLength / 2);
     }
     if ((cookedUrl.pQueryString != null) && (cookedUrl.QueryStringLength > 0))
     {
         this.m_CookedUrlQuery = Marshal.PtrToStringUni((IntPtr) cookedUrl.pQueryString, cookedUrl.QueryStringLength / 2);
     }
     this.m_Version = new Version(memoryBlob.RequestBlob.Version.MajorVersion, memoryBlob.RequestBlob.Version.MinorVersion);
     this.m_ClientCertState = ListenerClientCertState.NotInitialized;
     this.m_KeepAlive = TriState.Unspecified;
     if (Logging.On)
     {
         Logging.PrintInfo(Logging.HttpListener, this, ".ctor", "httpContext#" + ValidationHelper.HashString(httpContext) + " RequestUri:" + ValidationHelper.ToString(this.RequestUri) + " Content-Length:" + ValidationHelper.ToString(this.ContentLength64) + " HTTP Method:" + ValidationHelper.ToString(this.HttpMethod));
     }
     if (Logging.On)
     {
         StringBuilder builder = new StringBuilder("HttpListenerRequest Headers:\n");
         for (int i = 0; i < this.Headers.Count; i++)
         {
             builder.Append("\t");
             builder.Append(this.Headers.GetKey(i));
             builder.Append(" : ");
             builder.Append(this.Headers.Get(i));
             builder.Append("\n");
         }
         Logging.PrintInfo(Logging.HttpListener, this, ".ctor", builder.ToString());
     }
 }
Пример #11
0
 internal HttpListenerContext(HttpListener httpListener, RequestContextBase memoryBlob)
 {
     if (Logging.On)
     {
         Logging.PrintInfo(Logging.HttpListener, this, ".ctor", "httpListener#" + ValidationHelper.HashString(httpListener) + " requestBlob=" + ValidationHelper.HashString((IntPtr)memoryBlob.RequestBlob));
     }
     m_Listener = httpListener;
     m_Request  = new HttpListenerRequest(this, memoryBlob);
     m_AuthenticationSchemes    = httpListener.AuthenticationSchemes;
     m_ExtendedProtectionPolicy = httpListener.ExtendedProtectionPolicy;
     GlobalLog.Print("HttpListenerContext#" + ValidationHelper.HashString(this) + "::.ctor() HttpListener#" + ValidationHelper.HashString(m_Listener) + " HttpListenerRequest#" + ValidationHelper.HashString(m_Request));
 }
Пример #12
0
 internal HttpListenerContext(HttpListener httpListener, RequestContextBase memoryBlob)
 {
     if (NetEventSource.IsEnabled)
     {
         NetEventSource.Info(this, $"httpListener {httpListener} requestBlob={((IntPtr)memoryBlob.RequestBlob)}");
     }
     _listener                = httpListener;
     Request                  = new HttpListenerRequest(this, memoryBlob);
     AuthenticationSchemes    = httpListener.AuthenticationSchemes;
     ExtendedProtectionPolicy = httpListener.ExtendedProtectionPolicy;
     if (NetEventSource.IsEnabled)
     {
         NetEventSource.Info(this, $"HttpListener: {_listener} HttpListenerRequest: {Request}");
     }
 }
        internal void Close()
        {
            if (Logging.On)
            {
                Logging.Enter(Logging.HttpListener, this, "Close", "");
            }
            RequestContextBase memoryBlob = this.m_MemoryBlob;

            if (memoryBlob != null)
            {
                memoryBlob.Close();
                this.m_MemoryBlob = null;
            }
            this.m_IsDisposed = true;
            if (Logging.On)
            {
                Logging.Exit(Logging.HttpListener, this, "Close", "");
            }
        }
Пример #14
0
        //should only be called from httplistenercontext
        internal void Close()
        {
            if (NetEventSource.IsEnabled)
            {
                NetEventSource.Enter(this);
            }
            RequestContextBase memoryBlob = _memoryBlob;

            if (memoryBlob != null)
            {
                memoryBlob.Close();
                _memoryBlob = null;
            }
            _isDisposed = true;
            if (NetEventSource.IsEnabled)
            {
                NetEventSource.Exit(this);
            }
        }
 internal void DetachBlob(RequestContextBase memoryBlob)
 {
     if ((memoryBlob != null) && (memoryBlob == this.m_MemoryBlob))
     {
         this.m_MemoryBlob = null;
     }
 }
Пример #16
0
        internal HttpListenerContext HandleAuthentication(RequestContextBase memoryBlob, out bool stoleBlob)
        {
            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() memoryBlob:0x" + ((IntPtr) memoryBlob.RequestBlob).ToString("x"));

            string challenge = null;
            stoleBlob = false;

            // Some things we need right away.  Lift them out now while it's convenient.
            string verb = UnsafeNclNativeMethods.HttpApi.GetVerb(memoryBlob.RequestBlob);
            string authorizationHeader = UnsafeNclNativeMethods.HttpApi.GetKnownHeader(memoryBlob.RequestBlob, (int) HttpRequestHeader.Authorization);
            ulong connectionId = memoryBlob.RequestBlob->ConnectionId;
            ulong requestId = memoryBlob.RequestBlob->RequestId;
            bool isSecureConnection = memoryBlob.RequestBlob->pSslInfo != null;

            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() authorizationHeader:" + ValidationHelper.ToString(authorizationHeader));

            // if the app has turned on AuthPersistence, an anonymous request might
            // be authenticated by virtue of it coming on a connection that was
            // previously authenticated.
            // assurance that we do this only for NTLM/Negotiate is not here, but in the
            // code that caches WindowsIdentity instances in the Dictionary.
            DisconnectAsyncResult disconnectResult = (DisconnectAsyncResult) DisconnectResults[connectionId];
            if (UnsafeConnectionNtlmAuthentication)
            {
                if (authorizationHeader == null)
                {
                    WindowsPrincipal principal = disconnectResult == null ? null : disconnectResult.AuthenticatedConnection;
                    if (principal != null)
                    {
                        GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() got principal:" + ValidationHelper.ToString(principal) + " principal.Identity.Name:" + ValidationHelper.ToString(principal.Identity.Name) + " creating request");
                        stoleBlob = true;
                        HttpListenerContext ntlmContext = new HttpListenerContext(this, memoryBlob);
                        ntlmContext.SetIdentity(principal, null);
                        ntlmContext.Request.ReleasePins();
                        return ntlmContext;
                    }
                }
                else
                {
                    // They sent an authorization - destroy their previous credentials.
                    GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() clearing principal cache");
                    if (disconnectResult != null)
                    {
                        disconnectResult.AuthenticatedConnection = null;
                    }
                }
            }

            // Figure out what schemes we're allowing, what context we have.
            stoleBlob = true;
            HttpListenerContext httpContext = null;
            NTAuthentication oldContext = null;
            NTAuthentication newContext = null;
            NTAuthentication context = null;
            AuthenticationSchemes headerScheme = AuthenticationSchemes.None;
            AuthenticationSchemes authenticationScheme = AuthenticationSchemes;
            ExtendedProtectionPolicy extendedProtectionPolicy = m_ExtendedProtectionPolicy;
            try
            {
                // Take over handling disconnects for now.
                if (disconnectResult != null && !disconnectResult.StartOwningDisconnectHandling())
                {
                    // Oops!  Just disconnected just then.  Pretend we didn't see the disconnectResult.
                    disconnectResult = null;
                }

                // Pick out the old context now.  By default, it'll be removed in the finally, unless context is set somewhere. 
                if (disconnectResult != null)
                {
                    oldContext = disconnectResult.Session;
                }

                httpContext = new HttpListenerContext(this, memoryBlob);

                AuthenticationSelectorInfo authenticationSelector = m_AuthenticationDelegate;
                if (authenticationSelector != null)
                {
                    try
                    {
                        httpContext.Request.ReleasePins();
                        authenticationScheme = authenticationSelector.Delegate(httpContext.Request);
                        // Cache the results of authenticationSelector (if any)
                        httpContext.AuthenticationSchemes = authenticationScheme;
                        if (!authenticationSelector.AdvancedAuth &&
                            (authenticationScheme & (AuthenticationSchemes.Negotiate | AuthenticationSchemes.Ntlm | AuthenticationSchemes.Digest)) != 0)
                        {
                            throw m_SecurityException;
                        }
                        GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() AuthenticationSchemeSelectorDelegate() returned authenticationScheme:" + authenticationScheme);
                    }
                    catch (Exception exception)
                    {
                        if (NclUtilities.IsFatal(exception)) throw;

                        if (Logging.On) Logging.PrintError(Logging.HttpListener, this, "HandleAuthentication", SR.GetString(SR.net_log_listener_delegate_exception, exception));
                        GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() AuthenticationSchemeSelectorDelegate() returned authenticationScheme:" + authenticationScheme);
                        SendError(requestId, HttpStatusCode.InternalServerError, null);
                        httpContext.Close();
                        return null;
                    }
                }
                else
                {
                    // We didn't give the request to the user yet, so we haven't lost control of the unmanaged blob and can
                    // continue to reuse the buffer.
                    stoleBlob = false;
                }

                ExtendedProtectionSelector extendedProtectionSelector = m_ExtendedProtectionSelectorDelegate;
                if (extendedProtectionSelector != null) 
                {
                    extendedProtectionPolicy = extendedProtectionSelector(httpContext.Request);

                    if (extendedProtectionPolicy == null) 
                    {
                        extendedProtectionPolicy = new ExtendedProtectionPolicy(PolicyEnforcement.Never);
                    }
                    // Cache the results of extendedProtectionSelector (if any)
                    httpContext.ExtendedProtectionPolicy = extendedProtectionPolicy;
                }

                // Then figure out what scheme they're trying (if any are allowed)
                int index = -1;
                if (authorizationHeader != null && (authenticationScheme & ~AuthenticationSchemes.Anonymous) != AuthenticationSchemes.None)
                {
                    // Find the end of the scheme name.  Trust that HTTP.SYS parsed out just our header ok.
                    for (index = 0; index < authorizationHeader.Length; index++)
                    {
                        if (authorizationHeader[index] == ' ' || authorizationHeader[index] == '\t' ||
                            authorizationHeader[index] == '\r' || authorizationHeader[index] == '\n')
                        {
                            break;
                        }
                    }

                    // Currently only allow one Authorization scheme/header per request.
                    if (index < authorizationHeader.Length)
                    {
                        if ((authenticationScheme & AuthenticationSchemes.Negotiate) != AuthenticationSchemes.None &&
                            string.Compare(authorizationHeader, 0, NegotiateClient.AuthType, 0, index, StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            headerScheme = AuthenticationSchemes.Negotiate;
                        }
                        else if ((authenticationScheme & AuthenticationSchemes.Ntlm) != AuthenticationSchemes.None &&
                            string.Compare(authorizationHeader, 0, NtlmClient.AuthType, 0, index, StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            headerScheme = AuthenticationSchemes.Ntlm;
                        }
                        else if ((authenticationScheme & AuthenticationSchemes.Digest) != AuthenticationSchemes.None &&
                            string.Compare(authorizationHeader, 0, DigestClient.AuthType, 0, index, StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            headerScheme = AuthenticationSchemes.Digest;
                        }
                        else if ((authenticationScheme & AuthenticationSchemes.Basic) != AuthenticationSchemes.None &&
                            string.Compare(authorizationHeader, 0, BasicClient.AuthType, 0, index, StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            headerScheme = AuthenticationSchemes.Basic;
                        }
                        else
                        {
                            if (Logging.On) Logging.PrintWarning(Logging.HttpListener, this, "HandleAuthentication", SR.GetString(SR.net_log_listener_unsupported_authentication_scheme, authorizationHeader , authenticationScheme));
                        }
                    }
                }

                // httpError holds the error we will return if an Authorization header is present but can't be authenticated
                HttpStatusCode httpError = HttpStatusCode.InternalServerError;
                bool error = false;

                // See if we found an acceptable auth header
                if (headerScheme == AuthenticationSchemes.None)
                {
                    if (Logging.On) Logging.PrintWarning(Logging.HttpListener, this, "HandleAuthentication", SR.GetString(SR.net_log_listener_unmatched_authentication_scheme, ValidationHelper.ToString(authenticationScheme), (authorizationHeader == null ? "<null>" : authorizationHeader)));

                    // If anonymous is allowed, just return the context.  Otherwise go for the 401.
                    if ((authenticationScheme & AuthenticationSchemes.Anonymous) != AuthenticationSchemes.None)
                    {
                        if (!stoleBlob)
                        {
                            stoleBlob = true;
                            httpContext.Request.ReleasePins();
                        }
                        return httpContext;
                    }

                    httpError = HttpStatusCode.Unauthorized;
                    httpContext.Request.DetachBlob(memoryBlob);
                    httpContext.Close();
                    httpContext = null;
                }
                else
                {
                    // Perform Authentication
                    byte[] bytes = null;
                    byte[] decodedOutgoingBlob = null;
                    string outBlob = null;

                    // Find the beginning of the blob.  Trust that HTTP.SYS parsed out just our header ok.
                    for (index++; index < authorizationHeader.Length; index++)
                    {
                        if (authorizationHeader[index] != ' ' && authorizationHeader[index] != '\t' &&
                            authorizationHeader[index] != '\r' && authorizationHeader[index] != '\n')
                        {
                            break;
                        }
                    }
                    string inBlob = index < authorizationHeader.Length ? authorizationHeader.Substring(index) : "";

                    IPrincipal principal = null;
                    SecurityStatus statusCodeNew;
                    ChannelBinding binding;
                    GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() Performing Authentication headerScheme:" + ValidationHelper.ToString(headerScheme));
                    switch (headerScheme)
                    {
                        case AuthenticationSchemes.Digest:
                            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() package:WDigest headerScheme:" + headerScheme);

                            // WDigest had some weird behavior.  This is what I have discovered:
                            // Local accounts don't work, only domain accounts.  The domain (i.e. REDMOND) is implied.  Not sure how it is chosen.
                            // If the domain is specified and the credentials are correct, it works.  If they're not (domain, username or password):
                            //      AcceptSecurityContext (GetOutgoingDigestBlob) returns success but with a bogus 4k challenge, and
                            //      QuerySecurityContextToken (GetContextToken) fails with NoImpersonation.
                            // If the domain isn't specified, AcceptSecurityContext returns NoAuthenticatingAuthority for a bad username,
                            // and LogonDenied for a bad password.

                            // Also interesting is that WDigest requires us to keep a reference to the previous context, but fails if we
                            // actually pass it in!  (It't ok to pass it in for the first request, but not if nc > 1.)  For Whidbey,
                            // we create a new context and associate it with the connection, just like NTLM, but instead of using it for
                            // the next request on the connection, we always create a new context and swap the old one out.  As long
                            // as we keep the old one around until after we authenticate with the new one, it works.  For this reason,
                            // we also keep these contexts around past the lifetime of the connection, so that KeepAlive=false works.
                            binding = GetChannelBinding(connectionId, isSecureConnection, extendedProtectionPolicy);

                            context = new NTAuthentication(true, NegotiationInfoClass.WDigest, null,
                                GetContextFlags(extendedProtectionPolicy, isSecureConnection), binding);

                            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() verb:" + verb + " context.IsValidContext:" + context.IsValidContext.ToString());

                            outBlob = context.GetOutgoingDigestBlob(inBlob, verb, null, Realm, false, false, out statusCodeNew);
                            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() GetOutgoingDigestBlob() returned IsCompleted:" + context.IsCompleted + " statusCodeNew:" + statusCodeNew + " outBlob:[" + outBlob + "]");

                            // WDigest bug: sometimes when AcceptSecurityContext returns success, it provides a bogus, empty 4k buffer.
                            // Ignore it.  (Should find out what's going on here from WDigest people.)
                            if (statusCodeNew == SecurityStatus.OK)
                            {
                                outBlob = null;
                            }

                            if (context.IsValidContext)
                            {
                                SafeCloseHandle userContext = null;
                                try
                                {
                                    if (!CheckSpn(context, isSecureConnection, extendedProtectionPolicy)) {
                                        httpError = HttpStatusCode.Unauthorized;
                                    }
                                    else {
                                        httpContext.Request.ServiceName = context.ClientSpecifiedSpn;

                                        userContext = context.GetContextToken(out statusCodeNew);
                                        GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() GetContextToken() returned:" + statusCodeNew.ToString());
                                        if (statusCodeNew != SecurityStatus.OK)
                                        {
                                             httpError = HttpStatusFromSecurityStatus(statusCodeNew);
                                        }
                                        else if (userContext == null)
                                        {
                                            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() error: GetContextToken() returned:null statusCodeNew:" + statusCodeNew.ToString());
                                            httpError = HttpStatusCode.Unauthorized;
                                        }
                                        else
                                        {
                                            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() creating new WindowsIdentity() from userContext:" + userContext.DangerousGetHandle().ToString("x8"));
                                            principal = new WindowsPrincipal(CreateWindowsIdentity(userContext.DangerousGetHandle(), DigestClient.AuthType, WindowsAccountType.Normal, true));
                                        }
                                    }
                                }
                                finally {
                                    if (userContext!=null) {
                                        userContext.Close();
                                    }
                                }

                                newContext = context;

                                if (outBlob != null)
                                {
                                    challenge = DigestClient.AuthType + " " + outBlob;
                                }
                            }
                            else
                            {
                                httpError = HttpStatusFromSecurityStatus(statusCodeNew);
                            }
                            break;

                        case AuthenticationSchemes.Negotiate:
                        case AuthenticationSchemes.Ntlm:
                            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() headerScheme:" + headerScheme);
                            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() returned context#" + ValidationHelper.HashString(oldContext) + " for connectionId:" + connectionId);

                            string package = headerScheme == AuthenticationSchemes.Ntlm ? NtlmClient.AuthType : NegotiateClient.AuthType;
                            if (oldContext != null && oldContext.Package == package)
                            {
                                context = oldContext;
                            }
                            else
                            {
                                binding = GetChannelBinding(connectionId, isSecureConnection, extendedProtectionPolicy);

                                context = new NTAuthentication(true, package, null,
                                    GetContextFlags(extendedProtectionPolicy, isSecureConnection), binding);
                            }

                            try
                            {
                                bytes = Convert.FromBase64String(inBlob);
                            }
                            catch (FormatException)
                            {
                                GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() FromBase64String threw a FormatException.");
                                httpError = HttpStatusCode.BadRequest;
                                error = true;
                            }
                            if (!error)
                            {
                                decodedOutgoingBlob = context.GetOutgoingBlob(bytes, false, out statusCodeNew);
                                GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() GetOutgoingBlob() returned IsCompleted:" + context.IsCompleted + " statusCodeNew:" + statusCodeNew);
                                error = !context.IsValidContext;
                                if (error)
                                {
                                    // Bug #474228: SSPI Workaround
                                    // If a client sends up a blob on the initial request, Negotiate returns SEC_E_INVALID_HANDLE
                                    // when it should return SEC_E_INVALID_TOKEN.
                                    if (statusCodeNew == SecurityStatus.InvalidHandle && oldContext == null && bytes != null && bytes.Length > 0)
                                    {
                                        statusCodeNew = SecurityStatus.InvalidToken;
                                    }

                                    httpError = HttpStatusFromSecurityStatus(statusCodeNew);
                                }
                            }

                            if (decodedOutgoingBlob!=null) {
                                outBlob = Convert.ToBase64String(decodedOutgoingBlob);
                            }

                            if (!error)
                            {
                                if (context.IsCompleted) {
                                    SafeCloseHandle userContext = null;
                                    try
                                    {
                                        if (!CheckSpn(context, isSecureConnection, extendedProtectionPolicy)) {
                                            httpError = HttpStatusCode.Unauthorized;
                                        }
                                        else {
                                            httpContext.Request.ServiceName = context.ClientSpecifiedSpn;

                                            userContext = context.GetContextToken(out statusCodeNew);
                                            if (statusCodeNew != SecurityStatus.OK)
                                            {
                                                GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() GetContextToken() failed with statusCodeNew:" + statusCodeNew.ToString());
                                                httpError = HttpStatusFromSecurityStatus(statusCodeNew);
                                            }
                                            else
                                            {
                                                GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() creating new WindowsIdentity() from userContext:" + userContext.DangerousGetHandle().ToString("x8"));
                                                WindowsPrincipal windowsPrincipal = new WindowsPrincipal(CreateWindowsIdentity(userContext.DangerousGetHandle(), context.ProtocolName, WindowsAccountType.Normal, true));
                                                principal = windowsPrincipal;

                                                // if appropriate, cache this credential on this connection
                                                if (UnsafeConnectionNtlmAuthentication && context.ProtocolName == NegotiationInfoClass.NTLM)
                                                {
                                                    GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() inserting principal#" + ValidationHelper.HashString(principal) + " for connectionId:" + connectionId);

                                                    // We may need to call WaitForDisconnect.
                                                    if (disconnectResult == null)
                                                    {
                                                        RegisterForDisconnectNotification(connectionId, ref disconnectResult);
                                                    }
                                                    if (disconnectResult != null)
                                                    {
                                                        lock (DisconnectResults.SyncRoot)
                                                        {
                                                            if (UnsafeConnectionNtlmAuthentication)
                                                            {
                                                                disconnectResult.AuthenticatedConnection = windowsPrincipal;
                                                            }
                                                        }
                                                    }
                                                    else
                                                    {
                                                        // Registration failed - UnsafeConnectionNtlmAuthentication ignored.
                                                        GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() RegisterForDisconnectNotification() failed.");
                                                    }
                                                }
                                            }
                                        }
                                    }
                                    finally {
                                        if (userContext!=null) {
                                            userContext.Close();
                                        }
                                    }
                                }
                                else
                                {
                                    // auth incomplete
                                    newContext = context;

                                    challenge = (headerScheme==AuthenticationSchemes.Ntlm ? NtlmClient.AuthType : NegotiateClient.AuthType);
                                    if (!String.IsNullOrEmpty(outBlob))
                                    {
                                        challenge += " " + outBlob;
                                    }
                                }
                            }
                            break;

                        case AuthenticationSchemes.Basic:
                            try
                            {
                                bytes = Convert.FromBase64String(inBlob);

                                inBlob = WebHeaderCollection.HeaderEncoding.GetString(bytes, 0, bytes.Length);
                                index = inBlob.IndexOf(':');

                                if (index!=-1) {
                                    string userName = inBlob.Substring(0, index);
                                    string password = inBlob.Substring(index+1);

                                    GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() basic identity found, userName:"******"HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() FromBase64String threw a FormatException.");
                            }
                            break;
                    }

                    if (principal != null)
                    {
                        GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() got principal:" + ValidationHelper.ToString(principal) + " principal.Identity.Name:" + ValidationHelper.ToString(principal.Identity.Name) + " creating request");
                        httpContext.SetIdentity(principal, outBlob);
                    }
                    else
                    {
                        GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() handshake has failed");
                        if(Logging.On)Logging.PrintWarning(Logging.HttpListener, this, "HandleAuthentication", SR.GetString(SR.net_log_listener_create_valid_identity_failed));
                        httpContext.Request.DetachBlob(memoryBlob);
                        httpContext.Close();
                        httpContext = null;
                    }
                }

                // if we're not giving a request to the application, we need to send an error
                ArrayList challenges = null;
                if (httpContext == null)
                {
                    // If we already have a challenge, just use it.  Otherwise put a challenge for each acceptable scheme.
                    if (challenge != null)
                    {
                        AddChallenge(ref challenges, challenge);
                    }
                    else
                    {
                        // We're starting over.  Any context SSPI might have wanted us to keep is useless.
                        if (newContext != null)
                        {
                            if (newContext == context)
                            {
                                context = null;
                            }

                            if (newContext != oldContext)
                            {
                                NTAuthentication toClose = newContext;
                                newContext = null;
                                toClose.CloseContext();
                            }
                            else
                            {
                                newContext = null;
                            }
                        }

                        // If we're sending something besides 401, do it here.
                        if (httpError != HttpStatusCode.Unauthorized)
                        {
                            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() failed context#" + ValidationHelper.HashString(context) + " for connectionId:" + connectionId + " because of error:" + httpError.ToString());
                            SendError(requestId, httpError, null);
                            return null;
                        }

                        challenges = BuildChallenge(authenticationScheme, connectionId, out newContext,
                            extendedProtectionPolicy, isSecureConnection);
                    }
                }

                // Check if we need to call WaitForDisconnect, because if we do and it fails, we want to send a 500 instead.
                if (disconnectResult == null && newContext != null)
                {
                    RegisterForDisconnectNotification(connectionId, ref disconnectResult);

                    // Failed - send 500.
                    if (disconnectResult == null)
                    {
                        if (newContext != null)
                        {
                            if (newContext == context)
                            {
                                context = null;
                            }

                            if (newContext != oldContext)
                            {
                                NTAuthentication toClose = newContext;
                                newContext = null;
                                toClose.CloseContext();
                            }
                            else
                            {
                                newContext = null;
                            }
                        }

                        GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() failed context#" + ValidationHelper.HashString(context) + " for connectionId:" + connectionId + " because of failed HttpWaitForDisconnect");
                        SendError(requestId, HttpStatusCode.InternalServerError, null);
                        httpContext.Request.DetachBlob(memoryBlob);
                        httpContext.Close();
                        return null;
                    }
                }

                // Update Session if necessary.
                if (oldContext != newContext)
                {
                    if (oldContext == context)
                    {
                        // Prevent the finally from closing this twice.
                        context = null;
                    }

                    NTAuthentication toClose = oldContext;
                    oldContext = newContext;
                    disconnectResult.Session = newContext;

                    if (toClose != null)
                    {
                        // Save digest context in digest cache, we may need it later because of
                        // subsequest responses to the same req on the same/diff connection
                        if ((authenticationScheme & AuthenticationSchemes.Digest) != 0)
                        {
                            SaveDigestContext(toClose);
                        }
                        else
                        {
                            toClose.CloseContext();
                        }
                    }
                }

                // Send the 401 here.
                if (httpContext == null)
                {
                    SendError(requestId, challenges != null && challenges.Count > 0 ? HttpStatusCode.Unauthorized : HttpStatusCode.Forbidden, challenges);
                    GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::HandleAuthentication() SendUnauthorized(Scheme:" + authenticationScheme + ")");
                    return null;
                }

                if (!stoleBlob)
                {
                    stoleBlob = true;
                    httpContext.Request.ReleasePins();
                }
                return httpContext;
            }
            catch
            {
                if (httpContext != null)
                {
                    httpContext.Request.DetachBlob(memoryBlob);
                    httpContext.Close();
                }
                if (newContext != null)
                {
                    if (newContext == context)
                    {
                        // Prevent the finally from closing this twice.
                        context = null;
                    }

                    if (newContext != oldContext)
                    {
                        NTAuthentication toClose = newContext;
                        newContext = null;
                        toClose.CloseContext();
                    }
                    else
                    {
                        newContext = null;
                    }
                }
                throw;
            }
            finally
            {
                try
                {
                    // Clean up the previous context if necessary.
                    if (oldContext != null && oldContext != newContext)
                    {
                        // Clear out Session if it wasn't already.
                        if (newContext == null && disconnectResult != null)
                        {
                            disconnectResult.Session = null;
                        }

                        // Save digest context in digest cache, we may need it later because of
                        // subsequest responses to the same req on the same/diff connection

                        if ((authenticationScheme & AuthenticationSchemes.Digest) != 0)
                        {
                            SaveDigestContext(oldContext);
                        }
                        else
                        {
                            oldContext.CloseContext();
                        }
                    }

                    // Delete any context created but not stored.
                    if (context != null && oldContext != context && newContext != context)
                    {
                        context.CloseContext();
                    }
                }
                finally
                {
                    // Check if the connection got deleted while in this method, and clear out the hashtables if it did.
                    // In a nested finally because if this doesn't happen, we leak.
                    if (disconnectResult != null)
                    {
                        disconnectResult.FinishOwningDisconnectHandling();
                    }
                }
            }
        }
Пример #17
0
 internal unsafe bool ValidateRequest(RequestContextBase requestMemory)
 {
     // Block potential DOS attacks
     if (requestMemory.RequestBlob->Headers.UnknownHeaderCount > UnknownHeaderLimit)
     {
         SendError(requestMemory.RequestBlob->RequestId, HttpStatusCode.BadRequest, null);
         return false;
     }
     return true;
 }
Пример #18
0
        internal HttpListenerContext HandleAuthentication(RequestContextBase memoryBlob, out bool stoleBlob)
        {
            if (NetEventSource.IsEnabled) NetEventSource.Info(this, "HandleAuthentication() memoryBlob:0x" + ((IntPtr)memoryBlob.RequestBlob).ToString("x"));

            string challenge = null;
            stoleBlob = false;

            // Some things we need right away.  Lift them out now while it's convenient.
            string verb = Interop.HttpApi.GetVerb(memoryBlob.RequestBlob);
            string authorizationHeader = Interop.HttpApi.GetKnownHeader(memoryBlob.RequestBlob, (int)HttpRequestHeader.Authorization);
            ulong connectionId = memoryBlob.RequestBlob->ConnectionId;
            ulong requestId = memoryBlob.RequestBlob->RequestId;
            bool isSecureConnection = memoryBlob.RequestBlob->pSslInfo != null;

            if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"HandleAuthentication() authorizationHeader: ({authorizationHeader})");

            // if the app has turned on AuthPersistence, an anonymous request might
            // be authenticated by virtue of it coming on a connection that was
            // previously authenticated.
            // assurance that we do this only for NTLM/Negotiate is not here, but in the
            // code that caches WindowsIdentity instances in the Dictionary.
            DisconnectAsyncResult disconnectResult;
            DisconnectResults.TryGetValue(connectionId, out disconnectResult);
            if (UnsafeConnectionNtlmAuthentication)
            {
                if (authorizationHeader == null)
                {
                    WindowsPrincipal principal = disconnectResult?.AuthenticatedConnection;
                    if (principal != null)
                    {
                        if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"Principal: {principal} principal.Identity.Name: {principal.Identity.Name} creating request");
                        stoleBlob = true;
                        HttpListenerContext ntlmContext = new HttpListenerContext(this, memoryBlob);
                        ntlmContext.SetIdentity(principal, null);
                        ntlmContext.Request.ReleasePins();
                        return ntlmContext;
                    }
                }
                else
                {
                    // They sent an authorization - destroy their previous credentials.
                    if (NetEventSource.IsEnabled) NetEventSource.Info(this, "Clearing principal cache");
                    if (disconnectResult != null)
                    {
                        disconnectResult.AuthenticatedConnection = null;
                    }
                }
            }

            // Figure out what schemes we're allowing, what context we have.
            stoleBlob = true;
            HttpListenerContext httpContext = null;
            NTAuthentication oldContext = null;
            NTAuthentication newContext = null;
            NTAuthentication context = null;
            AuthenticationSchemes headerScheme = AuthenticationSchemes.None;
            AuthenticationSchemes authenticationScheme = AuthenticationSchemes;
            ExtendedProtectionPolicy extendedProtectionPolicy = _extendedProtectionPolicy;
            try
            {
                // Take over handling disconnects for now.
                if (disconnectResult != null && !disconnectResult.StartOwningDisconnectHandling())
                {
                    // Just disconnected just then.  Pretend we didn't see the disconnectResult.
                    disconnectResult = null;
                }

                // Pick out the old context now.  By default, it'll be removed in the finally, unless context is set somewhere. 
                if (disconnectResult != null)
                {
                    oldContext = disconnectResult.Session;
                }

                httpContext = new HttpListenerContext(this, memoryBlob);

                AuthenticationSchemeSelector authenticationSelector = _authenticationDelegate;
                if (authenticationSelector != null)
                {
                    try
                    {
                        httpContext.Request.ReleasePins();
                        authenticationScheme = authenticationSelector(httpContext.Request);
                        // Cache the results of authenticationSelector (if any)
                        httpContext.AuthenticationSchemes = authenticationScheme;
                        if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"AuthenticationScheme: {authenticationScheme}");
                    }
                    catch (Exception exception) when (!ExceptionCheck.IsFatal(exception))
                    {
                        if (NetEventSource.IsEnabled)
                        {
                            NetEventSource.Error(this, SR.Format(SR.net_log_listener_delegate_exception, exception));
                            NetEventSource.Info(this, $"authenticationScheme: {authenticationScheme}");
                        }
                        SendError(requestId, HttpStatusCode.InternalServerError, null);
                        httpContext.Close();
                        return null;
                    }
                }
                else
                {
                    // We didn't give the request to the user yet, so we haven't lost control of the unmanaged blob and can
                    // continue to reuse the buffer.
                    stoleBlob = false;
                }

                ExtendedProtectionSelector extendedProtectionSelector = _extendedProtectionSelectorDelegate;
                if (extendedProtectionSelector != null)
                {
                    extendedProtectionPolicy = extendedProtectionSelector(httpContext.Request);

                    if (extendedProtectionPolicy == null)
                    {
                        extendedProtectionPolicy = new ExtendedProtectionPolicy(PolicyEnforcement.Never);
                    }
                    // Cache the results of extendedProtectionSelector (if any)
                    httpContext.ExtendedProtectionPolicy = extendedProtectionPolicy;
                }

                // Then figure out what scheme they're trying (if any are allowed)
                int index = -1;
                if (authorizationHeader != null && (authenticationScheme & ~AuthenticationSchemes.Anonymous) != AuthenticationSchemes.None)
                {
                    // Find the end of the scheme name.  Trust that HTTP.SYS parsed out just our header ok.
                    for (index = 0; index < authorizationHeader.Length; index++)
                    {
                        if (authorizationHeader[index] == ' ' || authorizationHeader[index] == '\t' ||
                            authorizationHeader[index] == '\r' || authorizationHeader[index] == '\n')
                        {
                            break;
                        }
                    }

                    // Currently only allow one Authorization scheme/header per request.
                    if (index < authorizationHeader.Length)
                    {
                        if ((authenticationScheme & AuthenticationSchemes.Negotiate) != AuthenticationSchemes.None &&
                            string.Compare(authorizationHeader, 0, AuthConstants.Negotiate, 0, index, StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            headerScheme = AuthenticationSchemes.Negotiate;
                        }
                        else if ((authenticationScheme & AuthenticationSchemes.Ntlm) != AuthenticationSchemes.None &&
                            string.Compare(authorizationHeader, 0, AuthConstants.NTLM, 0, index, StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            headerScheme = AuthenticationSchemes.Ntlm;
                        }
                        else if ((authenticationScheme & AuthenticationSchemes.Digest) != AuthenticationSchemes.None &&
                            string.Compare(authorizationHeader, 0, AuthConstants.Digest, 0, index, StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            headerScheme = AuthenticationSchemes.Digest;
                        }
                        else if ((authenticationScheme & AuthenticationSchemes.Basic) != AuthenticationSchemes.None &&
                            string.Compare(authorizationHeader, 0, AuthConstants.Basic, 0, index, StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            headerScheme = AuthenticationSchemes.Basic;
                        }
                        else
                        {
                            if (NetEventSource.IsEnabled) NetEventSource.Error(this, SR.Format(SR.net_log_listener_unsupported_authentication_scheme, authorizationHeader, authenticationScheme));
                        }
                    }
                }

                // httpError holds the error we will return if an Authorization header is present but can't be authenticated
                HttpStatusCode httpError = HttpStatusCode.InternalServerError;

                // See if we found an acceptable auth header
                if (headerScheme == AuthenticationSchemes.None)
                {
                    if (NetEventSource.IsEnabled) NetEventSource.Error(this, SR.Format(SR.net_log_listener_unmatched_authentication_scheme, authenticationScheme.ToString(), (authorizationHeader == null ? "<null>" : authorizationHeader)));

                    // If anonymous is allowed, just return the context.  Otherwise go for the 401.
                    if ((authenticationScheme & AuthenticationSchemes.Anonymous) != AuthenticationSchemes.None)
                    {
                        if (!stoleBlob)
                        {
                            stoleBlob = true;
                            httpContext.Request.ReleasePins();
                        }
                        return httpContext;
                    }

                    httpError = HttpStatusCode.Unauthorized;
                    httpContext.Request.DetachBlob(memoryBlob);
                    httpContext.Close();
                    httpContext = null;
                }
                else
                {
                    throw new NotImplementedException();
                }

                // if we're not giving a request to the application, we need to send an error
                ArrayList challenges = null;
                if (httpContext == null)
                {
                    // If we already have a challenge, just use it.  Otherwise put a challenge for each acceptable scheme.
                    if (challenge != null)
                    {
                        AddChallenge(ref challenges, challenge);
                    }
                    else
                    {
                        // We're starting over.  Any context SSPI might have wanted us to keep is useless.
                        if (newContext != null)
                        {
                            if (newContext == context)
                            {
                                context = null;
                            }

                            if (newContext != oldContext)
                            {
                                NTAuthentication toClose = newContext;
                                newContext = null;
                                toClose.CloseContext();
                            }
                            else
                            {
                                newContext = null;
                            }
                        }

                        // If we're sending something besides 401, do it here.
                        if (httpError != HttpStatusCode.Unauthorized)
                        {
                            if (NetEventSource.IsEnabled) NetEventSource.Info(this, "ConnectionId:" + connectionId + " because of error:" + httpError.ToString());
                            SendError(requestId, httpError, null);
                            return null;
                        }

                        challenges = BuildChallenge(authenticationScheme, connectionId, out newContext,
                            extendedProtectionPolicy, isSecureConnection);
                    }
                }

                // Check if we need to call WaitForDisconnect, because if we do and it fails, we want to send a 500 instead.
                if (disconnectResult == null && newContext != null)
                {
                    RegisterForDisconnectNotification(connectionId, ref disconnectResult);

                    // Failed - send 500.
                    if (disconnectResult == null)
                    {
                        if (newContext != null)
                        {
                            if (newContext == context)
                            {
                                context = null;
                            }

                            if (newContext != oldContext)
                            {
                                NTAuthentication toClose = newContext;
                                newContext = null;
                                toClose.CloseContext();
                            }
                            else
                            {
                                newContext = null;
                            }
                        }

                        if (NetEventSource.IsEnabled) NetEventSource.Info(this, "connectionId:" + connectionId + " because of failed HttpWaitForDisconnect");
                        SendError(requestId, HttpStatusCode.InternalServerError, null);
                        httpContext.Request.DetachBlob(memoryBlob);
                        httpContext.Close();
                        return null;
                    }
                }

                // Update Session if necessary.
                if (oldContext != newContext)
                {
                    if (oldContext == context)
                    {
                        // Prevent the finally from closing this twice.
                        context = null;
                    }

                    NTAuthentication toClose = oldContext;
                    oldContext = newContext;
                    disconnectResult.Session = newContext;

                    if (toClose != null)
                    {
                        // Save digest context in digest cache, we may need it later because of
                        // subsequest responses to the same req on the same/diff connection
                        if ((authenticationScheme & AuthenticationSchemes.Digest) != 0)
                        {
                            SaveDigestContext(toClose);
                        }
                        else
                        {
                            toClose.CloseContext();
                        }
                    }
                }

                // Send the 401 here.
                if (httpContext == null)
                {
                    SendError(requestId, challenges != null && challenges.Count > 0 ? HttpStatusCode.Unauthorized : HttpStatusCode.Forbidden, challenges);
                    if (NetEventSource.IsEnabled) NetEventSource.Info(this, "Scheme:" + authenticationScheme);
                    return null;
                }

                if (!stoleBlob)
                {
                    stoleBlob = true;
                    httpContext.Request.ReleasePins();
                }
                return httpContext;
            }
            catch
            {
                if (httpContext != null)
                {
                    httpContext.Request.DetachBlob(memoryBlob);
                    httpContext.Close();
                }
                if (newContext != null)
                {
                    if (newContext == context)
                    {
                        // Prevent the finally from closing this twice.
                        context = null;
                    }

                    if (newContext != oldContext)
                    {
                        NTAuthentication toClose = newContext;
                        newContext = null;
                        toClose.CloseContext();
                    }
                    else
                    {
                        newContext = null;
                    }
                }
                throw;
            }
            finally
            {
                try
                {
                    // Clean up the previous context if necessary.
                    if (oldContext != null && oldContext != newContext)
                    {
                        // Clear out Session if it wasn't already.
                        if (newContext == null && disconnectResult != null)
                        {
                            disconnectResult.Session = null;
                        }

                        // Save digest context in digest cache, we may need it later because of
                        // subsequest responses to the same req on the same/diff connection

                        if ((authenticationScheme & AuthenticationSchemes.Digest) != 0)
                        {
                            SaveDigestContext(oldContext);
                        }
                        else
                        {
                            oldContext.CloseContext();
                        }
                    }

                    // Delete any context created but not stored.
                    if (context != null && oldContext != context && newContext != context)
                    {
                        context.CloseContext();
                    }
                }
                finally
                {
                    // Check if the connection got deleted while in this method, and clear out the hashtables if it did.
                    // In a nested finally because if this doesn't happen, we leak.
                    if (disconnectResult != null)
                    {
                        disconnectResult.FinishOwningDisconnectHandling();
                    }
                }
            }
        }
        internal unsafe HttpListenerContext HandleAuthentication(RequestContextBase memoryBlob, out bool stoleBlob)
        {
            string challenge = null;
            HttpListenerContext context3;
            stoleBlob = false;
            string verb = UnsafeNclNativeMethods.HttpApi.GetVerb(memoryBlob.RequestBlob);
            string knownHeader = UnsafeNclNativeMethods.HttpApi.GetKnownHeader(memoryBlob.RequestBlob, 0x18);
            ulong connectionId = memoryBlob.RequestBlob.ConnectionId;
            ulong requestId = memoryBlob.RequestBlob.RequestId;
            bool isSecureConnection = memoryBlob.RequestBlob.pSslInfo != null;
            DisconnectAsyncResult disconnectResult = (DisconnectAsyncResult) this.DisconnectResults[connectionId];
            if (this.UnsafeConnectionNtlmAuthentication)
            {
                if (knownHeader == null)
                {
                    WindowsPrincipal principal = (disconnectResult == null) ? null : disconnectResult.AuthenticatedConnection;
                    if (principal != null)
                    {
                        stoleBlob = true;
                        HttpListenerContext context = new HttpListenerContext(this, memoryBlob);
                        context.SetIdentity(principal, null);
                        context.Request.ReleasePins();
                        return context;
                    }
                }
                else if (disconnectResult != null)
                {
                    disconnectResult.AuthenticatedConnection = null;
                }
            }
            stoleBlob = true;
            HttpListenerContext context2 = null;
            NTAuthentication digestContext = null;
            NTAuthentication newContext = null;
            NTAuthentication authentication3 = null;
            System.Net.AuthenticationSchemes none = System.Net.AuthenticationSchemes.None;
            System.Net.AuthenticationSchemes authenticationSchemes = this.AuthenticationSchemes;
            System.Security.Authentication.ExtendedProtection.ExtendedProtectionPolicy extendedProtectionPolicy = this.m_ExtendedProtectionPolicy;
            try
            {
                ExtendedProtectionSelector selector;
                SecurityStatus invalidToken;
                ChannelBinding binding;
                string str6;
                ArrayList list;
                if ((disconnectResult != null) && !disconnectResult.StartOwningDisconnectHandling())
                {
                    disconnectResult = null;
                }
                if (disconnectResult != null)
                {
                    digestContext = disconnectResult.Session;
                }
                context2 = new HttpListenerContext(this, memoryBlob);
                AuthenticationSelectorInfo authenticationDelegate = this.m_AuthenticationDelegate;
                if (authenticationDelegate != null)
                {
                    try
                    {
                        context2.Request.ReleasePins();
                        authenticationSchemes = authenticationDelegate.Delegate(context2.Request);
                        if (!authenticationDelegate.AdvancedAuth && ((authenticationSchemes & (System.Net.AuthenticationSchemes.IntegratedWindowsAuthentication | System.Net.AuthenticationSchemes.Digest)) != System.Net.AuthenticationSchemes.None))
                        {
                            throw this.m_SecurityException;
                        }
                        goto Label_01A2;
                    }
                    catch (Exception exception)
                    {
                        if (NclUtilities.IsFatal(exception))
                        {
                            throw;
                        }
                        if (Logging.On)
                        {
                            Logging.PrintError(Logging.HttpListener, this, "HandleAuthentication", SR.GetString("net_log_listener_delegate_exception", new object[] { exception }));
                        }
                        this.SendError(requestId, HttpStatusCode.InternalServerError, null);
                        context2.Close();
                        return null;
                    }
                }
                stoleBlob = false;
            Label_01A2:
                selector = this.m_ExtendedProtectionSelectorDelegate;
                if (selector != null)
                {
                    extendedProtectionPolicy = selector(context2.Request);
                    if (extendedProtectionPolicy == null)
                    {
                        extendedProtectionPolicy = new System.Security.Authentication.ExtendedProtection.ExtendedProtectionPolicy(PolicyEnforcement.Never);
                    }
                }
                int length = -1;
                if ((knownHeader != null) && ((authenticationSchemes & ~System.Net.AuthenticationSchemes.Anonymous) != System.Net.AuthenticationSchemes.None))
                {
                    length = 0;
                    while (length < knownHeader.Length)
                    {
                        if (((knownHeader[length] == ' ') || (knownHeader[length] == '\t')) || ((knownHeader[length] == '\r') || (knownHeader[length] == '\n')))
                        {
                            break;
                        }
                        length++;
                    }
                    if (length < knownHeader.Length)
                    {
                        if (((authenticationSchemes & System.Net.AuthenticationSchemes.Negotiate) != System.Net.AuthenticationSchemes.None) && (string.Compare(knownHeader, 0, "Negotiate", 0, length, StringComparison.OrdinalIgnoreCase) == 0))
                        {
                            none = System.Net.AuthenticationSchemes.Negotiate;
                        }
                        else if (((authenticationSchemes & System.Net.AuthenticationSchemes.Ntlm) != System.Net.AuthenticationSchemes.None) && (string.Compare(knownHeader, 0, "NTLM", 0, length, StringComparison.OrdinalIgnoreCase) == 0))
                        {
                            none = System.Net.AuthenticationSchemes.Ntlm;
                        }
                        else if (((authenticationSchemes & System.Net.AuthenticationSchemes.Digest) != System.Net.AuthenticationSchemes.None) && (string.Compare(knownHeader, 0, "Digest", 0, length, StringComparison.OrdinalIgnoreCase) == 0))
                        {
                            none = System.Net.AuthenticationSchemes.Digest;
                        }
                        else if (((authenticationSchemes & System.Net.AuthenticationSchemes.Basic) != System.Net.AuthenticationSchemes.None) && (string.Compare(knownHeader, 0, "Basic", 0, length, StringComparison.OrdinalIgnoreCase) == 0))
                        {
                            none = System.Net.AuthenticationSchemes.Basic;
                        }
                        else if (Logging.On)
                        {
                            Logging.PrintWarning(Logging.HttpListener, this, "HandleAuthentication", SR.GetString("net_log_listener_unsupported_authentication_scheme", new object[] { knownHeader, authenticationSchemes }));
                        }
                    }
                }
                HttpStatusCode internalServerError = HttpStatusCode.InternalServerError;
                bool flag2 = false;
                if (none == System.Net.AuthenticationSchemes.None)
                {
                    if (Logging.On)
                    {
                        Logging.PrintWarning(Logging.HttpListener, this, "HandleAuthentication", SR.GetString("net_log_listener_unmatched_authentication_scheme", new object[] { ValidationHelper.ToString(authenticationSchemes), (knownHeader == null) ? "<null>" : knownHeader }));
                    }
                    if ((authenticationSchemes & System.Net.AuthenticationSchemes.Anonymous) != System.Net.AuthenticationSchemes.None)
                    {
                        if (!stoleBlob)
                        {
                            stoleBlob = true;
                            context2.Request.ReleasePins();
                        }
                        return context2;
                    }
                    internalServerError = HttpStatusCode.Unauthorized;
                    context2.Request.DetachBlob(memoryBlob);
                    context2.Close();
                    context2 = null;
                    goto Label_07AA;
                }
                byte[] bytes = null;
                byte[] inArray = null;
                string str4 = null;
                length++;
                while (length < knownHeader.Length)
                {
                    if (((knownHeader[length] != ' ') && (knownHeader[length] != '\t')) && ((knownHeader[length] != '\r') && (knownHeader[length] != '\n')))
                    {
                        break;
                    }
                    length++;
                }
                string incomingBlob = (length < knownHeader.Length) ? knownHeader.Substring(length) : "";
                IPrincipal principal2 = null;
                switch (none)
                {
                    case System.Net.AuthenticationSchemes.Digest:
                    {
                        binding = this.GetChannelBinding(connectionId, isSecureConnection, extendedProtectionPolicy);
                        authentication3 = new NTAuthentication(true, "WDigest", null, this.GetContextFlags(extendedProtectionPolicy, isSecureConnection), binding);
                        str4 = authentication3.GetOutgoingDigestBlob(incomingBlob, verb, null, this.Realm, false, false, out invalidToken);
                        if (invalidToken == SecurityStatus.OK)
                        {
                            str4 = null;
                        }
                        if (!authentication3.IsValidContext)
                        {
                            break;
                        }
                        SafeCloseHandle contextToken = null;
                        try
                        {
                            if (!this.CheckSpn(authentication3, isSecureConnection, extendedProtectionPolicy))
                            {
                                internalServerError = HttpStatusCode.Unauthorized;
                            }
                            else
                            {
                                context2.Request.ServiceName = authentication3.ClientSpecifiedSpn;
                                contextToken = authentication3.GetContextToken(out invalidToken);
                                if (invalidToken != SecurityStatus.OK)
                                {
                                    internalServerError = this.HttpStatusFromSecurityStatus(invalidToken);
                                }
                                else if (contextToken == null)
                                {
                                    internalServerError = HttpStatusCode.Unauthorized;
                                }
                                else
                                {
                                    principal2 = new WindowsPrincipal(this.CreateWindowsIdentity(contextToken.DangerousGetHandle(), "Digest", WindowsAccountType.Normal, true));
                                }
                            }
                        }
                        finally
                        {
                            if (contextToken != null)
                            {
                                contextToken.Close();
                            }
                        }
                        newContext = authentication3;
                        if (str4 != null)
                        {
                            challenge = "Digest " + str4;
                        }
                        goto Label_0761;
                    }
                    case System.Net.AuthenticationSchemes.Negotiate:
                    case System.Net.AuthenticationSchemes.Ntlm:
                        str6 = (none == System.Net.AuthenticationSchemes.Ntlm) ? "NTLM" : "Negotiate";
                        if ((digestContext == null) || !(digestContext.Package == str6))
                        {
                            goto Label_0549;
                        }
                        authentication3 = digestContext;
                        goto Label_056D;

                    case System.Net.AuthenticationSchemes.Basic:
                        try
                        {
                            bytes = Convert.FromBase64String(incomingBlob);
                            incomingBlob = WebHeaderCollection.HeaderEncoding.GetString(bytes, 0, bytes.Length);
                            length = incomingBlob.IndexOf(':');
                            if (length != -1)
                            {
                                string username = incomingBlob.Substring(0, length);
                                string password = incomingBlob.Substring(length + 1);
                                principal2 = new GenericPrincipal(new HttpListenerBasicIdentity(username, password), null);
                            }
                            else
                            {
                                internalServerError = HttpStatusCode.BadRequest;
                            }
                        }
                        catch (FormatException)
                        {
                        }
                        goto Label_0761;

                    default:
                        goto Label_0761;
                }
                internalServerError = this.HttpStatusFromSecurityStatus(invalidToken);
                goto Label_0761;
            Label_0549:
                binding = this.GetChannelBinding(connectionId, isSecureConnection, extendedProtectionPolicy);
                authentication3 = new NTAuthentication(true, str6, null, this.GetContextFlags(extendedProtectionPolicy, isSecureConnection), binding);
            Label_056D:
                try
                {
                    bytes = Convert.FromBase64String(incomingBlob);
                }
                catch (FormatException)
                {
                    internalServerError = HttpStatusCode.BadRequest;
                    flag2 = true;
                }
                if (!flag2)
                {
                    inArray = authentication3.GetOutgoingBlob(bytes, false, out invalidToken);
                    flag2 = !authentication3.IsValidContext;
                    if (flag2)
                    {
                        if (((invalidToken == SecurityStatus.InvalidHandle) && (digestContext == null)) && ((bytes != null) && (bytes.Length > 0)))
                        {
                            invalidToken = SecurityStatus.InvalidToken;
                        }
                        internalServerError = this.HttpStatusFromSecurityStatus(invalidToken);
                    }
                }
                if (inArray != null)
                {
                    str4 = Convert.ToBase64String(inArray);
                }
                if (!flag2)
                {
                    if (authentication3.IsCompleted)
                    {
                        SafeCloseHandle handle2 = null;
                        try
                        {
                            if (!this.CheckSpn(authentication3, isSecureConnection, extendedProtectionPolicy))
                            {
                                internalServerError = HttpStatusCode.Unauthorized;
                            }
                            else
                            {
                                context2.Request.ServiceName = authentication3.ClientSpecifiedSpn;
                                handle2 = authentication3.GetContextToken(out invalidToken);
                                if (invalidToken != SecurityStatus.OK)
                                {
                                    internalServerError = this.HttpStatusFromSecurityStatus(invalidToken);
                                }
                                else
                                {
                                    WindowsPrincipal principal3 = new WindowsPrincipal(this.CreateWindowsIdentity(handle2.DangerousGetHandle(), authentication3.ProtocolName, WindowsAccountType.Normal, true));
                                    principal2 = principal3;
                                    if (this.UnsafeConnectionNtlmAuthentication && (authentication3.ProtocolName == "NTLM"))
                                    {
                                        if (disconnectResult == null)
                                        {
                                            this.RegisterForDisconnectNotification(connectionId, ref disconnectResult);
                                        }
                                        if (disconnectResult != null)
                                        {
                                            lock (this.DisconnectResults.SyncRoot)
                                            {
                                                if (this.UnsafeConnectionNtlmAuthentication)
                                                {
                                                    disconnectResult.AuthenticatedConnection = principal3;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                            goto Label_0761;
                        }
                        finally
                        {
                            if (handle2 != null)
                            {
                                handle2.Close();
                            }
                        }
                    }
                    newContext = authentication3;
                    challenge = (none == System.Net.AuthenticationSchemes.Ntlm) ? "NTLM" : "Negotiate";
                    if (!string.IsNullOrEmpty(str4))
                    {
                        challenge = challenge + " " + str4;
                    }
                }
            Label_0761:
                if (principal2 != null)
                {
                    context2.SetIdentity(principal2, str4);
                }
                else
                {
                    if (Logging.On)
                    {
                        Logging.PrintWarning(Logging.HttpListener, this, "HandleAuthentication", SR.GetString("net_log_listener_create_valid_identity_failed"));
                    }
                    context2.Request.DetachBlob(memoryBlob);
                    context2.Close();
                    context2 = null;
                }
            Label_07AA:
                list = null;
                if (context2 == null)
                {
                    if (challenge != null)
                    {
                        AddChallenge(ref list, challenge);
                    }
                    else
                    {
                        if (newContext != null)
                        {
                            if (newContext == authentication3)
                            {
                                authentication3 = null;
                            }
                            if (newContext != digestContext)
                            {
                                NTAuthentication authentication4 = newContext;
                                newContext = null;
                                authentication4.CloseContext();
                            }
                            else
                            {
                                newContext = null;
                            }
                        }
                        if (internalServerError != HttpStatusCode.Unauthorized)
                        {
                            this.SendError(requestId, internalServerError, null);
                            return null;
                        }
                        list = this.BuildChallenge(authenticationSchemes, connectionId, out newContext, extendedProtectionPolicy, isSecureConnection);
                    }
                }
                if ((disconnectResult == null) && (newContext != null))
                {
                    this.RegisterForDisconnectNotification(connectionId, ref disconnectResult);
                    if (disconnectResult == null)
                    {
                        if (newContext != null)
                        {
                            if (newContext == authentication3)
                            {
                                authentication3 = null;
                            }
                            if (newContext != digestContext)
                            {
                                NTAuthentication authentication5 = newContext;
                                newContext = null;
                                authentication5.CloseContext();
                            }
                            else
                            {
                                newContext = null;
                            }
                        }
                        this.SendError(requestId, HttpStatusCode.InternalServerError, null);
                        context2.Request.DetachBlob(memoryBlob);
                        context2.Close();
                        return null;
                    }
                }
                if (digestContext != newContext)
                {
                    if (digestContext == authentication3)
                    {
                        authentication3 = null;
                    }
                    NTAuthentication authentication6 = digestContext;
                    digestContext = newContext;
                    disconnectResult.Session = newContext;
                    if (authentication6 != null)
                    {
                        if ((authenticationSchemes & System.Net.AuthenticationSchemes.Digest) != System.Net.AuthenticationSchemes.None)
                        {
                            this.SaveDigestContext(authentication6);
                        }
                        else
                        {
                            authentication6.CloseContext();
                        }
                    }
                }
                if (context2 == null)
                {
                    this.SendError(requestId, ((list != null) && (list.Count > 0)) ? HttpStatusCode.Unauthorized : HttpStatusCode.Forbidden, list);
                    return null;
                }
                if (!stoleBlob)
                {
                    stoleBlob = true;
                    context2.Request.ReleasePins();
                }
                context3 = context2;
            }
            catch
            {
                if (context2 != null)
                {
                    context2.Request.DetachBlob(memoryBlob);
                    context2.Close();
                }
                if (newContext != null)
                {
                    if (newContext == authentication3)
                    {
                        authentication3 = null;
                    }
                    if (newContext != digestContext)
                    {
                        NTAuthentication authentication7 = newContext;
                        newContext = null;
                        authentication7.CloseContext();
                    }
                    else
                    {
                        newContext = null;
                    }
                }
                throw;
            }
            finally
            {
                try
                {
                    if ((digestContext != null) && (digestContext != newContext))
                    {
                        if ((newContext == null) && (disconnectResult != null))
                        {
                            disconnectResult.Session = null;
                        }
                        if ((authenticationSchemes & System.Net.AuthenticationSchemes.Digest) != System.Net.AuthenticationSchemes.None)
                        {
                            this.SaveDigestContext(digestContext);
                        }
                        else
                        {
                            digestContext.CloseContext();
                        }
                    }
                    if (((authentication3 != null) && (digestContext != authentication3)) && (newContext != authentication3))
                    {
                        authentication3.CloseContext();
                    }
                }
                finally
                {
                    if (disconnectResult != null)
                    {
                        disconnectResult.FinishOwningDisconnectHandling();
                    }
                }
            }
            return context3;
        }
Пример #20
0
 //should only be called from httplistenercontext
 internal void Close()
 {
     if (NetEventSource.IsEnabled) NetEventSource.Enter(this);
     RequestContextBase memoryBlob = _memoryBlob;
     if (memoryBlob != null)
     {
         memoryBlob.Close();
         _memoryBlob = null;
     }
     _isDisposed = true;
     if (NetEventSource.IsEnabled) NetEventSource.Exit(this);
 }
Пример #21
0
        internal HttpListenerRequest(HttpListenerContext httpContext, RequestContextBase memoryBlob)
        {
            if (Logging.On) Logging.PrintInfo(Logging.HttpListener, this, ".ctor", "httpContext#" + ValidationHelper.HashString(httpContext) + " memoryBlob# " + ValidationHelper.HashString((IntPtr) memoryBlob.RequestBlob));
            if(Logging.On)Logging.Associate(Logging.HttpListener, this, httpContext);
            m_HttpContext = httpContext;
            m_MemoryBlob = memoryBlob;
            m_BoundaryType = BoundaryType.None;

            // Set up some of these now to avoid refcounting on memory blob later.
            m_RequestId = memoryBlob.RequestBlob->RequestId;
            m_ConnectionId = memoryBlob.RequestBlob->ConnectionId;
            m_SslStatus = memoryBlob.RequestBlob->pSslInfo == null ? SslStatus.Insecure :
                memoryBlob.RequestBlob->pSslInfo->SslClientCertNegotiated == 0 ? SslStatus.NoClientCert :
                SslStatus.ClientCert;
            if (memoryBlob.RequestBlob->pRawUrl != null && memoryBlob.RequestBlob->RawUrlLength > 0) {
                m_RawUrl = Marshal.PtrToStringAnsi((IntPtr) memoryBlob.RequestBlob->pRawUrl, memoryBlob.RequestBlob->RawUrlLength);
            }
            
            UnsafeNclNativeMethods.HttpApi.HTTP_COOKED_URL cookedUrl = memoryBlob.RequestBlob->CookedUrl;
            if (cookedUrl.pHost != null && cookedUrl.HostLength > 0) {
                m_CookedUrlHost = Marshal.PtrToStringUni((IntPtr)cookedUrl.pHost, cookedUrl.HostLength / 2);
            }
            if (cookedUrl.pAbsPath != null && cookedUrl.AbsPathLength > 0) {
                m_CookedUrlPath = Marshal.PtrToStringUni((IntPtr)cookedUrl.pAbsPath, cookedUrl.AbsPathLength / 2);
            }
            if (cookedUrl.pQueryString != null && cookedUrl.QueryStringLength > 0) {
                m_CookedUrlQuery = Marshal.PtrToStringUni((IntPtr)cookedUrl.pQueryString, cookedUrl.QueryStringLength / 2);
            }
            m_Version = new Version(memoryBlob.RequestBlob->Version.MajorVersion, memoryBlob.RequestBlob->Version.MinorVersion);
            m_ClientCertState = ListenerClientCertState.NotInitialized;
            m_KeepAlive = TriState.Unspecified;
            GlobalLog.Print("HttpListenerContext#" + ValidationHelper.HashString(this) + "::.ctor() RequestId:" + RequestId + " ConnectionId:" + m_ConnectionId + " RawConnectionId:" + memoryBlob.RequestBlob->RawConnectionId + " UrlContext:" + memoryBlob.RequestBlob->UrlContext + " RawUrl:" + m_RawUrl + " Version:" + m_Version.ToString() + " Secure:" + m_SslStatus.ToString());
            if(Logging.On)Logging.PrintInfo(Logging.HttpListener, this, ".ctor", "httpContext#"+ ValidationHelper.HashString(httpContext)+ " RequestUri:" + ValidationHelper.ToString(RequestUri) + " Content-Length:" + ValidationHelper.ToString(ContentLength64) + " HTTP Method:" + ValidationHelper.ToString(HttpMethod));
            // Log headers
            if(Logging.On) {
                StringBuilder sb = new StringBuilder("HttpListenerRequest Headers:\n");
                for (int i=0; i<Headers.Count; i++) {
                    sb.Append("\t");
                    sb.Append(Headers.GetKey(i));
                    sb.Append(" : ");
                    sb.Append(Headers.Get(i));
                    sb.Append("\n");
                }
                Logging.PrintInfo(Logging.HttpListener, this, ".ctor", sb.ToString());
            }
        }
Пример #22
0
 // Use this to save the blob from dispose if this object was never used (never given to a user) and is about to be
 // disposed.
 internal void DetachBlob(RequestContextBase memoryBlob)
 {
     if (memoryBlob != null && (object)memoryBlob == (object)_memoryBlob)
     {
         _memoryBlob = null;
     }
 }
 internal void Close()
 {
     if (Logging.On)
     {
         Logging.Enter(Logging.HttpListener, this, "Close", "");
     }
     RequestContextBase memoryBlob = this.m_MemoryBlob;
     if (memoryBlob != null)
     {
         memoryBlob.Close();
         this.m_MemoryBlob = null;
     }
     this.m_IsDisposed = true;
     if (Logging.On)
     {
         Logging.Exit(Logging.HttpListener, this, "Close", "");
     }
 }
Пример #24
0
        internal HttpListenerContext HandleAuthentication(RequestContextBase memoryBlob, out bool stoleBlob)
        {
            if (NetEventSource.IsEnabled) NetEventSource.Info(this, "HandleAuthentication() memoryBlob:0x" + ((IntPtr)memoryBlob.RequestBlob).ToString("x"));

            string challenge = null;
            stoleBlob = false;

            // Some things we need right away.  Lift them out now while it's convenient.
            string verb = Interop.HttpApi.GetVerb(memoryBlob.RequestBlob);
            string authorizationHeader = Interop.HttpApi.GetKnownHeader(memoryBlob.RequestBlob, (int)HttpRequestHeader.Authorization);
            ulong connectionId = memoryBlob.RequestBlob->ConnectionId;
            ulong requestId = memoryBlob.RequestBlob->RequestId;
            bool isSecureConnection = memoryBlob.RequestBlob->pSslInfo != null;

            if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"HandleAuthentication() authorizationHeader: ({authorizationHeader})");

            // if the app has turned on AuthPersistence, an anonymous request might
            // be authenticated by virtue of it coming on a connection that was
            // previously authenticated.
            // assurance that we do this only for NTLM/Negotiate is not here, but in the
            // code that caches WindowsIdentity instances in the Dictionary.
            DisconnectAsyncResult disconnectResult;
            DisconnectResults.TryGetValue(connectionId, out disconnectResult);
            if (UnsafeConnectionNtlmAuthentication)
            {
                if (authorizationHeader == null)
                {
                    WindowsPrincipal principal = disconnectResult?.AuthenticatedConnection;
                    if (principal != null)
                    {
                        if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"Principal: {principal} principal.Identity.Name: {principal.Identity.Name} creating request");
                        stoleBlob = true;
                        HttpListenerContext ntlmContext = new HttpListenerContext(this, memoryBlob);
                        ntlmContext.SetIdentity(principal, null);
                        ntlmContext.Request.ReleasePins();
                        return ntlmContext;
                    }
                }
                else
                {
                    // They sent an authorization - destroy their previous credentials.
                    if (NetEventSource.IsEnabled) NetEventSource.Info(this, "Clearing principal cache");
                    if (disconnectResult != null)
                    {
                        disconnectResult.AuthenticatedConnection = null;
                    }
                }
            }

            // Figure out what schemes we're allowing, what context we have.
            stoleBlob = true;
            HttpListenerContext httpContext = null;
            NTAuthentication oldContext = null;
            NTAuthentication newContext = null;
            NTAuthentication context = null;
            AuthenticationSchemes headerScheme = AuthenticationSchemes.None;
            AuthenticationSchemes authenticationScheme = AuthenticationSchemes;
            ExtendedProtectionPolicy extendedProtectionPolicy = _extendedProtectionPolicy;
            try
            {
                // Take over handling disconnects for now.
                if (disconnectResult != null && !disconnectResult.StartOwningDisconnectHandling())
                {
                    // Just disconnected just then.  Pretend we didn't see the disconnectResult.
                    disconnectResult = null;
                }

                // Pick out the old context now.  By default, it'll be removed in the finally, unless context is set somewhere. 
                if (disconnectResult != null)
                {
                    oldContext = disconnectResult.Session;
                }

                httpContext = new HttpListenerContext(this, memoryBlob);

                AuthenticationSchemeSelector authenticationSelector = _authenticationDelegate;
                if (authenticationSelector != null)
                {
                    try
                    {
                        httpContext.Request.ReleasePins();
                        authenticationScheme = authenticationSelector(httpContext.Request);
                        // Cache the results of authenticationSelector (if any)
                        httpContext.AuthenticationSchemes = authenticationScheme;
                        if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"AuthenticationScheme: {authenticationScheme}");
                    }
                    catch (Exception exception) when (!ExceptionCheck.IsFatal(exception))
                    {
                        if (NetEventSource.IsEnabled)
                        {
                            NetEventSource.Error(this, SR.Format(SR.net_log_listener_delegate_exception, exception));
                            NetEventSource.Info(this, $"authenticationScheme: {authenticationScheme}");
                        }
                        SendError(requestId, HttpStatusCode.InternalServerError, null);
                        httpContext.Close();
                        return null;
                    }
                }
                else
                {
                    // We didn't give the request to the user yet, so we haven't lost control of the unmanaged blob and can
                    // continue to reuse the buffer.
                    stoleBlob = false;
                }

                ExtendedProtectionSelector extendedProtectionSelector = _extendedProtectionSelectorDelegate;
                if (extendedProtectionSelector != null)
                {
                    extendedProtectionPolicy = extendedProtectionSelector(httpContext.Request);

                    if (extendedProtectionPolicy == null)
                    {
                        extendedProtectionPolicy = new ExtendedProtectionPolicy(PolicyEnforcement.Never);
                    }
                    // Cache the results of extendedProtectionSelector (if any)
                    httpContext.ExtendedProtectionPolicy = extendedProtectionPolicy;
                }

                // Then figure out what scheme they're trying (if any are allowed)
                int index = -1;
                if (authorizationHeader != null && (authenticationScheme & ~AuthenticationSchemes.Anonymous) != AuthenticationSchemes.None)
                {
                    // Find the end of the scheme name.  Trust that HTTP.SYS parsed out just our header ok.
                    for (index = 0; index < authorizationHeader.Length; index++)
                    {
                        if (authorizationHeader[index] == ' ' || authorizationHeader[index] == '\t' ||
                            authorizationHeader[index] == '\r' || authorizationHeader[index] == '\n')
                        {
                            break;
                        }
                    }

                    // Currently only allow one Authorization scheme/header per request.
                    if (index < authorizationHeader.Length)
                    {
                        if ((authenticationScheme & AuthenticationSchemes.Negotiate) != AuthenticationSchemes.None &&
                            string.Compare(authorizationHeader, 0, AuthenticationTypes.Negotiate, 0, index, StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            headerScheme = AuthenticationSchemes.Negotiate;
                        }
                        else if ((authenticationScheme & AuthenticationSchemes.Ntlm) != AuthenticationSchemes.None &&
                            string.Compare(authorizationHeader, 0, AuthenticationTypes.NTLM, 0, index, StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            headerScheme = AuthenticationSchemes.Ntlm;
                        }
                        else if ((authenticationScheme & AuthenticationSchemes.Basic) != AuthenticationSchemes.None &&
                            string.Compare(authorizationHeader, 0, AuthenticationTypes.Basic, 0, index, StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            headerScheme = AuthenticationSchemes.Basic;
                        }
                        else
                        {
                            if (NetEventSource.IsEnabled) NetEventSource.Error(this, SR.Format(SR.net_log_listener_unsupported_authentication_scheme, authorizationHeader, authenticationScheme));
                        }
                    }
                }

                // httpError holds the error we will return if an Authorization header is present but can't be authenticated
                HttpStatusCode httpError = HttpStatusCode.InternalServerError;
                bool error = false;

                // See if we found an acceptable auth header
                if (headerScheme == AuthenticationSchemes.None)
                {
                    if (NetEventSource.IsEnabled) NetEventSource.Error(this, SR.Format(SR.net_log_listener_unmatched_authentication_scheme, authenticationScheme.ToString(), (authorizationHeader == null ? "<null>" : authorizationHeader)));

                    // If anonymous is allowed, just return the context.  Otherwise go for the 401.
                    if ((authenticationScheme & AuthenticationSchemes.Anonymous) != AuthenticationSchemes.None)
                    {
                        if (!stoleBlob)
                        {
                            stoleBlob = true;
                            httpContext.Request.ReleasePins();
                        }
                        return httpContext;
                    }

                    httpError = HttpStatusCode.Unauthorized;
                    httpContext.Request.DetachBlob(memoryBlob);
                    httpContext.Close();
                    httpContext = null;
                }
                else
                {
                    // Perform Authentication
                    byte[] bytes = null;
                    byte[] decodedOutgoingBlob = null;
                    string outBlob = null;

                    // Find the beginning of the blob.  Trust that HTTP.SYS parsed out just our header ok.
                    for (index++; index < authorizationHeader.Length; index++)
                    {
                        if (authorizationHeader[index] != ' ' && authorizationHeader[index] != '\t' &&
                            authorizationHeader[index] != '\r' && authorizationHeader[index] != '\n')
                        {
                            break;
                        }
                    }
                    string inBlob = index < authorizationHeader.Length ? authorizationHeader.Substring(index) : "";

                    IPrincipal principal = null;
                    SecurityStatusPal statusCodeNew;
                    ChannelBinding binding;
                    if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"Performing Authentication headerScheme: {headerScheme}");
                    switch (headerScheme)
                    {
                        case AuthenticationSchemes.Negotiate:
                        case AuthenticationSchemes.Ntlm:
                            if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"context: {oldContext} for connectionId: {connectionId}");

                            string package = headerScheme == AuthenticationSchemes.Ntlm ? NegotiationInfoClass.NTLM : NegotiationInfoClass.Negotiate;
                            if (oldContext != null && oldContext.Package == package)
                            {
                                context = oldContext;
                            }
                            else
                            {
                                binding = GetChannelBinding(connectionId, isSecureConnection, extendedProtectionPolicy);
                                ContextFlagsPal contextFlags = GetContextFlags(extendedProtectionPolicy, isSecureConnection);
                                context = new NTAuthentication(true, package, CredentialCache.DefaultNetworkCredentials, null, contextFlags, binding);
                            }

                            try
                            {
                                bytes = Convert.FromBase64String(inBlob);
                            }
                            catch (FormatException)
                            {
                                if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"FormatException from FormBase64String");
                                httpError = HttpStatusCode.BadRequest;
                                error = true;
                            }
                            if (!error)
                            {
                                decodedOutgoingBlob = context.GetOutgoingBlob(bytes, false, out statusCodeNew);
                                if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"GetOutgoingBlob returned IsCompleted: {context.IsCompleted} and statusCodeNew: {statusCodeNew}");
                                error = !context.IsValidContext;
                                if (error)
                                {
                                    // SSPI Workaround
                                    // If a client sends up a blob on the initial request, Negotiate returns SEC_E_INVALID_HANDLE
                                    // when it should return SEC_E_INVALID_TOKEN.
                                    if (statusCodeNew.ErrorCode == SecurityStatusPalErrorCode.InvalidHandle && oldContext == null && bytes != null && bytes.Length > 0)
                                    {
                                        statusCodeNew = new SecurityStatusPal(SecurityStatusPalErrorCode.InvalidToken);
                                    }

                                    httpError = HttpStatusFromSecurityStatus(statusCodeNew.ErrorCode);
                                }
                            }

                            if (decodedOutgoingBlob != null)
                            {
                                outBlob = Convert.ToBase64String(decodedOutgoingBlob);
                            }

                            if (!error)
                            {
                                if (context.IsCompleted)
                                {
                                    SecurityContextTokenHandle userContext = null;
                                    try
                                    {
                                        if (!CheckSpn(context, isSecureConnection, extendedProtectionPolicy))
                                        {
                                            httpError = HttpStatusCode.Unauthorized;
                                        }
                                        else
                                        {
                                            httpContext.Request.ServiceName = context.ClientSpecifiedSpn;

                                            SafeDeleteContext securityContext = context.GetContext(out statusCodeNew);
                                            if (statusCodeNew.ErrorCode != SecurityStatusPalErrorCode.OK)
                                            {
                                                if (NetEventSource.IsEnabled)
                                                {
                                                    NetEventSource.Info(this,
                                                        $"HandleAuthentication GetContextToken failed with statusCodeNew: {statusCodeNew}");
                                                }

                                                httpError = HttpStatusFromSecurityStatus(statusCodeNew.ErrorCode);
                                            }
                                            else
                                            {
                                                SSPIWrapper.QuerySecurityContextToken(GlobalSSPI.SSPIAuth, securityContext, out userContext);

                                                if (NetEventSource.IsEnabled)
                                                {
                                                    NetEventSource.Info(this,
                                                        $"HandleAuthentication creating new WindowsIdentity from user context: {userContext.DangerousGetHandle().ToString("x8")}");
                                                }

                                                WindowsPrincipal windowsPrincipal = new WindowsPrincipal(
                                                    new WindowsIdentity(userContext.DangerousGetHandle(), context.ProtocolName));

                                                principal = windowsPrincipal;
                                                // if appropriate, cache this credential on this connection
                                                if (UnsafeConnectionNtlmAuthentication && context.ProtocolName == NegotiationInfoClass.NTLM)
                                                {
                                                    if (NetEventSource.IsEnabled)
                                                    {
                                                        NetEventSource.Info(this,
                                                            $"HandleAuthentication inserting principal: {principal} for connectionId: {connectionId}");
                                                    }

                                                    // We may need to call WaitForDisconnect.
                                                    if (disconnectResult == null)
                                                    {
                                                        RegisterForDisconnectNotification(connectionId, ref disconnectResult);
                                                    }
                                                    if (disconnectResult != null)
                                                    {
                                                        lock ((DisconnectResults as ICollection).SyncRoot)
                                                        {
                                                            if (UnsafeConnectionNtlmAuthentication)
                                                            {
                                                                disconnectResult.AuthenticatedConnection = windowsPrincipal;
                                                            }
                                                        }
                                                    }
                                                    else
                                                    {
                                                        // Registration failed - UnsafeConnectionNtlmAuthentication ignored.
                                                        if (NetEventSource.IsEnabled)
                                                        {
                                                            NetEventSource.Info(this, $"HandleAuthentication RegisterForDisconnectNotification failed.");
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                    finally
                                    {
                                        if (userContext != null)
                                        {
                                            userContext.Close();
                                        }
                                    }
                                }
                                else
                                {
                                    // auth incomplete
                                    newContext = context;

                                    challenge = (headerScheme == AuthenticationSchemes.Ntlm ? NegotiationInfoClass.NTLM : NegotiationInfoClass.Negotiate);
                                    if (!String.IsNullOrEmpty(outBlob))
                                    {
                                        challenge += " " + outBlob;
                                    }
                                }
                            }
                            break;

                        case AuthenticationSchemes.Basic:
                            try
                            {
                                bytes = Convert.FromBase64String(inBlob);

                                inBlob = WebHeaderEncoding.GetString(bytes, 0, bytes.Length);
                                index = inBlob.IndexOf(':');

                                if (index != -1)
                                {
                                    string userName = inBlob.Substring(0, index);
                                    string password = inBlob.Substring(index + 1);
                                    if (NetEventSource.IsEnabled)
                                    {
                                        NetEventSource.Info(this, $"Basic Identity found, userName: {userName}");
                                    }

                                    principal = new GenericPrincipal(new HttpListenerBasicIdentity(userName, password), null);
                                }
                                else
                                {
                                    httpError = HttpStatusCode.BadRequest;
                                }
                            }
                            catch (FormatException)
                            {
                                if (NetEventSource.IsEnabled)
                                {
                                    NetEventSource.Info(this, $"FromBase64String threw a FormatException.");
                                }
                            }
                            break;
                    }

                    if (principal != null)
                    {
                        if (NetEventSource.IsEnabled)
                        {
                            NetEventSource.Info(this, $"Got principal: {principal}, IdentityName: {principal.Identity.Name} for creating request.");
                        }

                        httpContext.SetIdentity(principal, outBlob);
                    }
                    else
                    {
                        if (NetEventSource.IsEnabled)
                        {
                            NetEventSource.Info(this, "Handshake has failed.");
                        }

                        httpContext.Request.DetachBlob(memoryBlob);
                        httpContext.Close();
                        httpContext = null;
                    }
                }

                // if we're not giving a request to the application, we need to send an error
                ArrayList challenges = null;
                if (httpContext == null)
                {
                    // If we already have a challenge, just use it.  Otherwise put a challenge for each acceptable scheme.
                    if (challenge != null)
                    {
                        AddChallenge(ref challenges, challenge);
                    }
                    else
                    {
                        // We're starting over.  Any context SSPI might have wanted us to keep is useless.
                        if (newContext != null)
                        {
                            if (newContext == context)
                            {
                                context = null;
                            }

                            if (newContext != oldContext)
                            {
                                NTAuthentication toClose = newContext;
                                newContext = null;
                                toClose.CloseContext();
                            }
                            else
                            {
                                newContext = null;
                            }
                        }

                        // If we're sending something besides 401, do it here.
                        if (httpError != HttpStatusCode.Unauthorized)
                        {
                            if (NetEventSource.IsEnabled) NetEventSource.Info(this, "ConnectionId:" + connectionId + " because of error:" + httpError.ToString());
                            SendError(requestId, httpError, null);
                            return null;
                        }

                        challenges = BuildChallenge(authenticationScheme, connectionId, out newContext,
                            extendedProtectionPolicy, isSecureConnection);
                    }
                }

                // Check if we need to call WaitForDisconnect, because if we do and it fails, we want to send a 500 instead.
                if (disconnectResult == null && newContext != null)
                {
                    RegisterForDisconnectNotification(connectionId, ref disconnectResult);

                    // Failed - send 500.
                    if (disconnectResult == null)
                    {
                        if (newContext != null)
                        {
                            if (newContext == context)
                            {
                                context = null;
                            }

                            if (newContext != oldContext)
                            {
                                NTAuthentication toClose = newContext;
                                newContext = null;
                                toClose.CloseContext();
                            }
                            else
                            {
                                newContext = null;
                            }
                        }

                        if (NetEventSource.IsEnabled) NetEventSource.Info(this, "connectionId:" + connectionId + " because of failed HttpWaitForDisconnect");
                        SendError(requestId, HttpStatusCode.InternalServerError, null);
                        httpContext.Request.DetachBlob(memoryBlob);
                        httpContext.Close();
                        return null;
                    }
                }

                // Update Session if necessary.
                if (oldContext != newContext)
                {
                    if (oldContext == context)
                    {
                        // Prevent the finally from closing this twice.
                        context = null;
                    }

                    NTAuthentication toClose = oldContext;
                    oldContext = newContext;
                    disconnectResult.Session = newContext;

                    if (toClose != null)
                    {
                        toClose.CloseContext();
                    }
                }

                // Send the 401 here.
                if (httpContext == null)
                {
                    SendError(requestId, challenges != null && challenges.Count > 0 ? HttpStatusCode.Unauthorized : HttpStatusCode.Forbidden, challenges);
                    if (NetEventSource.IsEnabled) NetEventSource.Info(this, "Scheme:" + authenticationScheme);
                    return null;
                }

                if (!stoleBlob)
                {
                    stoleBlob = true;
                    httpContext.Request.ReleasePins();
                }
                return httpContext;
            }
            catch
            {
                if (httpContext != null)
                {
                    httpContext.Request.DetachBlob(memoryBlob);
                    httpContext.Close();
                }
                if (newContext != null)
                {
                    if (newContext == context)
                    {
                        // Prevent the finally from closing this twice.
                        context = null;
                    }

                    if (newContext != oldContext)
                    {
                        NTAuthentication toClose = newContext;
                        newContext = null;
                        toClose.CloseContext();
                    }
                    else
                    {
                        newContext = null;
                    }
                }
                throw;
            }
            finally
            {
                try
                {
                    // Clean up the previous context if necessary.
                    if (oldContext != null && oldContext != newContext)
                    {
                        // Clear out Session if it wasn't already.
                        if (newContext == null && disconnectResult != null)
                        {
                            disconnectResult.Session = null;
                        }

                        oldContext.CloseContext();
                    }

                    // Delete any context created but not stored.
                    if (context != null && oldContext != context && newContext != context)
                    {
                        context.CloseContext();
                    }
                }
                finally
                {
                    // Check if the connection got deleted while in this method, and clear out the hashtables if it did.
                    // In a nested finally because if this doesn't happen, we leak.
                    if (disconnectResult != null)
                    {
                        disconnectResult.FinishOwningDisconnectHandling();
                    }
                }
            }
        }