/// <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; } }