Using OpenLDAP as an Address Book

One of the best uses for LDAP is as an address book. Whether this is a company white pages or a personal (or distributed) email address book, LDAP makes for a great means of storing addresses that are not often changed.

This will detail my own personal experiences in setting up OpenLDAP to serve as an address book for a number of different applications. I use mutt as my email client on Mac OS X (previously used it on Linux) and mutt’s aliases file served as a half-decent address book, although it was not portable at all. For instance, if I chose to use Mozilla to compose an email, or Apple’s Mail.app, I would have to view my mutt aliases file in order to find appropriate addresses. Using LDAP, I can avoid this and have Mozilla, Mail.app, and mutt all use the same source for obtaining email addresses.

Setting this up is a bit of chore, thus this topic. A few different tools are involved to get this setup working, and it should work with virtually any email client that supports LDAP (most do), and you can even use an intermediate tool called The Little Brother’s Database (lbdb) to help out (in fact, for mutt it’s pretty much a requirement).

We’ll look at getting mutt to use lbdb to access LDAP data (and the OS X Address Book for you Mac users), getting Mozilla to use it, and getting the OS X Address Book to use it as well. First, however, you must have OpenLDAP properly configured; something that can be done by following the Using OpenLDAP for User Authentication topic (just ignore the PAM/NSS and other authentication-specific items).

Creating the Address Book

The first step is to create the Address Book, and this can be extremely tedious the first time around. You need to create a LDIF file containing the skeleton for your new Organizational Unit (we’ll assume you are using ou=People for user authentication; if you’re not, feel free to use that OU). In this case, we will create a new OU called “email” which will be used solely to store email addresses. The LDIF file would look like this:

dn: ou=email,dc=mylan,dc=net
ou: email
objectClass: organizationalUnit

Of course, change the suffix to suit your setup (here it is dc=mylan,dc=net). Import this into the directory to create the structure by using:

# ldapadd -h localhost -D "cn=root,dc=mylan,dc=net" -W -x -f addr-skel.ldif

Change the parameters to, again, suit your setup. The “-h” option indicates the host to connect to (in this case, localhost), the “-D” option indicates the DN to bind as (in this case cn=root,dc=mylan,dc=net which would be your administrator DN). We also tell ldapadd we want to be prompted for our bind DN’s password, use simple authentication, and import the data from the file addr-skel.ldif (which would contain the contents noted above).

Once this is done, you can begin working on a new LDIF file (which we’ll call addr.ldif) which contains the actual entries. You’re not restricted to only using email addresses; you can specify any information you like provided by the organizationalUnit objectClass. The following are two example entries; the first with minimal data, the latter with a lot more.

# Vincent Danen
dn: cn=Vincent Danen,ou=email,dc=mylan,dc=net
cn: Vincent Danen
givenName: Vincent
sn: Danen
mail: vdanen@nospam.net
objectClass: inetOrgPerson

# Joe User
dn: cn=Joe User,ou=email,dc=mylan,dc=net
cn: Joe User
givenName: Joe
sn: User
mail: joe@nospam.net
labeledURI: http://linsec.ca/
telephoneNumber: 800-111-2222
postalAddress: 123 45 Nowhere Ave, Edmonton, AB, T1X 1T1
objectClass: inetOrgPerson

The first entry contains a few items: the DN for the entry, the CN (or Common Name), the givenName (first name), the SN, (surname), and a mail entry. This is all you really need if you’re aiming for just an email address book. The latter entry contains the same thing but also labeledURI (a URL), a telephone number, and postal address. This may be more useful for a company whitepages. There are a lot of other types you can use; take a look at the inetorgperson.schema for a full list.

Yes, this is the tedious part. Copy and pasting helps alleviate the pain to some degree. Scripts could probably be written quite easily to parse a flat file and generate the LDIF for you with a little bit of perl magic. That would save a lot of time. At any rate, once you have completed your addr.ldif file (or done as much as you can stand), you can import the entries into the directory by using ldapadd again and providing it with addr.ldif as the filename to import.

Once you have done this, use ldapsearch to verify that the data is available.

# ldapsearch -LL -H ldap://localhost -x "(mail=*) mail
version: 1

