Putting OpenLDAP to Work
Information inside an LDAP directory is stored in "entries". Each entry is a collection of attributes that have a globally unique Distinguished Name (DN), which contain a type and one or more values. An example of a type would be "mail", the value of which is an e-mail address. On the LDAP server, this information is arranged in a tree-like fashion from top to bottom. Typically, at the top of this tree you define the country (c=US) or domain (dc=com). Below this, we might have an organization (o=Acme) and organizational units (ou=People). An organizational unit can contain all your Human Resource employees, printers in a building or any other kind of category. In turn, each attribute contained under the organizational unit is controlled by an objectClass. The value of each objectClass attribute obeys a schema or set of rules that add attribute capabilities to your directory. For example, the inetorgPerson objectClass requires the sn (surname) and cn (common name) attributes but also allows optional entries like mail, telephoneNumber and localityName (see example below).
Designing the directory structure is one of the most important aspects of LDAP. We are going to use a simple example, which we will access with Netscape Address Book. Suppose there is a company called Acme (o=Acme), which is located in several states throughout the US (c=US). Acme wants to implement a small address book server for all its employees. We start out with a simple organizational DN.
dn: o=Acme, c=US
All of Acme's organizations and attributes will be stored under this DN, which is unique to the directory stored on the server. Acme wants to organize its employees under two departments, Managers (ou=Managers) and Employees (ou=Employees). The resulting relative distinguished names (RDN), meaning relative to the top DN, are
dn: ou=Managers, o=Acme, c=US dn: ou=Employees, o=Acme, c=US
Below you will see the hierarchical structure forming, with US at the top, down to our Management organizational unit and, thus, each individual employee. Acme is just starting out, so let's begin by constructing one manager and two employee entries.
dn: cn=Jason H. Smith, ou=Managers, o=Acme, c=US dn: cn=Ray D. Jones, ou=Employees, o=Acme, c=US dn: cn=Eric S. Woods, ou=Employees, o=Acme, c=US
To reference the common name entry Jason H. Smith, LDAP starts by taking the RDN cn=Jason H. Smith, and concatenating the previous parent entries till it reaches the top level DN.
cn=Jason H. Smith + ou=Managers + o=Acme + c=US -> cn=Jason H. Smith, ou=Managers, o=Acme, c=US
Now that we have the basic structure for our directory, importing the data is next. We will place all this information into an LDIF file. LDIF is the default file format for importing directory information. You can easily write Perl scripts to automate the creation of LDIF data files from system files such as /etc/passwd, NIS or you can grab the excellent migration scripts from the resource sidebar below.
The listing shows our test data, save the information as testdata.ldif. More information on this file format can be found in the LDIF man pages, sections five and eight.
Acme DN, which must exist in the directory before we can add any organizational units
dn: o=Acme, c=US objectClass: organization
The o attribute is required here
Manager organization unit DN. This entry must exist in the directory before we can add any managers.
dn: ou=Managers, o=Acme, c=US objectClass: organizationalUnit
The ou attribute is required here
The first manager DN
dn: cn=Jason H. Smith, ou=Managers, o=Acme, c=US objectClass: inetOrgPerson
Both cn and sn are required attributes
cn: Jason H. Smith sn: Smith
But these are optional attributes
telephoneNumber: 111-222-9999 mail: firstname.lastname@example.org localityName: Houston
We can define another organizational unit
dn: ou=Employees, o=Acme, c=US objectClass: organizationalUnit ou: Employees
And add employees below
dn: cn=Ray D. Jones, ou=Employees, o=Acme, c=US objectClass: inetOrgPerson cn: Ray D. Jones sn: Jones telephoneNumber: 444-555-6767 mail: email@example.com localityName: Houston dn: cn=Eric S. Woods, ou=Employees, o=Acme, c=US objectClass: inetOrgPerson cn: Eric S. Woods sn: Woods telephoneNumber: 444-555-6768 mail: firstname.lastname@example.org localityName: Houston
Now we need to setup OpenLDAP to accept the import of our directory structure and provide access to our address book in Netscape. One of the common questions asked on the OpenLDAP mailing lists is, "How do I get Netscape's address book to use my LDAP server?" Hosting address book information is a frequent use of LDAP directories because of their fast search/retrieve capabilities. Add to that advanced features, such as SSL/TLS session encryption and directory server replication, and you have a terrific open-source solution.
We are going to be using the freely available OpenLDAP package suite for Linux. The OpenLDAP team recently released v2 of their software, which now supports both LDAP v2 and v3. Notable additions with the introduction of LDAP v3 are the Transport Layer Security (TLS) and improved authentication methods. OpenLDAP can be installed in one of two ways: from source code or from a prepackaged deb/rpm. At the time this article was written, the latest stable version was openldap-2.0.6. Packages and/or source can either be obtained from http://www.openldap.org, your distribution CD, http://rpmfind.net, or apt-get. You will likely need both client and server packages if installing via rpm. Here is a quick rundown to install from source.
tar -xzvf openldap-2.0.6.tgz
cd openldap-2.06 ; ./configure --prefix=/usr/local
I like to place my ldap files in /usr/local, but it is not a requirement. The --prefix option will install the software relative to that value. Once configure is done, we need to make the dependencies and then the software.
make depend ; make
Let's run some comprehensive tests to make sure everything is okay before we install.
su -c 'make install'
If any compilation errors occur, consult the OpenLDAP mailing list for information. You might need to add /usr/local/libexec, /usr/local/bin and /usr/local/sbin to your shell PATH.
Begin by editing slapd.conf, the configuration file that controls the slapd dæmon. Slapd is responsible for returning query requests made by client applications accessing the directory service. The config file is located in /usr/local/etc/openldap.
We will need to add some extra schemas to be able to use Netscape address book attributes. Add these lines to the top of your slapd.conf file, near the other include statements. Note that, depending on how you installed OpenLDAP, the path to your schema directory might be a little different than what is shown here.
include /usr/local/etc/openldap/schema/cosine.schema include /usr/local/etc/openldap/schema/inetorgperson.schema
Further down in slapd.conf, replace the suffix and rootdn lines to reflect our Acme DN.
suffix "o=Acme, c=US" rootdn "cn=root, o=Acme, c=US"
The cn=root entry is our administrative DN, which is not subject to any type of access control or restrictions. It defaults to cn=Manager, but like all UNIX geeks, I want root access.
Add these lines to the bottom of the slapd.conf file, which will give Netscape the read access it needs to perform directory filtering and searches. All unauthenticated requests to our directory service will connect as anonymous. The DN entry below is "normalized", which means all spaces where taken out, and values are separated with commas. In access control, you MUST normalize the entry, or it will not work.
access to dn=".*,o=Acme,c=US" by anonymous read
Access permissions to the directory can be finely tuned to meet your personal preferences and needs. The OpenLDAP 2.0 Administrators Guide has a wonderful section on configuring access permissions in slapd.conf. For our testing purposes, though, this access level will be sufficient.
Now we need to start the LDAP server daemon slapd. If you installed via rpm/deb, depending on which flavor of Linux you are running, the rc script is probably /etc/rc.d/init.d/ldap or /etc/init.d/ldap. A manual startup for testing can be performed:
Test to see if slapd is running.
ps -ef | grep -i slapd | grep -v grep root 15479 1 0 10:42 ? 00:00:00 slapd root 15483 15479 0 10:42 ? 00:00:00 slapd root 15484 15483 0 10:42 ? 00:00:00 slapd root 15491 15483 0 10:43 ? 00:00:00 slapd root 15492 15483 0 10:43 ? 00:00:00 slapd
And then double-check we are bound to the default port 389.
netstat -an | grep 389 tcp 0 0 0.0.0.0:389 0.0.0.0:* LISTEN
Everything looks good there. Now, let's import the data into the database.
ldapadd -D "cn=root, o=Acme, c=US" -W -v -f testdata.ldif
We bind to the directory using the -D parameter and our unrestricted cn, which effectively allows us to write information to the directory. The -W parameter causes the server to prompt for a password. The default password is configured with the rootpw line inside slapd.conf and is secret. Leaving in the default password is a serious security risk; please change this after testing is done! Be sure to watch the verbose output (-v) for any strange errors that might appear.
After the data import is finished, we are ready to configure our client. Netscape address book supports many directory attributes. I have included a link to the Netscape Address Book API specification in the resource section if anyone wishes to investigate further. For our small test, we will be using the following attributes: cn, sn, mail, telephoneNumber and localityName. The "Nickname" entry in address book is supported by the attribute xmozillanickname, which is not a default value in any of our schemas and would require modifying one of the included schemas. I do not cover modifying schema values in this article.
Open up Netscape, then Address Book, then click File->New Directory. Enter the appropriate information for your LDAP server.
Description: Acme Address BookLDAP Server: the IP/hostname address of your LDAP serverServer Root: o=Acme, c=US
The port number and rest remain untouched for now. Again, we are connecting unauthenticated, so no name and password need to be set here.
Click okay, and then highlight "Acme Address Book" inside the directories box on the left. Finally, in the Show names containing: box, enter a query, such as Smith, and hit return. You should see a single line of data returned.
If you want to have a separate list for each organizational unit, you can create another new directory entry in Netscape address book.
Description: Acme ManagersLDAP Server: the IP/hostname address of your LDAP serverServer Root: ou=Managers, o=Acme, c=US
This will only search the organizational unit Managers inside our Acme directory, which gives us a level of filtering. The same can be done for Employees or any other category you might have.
Possibly you have run into a snag and need some help.
If the directory service is not returning data, edit your slapd.conf file and add the line "Loglevel 1". This will log all slapd daemon messages to syslog LOCAL4. You may need to edit your /etc/syslog.conf file to redirect that to a file. Check the log file and make sure slapd is starting correctly without any strange errors. This will also log some very verbose output for each request made to the database.
Make sure your PATH environment setting includes the path to all ldap commands.
If the data import fails, double-check the format of the LDIF file. Higher-level entries must go in first, starting at the top of your tree and working down.
You will need root permission to start slapd by default, unless you change the port to access an unreserved port about 1024.
Check the format of your slapd.conf file. If your access list is not normalized, you will not be able to connect.
Using Netscape's address book to access an LDAP server is a great way to get experience using basic LDAP concepts. Below is a list of resources you might find useful if you wish to venture out and have your LDAP directory authenticate some common Linux services, such as system logons and access to Samba.
http://www.openldap.org - OpenLDAP Web Sitehttp://www.openldap.org/doc/admin/ - OpenLDAP 2.0 Administrators Guidehttp://www.hklc.com/ldapschema/ - LDAP Schema Browserhttp://www.padl.com/pam_ldap.html - Pam-LDAP Authentication Module (they also have some Perl migration scripts)http://perl-ldap.sourceforge.net - Perl LDAP moduleshttp://www.unav.es/cti/ldap-smb-howto.html - Samba-PDC LDAP Howtohttp://developer.netscape.com/docs/manuals/communicator/addrapi.htm - Netscape Address Book API Specification