/// <summary>
        /// Validates a <see cref="KerberosReceiverSecurityToken"/>.
        /// </summary>
        /// <param name="token">The <see cref="KerberosReceiverSecurityToken"/> to validate.</param>
        /// <returns>A <see cref="ReadOnlyCollection{T}"/> of <see cref="ClaimsIdentity"/> representing the identities contained in the token.</returns>
        /// <exception cref="ArgumentNullException">The parameter 'token' is null.</exception>
        /// <exception cref="ArgumentException">The token is not assignable from <see cref="KerberosReceiverSecurityToken"/>.</exception>
        /// <exception cref="InvalidOperationException">Configuration <see cref="SecurityTokenHandlerConfiguration"/>is null.</exception>                
        /// <exception cref="InvalidOperationException">The <see cref="WindowsIdentity"/> of the <see cref="KerberosReceiverSecurityToken"/>is null.</exception>                
        public override ReadOnlyCollection<ClaimsIdentity> ValidateToken(SecurityToken token)
        {
            if (token == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("token");
            }

            KerberosReceiverSecurityToken kerbToken = token as KerberosReceiverSecurityToken;
            if (kerbToken == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("token", SR.GetString(SR.ID0018, typeof(KerberosReceiverSecurityToken)));
            }

            if (this.Configuration == null)
            {
                throw DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID4274));
            }

            try
            {
                if (kerbToken.WindowsIdentity == null)
                {
                    throw DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID4026));
                }

                // KerberosReceiveSecurityToken is disposable, best to make a copy as Dispose() nulls out the WindowsIdentity. The AuthenticationType was set when the kerbToken was created.
                WindowsIdentity wi = new WindowsIdentity(kerbToken.WindowsIdentity.Token, kerbToken.WindowsIdentity.AuthenticationType);

                // PARTIAL TRUST: will fail when adding claims, AddClaim is SecurityCritical.
                wi.AddClaim(new Claim(ClaimTypes.AuthenticationInstant, XmlConvert.ToString(DateTime.UtcNow, DateTimeFormats.Generated), ClaimValueTypes.DateTime));
                wi.AddClaim(new Claim(ClaimTypes.AuthenticationMethod, AuthenticationMethods.Windows, ClaimValueTypes.String));

                if (this.Configuration.SaveBootstrapContext)
                {
                    wi.BootstrapContext = new BootstrapContext(token, this);
                }

                this.TraceTokenValidationSuccess(token);

                List<ClaimsIdentity> identities = new List<ClaimsIdentity>(1);
                identities.Add(wi);
                return identities.AsReadOnly();
            }
            catch (Exception e)
            {
                if (Fx.IsFatal(e))
                {
                    throw;
                }

                this.TraceTokenValidationFailure(token, e.Message);
                throw e;
            }
        }
        /// <summary>
        /// Validates a <see cref="UserNameSecurityToken"/>.
        /// </summary>
        /// <param name="token">The <see cref="UserNameSecurityToken"/> to validate.</param>
        /// <returns>A <see cref="ReadOnlyCollection{T}"/> of <see cref="ClaimsIdentity"/> representing the identities contained in the token.</returns>
        /// <exception cref="ArgumentNullException">The parameter 'token' is null.</exception>
        /// <exception cref="ArgumentException">The token is not assignable from<see cref="UserNameSecurityToken"/>.</exception>
        /// <exception cref="InvalidOperationException">Configuration <see cref="SecurityTokenHandlerConfiguration"/>is null.</exception>
        /// <exception cref="ArgumentException">If username is not if the form 'user\domain'.</exception>
        /// <exception cref="SecurityTokenValidationException">LogonUser using the given token failed.</exception>
        public override ReadOnlyCollection<ClaimsIdentity> ValidateToken(SecurityToken token)
        {
            if (token == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("token");
            }

            UserNameSecurityToken usernameToken = token as UserNameSecurityToken;
            if (usernameToken == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("token", SR.GetString(SR.ID0018, typeof(UserNameSecurityToken)));
            }

            if (this.Configuration == null)
            {
                throw DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID4274));
            }

            try
            {
                string userName = usernameToken.UserName;
                string password = usernameToken.Password;
                string domain = null;
                string[] strings = usernameToken.UserName.Split('\\');
                if (strings.Length != 1)
                {
                    if (strings.Length != 2 || string.IsNullOrEmpty(strings[0]))
                    {
                        // Only support one slash and domain cannot be empty (consistent with windowslogon).
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("token", SR.GetString(SR.ID4062));
                    }

                    // This is the downlevel case - domain\userName
                    userName = strings[1];
                    domain = strings[0];
                }

                const uint LOGON32_PROVIDER_DEFAULT = 0;
                const uint LOGON32_LOGON_NETWORK_CLEARTEXT = 8;
                SafeCloseHandle tokenHandle = null;
                try
                {
                    if (!NativeMethods.LogonUser(userName, domain, password, LOGON32_LOGON_NETWORK_CLEARTEXT, LOGON32_PROVIDER_DEFAULT, out tokenHandle))
                    {
                        int error = Marshal.GetLastWin32Error();
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityTokenValidationException(SR.GetString(SR.ID4063, userName), new Win32Exception(error)));
                    }

                    WindowsIdentity windowsIdentity = new WindowsIdentity(tokenHandle.DangerousGetHandle(), AuthenticationTypes.Password, WindowsAccountType.Normal, true);

                    // PARTIAL TRUST: will fail when adding claims, AddClaim is SecurityCritical.
                    windowsIdentity.AddClaim(new Claim(ClaimTypes.AuthenticationInstant, XmlConvert.ToString(DateTime.UtcNow, DateTimeFormats.Generated), ClaimValueTypes.DateTime));
                    windowsIdentity.AddClaim(new Claim(ClaimTypes.AuthenticationMethod, AuthenticationMethods.Password));

                    if (this.Configuration.SaveBootstrapContext)
                    {
                        if (RetainPassword)
                        {
                            windowsIdentity.BootstrapContext = new BootstrapContext(usernameToken, this);
                        }
                        else
                        {
                            windowsIdentity.BootstrapContext = new BootstrapContext(new UserNameSecurityToken(usernameToken.UserName, null), this);
                        }
                    }

                    this.TraceTokenValidationSuccess(token);

                    List<ClaimsIdentity> identities = new List<ClaimsIdentity>(1);
                    identities.Add(windowsIdentity);
                    return identities.AsReadOnly();
                }
                finally
                {
                    if (tokenHandle != null)
                    {
                        tokenHandle.Close();
                    }
                }
            }
            catch (Exception e)
            {
                if (Fx.IsFatal(e))
                {
                    throw;
                }

                this.TraceTokenValidationFailure(token, e.Message);
                throw e;
            }
        }