A windows authentication session
Inheritance: IDisposable
        /// <summary>
        /// Try to get a state by its key
        /// </summary>
        /// <param name="key"></param>
        /// <param name="state"></param>
        /// <returns></returns>
        public bool TryGet(string key, out HandshakeState state)
        {
            object tmp;
            if (Cache.TryGetValue(key, out tmp))
            {
                if (tmp != null)
                {
                    state = (HandshakeState)tmp;
                    return true;
                }
            }

            state = default(HandshakeState);
            return false;
        }
        /// <summary>
        /// Try to get a state by its key
        /// </summary>
        /// <param name="key"></param>
        /// <param name="state"></param>
        /// <returns></returns>
        public bool TryGet(string key, out HandshakeState state)
        {
            object tmp;

            if (Cache.TryGetValue(key, out tmp))
            {
                if (tmp != null)
                {
                    state = (HandshakeState)tmp;
                    return(true);
                }
            }

            state = default(HandshakeState);
            return(false);
        }
 /// <summary>
 /// Add a new state to the cache and set a custom cache item policy
 /// </summary>
 /// <param name="key"></param>
 /// <param name="state"></param>
 /// <param name="policy"></param>
 public void Add(string key, HandshakeState state, MemoryCacheEntryOptions options)
 {
     this.Cache.Set(key, state, options);
 }
 /// <summary>
 /// Add a new state to the cache
 /// </summary>
 /// <param name="key"></param>
 /// <param name="state"></param>
 public void Add(string key, HandshakeState state)
 {
     this.Cache.Set(key, state, GetCacheEntryOptions(this.ExpirationTime));
 }
        protected override async Task <AuthenticateResult> HandleAuthenticateAsync()
        {
            //if accessed from a different URL - ignore
            if (!Request.Path.Equals(Options.CallbackPath))
            {
                Context.Items[RedirectToEndpointKey] = true;
                Response.StatusCode = 302;
                return(AuthenticateResult.Fail("Redirecting to authentication route /windowsauthentication/ntlm"));
            }

            //check if the request has an NTLM header
            var authorizationHeader = Request.Headers["Authorization"];

            byte[] token   = null;
            var    hasNtlm = authorizationHeader.Any(h => h.StartsWith("NTLM "));

            if (!hasNtlm)
            {
                // This code runs under following conditions:
                // - authentication failed (in either step: IsClientResponseValid() or TryAcquireServerChallenge())
                // - there's no token in the headers
                //
                // This means we've got to set the WWW-Authenticate header and return a 401
                // 401 tells the browser that the request is unauthenticated and the WWW-Authenticate
                // header tells the browser to try again with NTLM
                Response.Headers.Add("WWW-Authenticate", new[] { "NTLM" });
                Response.StatusCode             = 401;
                Context.Items[RespondNoNtlmKey] = true;

                //We're creating a unique guid to identify the client between the
                //Type 2 and Type 3 handshake
                var requestUniqueId = Guid.NewGuid();
                Response.Cookies.Append(NtlmAuthUniqueIdCookieKey, requestUniqueId.ToString());

                return(AuthenticateResult.Fail("No NTLM header, returning WWW-Authenticate NTLM."));
            }

            if (!string.IsNullOrEmpty(authorizationHeader) && hasNtlm)
            {
                var header = authorizationHeader.First(h => h.StartsWith("NTLM "));
                token = Convert.FromBase64String(header.Substring(5));
            }

            var            responseUniqueId = Request.Cookies[NtlmAuthUniqueIdCookieKey];
            HandshakeState state            = null;

            //see if the response is from a known client handshake
            if (!string.IsNullOrWhiteSpace(responseUniqueId))
            {
                this.Options.LoginStateCache.TryGet(responseUniqueId, out state);
            }

            if (state == null)
            {
                state = new HandshakeState();
            }

            // First eight bytes are header containing NTLMSSP\0 signature
            // Next byte contains type of the message recieved.
            // No Token - it's the initial request. Add a authenticate header
            // Message Type 1 — is initial client's response to server's 401 Unauthorized error.
            // Message Type 2 — is the server's response to it. Contains random 8 bytes challenge.
            // Message Type 3 — is encrypted password hashes from client ready to server validation.
            if (token != null && token[8] == 1)
            {
                // Message of type 1 was received
                if (state.TryAcquireServerChallenge(ref token))
                {
                    // send the type 2 message
                    var authorization = Convert.ToBase64String(token);
                    Response.Headers.Add("WWW-Authenticate", new[] { string.Concat("NTLM ", authorization) });
                    Response.StatusCode = 401;

                    Options.LoginStateCache.Add(responseUniqueId, state);
                    Context.Items[RespondType2Key] = true;

                    return(AuthenticateResult.Fail("Received NTLM Type 1, sending Type 2 with status 401."));
                }
            }
            else if (token != null && token[8] == 3)
            {
                // message of type 3 was received, we validate it
                if (state.IsClientResponseValid(token))
                {
                    // Authorization successful
                    var properties = state.AuthenticationProperties;

                    if (Options.Filter == null || Options.Filter.Invoke(state.WindowsIdentity, Request))
                    {
                        AuthenticationTicket ticket = await CreateAuthenticationTicket(state.WindowsIdentity.Claims, properties);

                        // We don't need that state anymore
                        Options.LoginStateCache.TryRemove(responseUniqueId);

                        //throw the succeded event
                        await Options.Events.AuthenticationSucceeded(new Events.AuthenticationSucceededContext(Context, Options)
                        {
                            Ticket = ticket //pass the ticket
                        });

                        return(AuthenticateResult.Success(ticket));
                    }
                }
            }

            await Options.Events.AuthenticationFailed(new Events.AuthenticationFailedContext(Context, Options));

            return(AuthenticateResult.Fail("Unauthorized"));
        }
 /// <summary>
 /// Add a new state to the cache and set a custom cache item policy
 /// </summary>
 /// <param name="key"></param>
 /// <param name="state"></param>
 /// <param name="policy"></param>
 public void Add(string key, HandshakeState state, MemoryCacheEntryOptions options)
 {
     this.Cache.Set(key, state, options);
 }
 /// <summary>
 /// Add a new state to the cache
 /// </summary>
 /// <param name="key"></param>
 /// <param name="state"></param>
 public void Add(string key, HandshakeState state)
 {
     this.Cache.Set(key, state, GetCacheEntryOptions(this.ExpirationTime));
 }