![]() |
Show Changes |
![]() |
Edit |
![]() |
|
![]() |
Recent Changes |
![]() |
Subscriptions |
![]() |
Lost and Found |
![]() |
Find References |
![]() |
Rename |
| Search |
History
| 7/26/2004 6:08:44 PM |
![]() |
List all versions |
These classes work together to represent a Windows token (WhatIsAToken) and provide implementations of the abstract interfaces IIdentity and IPrincipal, which I discussed in WhatIsSecurityContext. Here are the public members of these classes.
namespace System.Security.Principal {
public class WindowsIdentity : IIdentity {
// I've omitted some redundant constructor overloads
public WindowsIdentity(IntPtr token,
string authnType,
WindowsAccountType accountType,
bool isAuthenticated);
public WindowsIdentity(string userPrincipalName,
string authnType);
public bool IsAnonymous { get; }
public bool IsSystem { get; }
public bool IsGuest { get; }
public virtual IntPtr Token { get; }
public virtual WindowsImpersonationContext
Impersonate();
public static WindowsIdentity GetAnonymous();
public static WindowsIdentity GetCurrent();
public static WindowsImpersonationContext
Impersonate(IntPtr token);
// IIdentity implementation
public bool IsAuthenticated { get; }
public string Name { get; }
public string AuthenticationType { get; }
}
public class WindowsPrincipal : IPrincipal {
public WindowsPrincipal(WindowsIdentity id);
public virtual bool IsInRole(int rid);
public virtual bool IsInRole(WindowsBuiltInRole
wellKnownGroup);
// IPrincipal implementation
public virtual IIdentity Identity { get; }
public virtual bool IsInRole(string roleName);
}
}
As you can see, these concrete classes expose quite a bit more functionality than the abstract interfaces they implement. For example, you can use IIdentity to ask about the user's name, but you can get the user's raw token via WindowsIdentity.Token. This allows you to find out much more about the user's security context, including what privileges (WhatIsAPrivilege) she has, although you'll have to do so using P/Invoke to call the appropriate Win32 function (GetTokenInformation). If you use this property to retrieve the underlying token handle, be aware that you're just getting a peek at it. It's not a duplicated token or even a duplicated handle, so don't close it! I've asked the documentation team to clarify this.
It's interesting that these classes are not sealed and they provide virtual functions that you can override. This could be helpful if you wanted to provide a custom principal class that exposed application-specific roles instead of Windows groups, as I sketched out in WhatIsSecurityContext.
Looking at WindowsPrincipal, note that there are a couple of overloads for IsInRole. The second is interesting because I can look for well-known SIDs in the token, as the following code snippet shows:
void ProbeToken(IPrincipal p) {
WindowsPrincipal wp = p as WindowsPrincipal;
if (null != wp) {
if (wp.IsInRole(WindowsBuiltInRole.Administrator)) {
Console.WriteLine("This is an administrator!");
}
if (wp.IsInRole(WindowsBuiltInRole.Guest)) {
Console.WriteLine("This is a guest!");
}
}
else Console.WriteLine("No token to probe! " +
"This is not a WindowsPrincipal.");
}
What's unfortunate is that the WindowsBuiltInRole enumeration is quite limited. I couldn’t care less if the user is a member of the antiquated Account Operators group. What I do care about is whether the Authenticated Users group is in the token, but unfortunately the WindowsBuiltInRole enumeration doesn't include this one. And the other overload that allows you to pass a relative ID (the least significant part of a SID, as I discussed in WhatIsASID) only works for a very limited set of RIDs — namely, those represented by the WindowsBuiltInRole enumeration. Bah!
As for WindowsIdentity, under the covers it consists of a handle to a token and a couple of fields. One field is a Boolean and backs the IsAuthenticated property; the other tracks the "account type." This comes from the WindowsAccountType enumeration.
namespace System.Security.Principal {
public enum WindowsAccountType : Int32 {
Normal,
Guest,
System,
Anonymous
}
}
What's funny is that by looking at a token you can normally determine whether it's a Guest, System, or Anonymous logon just by the SIDs in it. But the WindowsIdentity.IsSystem property doesn't look at the token to decide, for example, whether it's a token for SYSTEM. Rather, it looks at the private account type field. So if you ever construct a WindowsIdentity from a token, you'll need to do these checks yourself and set the account type manually. The same goes for the IsAuthenticated property. I show how to do this in HowToCreateAWindowsPrincipalGivenAToken. The various properties on WindowsIdentity that start with Is are implemented by simply checking these two fields, which must be set up correctly when the WindowsIdentity is first constructed.
WindowsIdentity.GetCurrent is quite useful. It constructs a WindowsIdentity to wrap your process token, unless the thread that makes the call is impersonating (WhatIsImpersonation), in which case the thread token is used. I use this method all the time when diagnosing security problems. For example, if you’re writing a server and suddenly you find that you're being denied access to a file you’re normally allowed to read, your first instinct should be to ask, "Gee, I wonder what security context I was in when I tried to open the file?" A quick call to GetCurrent will answer that question!
WindowsIdentity.GetAnonymous is odd, as I describe in HowToDealWithUnauthenticatedClients. You would expect that, on a class dedicated specifically to dealing with Windows tokens, this would be implemented with a null session token (WhatIsANullSession). Sadly it's not. Instead, it returns a WindowsIdentity whose token is set to IntPtr.Zero and can’t be impersonated. This really restricts its utility! I show a better way to represent an anonymous user in HowToDealWithUnauthenticatedClients.
The AuthenticationType property on WindowsIdentity is almost always hardcoded to be "NTLM", even though the token may have been generated via the Kerberos package, so don't put too much stock in this property.
To learn how to use the Impersonate method, check out HowToImpersonateAUserGivenHerToken.
One very useful feature of WindowsIdentity is that it tremendously simplifies group lookup for domain users in Windows Server 2003 and eases the use of a new feature on that platform called "protocol transition." Briefly, this feature allows a trusted server to obtain network credentials for a user without knowing that user's password. You can read more about the ideas behind this feature and how it works in WhatIsProtocolTransition. All this magic is worked through the deceptively simple constructor for WindowsIdentity that takes a single string as input. See HowToGetATokenForAUser for details on how to use this constructor.
Keith's first book-in-a-wiki. If you would like to read the book online or order a physical copy to throw at annoying coworkers, surf to the HomePage. Please note that due to overwhelming wikispam, this particular wiki is no longer editable.
About FlexWiki.
Recent Topics