From b5bd63140f40f3bd479497f0dbb96d2ec95dc330 Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Wed, 18 Apr 2012 03:25:46 +0200 Subject: LDAP: Using ACL Sets for self managed domains. --- fripost-docs.org | 191 +++++++++++++++++++++++++++---------------------------- 1 file changed, 95 insertions(+), 96 deletions(-) diff --git a/fripost-docs.org b/fripost-docs.org index 73b0982..9ecbe59 100644 --- a/fripost-docs.org +++ b/fripost-docs.org @@ -677,26 +677,28 @@ Jamm's (http://jamm.sourceforge.net/howto/html/implementation.html). | | userPassword: xxxxxx | | maildir: fripost.org/user1/ | | isActive: TRUE - | | |- mailTarget=user1@fripost.org - | | | mailTarget: user1@fripost.org - | | | mailLocalAddress: user1-alias@example.org - | | | isActive: TRUE - | | `- dc=example.org - | | dc: example.org - | | isActive: TRUE - | | `- mailTarget=user1@fripost.org - | | | mailTarget: user1@fripost.org - | | | mailLocalAddress: user1@example.org - | | | isActive: TRUE - | | | - | | `- mailTarget=user1-alias@fripost.org | | | `- uid=user2@fripost.org | |- ou=domains - | `- dc=fripost.org - | dc: fripost.org - | isActive: TRUE + | |- dc=fripost.org + | | dc: fripost.org + | | isActive: TRUE + | | `- mailTarget=user1@fripost.org + | | mailTarget: user1@fripost.org + | | mailLocalAddress: user1-alias@example.org + | | isActive: TRUE + | | + | `- dc=example.org + | dc: example.org + | owner: uid=user1@fripost.org,ou=mailboxes,dc=mail,dc=fripost,dc=org + | isActive: TRUE + | `- mailTarget=user1@fripost.org + | | mailTarget: user1@fripost.org + | | mailLocalAddress: user1@example.org + | | isActive: TRUE + | | + | `- mailTarget=user1-alias@fripost.org | |- ou=managers | |- cn=admin1 @@ -734,7 +736,7 @@ Jamm's (http://jamm.sourceforge.net/howto/html/implementation.html). SUP top STRUCTURAL DESC 'Virtual Domains.' MUST ( dc $ isActive ) - MAY ( description ) ) + MAY ( owner $ description ) ) olcObjectclasses: ( 1.3.6.1.4.1.12461.1.2.2 NAME 'virtualAliases' SUP top STRUCTURAL DESC 'Virtual Aliases.' @@ -812,6 +814,9 @@ be looking for e.g., the `mail' attribute. - add: olcDbIndex olcDbIndex: isActive eq + - + add: olcDbIndex + olcDbIndex: owner eq ldapmodify -QY EXTERNAL -H ldapi:/// -f /etc/ldap/local/mail.fripost.org-index.ldif @@ -825,12 +830,16 @@ ldapmodify -QY EXTERNAL -H ldapi:/// -f /etc/ldap/local/mail.fripost.org-index.l olcDbIndex: uid eq,sub olcDbIndex: mailLocalAddress eq olcDbIndex: isActive eq + olcDbIndex: owner eq ***** Restrict the access The default ACL is not restrictive enough for our purpose. Note: The ACLs are evaluated in order, hence the more specific rules should come first. +We are using the so-called "Sets" to let the users manage their domain themselves. +See section 8.5 "Sets - Granting rights based on relationships" in LDAP's manual +http://www.openldap.org/doc/admin24/access-control.html for details. :: ldapsearch -LLLQY EXTERNAL -H ldapi:/// -b cn=config "(olcDatabase={1}hdb)" [...] @@ -842,41 +851,48 @@ first. :: /etc/ldap/local/mail.fripost.org-acl.ldif - dn: olcDatabase={1}hdb,cn=config - changetype: modify - add: olcAccess - olcAccess: {0}to dn.children="dc=mail,dc=fripost,dc=org" attrs=userPassword - by self write - by dn.one="ou=managers,dc=mail,dc=fripost,dc=org" write - by anonymous auth - - - add: olcAccess - olcAccess: {1}to dn.one="ou=mailboxes,dc=mail,dc=fripost,dc=org" attrs=children,gn,sn - by self write - by dn.one="ou=managers,dc=mail,dc=fripost,dc=org" write - by * break - - - add: olcAccess - olcAccess: {2}to dn.regex="(.+,)?dc=[^,]+,(uid=[^,]+,ou=mailboxes,dc=mail,dc=fripost,dc=org)$" - by dn.exact,expand="$2" write - by dn.one="ou=managers,dc=mail,dc=fripost,dc=org" write - by * break - - - add: olcAccess - olcAccess: {3}to dn.children="ou=domains,dc=mail,dc=fripost,dc=org" attrs=entry,dc - by dn="cn=SMTP,ou=services,dc=mail,dc=fripost,dc=org" read - by * break - - - add: olcAccess - olcAccess: {4}to dn.children="ou=mailboxes,dc=mail,dc=fripost,dc=org" attrs=entry,dc,uid,maildir,mailLocalAddress,mailTarget - by dn="cn=SMTP,ou=services,dc=mail,dc=fripost,dc=org" read - by * break - - - add: olcAccess - olcAccess: {5}to dn.subtree="dc=mail,dc=fripost,dc=org" - by dn.one="ou=managers,dc=mail,dc=fripost,dc=org" write - by self read - by * search + dn: olcDatabase={1}hdb,cn=config + changetype: modify + # User passwords are only writable (hence readable) by the admins and the + # user him/herself. Anonymous users are only allowed to bind. + add: olcAccess + olcAccess: {0}to dn.children="dc=mail,dc=fripost,dc=org" attrs=userPassword + by self write + by dn.one="ou=managers,dc=mail,dc=fripost,dc=org" write + by anonymous auth + - + # User names are only writable (hence readable) by the admins and the user + # him/herself. + add: olcAccess + olcAccess: {1}to dn.one="ou=mailboxes,dc=mail,dc=fripost,dc=org" attrs=gn,sn + by self write + by dn.one="ou=managers,dc=mail,dc=fripost,dc=org" write + - + # Users are allowed to manage (create/delete/toggle activation) the + # aliases for the domains they own. The SMTP server can read these + # attributes. + add: olcAccess + olcAccess: {2}to dn.regex="(.+,)?(dc=[^,]+,ou=domains,dc=mail,dc=fripost,dc=org)$" + attrs=entry,children,dc,mailLocalAddress,mailTarget,isActive,description + by dn.exact="cn=SMTP,ou=services,dc=mail,dc=fripost,dc=org" read + by set.expand="[$2]/owner & user" write + by dn.one="ou=managers,dc=mail,dc=fripost,dc=org" write + by * none + - + # The SMTP server needs to read the user login and his/her maildir. + add: olcAccess + olcAccess: {3}to dn.one="ou=mailboxes,dc=mail,dc=fripost,dc=org" + attrs=entry,uid,maildir,isActive + by dn.exact="cn=SMTP,ou=services,dc=mail,dc=fripost,dc=org" read + by * break + - + # Admins have writing rights on the branch. Authenticated users can read + # their entry. The SMTP server can search through the branch. + add: olcAccess + olcAccess: {4}to dn.subtree="dc=mail,dc=fripost,dc=org" + by dn.one="ou=managers,dc=mail,dc=fripost,dc=org" write + by self read + by dn.exact="cn=SMTP,ou=services,dc=mail,dc=fripost,dc=org" search ldapmodify -QY EXTERNAL -H ldapi:/// -f /etc/ldap/local/mail.fripost.org-acl.ldif @@ -884,20 +900,25 @@ ldapmodify -QY EXTERNAL -H ldapi:/// -f /etc/ldap/local/mail.fripost.org-acl.ldi :: ldapsearch -LLLQY EXTERNAL -H ldapi:/// -b cn=config "(olcDatabase={1}hdb)" [...] olcAccess: {0}to dn.children="dc=mail,dc=fripost,dc=org" attrs=userPassword by self write by dn.one="ou=managers,dc=mail,dc=fripost,dc=org" write by anonymous auth - olcAccess: {1}to dn.one="ou=mailboxes,dc=mail,dc=fripost,dc=org" attrs=children,gn,sn by self write by dn.one="ou=managers,dc=mail,dc=fripost,dc=org" write - olcAccess: {2}to dn.regex="(.+,)?dc=[^,]+,(uid=[^,]+,ou=mailboxes,dc=mail,dc=fripost,dc=org)$" by dn.exact,expand="$2" write by dn.one="ou=managers,dc=mail,dc=fripost,dc=org" write by * break - olcAccess: {3}to dn.children="ou=domains,dc=mail,dc=fripost,dc=org" attrs=dc,entry by dn="cn=SMTP,ou=services,dc=mail,dc=fripost,dc=org" read by * break - olcAccess: {4}to dn.children="ou=mailboxes,dc=mail,dc=fripost,dc=org" attrs=entry,dc,uid,maildir,mailLocalAddress,mailTarget by dn="cn=SMTP,ou=services,dc=mail,dc=fripost,dc=org" read by * break - olcAccess: {5}to dn.subtree="dc=mail,dc=fripost,dc=org" by dn.one="ou=managers,dc=mail,dc=fripost,dc=org" write by * search - olcAccess: {6}to attrs=userPassword,shadowLastChange by self write by anonymous auth by dn="cn=admin,dc=fripost,dc=org" write by * none - olcAccess: {7}to dn.base="" by * read - olcAccess: {8}to * by self write by dn="cn=admin,dc=fripost,dc=org" write by * read + olcAccess: {1}to dn.one="ou=mailboxes,dc=mail,dc=fripost,dc=org" attrs=gn,sn by self write by dn.one="ou=managers,dc=mail,dc=fripost,dc=org" write + olcAccess: {2}to dn.regex="(.+,)?(dc=[^,]+,ou=domains,dc=mail,dc=fripost,dc=org)$" attrs=entry,children,dc,mailLocalAddress,mailTarget,isActive,description by dn.exact="cn=SMTP,ou=services,dc=mail,dc=fripost,dc=org" read by set.expand="[$2]/owner & user" write by dn.one="ou=managers,dc=mail,dc=fripost,dc=org" write by * none + olcAccess: {3}to dn.one="ou=mailboxes,dc=mail,dc=fripost,dc=org" attrs=entry,uid,maildir,isActive by dn.exact="cn=SMTP,ou=services,dc=mail,dc=fripost,dc=org" read by * break + olcAccess: {4}to dn.subtree="dc=mail,dc=fripost,dc=org" by dn.one="ou=managers,dc=mail,dc=fripost,dc=org" write by self read by dn.exact="cn=SMTP,ou=services,dc=mail,dc=fripost,dc=org" search + olcAccess: {5}to attrs=userPassword,shadowLastChange by self write by anonymous auth by dn="cn=admin,dc=fripost,dc=org" write by * none + olcAccess: {6}to dn.base="" by * read + olcAccess: {7}to * by self write by dn="cn=admin,dc=fripost,dc=org" write by * read [...] Note: Users are here allowed to manage their aliases themselves. Before inserting, we should ensure that aliases are fully qualified with the domain they own! Otherwise it'd be easy to steal aliases and probably even spy on other users... +Note: Users are allowed to manage their domain, but an admin is needed to add a domain to the +tree. A possibility to avoid that with a web-form is to send a mail to the postmaster@example.org +(or even to the mail that appears in the WHOIS) with a confirmation hash. That would simply require +a new ACL with writable [ou=domains,...]/children, and [dc=...,ou=domains,...]/entry. (And probably a +"semi-admin" with only these rights.) + **** Create the base tree :: /etc/ldap/local/mail.fripost.org-base.ldif @@ -957,21 +978,14 @@ To delete a leaf or a sub-tree: maildir: fripost.org/user/ isActive: TRUE - dn: mailTarget=user@fripost.org,uid=user@fripost.org,ou=mailboxes,dc=mail,dc=fripost,dc=org - mailTarget: user@fripost.org - objectClass: top - objectClass: inetLocalMailRecipient - objectClass: virtualAliases - mailLocalAddress: user-alias@fripost.org - isActive: TRUE - - dn: dc=example.org,uid=user@fripost.org,ou=mailboxes,dc=mail,dc=fripost,dc=org + dn: dc=example.org,ou=domains,dc=mail,dc=fripost,dc=org dc: example.org objectClass: top objectClass: virtualDomain + owner: uid=user@fripost.org,ou=mailboxes,dc=mail,dc=fripost,dc=org isActive: TRUE - dn: mailTarget=user@fripost.org,dc=example.org,uid=user@fripost.org,ou=mailboxes,dc=mail,dc=fripost,dc=org + dn: mailTarget=user@fripost.org,dc=example.org,ou=domains,dc=mail,dc=fripost,dc=org mailTarget: user@fripost.org objectClass: top objectClass: inetLocalMailRecipient @@ -1005,6 +1019,12 @@ e.g., `slappasswd -h "{SSHA}"'. **** Check the SASL binds (authentication) +`slapacl' is an helpful tool to debugs the ACLS. For instance, to check what are +the rights of user@fripost.org on the domain example.org, we can run: + slapacl -b 'dc=example.org,ou=domains,dc=mail,dc=fripost,dc=org' -D 'uid=user@fripost.org,ou=mailboxes,dc=mail,dc=fripost,dc=org' + +We can also check ACLs with concrete examples: + ldapwhoami -xD "uid=user@fripost.org,ou=mailboxes,dc=mail,dc=fripost,dc=org" -W should return the whole dn: @@ -1050,9 +1070,9 @@ The user should be able to change his/her password, and aliases in his/her own d dn: uid=user@fripost.org,ou=mailboxes,dc=mail,dc=fripost,dc=org changetype: modify replace: userPassword - userPassword: hop + userPassword: xxxxxx - dn: mailTarget=user@fripost.org,dc=example.org,uid=user@fripost.org,ou=mailboxes,dc=mail,dc=fripost,dc=org + dn: mailTarget=user@fripost.org,dc=example.org,ou=domain,dc=mail,dc=fripost,dc=org changetype: modify add: mailLocalAddress mailLocalAddress: user-alias2@example.org @@ -1075,34 +1095,13 @@ We now ensure that the leaf has been updated: modifiersName: uid=user@fripost.org,ou=mailboxes,dc=mail,dc=fripost,dc=org modifyTimestamp: 20120404215647Z - -Also, he/she's allowed to add new virtual domains: - - :: /tmp/newdomain.ldif - - dn: dc=example2.org,uid=user@fripost.org,ou=mailboxes,dc=mail,dc=fripost,dc=org - objectClass: top - objectClass: virtualDomain - dc: example2.org - isActive: TRUE - - dn: mailTarget=user-alias@fripost.org,dc=example2.org,uid=user@fripost.org,ou=mailboxes,dc=mail,dc=fripost,dc=org - mailTarget: user-alias@fripost.org - objectClass: top - objectClass: inetLocalMailRecipient - objectClass: virtualAliases - isActive: TRUE - mailLocalAddress: user@example2.org - -ldapadd -D "uid=user@fripost.org,ou=mailboxes,dc=mail,dc=fripost,dc=org" -W -f /tmp/newdomain.ldif - On other modifications, for instance of `maildir', `ldapmodify' should refuse with `Insufficient access (50)'. *** Configuring the main IMAP server **** Install packages -sudo aptitude install postfix postfix-mysql +sudo aptitude install postfix postfix-ldap **** /etc/postfix/main.cf @@ -1184,7 +1183,7 @@ http://www.tehinterweb.co.uk/roundcube/#pisieverules server_host = ldap://localhost/ version = 3 - search_base = dc=mail,dc=fripost,dc=org + search_base = ou=domains,dc=mail,dc=fripost,dc=org bind = yes bind_dn = cn=SMTP,ou=services,dc=mail,dc=fripost,dc=org bind_pw = xxxxxx @@ -1201,7 +1200,7 @@ Test it: server_host = ldap://localhost/ version = 3 - search_base = ou=mailboxes,dc=mail,dc=fripost,dc=org + search_base = ou=domains,dc=mail,dc=fripost,dc=org bind = yes bind_dn = cn=SMTP,ou=services,dc=mail,dc=fripost,dc=org bind_pw = xxxxxx -- cgit v1.2.3