Add LDAP post.
[blog.git] / posts / LDAP.mdwn
diff --git a/posts/LDAP.mdwn b/posts/LDAP.mdwn
new file mode 100644 (file)
index 0000000..8d2899f
--- /dev/null
@@ -0,0 +1,220 @@
+I'm using [LDAP][] ([RFC 4510][rfc4510]) to maintain a centralized
+address book at home.  Here are my setup notes, mostly following
+Gentoo's [LDAP howto][howto].
+
+Install [OpenLDAP][] with the `ldap` USE flag enabled:
+
+    # emerge -av openldap
+
+If you get complaints about a `cyrus-sasl` ↔ `openldap` dependency
+cycle, you should temporarily (or permanently) disable the `ldap` USE
+flag for `cyrus-sasl`:
+
+    # echo 'dev-libs/cyrus-sasl -ldap' > /etc/portage/package.use/ldap
+    # -ldap" emerge -av1 cyrus-sasl
+    # emerge -av openldap
+
+Generate an administrative password:
+
+    $ slappasswd 
+    New password: 
+    Re-enter new password: 
+    {SSHA}EzP6I82DZRnW+ou6lyiXHGxSpSOw2XO4
+
+Configure the `slapd` LDAP server.  Here is a very minimal
+configuration, read the [OpenLDAP Admin Guide][admin] for details:
+
+    # emacs /etc/openldap/slapd.conf
+    # cat /etc/openldap/slapd.conf
+    include         /etc/openldap/schema/core.schema
+    include         /etc/openldap/schema/cosine.schema
+    include         /etc/openldap/schema/inetorgperson.schema
+    pidfile         /var/run/openldap/slapd.pid
+    argsfile        /var/run/openldap/slapd.args
+    database        hdb
+    suffix          "dc=example,dc=com"
+    checkpoint      32      30
+    rootdn          "cn=Manager,dc=example,dc=com"
+    rootpw          {SSHA}EzP6I82DZRnW+ou6lyiXHGxSpSOw2XO4
+    directory       /var/lib/openldap-data
+    index   objectClass     eq
+
+Note that [inetorgperson][] is huge, but it's standardized.  I think
+it's better to pick a big standard right off, than to outgrow
+something smaller and need to migrate.
+
+Gentoo creates the default database directory for you, so you can ignore warnings about needing to create it yourself.
+
+Configure LDAP client access.  Again, read the docs for details on
+adapting this to your particular situation:
+
+    # emacs /etc/openldap/ldap.conf
+    $ cat /etc/openldap/ldap.conf
+    BASE    dc=example,dc=com
+    URI     ldap://ldapserver.example.com
+
+You can edit '/etc/conf.d/slapd' if you want command line options
+passed to `slapd` when the service starts, but the defaults looked
+fine to me.
+
+Start `slapd`:
+
+    # /etc/init.d/slapd start
+
+Add it to your default runlevel:
+
+    # eselect rc add /etc/init.d/slapd default
+
+Test the server with
+
+    $ ldapsearch -x -b '' -s base '(objectclass=*)'
+
+Build a hierarchy in your database (this will depend on your
+organizational structure):
+
+    $ emacs /tmp/people.ldif
+    $ cat /tmp/people.ldif
+    version: 1
+
+    dn: dc=example, dc=com
+    objectClass: dcObject
+    objectClass: organization
+    o: Example, Inc.
+    dc: example
+
+    dn: ou=people, dc=example,dc=com
+    objectClass: organizationalUnit
+    ou: people
+    description: All people in organisation
+
+    dn: cn=Manager, dc=example,dc=com
+    objectClass: organizationalRole
+    cn: Manager
+    description: Directory Manager
+    $ ldapadd -D "cn=Manager,dc=example,dc=com" -xW -f /tmp/people.ldif
+    $ rm /tmp/people.ldif
+
+abook
+-----
+
+If you currently keep your addresses in [abook][], you can export them
+to [LDIF][] with:
+
+    $ abook --convert --infile ~/.abook/addressbook --outformat ldif \
+      | abook-ldif-cleanup.py --basedn 'ou=people,dc=example,dc=com' > dump.ldif
+
+where [[abook-ldif-cleanup.py]] does some compatibility processing
+using the [python-ldap][] module.
+
+Add the people to your LDAP database:
+
+    $ ldapadd -D "cn=Manager,dc=example,dc=com" -xW -f dump.ldif
+
+To check if that worked, you can list all the entries in your
+database:
+
+    $ ldapsearch -x -b 'dc=example,dc=com' '(objectclass=*)'
+
+Then remove the temporary files:
+
+    $ rm -rf dump.ldif
+
+Aliases
+-------
+
+Ok, we've put lots of people into the `people` OU, but what if we want
+to assign them to another department?  We can use aliases ([RFC
+4512][rfc4512]), the symlinks of the LDAP world.  To see how this
+works, lets create a test OU to play with:
+
+    $ emacs /tmp/test.ldif
+               $ cat /tmp/test.ldif
+               version: 1
+    dn: ou=test, dc=example,dc=com
+    objectClass: organizationalUnit
+    ou: testing
+    $ ldapadd -D "cn=Manager,dc=example,dc=com" -xW -f /tmp/test.ldif
+    $ rm /tmp/test.ldif
+
+Now assign one of your people to that group:
+
+         $ emacs /tmp/alias.ldif
+    $ cat /tmp/alias.ldif
+               version: 1
+               dn: cn=Jane Doe, ou=test,dc=example,dc=com
+               objectClass: alias
+               aliasedObjectName: cn=Jane Doe, ou=people,dc=example,dc=com
+    $ ldapadd -D "cn=Manager,dc=example,dc=com" -xW -f /tmp/alias.ldif
+    $ rm /tmp/alias.ldif
+
+The `extensibleObject` class allows us to add the DN field, without it
+you get:
+
+    $ ldapadd -D "cn=Manager,dc=example,dc=com" -xW -f /tmp/alias.ldif
+               Enter LDAP Password: 
+               adding new entry "cn=Jane Doe, ou=test,dc=example,dc=com"
+    ldap_add: Object class violation (65)
+            additional info: attribute 'cn' not allowed
+
+You can search for all entries (including aliases) with
+
+    $ ldapsearch -x -b 'ou=test, dc=example,dc=com' '(objectclass=*)'
+    ...
+    dn: cn=Jane Doe,ou=test,dc=example,dc=com
+    objectClass: alias
+    objectClass: extensibleObject
+    aliasedObjectName:: Y249TWljaGVsIFZhbGxpw6hyZXMsb3U9cGVvcGxlLGRjPXRyZW1pbHksZGM9dXM=
+    ...
+
+You can control dereferencing with the `-a` option:
+
+    $ ldapsearch -x -a always -b 'ou=test, dc=example,dc=com' '(objectclass=*)'
+    ...
+    dn: cn=Jane Doe,ou=people,dc=example,dc=com
+    cn: Jane Doe
+    sn: Doe
+    ...
+
+Once you've played around, you can remove the `test` OU and its
+descendants:
+
+    $ ldapdelete -D "cn=Manager,dc=example,dc=com" -xW -r ou=test,dc=example,dc=com
+
+shelldap
+--------
+
+There are a number of tools to make it easier to manage LDAP
+databases.  Command line junkies will probably like [shelldap][]:
+
+    $ shelldap --server ldapserver.example.com
+    ~ > ls
+    cn=Manager
+    ou=people
+    ~ > cat cn=Manager 
+    
+    dn: cn=Manager,dc=example,dc=com
+    objectClass: organizationalRole
+    cn: Manager
+    
+    ~ > cd ou=people 
+    ou=people,~ > ls
+
+References
+----------
+
+There's a [good overview][schema] of schema and objectclasses by Brian
+Jones on O'Reilly.  If you want to use inetOrgPerson but also include
+the countryName attribute, ...
+
+[LDAP]: http://en.wikipedia.org/wiki/LDAP
+[rfc4510]: http://tools.ietf.org/html/rfc4510
+[howto]: http://www.gentoo.org/doc/en/ldap-howto.xml
+[OpenLDAP]: http://www.openldap.org/
+[admin]: http://www.openldap.org/doc/admin/
+[inetorgperson]: http://www.apps.ietf.org/rfc/rfc2798.html
+[abook]: http://abook.sourceforge.net/
+[LDIF]: http://en.wikipedia.org/wiki/LDAP_Data_Interchange_Format
+[python-ldap]: http://www.python-ldap.org/
+[rfc4512]: http://tools.ietf.org/html/rfc4512
+[shelldap]: http://projects.martini.nu/shelldap/
+[schema]: http://www.oreillynet.com/pub/a/sysadmin/2006/11/09/demystifying-ldap-data.html