I will look into this later on while doing v0.07, but IIRC the reason
for this is the broken way that AD does group membership.
For everyone else, there is a group object with CNs as members. In AD,
each member has its groups stored in its own CN as “memberOf”.
Having just been looking at group membership in AD, let me chime in
here. While Microsoft has made some questionable decisions here and
there, I think they do group membership sanely. Group memberships are
effectively a doubly-linked list:
This means that it is easy both to (a) find all the groups of which a
user is a member and (b) find all the users who are members of a
particular group. This is in fact much easier than, say, group
membership under Linux, where (a) is hard (you have to scan through
the entire list of groups and then for each group loop through all the
members), and (b) is only easy if you ignore primary group membership.
AD supports recursive group membership, which means that groups can be
members of other groups (groups can have “memberOf” attributes, and
may include groups in their “member” attributes). This is great from
an organizational standpoint; for example, in our IT organization, we
have groups for engineering, helpdesk, web, etc., and then a single
"itstaff" group of which all the other groups are members. Typically,
this means that when someone joins, we only need to add them to a
single group to give them appropriate permissions, rather than to a
series of groups. Note that NIS Netgroups work the same way.
For example, the following Python code (because I happen to have it
sitting in front of me right now) resolves group membership for a
given DN. Basically, we start with the list of groups in the
"memberOf" attribute for the given DN, and then recursively call the
resolveGroups() function for each of those DNs and so work our way up
def resolveGroups( dn ):
groups = 
obj = ldapServer.search(dn, scope = ldap.SCOPE_BASE)
Note that this returns a list of list, of the form:
( (dn, attributes), (dn, attributes) )
Which should explain all of the list dereferencing you’re about to see.
We only expect a single result (or no result), which is why we’re
if obj and obj:
# add contents of memberOf attribute to list of groups
# call resolveGroups for each of those group DNs
for gdn in obj.get(‘memberOf’, ):
groups = groups + resolveGroups(gdn)
Lars Kellogg-Stedman firstname.lastname@example.org