Lighting up LDAP
A beginner's guide to directory development
Do you know how to develop Lightweight Directory Access Protocol (LDAP) applications? If you're like Cameron and Kathryn, you only feel comfortable with a technology after you've written your own application that uses it. This beginner's tutorial traces the initial steps to learning LDAP. (2,800 words)
hile there are several standards for directories, LDAP's mindshare is ballooning now. Such disparate vendors as Microsoft, Sun, Oracle, Novell, and Netscape support LDAP. Moreover, the number of LDAP books in print will triple this year, and more and more organizations are using it successfully in important applications. So, it is a good idea to learn LDAP (see Resources for pointers to references, software, and other information).
Directories are the online telephone books that keep such information as e-mail addresses, printers' room locations, and the fax numbers of businesses' purchasing departments. The LDAP definition is structured in terms of four basic models, having to do with the information, naming, function, and security of an LDAP installation. The goal of this tutorial is to help you practice accessing directory data using LDAP. You'll soon see how LDAP exposes such functional concepts as adding, searching for, and deleting data entries.
Start by thinking of LDAP's dataflow as that of a data management system (DMS) like those exposed by Structured Query Language (SQL) or Open Database Connectivity (ODBC). Most DMSs emphasize language aspects, while LDAP's name appears to connect it with other protocols such as File Transfer Protocol (FTP) or Simple Mail Transfer Protocol (SMTP). Moreover, most popular DMSs support concepts of transactions, concurrency management, and the other elements of the ACID (atomic, consistent, isolated, and durable) criterion. Part of LDAP's "lightness" is that it doesn't model these features. From a programming perspective, though, LDAP is just another client/server DMS.
To see LDAP in action, therefore, you need to assemble at least these four elements and have them cooperate:
You know how clumsy beginners look the first time they set up a tent? It isn't that the steps are hard; a lot of the difficulty has to do simply with combining multiple unfamiliar motions all at the same time. Don't let the list of elements above scare you. We'll start first with a warm-up exercise. Several organizations expose LDAP servers to the Net at large, and they've already loaded them with millions of records of content you can search.
All you need, then, is a client that returns interesting results. You probably have one already: Recent versions of e-mail user agents such as Pine and Internet browsers including Netscape Navigator and Microsoft Internet Explorer (IE), for example, know how to talk LDAP. You can practice your LDAP concepts by feeding Navigator or IE such URLs as ldap://ldap.four11.com/??sub?sn=Joy or ldap://ldap.yahoo.com/??sub?&(sn=Joy)(c=NZ).
The first returns pages of information about people with surnames that begin with Joy; the second selects only the New Zealanders among them. Strict interpretation of LDAP search syntax says that (sn=Joy) should include only exact matches, but apparently these public services have decided to add a bit of fuzziness to their servers.
When you install one of the LDAP packages below, it will include a
command-line utility called
Once you've generated this, you can launch analogous searches as
ldapsearch -h ldap.four11.com sn=Joy
ldapsearch -h ldap.yahoo.com "&(sn=Joy)(c=NZ)"
Now that you've seen for yourself a little of what LDAP does, you can put together all the pieces to run your own application.
LDAP data managers
One intriguing aspect of LDAP is its flexible underlying data store. Real-world LDAP applications use everything from a network information system (NIS) account registry to conventional relational database management systems (RDBMSs) such as Informix and DB2 as a backend. LDAP originally arose as an access method to X.500, an older and considerably more cumbersome directory DMS. You can think of LDAP as a convenient and consistent frontend view to a whole range of DMS technologies. For example, application programmers can develop e-mail projects without concerning themselves about whether account information is coming from personnel department files on a mainframe, NIS logins on engineering workstations, or a Windows NT domain controller.
For an LDAP beginner with Solaris or Linux resources, though, it's best to start with an LDAP package that transparently integrates a data store. Among the natural choices are Netscape's Directory Server, MessagingDirect's MD Directory, Innosoft's Distributed Directory Server, the University of Michigan's LDAP project server, and the OpenLDAP project's LDAP server. The first three are commercial products generally available for trial, while OpenLDAP is an open source licenser. Despite the fact that the UMich free software project server is moribund, with no current official support, it continues to be used in a number of new applications. Moreover, it occupies a position similar to Mosaic among Web browsers: Most of the current products have UMich source code somewhere inside. It's often handy to refer to the UMich legacy in order to understand more recent developments.
LDAP is more complex and time-consuming to install than, say, a typical compiler or e-mail server. The worst aspect for LDAP newcomers is that many error messages are opaque and incomplete; it can be hard to know how to correct mistakes. Everything works reliably, though, once properly configured.
An LDAP package includes both client and server software. All providers' client software works with little fuss and a reasonable amount of faults. Generating client libraries and utilities with the open source packages is relatively foolproof.
The server side is more of a problem. Supporting LDAP's extreme flexibility and its performance on a wide variety of platforms is difficult. One consequence is that generation of the open source servers is rather delicate. Although the OpenLDAP project has made rapid progress with these problems, we think it's important to detail a sample configuration to ensure your success. The next section supplies such a recipe.
For many readers, the simplest way to get started with LDAP is to download a trial server from one of the commercial vendors. Expect to invest a few hours even if you take this approach. Netscape's Directory Server download is around 40 MB, and correspondingly involved to configure.
Generating and configuring a simple Solaris LDAP server
This is what you should do the first time you set up OpenLDAP on a Solaris host:
Download the 2.7.5 release of the Berkeley DB database manager product (see Resources). Generate and install it. Berkeley DB, interestingly enough, is the DMS that at least a couple of the commercial vendors use for their standalone backends.
Download the 1.2.3 release of OpenLDAP.
Read the OpenLDAP README and INSTALL, and the documents to which they refer. Don't be alarmed that README is labeled "1.2.1." Be careful when following pointers; some documents actually belong to the UMich distribution, and details differ between it and OpenLDAP. The OpenLDAP team is responsive. If you report errors or ambiguities in the documentation, they're likely to be corrected in the next release.
Configure the distribution with a sequence such as
CPPFLAGS=-I/usr/local/BerkeleyDB/include LDFLAGS=-L/usr/local/BerkeleyDB/lib LIBS="-lpthread -lposix4" export CPPFLAGS LDFLAGS LIBS configure --with-threads --with-ldbm-api=db2
(Adjust to fit the syntax of your login shell.)
make. This is likely to last 10 to 30 minutes.
As the root user, run
Now it's time to configure operation of the LDAP server, generally
slapd. The bottom half of
database ldbm suffix "dc=your-domain, dc=com" #suffix "o=Your Organization Name, c=US" directory /usr/tmp rootdn "cn=root, dc=your-domain, dc=com" #rootdn "cn=root, o=Your Organization Name, c=US" rootpw secret # cleartext passwords, especially for the rootdn, should # be avoid. See slapd.conf(5) for details.
Change this to
database ldbm suffix "o=MYORG, c=US" directory /usr/local/ldap rootdn "cn=root, o=MYORG, c=US" rootpw secret index cn,sn,uid index objectclass pres,eq index default none
You need to be root to edit
Create the directory
As you become more expert and confident with LDAP, you'll probably change some of these settings. Start here, though:
slapd server by executing
/usr/local/libexec/slapd. Again, you
must be root to do this.
Confirm that the server process is running using
ps -p `cat
/usr/local/var/slapd.pid`. You should see a terse report on the
Confirm that the server is responsive to client requests with the
ldapsearch -s base -b cn=monitor
'objectclass=*'. This causes the server to report 16 lines
of runtime variables.
At this point, you have a working OpenLDAP server.
The schema is the easy part, as least for now. You don't have to do anything. The LDAP definition specifies a default schema that all implementations provide. It's quite practical to use this one for your first experiments.
We saw above that LDAP is a DMS, but one that's different from most in that it doesn't support transactions and related functions. LDAP is also a DMS in that a textual schema describes the data and their relations. However, LDAP's schemata conform to a hierarchical structure that's quite different from those of the relational database managers with which you're probably most familiar. It's not just that LDAP has "entries" with "attributes," whereas RDBMS has "records" with "values." The semantics of these LDAP and RDBMS elements are different. To support its directory role, for example, an LDAP telephone number attribute is defined to permit multiple values, all of which are searched and compared, ignoring spaces and dashes. There's no corresponding concept in RDBMSs.
LDAP's default schema is a practical advantage LDAP has over most DMSs. Within other DMSs, data modeling is entirely general, and therefore requires you to learn at least the rudiments of schema management before you can begin any data operations.
When the time comes to customize the data schema for your specific needs, buy a copy of Understanding and Deploying LDAP Directory Services and read the consecutive chapters on data design and schema design (at least). The first one crystallizes enough wisdom about data management to be valuable reading for programmers working in any domain, while the second is essential for those working specifically with LDAP. Authors Howes, Smith, and Good also wrote the pertinent RFCs and other public documentation. This book, though, is more than just a repackaging of online manual pages: It's more readable and also more motivating in explaining engineering conventions and choices.
If you're using OpenLDAP, you'll find in
/usr/local/etc/openldap/slapd.oc.conf such fragments as
objectclass person requires objectClass, sn, cn allows description, seeAlso, telephoneNumber, userPassword
Most other LDAP packages also have a
slapd.oc.conf (installed in a
different directory) with identical contents. For the first
experiment, we'll use this default schema.
To load the first batch of data into your LDAP data store, you'll use a command-line utility. In principle, you could enlist any of several form-based GUI "data-entry" applications. Do not do so for this step. It will be preferable to start by building a textual representation of your data and feeding it into LDAP with the
ldapadd command-line utility.
Just as there's a canonical schema, there are a few stereotyped operations every LDAP installation needs to render it useful. LDAP schemata are "rooted hierarchies," so we need to create a root object:
ldapadd -D "cn=root, o=MYORG, c=US" -w secret <<EOR dn: o=MYORG, c=US o: MYORG objectclass: organization EOR
Verify the object was created correctly with the following:
ldapsearch -b "o=MYORG, c=US" '(objectclass=*)'
You should see the same data you just entered.
Now you're ready to add useful data. Create a file called
(LDIF is an acronym for LDAP Data Interchange Format) with contents
dn: cn=Mary, o=MYORG, c=US cn: Mary sn: Smith objectclass: person telephoneNumber: 938-555-1212 dn: cn=Bob, o=MYORG, c=US cn: Bob sn: Jones objectclass: person telephoneNumber: 415-777-1212
Keep in mind that the LDIF format permits no leading spaces or tabs. Enter these records into LDAP with
ldapadd -D "cn=root, o=MYORG, c=US" -w secret < /tmp/myldif
You can now retrieve the records with
ldapseach -b "o=MYORG, c=US" "objectclass=*"
You're a success! At this point, you've successfully loaded data into LDAP and retrieved it. You can also wipe your entries out and start over, with the command
ldapdelete -D "cn=root, o=MYORG, c=US" -w secret \ "cn=Mary, o=MYORG, c=US" "cn=Bob, o=MYORG, c=US"
Designing an LDAP application
From an architectural standpoint, LDAP installations typically involve few writes and a lot of reads. Like other kinds of enterprise-level programming, much of the hard work of real LDAP projects involves coping with dirty data -- old room assignments, misspellings, misapplications of policy regarding maiden names, etc. But there's no need to complicate your first LDAP experience with such issues. Start with a simple LDIF and work your way up to examples of the scale you'll need for daily work. A most natural example would be to move your own address book online. In his tutorial on installing OpenLDAP, Rasmus Lerdorf demonstrates that going to the trouble of making this data available through LDAP can be a worthwhile investment even if you're the only end user (see Resources).
Howes and Smith wrote an earlier book, Programming Directory-Enabled Applications with Lightweight Directory Access Protocol. Their examples demonstrate that it isn't difficult to write useful LDAP applications in C, but that it's tedious to do so. Providers define C bindings for software development kits (SDKs) that are generally consistent, although details differ enough that you'll need a few
#ifdef-s for almost anything you want to be
compatible across multiple vendors. Equally annoying is that C coding
of real applications has a lot of "syntactic overhead." Marshalling
data into structures and pulling results back fills up source code
for LDAP applications written in C. Even in comparison with
embedded SQL, a data manipulation language with a difficult
reputation, the algorithmic content of LDAP programs is easily
One warning before you begin C coding: Several of the older SDKs
have a broken
ldap_init(). That sounds awful because
the one necessary entry point in every LDAP client program. The
workaround, though, is simple. If you have a minimal C-coded
program that returns only errors, substitute
ldap_open() in place of
ldap_open() is a deprecated entry point with slightly different functionality that can effectively substitute for
ldap_init() until you move to a more current SDK.
If there's a language you prefer to C, feel free to use it. Good
LDAP bindings are now available for most common languages, including
Java, Perl, PHP, and many others. You can even use the standard
ldapadd, and so on, to build modestly ambitious programs in
sh or one of its descendants. Most LDAP applications, at least to this point, are relatively simple. The majority fall in one of these categories: end-user search
facilities; a simple form for updating records; batch data loaders;
or data validators. A small percentage of all LDAP applications
exploit its sophisticated facilities: asynchronous operation;
replication; referral computations; complex filters and security;
Even more than with most data management projects, the value of LDAP applications lies in the schema and other dimensions that are independent of coding language. It generally isn't too expensive to switch between client-side languages, as your needs expand. You can compare for yourself how different languages manage the most common requirements. You might build a simple service that lists e-mail addresses reported for any matches on first name with a single command-line:
ldapsearch "givenname=$1" cn mail st
To express the same in C requires close to a hundred lines, mostly to set up the LDAP session, catch error conditions, and loop through all matches. The verbosity of other languages is intermediate.
One advantage of the C application programming interface (API) is that it's generally the most complete. Still, our usual advice is that beginners should start their experiments with the brevity of a more expressive language, and switch to C only after exhausting more streamlined alternatives.
Your future with LDAP
Once you've built a practice application or two, you'll be equipped to tackle such departmental jobs as implementing single login. Employment recruiters are starting to ask about LDAP, several more books are in the pipeline, and a slew of LDAP-aware products are slated to appear in the next year or so. Your LDAP experience should serve you increasingly well.
Thanks to Randy Kunkee and Mark Smith for their instruction and advice. Special thanks for Kurt Zeilenga of the OpenLDAP project for his patience.
About the author
Cameron Laird and Kathryn Soraiz manage their own software consultancy, Network Engineered Solutions, from just outside Houston, TX.
If you have technical problems with this magazine, contact firstname.lastname@example.org