dn: cn=Vincent Danen,ou=email,dc=mylan,dc=net
mail: vdanen@nospam.net

dn: cn=Joe User,ou=email,dc=mylan,dc=net
mail: joe@nospam.net

The ldapsearch command will list all DN’s with a mail entry (so if you use LDAP for authentication as well, you’ll likely see some entries from ou=People as well). If your output is returned similar to the above, your address book works.

Modifying Entries in the Address Book

TODO

Configuring lbdb

The next step is to configure lbdb to use LDAP as a query source for mutt. Download lbdb from the homepage (as of this writing, the latest version is 0.27) and untar the file somewhere like /usr/local/src. Compiling lbdb is extremely straightforward:

# cd /usr/local/src/lbdb-0.27
# ./configure
# make
# make install

This will install lbdb into /usr/local. Create a new configuration file for lbdb in ~/.lbdbrc that looks something like this:

# lbdb config file

# methods to search
METHODS="m_ldap m_muttalias m_osx_addressbook"
# modules location
MODULES_PATH="/usr/local/lib"
# ldap nicks
LDAP_NICKS="ldap"

Here we define what methods we want to use (or what sources we want to search). In this case, we want to use the m_ldap method (which uses mutt_ldap_query to query the LDAP server), m_muttalias (which queries our local mutt aliases file), and (for the OS X users), m_osx_addressbook (which queries the OS X Address Book). Order is important since, by default, lbdb filters out duplicates. The last duplicate remains, so the methods listed last have a higher precedence. In this case, if an address is matched in all three methods, the one in the OS X Address Book is shown. We also specify the path that contains the modules ($prefix/lib or /usr/local/lib by default); this is the directory that contains the actual methods files. Finally, we specify our LDAP nicknames with the LDAP_NICKS keyword. More on this in a moment.

lbdb uses /usr/local/lib/mutt_ldap_query to do the actual lookups, and this is a perl script that requires the Net::LDAP perl module. If you don’t have this installed, you can install from RPM or DEB packages if your vendor provides it, or use CPAN to install it. Installing from RPM and DEB files is pretty self-explanatory, so if you don’t have one available to you, you’ll need to install via CPAN using something like this:

# perl -MCPAN -e 'install Bundle::Net::LDAP'

If this is your first time using CPAN to install a perl module, you’ll have to answer a few questions to get things configured correctly, but it’s pretty straightforward. Once this is completed, you’ll need to edit the /usr/local/lib/mutt_ldap_query file directly to set the $prefix variable, otherwise it will die with errors. Simply modify the file to look like this:

my $config_file = ' ';
my $prefix = '/usr/local';

Where you’re adding the line {{{1}}} below the $config_file variable declaration.

Next create a configuration file for mutt_ldap_query; the best to use is ~/.mutt_ldap_query.rc. It should look something like this:

# mutt_ldap resource file

# The format of each entry of the ldap server database is the following:
# LDAP_NICKNAME => ['LDAP_SERVER',
#                   'LDAP_SEARCH_BASE',
#                   'LDAP_SEARCH_FIELDS',
#                   'LDAP_EXPECTED_ANSWERS',
#                   'LDAP_RESULT_EMAIL',
#                   'LDAP_RESULT_REALNAME',
#                   'LDAP_RESULT_COMMENT',
#                   IGNORANT],
# (IGNORANT is an optional argument. If you set it to 1, mutt_ldap_query
# uses wildcards *foo* for searching).

%ldap_server_db = (
  'ldap'     => ['ldap.mylan.net', 'ou=email,dc=mylan,dc=net', 'cn sn givenname mail', 'cn sn givenname mail', '${mail}', '${givenname} ${sn}', '(LDAP)', '1']
);

$ldap_server           = 'ldap.mylan.net';
$search_base           = 'ou=email,dc=mylan,dc=net';
$ldap_search_fields    = 'givenname sn cn mail';
$ldap_expected_answers = 'givenname sn cn mail';
$ldap_result_email     = '${mail}';
$ldap_result_realname  = '${givenname} ${sn}';
$ldap_result_comment   = '(LDAP)';
$ignorant              = 0;

$prefix                = '/usr/local';

