/// <summary>
        /// Implements IDisposable interface(from NetworkStream)
        /// </summary>
        /// <param name="disposing">Indicates if there's managed resource to release</param>
        protected override void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    // Clean managed resource
                    CloseServerStream();

                    if (context != null)
                    {
                        context.Dispose();
                        context = null;
                    }
                }
                this.disposed = true;
                this.isAuthenticated = false;
            }

            base.Dispose(disposing);
        }
        /// <summary>
        /// Performs CredSSP authentication.
        /// </summary>
        /// <param name="x509Cert">The certificate used by TLS.</param>
        /// <exception cref="IOException">Raised when attempting to read from/write to the remote connection which
        /// has been closed</exception>
        /// <exception cref="EndOfStreamException">Raised when the username or password doesn't match or authentication
        /// fails</exception>
        public void Authenticate(X509Certificate x509Cert)
        {
            // Authenticated already, do nothing
            if (isAuthenticated)
            {
                return;
            }

            credential = new CertificateCredential(x509Cert);

            byte[] receivedBuffer = new byte[MaxBufferSize];
            int bytesReceived = 0;

            // Dispose the context as it may be timed out
            if (context != null)
            {
                context.Dispose();
            }

            context = new SspiServerSecurityContext(
                SecurityPackageType.CredSsp,
                credential,
                serverPrincipal,
                attribute,
                SecurityTargetDataRepresentation.SecurityNativeDrep);

            // Get first token
            byte[] token = context.Token;
            // Credssp handshake
            while (context.NeedContinueProcessing)
            {
                // Get handshake resopnse
                bytesReceived = serverStream.Read(receivedBuffer, 0, receivedBuffer.Length);
                // The remote connection has been closed
                if (bytesReceived == 0)
                {
                    throw new EndOfStreamException("Authentication failed: remote connection has been closed.");
                }

                byte[] inToken = new byte[bytesReceived];
                Array.Copy(receivedBuffer, inToken, bytesReceived);
                // Get next token from response
                context.Accept(inToken);
                token = context.Token;

                if (token != null)
                {
                    // Send handshake request
                    serverStream.Write(token, 0, token.Length);
                }
            }

            isAuthenticated = true;
        }