OpenLDAP ACL’s using sets

access-control-listopenldap

So, I am attempting to write some LDAP rules that will allow certain people the ability to write some subtrees.

Let's say we have this user:

dn: uid=minion1,o=mycompany,ou=cust,dc=some,dc=domain
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
isAdmin: TRUE

And this user:

dn: uid=minion2,o=mycompany,ou=cust,dc=some,dc=domain
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
isAdmin: FALSE

Oh, and this user:

dn: uid=minion3,o=notmycompany,ou=cust,dc=some,dc=domain
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
isAdmin: FALSE

I'm attempting to set permissions for minion1 to modify minion2's account, but not minion3 (if you look, minion3 is in a different organization "notmycompany" where the other two are in "mycompany").

The basic rule is that a user should have the ability to add/modify/delete entries in its organization based on if the "isAdmin" property set to TRUE, AND if the object is in the same organization as the user he/she wishes to modify.

My partially working ACL is:

to dn.regex="^.+o=([^,]+),ou=cust,dc=some,dc=domain$" 
by set="user/isAdmin & [TRUE]" write 

This will of course allow them to modify minion3's account as well. I would like to add

"[^.+,o=$1,ou=cust,dc=some,dc=domain$]"

to the by line above, but so far I have failed miserably. Does anyone have any good ideas I might try? (Did I explain what I'm attempting to do here adequately)?

Thanks in advance;

Best Answer

I've spent some time looking through the documentation on sets, and the problem you've got is that set operators (like &) really only work on data of the same type...so you can ask for the intersection of a DN and a DN, or an attribute value and a string, but intersections of things of different types doesn't make sense.

So, we build a string using the isAdmin attribute and the wonders of string concatenation, like this:

olcAccess: {1}to dn.regex="o=([^,]+),ou=cust,dc=some,dc=domain$" 
    by set.expand="([admin=] + user/isAdmin + [,] + user/-1) & ([admin=TRUE] + [,o=$1,ou=cust,dc=some,dc=domain])" write 
    by * break

Note the user of set.expand, because we want to use $1 in the set definition, and note the use of [...] to put literal values into the strings we're evaluating.

For someone logged in as minion1, this will ask for the intersection of:

admin=TRUE,o=mycompany,ou=cust,dc=some,dc=domain

and the literal value:

admin=TRUE,o=mycompany,ou=cust,dc=some,dc=domain

Which is a nonempty set, so it works. For someone with isAdmin=FALSE (or no isAdmin attribute), the comparison would be with admin=FALSE,... or admin=,.... Similarly, for someone not in the same organization o=... as the target, the intersection will produce an empty set.

If you're interested, this is what I actually used for testing. I'm using employeeType instead of isAdmin because I didn't want to muck about with adding a new attribute to my schema.

Also: slapd -dacl ... is your friend.

Related Topic