(Answer) (Category) OpenLDAP Faq-O-Matic : (Category) OpenLDAP Software FAQ : (Category) Configuration : (Category) SLAPD Configuration : (Category) Access Control : (Category) More information about Access Control : (Category) Specifying the subject : (Answer) Sets in Access Controls
This is an elaboration on the message originally written by Mark Valence describing his set syntax. The original message is available in the openldap-devel archive.

Here's the syntax for what have been called "sets" (for lack of a better term). Look at it as an overview, as the details are easy to change. The literal op ("[ ]") below can hold any value, it is not limited to DNs; however, it needs to contain a DN in order to allow the use of the dereference op ("/").

In the examples, DNs have been abbreviated for readability. Readers should be able to get the idea, though.

NOTE: a new feature (since OpenLDAP 2.3) is the possibility to dereference URIs as well. Whenever a literal starts with "ldap://" it is treated as a URI that performs an internal lookup, provided the literal is dereferenced. The LDAP search corresponding to the URI's DN, attributes, scope and filter is performed, and all the matching entries are dereferenced.
NOTE: another new feature (since OpenLDAP 2.3) is the "+" operator to concatenate strings.
NOTE: another new feature (since OpenLDAP 2.4) is the "/-" operator that replaces DNs with their ancestors.

Pardon the pseudo-BNF:

   <set> :=        <base>
                 | "(" <set> ")"
                 | <set> <conj> <set>
                 | <set> "/" <attribute> "*"
                 | <set> "/" <attribute>
                 | <set> "/-" <level>
                 | <set> "/-*"
   <base> :=       "this"
                 | "user"
                 | "[" <any text> "]"
   <conj> :=       "&" | "|" | "+"
   <attribute> :=  an attributeType as defined in the schema
Anywhere in the string, submatch replacements can appear in the form $<digit> or ${<digits>}; they are expanded if the set is configured with the style specifier "expand" (since OpenLDAP 2.3; used to be "regex"). The base "this" refers to the target directory object to which the set applies (the <what> clause). The base "user" refers to the directory object for the currently connected user (the identity the <by> clause is testing access rights for). The base "[<any text>]" can refer to an object by its DN, if "<any text>" is a valid DN.

Use parentheses to override the usual operator precedence. The operator "*" (recursion) has the highest precedence, followed by "/" (dereference). "&" (intersection), "|" (union) and "+" (concatenation) have the lowest, and equal precedence. Operations of equal precedence are evaluated left-to-right unless parentheses dictate otherwise.

The conjunction operators, "&", "|" and "+", combine the sets that are described by their operands. "&" will produce the intersection of the two operand sets, while "|" will produce the union. "+" will concatenate the members of the two sets much like an outer product, i.e. L left members "+" R right members will produce L*R members obtained appending all the right members to each of the lefters. The operators are case sensitive.

The operator "/" applied to an attribute produces the set of all normalized values for the given attribute for all objects in the given set; as a consequence, literals must be provided in normalized form, since sets do not know about the syntax of literals and thus cannot normalize them. As a consequence, the set must contain valid DNs (or URIs, since OpenLDAP 2.3) in order to allow dereferencing. The closure (or recursion) operator "*" will recursively add the values of the attributes for the given set. As a consequence, the attributeType must have distinguishedName syntax (or be able to contain valid "ldap:///" URIs) to allow recursion.

(Introduced in OpenLDAP 2.4) The operator "/" followed by a dash "-" and an integer <level> greater than zero causes all members of a set to be replaced by their <level> ancestor, assuming the set is populated by DN-valued strings and their <level> ancestor exists. The special level "*" causes all set members to be expanded into all their ancestors, including the empty DN "".

For example, say the target object ("this") is "cn=Resource" and the user object is "cn=User". Then:

     user | this :  resolves to the set { "cn=User", "cn=Resource" }
If there is a group "cn=Group" with members "cn=User" and "cn=Other", then:
     [cn=Group]/member & user :  resolves to the set { "cn=User" }
If another group, "cn=Group2" has members "cn=Group" and "cn=Person", then
     [cn=Group2]/member* :  resolves to { "cn=User", "cn=Other", "cn=Person" }
Note that literal bases (things enclosed in "[" "]") do not have to be DNs. So, to test if the current user speaks English:
     user/preferredLanguage & [English]
which resolves to the empty set if the user does not speak English, otherwise it resolves to the set { "English" }. Of course, when the target object "this" is something like a document, a more useful template would be:
     this/preferredLanguage & user/preferredLanguage
The "+" operator allows, for instance, to compute strings out of attribute values; if "this/description" contains { "Group 1", "Group 2" }, the statememnt
builds a set { "cn=group 1,ou=groups", "cn=group 2,ou=groups" }, i.e. the group name is built out of a set of values in the target. Note that the literals are strictly normalized. This can be used, for instance, to test membership in a group whose name is computed from some data in the target, e.g.
    user & ([cn=]+this/description+[,ou=groups])/member

Here's a way to specify all of the immediate managers of the target object's owner who are in either of the (possibly nested) groups "cn=Marketing" or "cn=Sales":

     this/owner/manager & ([cn=Marketing]/member* | [cn=Sales]/member*)
Normally, for access permissions, we care only if there is some relationship of the current user to the resulting set. So, the above set would be more useful as:
     this/owner/manager & ([cn=Marketing]/member* | [cn=Sales]/member*) & user

URI expansion requires dereferencing to be triggered; so the URI must be used as

The <attrs> portion of the URI is honored by expanding the listed attributes in addition to that indicated by the sets dereferentiation, <attr>. If no <attrs> are provided in the URI, only <attr> is dereferenced. If all is desired is the DN of the resulting entries, the URI should be used as

We could make this more powerful (and more complex and costly to compute) by allowing base sets to be built from LDAP filters. This is something to consider, because the combination of filters and sets (which have little overlap in what they can express) is very powerful. This is partially provided by the URI expansion capability.

An example on how sets can be used to give modify/delete permissions only to the creator of an entry is given here.

The original message (written in June 2000) used "." instead of "/"; this was revised because dots do appear in OIDs, which can be used to specify attributeTypes.

A DN containing "[" "]" does not expand correctly.

Sets are considered experimental.
A new feature (since OpenLDAP 2.4) is the "/-" operator to return the nth parent of an entry. For example, if user is "cn=user,ou=people,dc=example,dc=com":
user/-1 : resolves to set { "ou=people,dc=example,dc=com" }
user/-2 : resolves to set { "dc=example,dc=com" }
Of course it works the same for sets of more than 1 element.

Note the special case: "/-*" returns all the parents of the entry. Example:
user/-* : resolves to set { "cn=user,ou=people,dc=example,dc=com" ,
"ou=people,dc=example,dc=com", "dc=example,dc=com" , "dc=com" , "" }

[Append to This Answer]
Previous: (Answer) Example of Group access
Next: (Answer) Sets as "reversed groups"
This document is: http://www.openldap.org/faq/index.cgi?file=1133
[Search] [Appearance]
This is a Faq-O-Matic 2.721.test.
© Copyright 1998-2013, OpenLDAP Foundation, info@OpenLDAP.org