Friday, April 01, 2005

Enumerating a user's groups in .NET

I have seen a number of techniques for enumerating a user's group in Active Directory and .NET.  Here is one that seems to crop up every now and then (note, I cleaned this up so at least we were calling Dispose() on our DirectoryEntrys):

        ArrayList al = new ArrayList();
        using (DirectoryEntry user = new DirectoryEntry(_adsPath, _username, _password, AuthenticationTypes.Secure))
        {
            object adsGroups = user.Invoke("Groups");
 
            foreach (object adsGroup in (IEnumerable)adsGroups)
            {
                using (DirectoryEntry group = new DirectoryEntry(adsGroup))
                {
                    al.Add(group.Name);
                }
            }
        }

As we can see, this one uses Reflection to grab the native IADsMembers interface.  We then enumerate the groups by placing each native object into a DirectoryEntry and consuming it as we wish.

What's wrong with this method?  At first glance, nothing really.  Sure, it seems a little more complex than just retrieving the 'memberOf' property from the user to begin with.  We also know that this will not expose the nested group relationships like enumerating the 'tokenGroup' attribute will.

No, the real issue with this is that we are at risk for a memory leak.  What would happen if an error occurred right after we .Invoke() and before the foreach loop finishes?  We would have left a bunch of native IADs objects in limbo.  Only the DirectoryEntry has the .Dispose() pattern that will calls the appropriate Marshal.ReleaseComObject() on the native IADs object.

Developers make mistakes and this one is fraught with peril.  Don't use it.  Instead, enumerate the 'memberOf' attribute or 'tokenGroups' and avoid the issue.

Comments are closed.