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];

    }