Add Apple Address Book + LDAP information.
[blog.git] / posts / LDAP.mdwn
1 I'm using [LDAP][] ([RFC 4510][rfc4510]) to maintain a centralized
2 address book at home.  Here are my setup notes, mostly following
3 Gentoo's [LDAP howto][howto].
4
5 Install [OpenLDAP][] with the `ldap` USE flag enabled:
6
7     # emerge -av openldap
8
9 If you get complaints about a `cyrus-sasl` ↔ `openldap` dependency
10 cycle, you should temporarily (or permanently) disable the `ldap` USE
11 flag for `cyrus-sasl`:
12
13     # echo 'dev-libs/cyrus-sasl -ldap' > /etc/portage/package.use/ldap
14     # -ldap" emerge -av1 cyrus-sasl
15     # emerge -av openldap
16
17 Generate an administrative password:
18
19     $ slappasswd 
20     New password: 
21     Re-enter new password: 
22     {SSHA}EzP6I82DZRnW+ou6lyiXHGxSpSOw2XO4
23
24 Configure the `slapd` LDAP server.  Here is a very minimal
25 configuration, read the [OpenLDAP Admin Guide][admin] for details:
26
27     # emacs /etc/openldap/slapd.conf
28     # cat /etc/openldap/slapd.conf
29     include         /etc/openldap/schema/core.schema
30     include         /etc/openldap/schema/cosine.schema
31     include         /etc/openldap/schema/inetorgperson.schema
32     pidfile         /var/run/openldap/slapd.pid
33     argsfile        /var/run/openldap/slapd.args
34     database        hdb
35     suffix          "dc=example,dc=com"
36     checkpoint      32      30
37     rootdn          "cn=Manager,dc=example,dc=com"
38     rootpw          {SSHA}EzP6I82DZRnW+ou6lyiXHGxSpSOw2XO4
39     directory       /var/lib/openldap-data
40     index   objectClass     eq
41
42 Note that [inetorgperson][] is huge, but it's standardized.  I think
43 it's better to pick a big standard right off, than to outgrow
44 something smaller and need to migrate.
45
46 Gentoo creates the default database directory for you, so you can ignore warnings about needing to create it yourself.
47
48 Configure LDAP client access.  Again, read the docs for details on
49 adapting this to your particular situation:
50
51     # emacs /etc/openldap/ldap.conf
52     $ cat /etc/openldap/ldap.conf
53     BASE    dc=example,dc=com
54     URI     ldap://ldapserver.example.com
55
56 You can edit '/etc/conf.d/slapd' if you want command line options
57 passed to `slapd` when the service starts, but the defaults looked
58 fine to me.
59
60 Start `slapd`:
61
62     # /etc/init.d/slapd start
63
64 Add it to your default runlevel:
65
66     # eselect rc add /etc/init.d/slapd default
67
68 Test the server with
69
70     $ ldapsearch -x -b '' -s base '(objectclass=*)'
71
72 Build a hierarchy in your database (this will depend on your
73 organizational structure):
74
75     $ emacs /tmp/people.ldif
76     $ cat /tmp/people.ldif
77     version: 1
78
79     dn: dc=example, dc=com
80     objectClass: dcObject
81     objectClass: organization
82     o: Example, Inc.
83     dc: example
84
85     dn: ou=people, dc=example,dc=com
86     objectClass: organizationalUnit
87     ou: people
88     description: All people in organisation
89
90     dn: cn=Manager, dc=example,dc=com
91     objectClass: organizationalRole
92     cn: Manager
93     description: Directory Manager
94     $ ldapadd -D "cn=Manager,dc=example,dc=com" -xW -f /tmp/people.ldif
95     $ rm /tmp/people.ldif
96
97 abook
98 -----
99
100 If you currently keep your addresses in [abook][], you can export them
101 to [LDIF][] with:
102
103     $ abook --convert --infile ~/.abook/addressbook --outformat ldif \
104       | abook-ldif-cleanup.py --basedn 'ou=people,dc=example,dc=com' > dump.ldif
105
106 where [[abook-ldif-cleanup.py]] does some compatibility processing
107 using the [python-ldap][] module.
108
109 Add the people to your LDAP database:
110
111     $ ldapadd -D "cn=Manager,dc=example,dc=com" -xW -f dump.ldif
112
113 To check if that worked, you can list all the entries in your
114 database:
115
116     $ ldapsearch -x -b 'dc=example,dc=com' '(objectclass=*)'
117
118 Then remove the temporary files:
119
120     $ rm -rf dump.ldif
121
122 Aliases
123 -------
124
125 Ok, we've put lots of people into the `people` OU, but what if we want
126 to assign them to another department?  We can use aliases ([RFC
127 4512][rfc4512]), the symlinks of the LDAP world.  To see how this
128 works, lets create a test OU to play with:
129
130     $ emacs /tmp/test.ldif
131     $ cat /tmp/test.ldif
132     version: 1
133     dn: ou=test, dc=example,dc=com
134     objectClass: organizationalUnit
135     ou: testing
136     $ ldapadd -D "cn=Manager,dc=example,dc=com" -xW -f /tmp/test.ldif
137     $ rm /tmp/test.ldif
138
139 Now assign one of your people to that group:
140
141     $ emacs /tmp/alias.ldif
142     $ cat /tmp/alias.ldif
143     version: 1
144     dn: cn=Jane Doe, ou=test,dc=example,dc=com
145     objectClass: alias
146     aliasedObjectName: cn=Jane Doe, ou=people,dc=example,dc=com
147     $ ldapadd -D "cn=Manager,dc=example,dc=com" -xW -f /tmp/alias.ldif
148     $ rm /tmp/alias.ldif
149
150 The `extensibleObject` class allows us to add the DN field, without it
151 you get:
152
153     $ ldapadd -D "cn=Manager,dc=example,dc=com" -xW -f /tmp/alias.ldif
154     Enter LDAP Password: 
155     adding new entry "cn=Jane Doe, ou=test,dc=example,dc=com"
156     ldap_add: Object class violation (65)
157             additional info: attribute 'cn' not allowed
158
159 You can search for all entries (including aliases) with
160
161     $ ldapsearch -x -b 'ou=test, dc=example,dc=com' '(objectclass=*)'
162     ...
163     dn: cn=Jane Doe,ou=test,dc=example,dc=com
164     objectClass: alias
165     objectClass: extensibleObject
166     aliasedObjectName:: Y249TWljaGVsIFZhbGxpw6hyZXMsb3U9cGVvcGxlLGRjPXRyZW1pbHksZGM9dXM=
167     ...
168
169 You can control dereferencing with the `-a` option:
170
171     $ ldapsearch -x -a always -b 'ou=test, dc=example,dc=com' '(objectclass=*)'
172     ...
173     dn: cn=Jane Doe,ou=people,dc=example,dc=com
174     cn: Jane Doe
175     sn: Doe
176     ...
177
178 Once you've played around, you can remove the `test` OU and its
179 descendants:
180
181     $ ldapdelete -D "cn=Manager,dc=example,dc=com" -xW -r ou=test,dc=example,dc=com
182
183 shelldap
184 --------
185
186 There are a number of tools to make it easier to manage LDAP
187 databases.  Command line junkies will probably like [shelldap][]:
188
189     $ shelldap --server ldapserver.example.com
190     ~ > ls
191     cn=Manager
192     ou=people
193     ~ > cat cn=Manager 
194     
195     dn: cn=Manager,dc=example,dc=com
196     objectClass: organizationalRole
197     cn: Manager
198     
199     ~ > cd ou=people 
200     ou=people,~ > ls
201
202 Mutt
203 ----
204
205 If you use the [[Mutt]] email client (or just want a simple way to
206 query email addresses from the command line) there are a [number of
207 scripts][mutts] available.  Pick whichever sounds most appealing to
208 you.  I wrote up [[mutt-ldap.py]], which lets you configuration the
209 connection details via a config file (`~/.mutt-ldap.rc`) rather than
210 editing the script itself.  Usage details are available in the
211 docstring.
212
213 Apple Address Book
214 ------------------
215
216 You can configure Apple's [Address Book][aab] to search an LDAP
217 directory.  See [[Humanizing_OS_X]] for details.
218
219 SSL/TLS
220 -------
221
222 It took me a bit of work to get [SSL/TLS][] working with my
223 [[GnuTLS]]-linked OpenLDAP.  First, you'll probably need to generate
224 new SSL/TLS keys (`/etc/openldap/ssl/*`) with [certtool][] (see
225 [[X.509_certificates]]).  Then add the following lines to
226 `/etc/openldap/slapd.conf`:
227
228     TLSCipherSuite NORMAL
229     TLSCACertificateFile /etc/openldap/ssl/ca.crt
230     TLSCertificateFile /etc/openldap/ssl/ldap.crt
231     TLSCertificateKeyFile /etc/openldap/ssl/ldap.key
232     TLSVerifyClient never
233
234 Where `ca.crt`, `ldap.crt`, and `ldap.key` are your new CA,
235 certificate, and private key.  If you want to disable unencrypted
236 connections completely, remove the `ldap://` entry from your `slapd`
237 command line by editing (on Gentoo) `/etc/conf.d/slapd` so it has
238
239     OPTS="-h 'ldaps:// ldapi://%2fvar%2frun%2fopenldap%2fslapd.sock'"
240
241 Now you should be able to restart `slapd` so it will use the new
242 configuration.
243
244 Have clients running on your server use the local socket by editing
245 `/etc/openldap/ldap.conf` to set:
246
247     URI     ldapi://%2fvar%2frun%2fopenldap%2fslapd.sock
248
249 Test your server setup by running (on the server)
250
251     $ ldapsearch -x -b '' -s base '(objectclass=*)'
252
253 Copy your CA over to any client machines (I put it in
254 `/etc/openldap/ssl/ldapserver.crt`), and set them up with the
255 following two lines in `/etc/openldap/ldap.conf`:
256
257     URI         ldaps://ldapserver.example.com
258     TLS_CACERT  /etc/openldap/ssl/ldapserver.crt
259
260 Test your client setup by running (on the client)
261
262     $ ldapsearch -x -b '' -s base '(objectclass=*)'
263
264 You can configure `shelldap` with the following lines in
265 `~/.shelldap.rc`:
266
267     server: ldaps://ldapserver.example.com
268     tls: yes
269     tls_cacert: /etc/openldap/ssl/ldapserver.crt
270
271 You can configure `mutt-ldap.py` with the following lines in
272 `~/.mutt-ldap.rc`:
273
274     port = 636
275     ssl = yes
276
277 References
278 ----------
279
280 There's a [good overview][schema] of schema and objectclasses by Brian
281 Jones on O'Reilly.  If you want to use inetOrgPerson but also include
282 the countryName attribute, ...
283
284 [LDAP]: http://en.wikipedia.org/wiki/LDAP
285 [rfc4510]: http://tools.ietf.org/html/rfc4510
286 [howto]: http://www.gentoo.org/doc/en/ldap-howto.xml
287 [OpenLDAP]: http://www.openldap.org/
288 [admin]: http://www.openldap.org/doc/admin/
289 [inetorgperson]: http://www.apps.ietf.org/rfc/rfc2798.html
290 [abook]: http://abook.sourceforge.net/
291 [LDIF]: http://en.wikipedia.org/wiki/LDAP_Data_Interchange_Format
292 [python-ldap]: http://www.python-ldap.org/
293 [rfc4512]: http://tools.ietf.org/html/rfc4512
294 [shelldap]: http://projects.martini.nu/shelldap/
295 [mutts]: http://wiki.mutt.org/?QueryCommand
296 [aab]: http://support.apple.com/kb/ht2486
297 [SSL/TLS]: http://en.wikipedia.org/wiki/Transport_Layer_Security
298 [certtool]:http://www.gnu.org/software/gnutls/manual/html_node/Invoking-certtool.html#Invoking-certtool
299 [schema]: http://www.oreillynet.com/pub/a/sysadmin/2006/11/09/demystifying-ldap-data.html
300
301 [[!tag tags/linux]]
302 [[!tag tags/tools]]