Showing results for 
Search instead for 
Did you mean: 

Dynamic Groups

UnboundID PhilipP
0 Kudos

History of Static Groups


Before beginning a discussion of dynamic groups, a quick discussion of the more traditional (static) LDAP group, and some of its drawbacks.


The traditional LDAP group is basically an explicit list of all of its members (listing members by DN). Because of what some may consider to be poor definitions, there are actually three different static groups. Two are defined by an LDAP RFC (4519): groupOfNames and groupOfUniqueNames. The difference between these being fairly obvious from the names. One allows entries to be repeated, the other does not.


Both of these definitions have another perceived deficiency in that they require at least one member. It is impossible to have an empty group, and it is impossible to remove the last member. Thus applications would have to be coded to deal with removal of the last member in some different way than other members.


In an attempt to deal with this, there was a proposed RFC for a third type of group (groupOfEntries) which explicitly allows the member list to be empty. The draft proposal for this has expired without it becoming a formal RFC. However, many LDAP implementations (including UnboundID) implement this.


The UnboundID implementation of groupOfNames and groupOfUniqueNames deviates from the formal definition by allowing for an empty member list (in common with many other implementations).


Member entries are specified by a member attribute in groupOfNames and groupOfEntries, and by a uniquemember attribute in groupOfUniqueNames.


The potential for three different object classes and two different member attribute names makes writing portable code to deal with any of these rather complex.


For example, simply attempting to find all the groups that a given user belongs to might have to be written thus:


$ bin/ldapsearch --baseDN "dc=example,dc=com" --searchScope sub \
  "(|(&(objectClass=groupOfNames) \
  (member=uid=john.doe,ou=People,dc=example,dc=com)) \
  (uniqueMember=uid=john.doe,ou=People,dc=example,dc=com)) \
  (&(objectClass=groupOfEntries) \
  (member=uid=john.doe,ou=People,dc=example,dc=com)))" "1.1"


The implementation of these groups as entries with a potentially long list of attribute values leads to performance issues when the list becomes very large (thousands, or even millions of entries).


An example of a group entry:


dn: cn=Development,ou=groups,dc=example,dc=com
objectclass: top
objectclass: groupOfUniqueNames
cn: Development
ou: groups
uniquemember: uid=user.14,ou=People,dc=example,dc=com
uniquemember: uid=user.91,ou=People,dc=example,dc=com
uniquemember: uid=user.180,ou=People,dc=example,dc=com


Different LDAP implementation have used varying methods to try to ameliorate this, such as implementations using a hash table to locate entries for fast determination of whether a particular member is present, or keeping the list sorted and using binary search etc. etc. These techniques have made huge performance improvements, but still leave the problem that the group entry itself becomes very large. Frequent updates will require frequent writing of this very large entry to disk for every update.


When attempting to deal with millions, tens of millions or even hundreds of millions of potential entries as may be the case with some modern LDAP databases, the traditional LDAP group can easily become a bottleneck.


Dynamic Groups


Dynamic groups are not a total replacement for static groups, but certainly help to resolve some of the static group deficiencies.


There is no formal standard covering dynamic LDAP groups, but fortunately most LDAP implementations follow the same pattern. One obvious exception being Microsoft Active Directory which uses an non LDAP compatible implementation for defining its dynamic groups.


This document will concentrate on the UnboundID implementation, but this is shared by the majority of other LDAP implementations.


The fundamental different with dynamic groups is that there is no explicit list of members. Instead, there is one or more LDAP URLs. Any entry matching any one of those URLs is automatically a member.


As an example, consider the following dynamic group definition:


dn: cn=eng-staff,ou=groups,dc=example,dc=com
objectclass: top
objectclass: groupOfURLs
ou: groups
cn: eng-staff
memberURL: ldap:///ou=People,dc=example,dc=com??sub?(ou=Engineering)


That memberURL will match any entry below ou=people,dc=example, dc=com that has an OU attribute with a value of “Engineering”.


One of the advantages of these sorts of groups is that there is no need to explicitly add entries. They become members purely by having (in this case) an attribute/value pair added.


The isMemberOf attribute


To make effective use of dynamic groups, there is a virtual attribute added automatically by the server when an entry is read. This is a multi-valued attribute listing every group that entry is a member of.


(The UnboundID implementation sets this for every group type, including static groups. Many other implementations only set this for dynamic group membership).


The isMemberOf attribute is set when an entry is read. This simplifies the task of finding which groups a particular user/entry is a member of, simply read the entry and request the isMemberOf attribute (you have to explicitly request this since it is an operational attribute, and not normally returned unless requested).


As an example, determine what groups “user.15” is a member of:


ldapsearch --baseDN dc=example,dc=com "(uid=user.15)" isMemberOf

dn: uid=user.15,ou=People,dc-example,dc=com
isMemberOf: cn=eng-staff,ou=groups,dc=example,dc=com


Here we see that user.15 is a member of only one group, our previously defined eng-staff group.


It is possible to enumerate group members by searching for entries having specific isMemberOf values:


ldapsearch –-baseDN ou=people,dc=example,dc=com \


Howerver, the isMemberOf attribute is operational, meaning that it cannot be indexed. This search would have to examine every entry under ou=people,dc=example,dc=com. That may be acceptable with relatively small numbers of entries, but becomes prohibitive with larger numbers.


If you know what the LDAP URL of the group is, and if the filter attributes are indexed, it is more efficient to simply search using the URL base and filter:


ldapsearch –-baseDN ou=people,dc=example,dc=com ‘(ou=Engineering)’


Dynamic groups may be used in internal operation, for example, in an ACI:


aci: (targetattr="employeeType")
  (version 3.0; acl "Grant write access to employeeType" ;
    allow (all) groupdn="ldap:///cn=department202,ou=groups,dc=example,dc=com";)



Virtual Static Groups


One of the problems with dynamic groups is that legacy applications written to work with static groups will not be able to use these groups.


UnboundID provides the option of mapping dynamic groups into virtual static groups. These behave externally as static groups, but the underlying mechanism is a dynamic group.


A virtual static group definition might look like:



dn: cn=Virtual Static Sales Group,ou=Groups,dc=example,dc=com
objectClass: top
objectClass: groupOfNames
objectClass: ds-virtual-static-group
cn: Virtual Static Sales Group
ds-target-group-dn: cn=Sales Group,ou=Groups,dc=example,dc=com



Since the underlying mechanism is a dynamic group, although enumeration of the members will work, it is highly likely that it will be inefficient and slow. Because of this, enumeration is disabled by default. To enable it use dsconfig to enable the allow- retrieving-membership property for the Virtual Static uniqueMember virtual attribute:



dsconfig set-virtual-attribute-prop --name "Virtual Static member" \
--set allow-retrieving-membership:true