Fetching groups using ldapsearch

There are a few pitfalls when trying to fetch groups from LDAP. I document some here so I remember it for the next time I have to do it.

Use an appropriate object filter

It is possible to filter for object classes in LDAP. By default, ldapsearch should not impose a filter on the object class. If you want to distinguish users from groups, you will therefore need to set it manually. For example, use objectClass=group to only obtain groups in your LDAP result.

Joining LDAP filters

It is possible to join several filters in an LDAP query. However, LDAP queries use a prefix notation syntax for that, which may feel a bit unintuitive at first. For example, you may only want to list groups that are member of another group. In that case, you need to join the objectClass filter with a memberOf-filter. For that, use the (& (...) (...) ...) notation:

(& (objectClass=group) (memberof=CN=GroupName,OU=OrgUnit,DC=AD,DC=domain,DC=de) (!(memberof=CN=OtherGroupName,OU=OrgUnit,DC=AD,DC=domain,DC=de)))

As you can see, it is possible to join two or more filter conditions with an &. You can even use ! to negate filters.

At least Active Directory LDAP supports recursive group search, i.e. including objects that are members of subobjects of the specified object. However, it uses a quite arbitrary constant for that: :1.2.840.113556.1.4.1941:. So if you want to e.g. search for subgroups recursively, use the memberof:1.2.840.113556.1.4.1941: instead of memberof:

(& (objectClass=group) (memberof:1.2.840.113556.1.4.1941:=CN=GroupName,OU=OrgUnit,DC=AD,DC=domain,DC=de) (!(memberof:1.2.840.113556.1.4.1941:=CN=OtherGroupName,OU=OrgUnit,DC=AD,DC=domain,DC=de)))

Make sure the base DN includes groups

When searching an LDAP directory, the tree in which to search in needs to be specified. This is called the “base DN” in LDAP terms. Usually, you set this once and forget about it, using it again and again for each query.

However, it is common that organizations have different trees for users and groups. Which makes sense, as you don’t want to worry about obtaining groups when searching for users. Of course, this means in turn that a search for groups in such a base DN will not return any results.

For example, if you use the LDAP filter example from above on a base DN that’s e.g. ou=AllUsers,dc=ad,dc=domain,dc=de, using an ldapsearch like this:

ldapsearch -v -LLL -H ldaps://ldaps.ad.domain.de -b ou=AllUsers,dc=ad,dc=domain,dc=de -D ldapuser@ad.domain.de -W "(& (objectClass=group) (memberof:1.2.840.113556.1.4.1941:=CN=GroupName,OU=OrgUnit,DC=AD,DC=domain,DC=de) (!(memberof:1.2.840.113556.1.4.1941:=CN=OtherGroupName,OU=OrgUnit,DC=AD,DC=domain,DC=de)))" cn

you may not obtain any results, because the Groups are not part of the AllUsers tree and will never be inspected during the search. In that case, it must be ensured that the base DN also includes group objects.

Using the parent group as a base DN

Of course, you may also use the parent group as the base DN for your search:

ldapsearch -LLL -x -H ldaps://ldaps.ad.domain.de -D "ldapuser@ad.domain.de" -W -b "CN=GroupName,OU=OrgUnit,DC=AD,DC=domain,DC=de" cn members

will fetch the attributes cn and members from the parent group specified as the base DN and therefore also list all members. However, you cannot filter for members like that, because now the members are now only part of the single object matched in the base DN, and not individual objects that could be filtered by a filter. So specifying an additional filter like

ldapsearch -LLL -x -H ldaps://ldaps.ad.domain.de -D "ldapuser@ad.domain.de" -W -b "CN=GroupName,OU=OrgUnit,DC=AD,DC=domain,DC=de" "objectClass=group" cn members

will not remove any user members from the result.