antiduh / nsspi

A C# / .Net interface to the Win32 SSPI authentication API

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

"Context not yet fully formed" exceptions

valorl opened this issue · comments

From time to time, I can see The context is not yet fully formed. exceptions being thrown when trying to access ServerContext.ContextUserName property.

The property is being accessed (for logging purposes) immediately after AcceptToken is called and successful.

Interestingly, the next thing after that logging call is an ImpersonateClient() call which always works.

Is there any hidden race condition/concurrency I'm perhaps not aware of here?

Here's an illustration of what my code is doing:

var status= ctx.AcceptToken(negotiateToken), out var serverToken);
LogTokenAccepted(ctx) // ctx.ContextUserName is being accessed here
using (ctx.ImpersonateClient()) { ... } // This never fails

That exception occurs when the server has not yet seen an AcceptToken call that results in a status of SecurityStatus.OK and you try to perform some action that requires a fully initialized context. That means that the authentication cycle is not complete. Check the return value from AcceptToken, and do not use the context before it returns SecurityStatus.OK.

This snippit from Context.cs shows how the exception occurs when init isn't done:

        public string ContextUserName
        {
            get
            {
                CheckLifecycle();  // <------------------
                return QueryContextString( ContextQueryAttrib.Names );
            }
        }

        protected void Initialize( DateTime expiry )
        {
            this.Expiry = expiry;
            this.Initialized = true;    // <------------------
        }

        private void CheckLifecycle()
        {
            if( this.Initialized == false )    // <------------------
            {
                throw new InvalidOperationException( "The context is not yet fully formed." );
            }
            else if( this.Disposed )
            {
                throw new ObjectDisposedException( "Context" );
            }
        }

This snippit from ServerContext.cs shows when init is called, which would disable the exception:

        public SecurityStatus AcceptToken( byte[] clientToken, out byte[] nextToken )
        {
             ...
                    if( this.ContextHandle.IsInvalid )
                    {
                        status = ContextNativeMethods.AcceptSecurityContext_1( ... );
                    }
                    else
                    {
                        status = ContextNativeMethods.AcceptSecurityContext_2( ... );
                    }
                }
            }

            if( status == SecurityStatus.OK )
            {
                nextToken = null;

                base.Initialize( rawExpiry.ToDateTime() ); // <-------------
...

I am accepting Kerberos tokens only, in which case AcceptToken results in SecurityStatus.OK on the first call. This is why I expected to not see this exception, but I figured out there were some unusual clients triggering this by sending NTLM tokens.

Thanks for the help :)