Exemple #1
0
        private bool XPUpdate(string challenge, HttpWebRequest httpWebRequest)
        {
            SecurityStatus   status;
            NTAuthentication securityContext = httpWebRequest.CurrentAuthenticationState.GetSecurityContext(this);

            if (securityContext == null)
            {
                return(false);
            }
            int index = (challenge == null) ? -1 : AuthenticationManager.FindSubstringNotInQuotes(challenge, Signature);

            if (index < 0)
            {
                httpWebRequest.ServicePoint.SetCachedChannelBinding(httpWebRequest.ChallengedUri, securityContext.ChannelBinding);
                this.ClearSession(httpWebRequest);
                return(true);
            }
            if (httpWebRequest.ResponseStatusCode != httpWebRequest.CurrentAuthenticationState.StatusCodeMatch)
            {
                httpWebRequest.ServicePoint.SetCachedChannelBinding(httpWebRequest.ChallengedUri, securityContext.ChannelBinding);
                this.ClearSession(httpWebRequest);
                return(true);
            }
            string incomingBlob = RefineDigestChallenge(challenge, index);

            securityContext.GetOutgoingDigestBlob(incomingBlob, httpWebRequest.CurrentMethod.Name, null, null, false, true, out status);
            httpWebRequest.CurrentAuthenticationState.Authorization.MutuallyAuthenticated = securityContext.IsMutualAuthFlag;
            return(securityContext.IsCompleted);
        }
        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;
        }
 private ArrayList BuildChallenge(System.Net.AuthenticationSchemes authenticationScheme, ulong connectionId, out NTAuthentication newContext, System.Security.Authentication.ExtendedProtection.ExtendedProtectionPolicy policy, bool isSecureConnection)
 {
     ArrayList challenges = null;
     newContext = null;
     if ((authenticationScheme & System.Net.AuthenticationSchemes.Negotiate) != System.Net.AuthenticationSchemes.None)
     {
         AddChallenge(ref challenges, "Negotiate");
     }
     if ((authenticationScheme & System.Net.AuthenticationSchemes.Ntlm) != System.Net.AuthenticationSchemes.None)
     {
         AddChallenge(ref challenges, "NTLM");
     }
     if ((authenticationScheme & System.Net.AuthenticationSchemes.Digest) != System.Net.AuthenticationSchemes.None)
     {
         NTAuthentication authentication = null;
         try
         {
             SecurityStatus status;
             string str = null;
             ChannelBinding channelBinding = this.GetChannelBinding(connectionId, isSecureConnection, policy);
             authentication = new NTAuthentication(true, "WDigest", null, this.GetContextFlags(policy, isSecureConnection), channelBinding);
             str = authentication.GetOutgoingDigestBlob(null, null, null, this.Realm, false, false, out status);
             if (authentication.IsValidContext)
             {
                 newContext = authentication;
             }
             AddChallenge(ref challenges, "Digest" + (string.IsNullOrEmpty(str) ? "" : (" " + str)));
         }
         finally
         {
             if ((authentication != null) && (newContext != authentication))
             {
                 authentication.CloseContext();
             }
         }
     }
     if ((authenticationScheme & System.Net.AuthenticationSchemes.Basic) != System.Net.AuthenticationSchemes.None)
     {
         AddChallenge(ref challenges, "Basic realm=\"" + this.Realm + "\"");
     }
     return challenges;
 }
        private ArrayList BuildChallenge(AuthenticationSchemes authenticationScheme, ulong connectionId, 
            out NTAuthentication newContext, ExtendedProtectionPolicy policy, bool isSecureConnection)
        {
            GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::BuildChallenge()  authenticationScheme:" + authenticationScheme.ToString());
            ArrayList challenges = null;
            newContext = null;

            if ((authenticationScheme & AuthenticationSchemes.Negotiate) != 0)
            {
                AddChallenge(ref challenges, NegotiateClient.AuthType);
            }

            if ((authenticationScheme & AuthenticationSchemes.Ntlm) != 0)
            {
                AddChallenge(ref challenges, NtlmClient.AuthType);
            }

            if ((authenticationScheme & AuthenticationSchemes.Digest) != 0)
            {
                GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::BuildChallenge() package:WDigest");

                NTAuthentication context = null;
                try
                {
                    string outBlob = null;
                    ChannelBinding binding = GetChannelBinding(connectionId, isSecureConnection, policy);

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

                    SecurityStatus statusCode;
                    outBlob = context.GetOutgoingDigestBlob(null, null, null, Realm, false, false, out statusCode);
                    GlobalLog.Print("HttpListener#" + ValidationHelper.HashString(this) + "::BuildChallenge() GetOutgoingDigestBlob() returned IsCompleted:" + context.IsCompleted + " statusCode:" + statusCode + " outBlob:[" + outBlob + "]");

                    if (context.IsValidContext)
                    {
                        newContext = context;
                    }

                    AddChallenge(ref challenges, DigestClient.AuthType + (string.IsNullOrEmpty(outBlob) ? "" : " " + outBlob));
                }
                finally
                {
                    if (context != null && newContext != context)
                    {
                        context.CloseContext();
                    }
                }
            }

            if ((authenticationScheme & AuthenticationSchemes.Basic) != 0)
            {
                AddChallenge(ref challenges, BasicClient.AuthType + " realm=\"" + Realm + "\"");
            }

            return challenges;
        }
        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();
                    }
                }
            }
        }
        public static bool Update(string challenge, WebRequest webRequest)
        {
            GlobalLog.Print("XPDigestClient::Update(): " + challenge);

            HttpWebRequest httpWebRequest = webRequest as HttpWebRequest;

            GlobalLog.Assert(httpWebRequest != null, "XPDigestClient::Update() httpWebRequest==null", "");
            if (httpWebRequest == null || httpWebRequest.ChallengedUri == null)
            {
                //
                // there has been no challenge:
                // 1) the request never went on the wire
                // 2) somebody other than us is calling into AuthenticationManager
                //
                GlobalLog.Print("XPDigestClient::Update(): no request. returning true");
                return(true);
            }

            NTAuthentication authSession = sessions[httpWebRequest.CurrentAuthenticationState] as NTAuthentication;

            GlobalLog.Print("XPDigestClient::Update() key:" + ValidationHelper.HashString(httpWebRequest.CurrentAuthenticationState) + " retrieved authSession:" + ValidationHelper.HashString(authSession));
            if (authSession == null)
            {
                return(false);
            }

            int index = challenge == null ? -1 : AuthenticationManager.FindSubstringNotInQuotes(challenge.ToLower(CultureInfo.InvariantCulture), DigestClient.Signature);

            if (index < 0)
            {
                GlobalLog.Print("XPDigestClient::Update(): no challenge. returning true");
                return(true);
            }

            // here's how we know if the handshake is complete when we get the response back,
            // (keeping in mind that we need to support stale credentials):
            // !40X - complete & success
            // 40X & stale=false - complete & failure
            // 40X & stale=true - !complete

            if (httpWebRequest.ResponseStatusCode != httpWebRequest.CurrentAuthenticationState.StatusCodeMatch)
            {
                GlobalLog.Print("XPDigestClient::Update() removing authSession:" + ValidationHelper.HashString(authSession) + " from:" + ValidationHelper.HashString(httpWebRequest.CurrentAuthenticationState));
                sessions.Remove(httpWebRequest.CurrentAuthenticationState);

                GlobalLog.Print("XPDigestClient::Update(): no status code match. returning true");
                return(true);
            }

            int    blobBegin = index + DigestClient.SignatureSize;
            string incoming  = null;

            //
            // there may be multiple challenges. If the next character after the
            // package name is not a comma then it is challenge data
            //
            if (challenge.Length > blobBegin && challenge[blobBegin] != ',')
            {
                ++blobBegin;
            }
            else
            {
                index = -1;
            }
            if (index >= 0 && challenge.Length > blobBegin)
            {
                incoming = challenge.Substring(blobBegin);
            }

            // we should get here only on invalid or stale credentials:

            bool   handshakeComplete;
            string clientResponse = authSession.GetOutgoingDigestBlob(incoming, httpWebRequest.CurrentMethod, out handshakeComplete);

            GlobalLog.Print("XPDigestClient::Update() GetOutgoingDigestBlob(" + incoming + ") returns:" + ValidationHelper.ToString(clientResponse));

            GlobalLog.Assert(handshakeComplete, "XPDigestClient::Update() handshakeComplete==false", "");

            GlobalLog.Print("XPDigestClient::Update() GetOutgoingBlob() returns clientResponse:[" + ValidationHelper.ToString(clientResponse) + "] handshakeComplete:" + handshakeComplete.ToString());

            return(handshakeComplete);
        }