Which Groups Does WindowsIdentity.Groups Return?
WindowsIdentity exposes a Groups property which returns a collection of IdentityReferences for the groups that a particular user is a member of. However, if you look closely, you'll find that these returned groups won't necessarily include all of the groups that the user is a member of.
Under the covers, WindowsIdentity populates the groups collection by querying Windows for information on the groups that the user token is a member of. However, before returning this list, the Groups property filters out some of the returned groups.
Specifically, any groups which were on the token for deny-only will not be returned in the Groups collection. Similarly, a group which is the SE_GROUP_LOGON_ID will not be returned.
Generally, this is exactly the behavior you want. For instance, if your application is going allow a specific action because the user is a member of a group, you don't want to allow it if the user is a member of the group for deny-only.
If you want to retrieve all of the groups however, there's not an easy built-in way for you to do this. Instead, you'll have to P/Invoke to the GetTokenInformation API to retrieve the groups yourself.
It can be interesting to dump out the groups that specific users are part of -- here's a simple little snippet of code that does just that. (And uses some of those fancy new C# 3.0 features to display them grouped by domain):
public static void Main()
{
using (WindowsIdentity currentIdentity = WindowsIdentity.GetCurrent())
{
var groups = // Get all of the groups from our account, and translate them from IdentityReferences to NTAccounts
from groupIdentity in currentIdentity.Groups
where groupIdentity.IsValidTargetType(typeof(NTAccount))
select groupIdentity.Translate(typeof(NTAccount)) as NTAccount into ntAccounts
// Sort the NTAccounts by their account name
let domainName = ntAccounts.GetDomainName()
let groupName = ntAccounts.GetAccountName()
orderby domainName
// Group the sorted accounts by the domain they belong to, and sort the grouped groups by domain name
group ntAccounts by domainName into domainGroups
orderby domainGroups.Key
select domainGroups;
foreach (var domainGroups in groups)
{
Console.WriteLine("Groups from domain: {0}", domainGroups.Key);
foreach (var group in domainGroups)
{
Console.WriteLine(" {0}", group.GetAccountName());
}
}
}
}
private static string GetDomainName(this NTAccount account)
{
string[] split = account.Value.Split('\\');
return split.Length == 1 ? String.Empty : split[0];
}
private static string GetAccountName(this NTAccount account)
{
string[] split = account.Value.Split('\\');
return split[split.Length - 1];
}
Comments
- Anonymous
August 03, 2009
This is quite helpful! Thanks for sharing your code.