1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
|
//------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------------------------
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IdentityModel.Tokens;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Xml;
using System.Security.Claims;
using System.IdentityModel.Configuration;
using System.Collections.Generic;
using System.Runtime;
namespace System.IdentityModel.Tokens
{
/// <summary>
/// The token handler will validated the Windows Username token.
/// </summary>
public class WindowsUserNameSecurityTokenHandler : UserNameSecurityTokenHandler
{
/// <summary>
/// Initializes an instance of <see cref="WindowsUserNameSecurityTokenHandler"/>
/// </summary>
public WindowsUserNameSecurityTokenHandler()
{
}
/// <summary>
/// Returns true to indicate that the token handler can Validate
/// UserNameSecurityToken.
/// </summary>
public override bool CanValidateToken
{
get
{
return true;
}
}
/// <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;
}
}
}
}
|