Dynamic lists are designed to perform an internal search to build up an entries content. The most common use case would be for groups, or aka Dynamic Groups. There is a new plugin called cn=Dynamic Lists,cn=plugins,cn=config where you can configure which objectclass an entry must have to identify it was a dynamic entry, which attribute contains an LDAP URI, and which attribute will get populated with the dynamic data. This attribute that contains the dynamic data will contain the DN of the matching entries, but this can be bypassed to use a different attribute/value from the matching entries by requesting an attribute in the LDAP URI. More on this later…
This feature is implemented as a preoperation entry plugin. When returning the result to the client, if the entry matches the dynamic list parameters (it has the objectclass and URL attribute), it will perform an internal search using the LDAP URI to find the content to populate the resulting entry with:
#0 dynamic_lists_pre_entry (pb=0x50800051c020) at ldap/servers/plugins/dynamic_lists/dynamic_lists.c:162
#1 plugin_call_func (list=0x517000023400, operation=operation@entry=410, pb=pb@entry=0x50800051c020,
call_one=call_one@entry=0) at ldap/servers/slapd/plugin.c:1996
#2 plugin_call_list (list=<optimized out>, operation=410, pb=0x50800051c020) at ldap/servers/slapd/plugin.c:1939
#3 plugin_call_plugins (pb=0x50800051c020, whichfunction=<optimized out>) at ldap/servers/slapd/plugin.c:414
#4 send_ldap_search_entry_ext (pb=<optimized out>, e=0x510000550640, ectrls=<optimized out>,
attrs=0x502000483090, attrsonly=<optimized out>, send_result=send_result@entry=0, nentries=<optimized out>, urls=<optimized out>)
at ldap/servers/slapd/result.c:1643
#5 send_ldap_search_entry (pb=<optimized out>, e=<optimized out>, ectrls=<optimized out>, attrs=<optimized out>,
attrsonly=<optimized out>) at ldap/servers/slapd/result.c:1206
#6 send_entry (pb=0x50800051c020, e=<optimized out>, operation=0x5150000f0300, attrs=<optimized out>,
attrsonly=<optimized out>, pnentries=<optimized out>) at ldap/servers/slapd/opshared.c:1204
#7 iterate (send_result=1, pb=0x50800051c020, be=0x5100002c2c40, pnentries=0x7f6cb9b3c090, pagesize=-1, pr_statp=0x7f6cb9b3c060)
at ldap/servers/slapd/opshared.c:1390
#8 send_results_ext.constprop.0 (pb=pb@entry=0x50800051c020, nentries=nentries@entry=0x7f6cb9b3c090, pagesize=<optimized out>,
pr_stat=pr_stat@entry=0x7f6cb9b3c060, send_result=<optimized out>) at ldap/servers/slapd/opshared.c:1607
#9 op_shared_search (pb=pb@entry=0x50800051c020, send_result=send_result@entry=1)
at ldap/servers/slapd/opshared.c:943
#10 do_search (pb=<optimized out>) at ldap/servers/slapd/search.c:411
...
The LDAP URL can only be run locally and will not query a remote server. This is why we reference it as a URI as the host/port are ignored:
ldap:/// <_BASE_DN_> ? <_ATTRIBUTE_> ? <_SCOPE_> ? <_FILTER_>
ldap:///ou=people,dc=example,dc=com??one?(&(objectclass=posixAccount)(uid=*))
If the scope is not specified then a scope of “base” is assumed, and this is probably not desired. So don’t forget to set the search scope (base, one, sub)
As previously mentioned you can override what attribute/content is added to the resulting entry by specifying an attribute in the LDAP URI
ldap:///ou=people,dc=example,dc=com?mail?one?(&(objectclass=posixAccount)(uid=*))
Here we set mail as the requested attribute. The plugin will take the “mail” attribute and value and add it the resulting entry. Note, the attribute specified in the plugin configuration (dynamicListAttribute) is now bypassed and will not be written to the dynamic entry. See the Example section to see how this looks.
dn: cn=Dynamic Lists,cn=plugins,cn=config
objectclass: top
objectclass: nsSlapdPlugin
objectclass: extensibleObject
cn: Dynamic Lists
nsslapd-pluginpath: libdynamic-lists-plugin
nsslapd-plugininitfunc: dynamic_lists_init
nsslapd-plugintype: preoperation
nsslapd-pluginenabled: off
nsslapd-pluginDescription: dynamic lists plugin
nsslapd-pluginId: dynamic-lists
dynamicListObjectclass: groupOfUrls
dynamicListUrlAttr: memberUrl
dynamicListAttr: member
Here are some different configurations and how it will impact the search
Plugin configuration
dynamicListObjectclass: groupOfUrls
dynamicListUrlAttr: memberUrl
dynamicListAttr: member
Dynamic entry
cn=my_dynamic_group,ou=groups,dc=example,dc=com
objectclass: top
objectclass: groupOfUrls
memberUrl: ldap:///ou=people,dc=example,dc=com??sub?(uid=*)
The search
$ ldapsearch -xLLL -H ldap://localhost:389 -D "cn=directory manager" -w PASSWORD -b "dc=example,dc=com" cn=my_dynamic_group
dn: cn=my_dynamic_group,ou=groups,dc=example,dc=com
objectclass: top
objectclass: groupOfUrls
memberUrl: ldap:///ou=people,dc=example,dc=com??sub?(uid=*)
member: uid=mreynolds,ou=people,dc=example,dc=com
member: uid=tbordaz,ou=people,dc=example,dc=com
member: uid=spichugi,ou=people,dc=example,dc=com
member: uid=progier,ou=people,dc=example,dc=com
member: uid=jchapman,ou=people,dc=example,dc=com
No matter what attribute is configured it is always populated with the DN of the entry returned by the LDAP URL.
Plugin configuration (same as the last example)
dynamicListObjectclass: groupOfUrls
dynamicListUrlAttr: memberUrl
dynamicListAttr: member
A dynamic entry that uses an attribute “employeeNumber” in the URL causes dynamicListAttr to be ignored. While the LDAP standard allows for multiple attributes to be requested in an LDAP Url the plugin only looks at the first requested attribute. All other requested attributes are ignored.
cn=dynamic_employee_group,ou=groups,dc=example,dc=com
objectclass: top
objectclass: groupOfUrls
memberUrl: ldap:///ou=people,dc=example,dc=com?employeeNumber?sub?(&(objectclass=posixAccount)(uid=*))
The search
$ ldapsearch -xLLL -H ldap://localhost:389 -D "cn=directory manager" -w PASSWORD -b "dc=example,dc=com" cn=dynamic_employee_group
dn: cn=dynamic_employee_group,ou=groups,dc=example,dc=com
objectclass: top
objectclass: groupOfUrls
memberUrl: ldap:///ou=people,dc=example,dc=com?employeeNumber?sub?(&(objectclass=posixAccount)(uid=*))
employeeNumber: 1001
employeeNumber: 628
So this search looks at each matching entry and extracts the employeeNumber attribute value and uses that to populate the dynamic entry. So the LDAP Url controls how the dynamic content is built. The plugin configuration mainly just specifies the criteria for what is a dynamic entry.
[1] https://github.com/389ds/389-ds-base/issues/1793
[2] https://github.com/389ds/389-ds-base/issues/82