Open Ldap has very flexible and powerful access controls, however they aren't well documented. Sure there is lots of documentation about them, but none of the documentation says anything useful. The most useful part of the documentation I found was the BNF, but as most people soon realise a BNF tells you how, but leaves you n.f.i what is going to happen with a particular grammer.

Anyhow, I'm going to try and explain the access controls I use (which I think covers most of the more advanced features).

Some points to note before we start (for good luck):

  1. Order of access's matters. openldap will stop looking on the first one that matches
  2. Order of by's matters. openldap will stop looking on the first one that matches
So this is the config I use

access to attribute=userPassword

by group/groupofuniquenames/uniquemember="ou=!AdminUsers?,ou=Accounts,$BASEDN" write by dnattr=owner write by anonymous auth by self write by * none

access to dn=".*,ou=Domains,$BASEDN"

by group/groupofuniquenames/uniquemember="ou=!AdminUsers?,ou=Accounts,$BASEDN" write by dnattr=owner write by * read

access to *

by group/groupOfUniqueNames/uniqueMember="ou=!AdminUsers?,ou=Accounts,$BASEDN" write by * read

Now, lets go over it step by step.

The first access is used to protect the userPassword attribute, which stores passwords.

access to attribute=userPassword

So, this matches anything which has a "userPassword" attribute anywhere in the tree. Simple enough.

by group/groupofuniquenames/uniquemember="ou=!AdminUsers?,ou=Accounts,$BASEDN" write

This matches the DN of the person doing the accessing against the uniquemember attribute of groupofuniquenames in the ou=!AdminUsers?,ou=Accounts,$BASEDN object and gives them write access.

This is somewhat confusing so lets go over this again. cn=alice,ou=Accounts,$BASEDN wants to modify cn=bob,ou=Accounts,$BASEDN's foo attribute. This looks up the "uniquemember" attribute on ou=!AdminUsers?,ou=Accounts,$BASEDN and checks to see if cn=alice,ou=Accounts,$BASEDN is there, and, if so, lets her modify cn=bob,ou=Accounts,$BASEDN's object.

For reference the ou=!AdminUsers?,ou=Accounts,$BASEDN object looks like
dn: ou=!AdminUsers?,ou=Accounts,$BASEDN objectClass: top objectClass: groupOfUniqueNames ou: !AdminUsers? uniqueMember: cn=alice,ou=Accounts,$BASEDN uniqueMember: cn=James Curtis,ou=Accounts,$BASEDN uniqueMember: cn=Perry Lorier,ou=Accounts,$BASEDN

Adding/Removing people from the uniqueMember relation will grant/revoke their access.

by dnattr=owner write

This checks to see if the user doing the access appears in the "owner" attribute of the object being modified. For instance, if cn=charlie,ou=Accounts,$BASEDN wanted to access cn=bob,ou=Accounts,$BASEDN's foo attribute, then this sould check to see if cn=charlie,ou=Accounts,$BASEDN appeared in cn=bob,ou=Accounts,$BASEDN's owner attribute first.

by anonymous auth

This lets the anonymous user (a user who hasn't yet logged in) authenticate using the password, but they can't read or write it.

by self write

This lets the user who matches the dn of the object write to the object. For instance if cn=bob,ou=Accounts,$BASEDN wanted to change his password he could (since the object he is accessing is the object he is coming from).

by * none

Noone else must be able to read, or write the password. Fairly simple really.

access to dn=".*,ou=Domains,$BASEDN"

Right, onto the next access. This matches everything under the domains subtree. Note the use of a regex(7)

by group/groupofuniquenames/uniquemember="ou=!AdminUsers?,ou=Accounts,$BASEDN" write

Once again, anyone in the !AdminUsers? group can modify this tree.

by dnattr=owner write

And, the person that owns this object can modify it.

by * read

And, by default anyone can read this.

access to *

Now, for everything else in the tree (a catchall). Note that this is just "", it doesn't have to be "."

by group/groupOfUniqueNames/uniqueMember="ou=!AdminUsers?,ou=Accounts,$BASEDN" write

Admins can write, because admins are power tripping egomaniacs with something to prove.

by * read

And everyone else can look but not touch, you never know when some user is going to accidently destroy your entire tree, so you'd rather not give them the opertunity.