Essentially, we are defining the same thing in two places; an LDAP server with the nick name “ldap” (remember the LDAP_NICKS setting in ~/.lbdbrc?), which has a hostname of “ldap.mylan.net”. Our search base is “ou=email,dc=mylan,dc=net”. We’re looking for a few specific items, particularly the common name (cn), surname (sn), first name (givenname), and email address (mail) records from the LDAP directory. I also found it necessary to define the $prefix variable in the file directly, otherwise mutt_ldap_query would complain and give errors.

Once this is done, you can give it a test. The program used to query the various sources of information is lbdbq, so we execute it with what we’re searching for:

$ lbdbq vdanen
lbdbq: 1 matches
vdanen@nospam.net Vincent Danen   (LDAP)

If you get the above without any errors, congratulations! If you do encounter some difficulties, make sure that you have Net::LDAP installed, that your configuration files are correct, and that you’ve told lbdb to look in the right place for the methods files.

Configuring mutt

Configuring mutt is the easiest part of this entire exercise. Edit your mutt configuration file (ie. ~/.muttrc) and add:

set query_command="/usr/local/bin/lbdbq %s" # query tlr's little brothers database.

At this point, you can use the query command in mutt to search for email addresses using lbdb. By default this is <ESC>q in mutt. When you hit this key combination, you will be prompted for a Query string. Enter your search string, press enter, and you’ll get a list of matching addresses from lbdb’s output. Move your cursor to highlight the address you were looking for, press enter, and you’ll be composing an email to that person.

Configuring Apple’s Address Book

The Address Book tool in OS X also has the ability to query and search from an LDAP database. It’s quite simple to configure Address Book to search through as many LDAP servers as you like. Launch Address Book and go into the Preferences. There are two tabs here; “General” and “LDAP”. Click on the “LDAP” tab and then click on the “Add” button near the bottom of the panel.

Give the LDAP directory a name to describe it and define the FQDN for the server itself (ie. ldap.mylan.net). The Search Base should be “ou=email,dc=mylan,dc=net”; the OU you defined when first creating your directory structure. The port should be 389 unless your LDAP server uses a non-standard port, and the scope should be Subtree. Save your entry and make sure that it is marked active in the LDAP tab list.

Close the Preferences and go back to the Address Book main window. In the Group column you should have at least two rows: “All” and “Directories” (possibly more if you created your own groups). Click on “Directories” and then click on the name of your newly defined LDAP directory (or “All”, which would allow Address Book to search in multiple LDAP directories).

Unfortunately, you won’t get any data out of the LDAP directory unless you search for it, similar to using lbdb. In the search text entry field, type in your search criteria and as you type, Address Book will start searching the directory and will display the results in the final column. If you chose to include more data than just an email address, you may be disappointed to see that you can’t view it all; all you will see is the givenName and sn entries (combined in the Name column) and either the Email address or Phone number in the last column. All the other data that may be in the directory is left there.

Another option is Addressbook4LDAP which is both an address book and contact-centric LDAP tool for OS X.

Configuring Mozilla

Mozilla is not as straightforward as Address Book, but it’s also a little more flexible. To configure Mozilla to use a directory, go into the Mozilla preferences, then “Mail & Newsgroups” then “Addressing”. In this section, under “Address Autocompletion” is a checkbox allowing you to enable or disable “Directory Server”. Click on the checkbox to activate it, then click on the “Edit Directories…” button. A new window should pop up listing your defined LDAP servers, but since none are currently defined, click the “Add” button. Here you can define the name (or alias) of the LDAP server, the hostname for it (ie. ldap.mylan.net), the Base DN (ie. “ou=email,dc=mylan,dc=net”), port number, and you can even specify a DN to bind as (leaving this blank will allow you to bind anonymously). If you like, you can use SSL to connect to the LDAP server as well. Save the entry and exit Preferences and fire up the Address Book. In the Address Books column you should see three entries (more if you added them, of course): Personal Address Book, Collected Addresses, and the name of the LDAP server you defined.

To search the LDAP directory, type in your search criteria in the “Name or Email contains” search box and press enter. You’ll see the matching entries show up in the column view below.

Resources