(Answer) (Category) OpenLDAP Faq-O-Matic : (Category) OpenLDAP Software FAQ : (Category) Configuration : (Category) SLAPD Configuration : (Category) Access Control : (Answer) A (nearly) complete Address Book example
Here is a complete address book example. An address book means that a database tree contains a set of users; some of these users can have a child entry whose RDN is something like ou=Address Book, which acts as parent to the entries of that person's address book. The owner of the address book must be able to manage it, i.e. add new entries, modify or delete existing entries, but not alter its own entry, the ou=Address Book entry, or, in this example, to add children to the address book entries. The database is structured as follows:
  • a naming context: dc=example,dc=com
  • a container for persons: ou=People,dc=example,dc=com
  • an address book database administrator, which differs from the rootdn, and must have write access to all the portions of the tree that relate to address book administration: cn=Admin,ou=People,dc=example,dc=com
  • an organization-wide address book: ou=Address Book,dc=example,dc=com
  • a set of persons, e.g. cn=Flash Gordon,ou=People,dc=example,dc=com
We assume a minimal database setup, e.g. loading a minimal set of schema files in the global directives section, plus a minimal database directives section like:
    database        bdb
    suffix          "dc=example,dc=com"
    directory       /path/to/db
    rootdn          "cn=Manager,dc=example,dc=com"
    rootpw          ******
    index           objectClass     eq
First of all, clients should be able to authenticate:
    # allow everybody to try to bind
    access to attrs=userPassword
        by self write
        by anonymous auth
Note that this works for simple bind; SASL bind may require auth privileges on a number of attributes that are needed, for instance, to allow the client to find out what SASL mechanisms are available and so.

The address book administrator must be able to create the ou=Address Book child of every user's entry; to this purpose, it needs write access to the children pseudo-attribute of all users:

    # give write access to one's entry's children to admin only
    access to dn.regex="^cn=[^,]+,ou=People,dc=example,dc=com$"
            attrs=children
        by dn.exact="cn=Admin,ou=People,dc=example,dc=com" write
To allow a user to create entries under its own addressbook, and to give the same permission to the address book administrator, one needs write access to the children pseudo-attribute of the ou=Address Book entry, and to the entry pseudo-attribute of the address book entries; at the same time we don't want anybody else to be able to read that entry; note that the user's DN match in the <by> clause uses exact,expand, which is cheaper than regex while allowing substring expansion using the submatches of the <what> clause:
    # allow one to create children of its own addressbook
    access to dn.regex="^ou=Address Book,cn=([^,]+),ou=People,dc=example,dc=com$"
            attrs=children
        by dn.exact="cn=Admin,ou=People,dc=example,dc=com" write
        by dn.exact,expand="cn=$1,ou=People,dc=example,dc=com" write
    # give write access to one's address book entry to admin only
    access to dn.regex="^ou=Address Book,cn=([^,]+),ou=People,dc=example,dc=com$"
            attrs=entry,@organizationalUnit
        by dn.exact="cn=Admin,ou=People,dc=example,dc=com" write
        by dn.exact,expand="cn=$1,ou=People,dc=example,dc=com" read
Then, in our example, a user's entry should be readable only by itself; the <what> part of the access clause uses a regex to make sure that only entries with a leading cn= in the RDN match; the cn=Admin,ou=People,dc=example,dc=com <by> clause comes first, otherwise self would apply to it as well:
    # give read access to one's entry to himself only
    access to dn.regex="^cn=[^,]+,ou=People,dc=example,dc=com$"
        by self read
To allow a user to write entries into its own address book, we need to give it wrote access to the entry pseudo-attribute, and to the attributes that are needed to create a valid address book entry; in our example, we assume valid address book entries can be shaped on the inetOrgPerson objectClass, so we use it as a shortcut to avoid listing too many attributes (note the @ prefix before the objectClass in the attributeType list):
    # allow one to create entries in its own addressbook; no-one else can access it
    access to dn.regex="[^,]+,ou=Address Book,cn=([^,]+),ou=People,dc=example,dc=com$"
            attrs=entry,@inetOrgPerson
        by dn.exact="cn=Admin,ou=People,dc=example,dc=com" write
        by dn.exact,expand="cn=$1,ou=People,dc=example,dc=com" write
Users should be allowed to read the company-wide address book, which is supposed to be made only of children of the ou=Address Book,dc=example,dc=com entry; no-one else should be able to read it; the address book administrator should also be able to write the entry pseudo-attribute of the company-wide address book entries:
    # allow address book admin to add to company-wide address book
    access to dn.onelevel="ou=Address Book,dc=example,dc=com"
            attrs=entry
        by dn.exact="cn=Admin,ou=People,dc=example,dc=com" write
    # allow users to read the company-wide addressbook
    access to dn.onelevel="ou=Address Book,dc=example,dc=com"
        by dn.exact="cn=Admin,ou=People,dc=example,dc=com" write
        by users read
The address book administrator should also be able to write the children pseudo-attribute of the company-wide address book entry:
    # allow address book admin to add children to company-wide address book
    access to dn.exact="ou=Address Book,dc=example,dc=com"
            attrs=children
        by dn.exact="cn=Admin,ou=People,dc=example,dc=com" write
No-one, including users, should be able to read anything else; this statement is pointless, because it is the default:
    # allow no-one to read anything else
    access to *
        by * none
The database and ACL portions of the slapd.conf, and the sample LDIF data I used are available for testing.

Many thanks to Howard Chu for reviewing this configuration example.

I am using OpenLDAP 2.1.29-1. I have to change a little bit in the following ACL, otherwise users cannot use company-wide address book.
# allow address book admin to add to company-wide address book
    access to dn.one="ou=Address Book,dc=example,dc=com"
            attrs=entry
        by dn.exact="cn=Admin,ou=People,dc=example,dc=com" write
        by users read
(I adds 'by users read')
Other changes:
    dn.onelevel changed to dn.one
    no @ before objectClass name in ACL

[Append to This Answer]
Previous: (Answer) How do I grant/deny access based on security strength factors?
Next: (Answer) I have multiple access rules in slapd.conf, but some do not seem to work
This document is: http://www.openldap.org/faq/index.cgi?file=1005
[Search] [Appearance]
This is a Faq-O-Matic 2.721.test.
© Copyright 1998-2013, OpenLDAP Foundation, info@OpenLDAP.org