LDAP from the Server Side

OpenLDAP includes two daemons: SLAPD and SLURPD. SLAPD is the main server, and we will examine its operation throughout this book. SLURPD is a special-purpose daemon used for replicating directories. While it is still in use, it is now deprecated in favor of a more robust replication mechanism. We will cover it only briefly in this book.

The first, SLAPD, is the stand-alone LDAP daemon. It is the LDAP server. It listens for client requests and, when it receives a request, performs the requested operation and returns any necessary data. In the most common case a client will send a query message to the server. The SLAPD server will then look up the information and return the results. Let's consider an example (in conversational English):

This example is very simplistic (and omits lots of the details of an LDAP transaction), but it should give you the main idea of what SLAPD does.

The SLAPD program is called, appropriately enough, slapd. It is located at /usr/sbin (if you compiled from source, it is in /usr/local/libexec). In the previous chapter we configured SLAPD using the /etc/ldap/slapd.conf configuration file.

The SLAPD server handles all client interactions, including authentication, processing ACLs, performing searches, and handling changes, additions, and deletions of the data. It also manages the databases that store LDAP content. All of the clients that we look at in this chapter interact directly with SLAPD. The utilities provide maintenance services for SLAPD, though they rarely directly interact with the SLAPD server (they tend to operate on files that the directory uses).

Let's take a slightly more technical look at the simple LDAP exchange that we outlined here. We can break the exchange into two major parts: the authentication process (called binding in LDAP parlance) and the search process.

The first thing that must happen is the client must authenticate to the server. Keep in mind that in order to interact with an LDAP server the client must provide two pieces of information: a DN and a password.

Typically, there are two different ways by which a client can authenticate to a server: through a Simple Bind, and through an SASL Bind. It is possible to write custom methods of binding, too, but that's a significant undertaking. Let's look at the way clients connect to LDAP using the Simple Bind method.

Typically, to authenticate a user, SLAPD looks up the DN (and the DN's userPassword attribute) in the directory and verifies the following:

In our example scenario the user Bob wants to bind to the directory. For Bob to bind according to the outlined steps, the client would have to provide Bob's full DN, which might be something like cn=Bob,dc=example,dc=net. But, not all clients know the full DN of the user. Most applications require only a username and password, not a full DN. To solve this problem, LDAP servers support the idea of the Anonymous user.

When the LDAP server receives a bind request with an empty DN and an empty password field, the server treats the user as Anonymous. The Anonymous user can be granted or denied access to information in the directory based on the ACLs specified for SLAPD. Generally, the task of the Anonymous user is to get Bob's DN out of the directory and request that Bob be authenticated.

How does this happen? The client first connects to the server as Anonymous, then searches the directory for Bob's entry with a filter of something like this: entries whose CN is "Bob" and who have the objectclass "organizationalPerson".

Assuming that the filter is specific enough, and the directory actually has an entry for Bob, then the server would then send the client one DN: cn=Bob,dc=example,dc=net. The client would then re-bind, this time as cn=Bob,dc=example,dc=net (and with Bob's password), rather than as Anonymous.

In order for anonymous authentication to work, the ACLs will need to allow the Anonymous user to bind and attempt to perform authentication. The ACLs we added to slapd.conf in the previous chapter allowed the Anonymous user to request authentication services with the userPassword attribute.

In this chapter, we will use Simple Binding, though we will specify a full DN, rather than bind as Anonymous and search, and then rebind. Simple Bind sends the password from the client to the server. Without additional security (like SSL or TLS encryption), this makes the authentication process vulnerable to attacks. SASL (Simple Authentication and Security Layer) Binding provides another method of authenticating that relies on external security measures for added security. In Chapter 4, we will look at the authentication process in more detail, with particular emphasis on security.

In our example scenario, after Bob authenticates to the server he searches for all the email addresses that begin with the letter m. Let's examine that process in a little more detail.

In order to search the directory we need to know the following things:

Let's look at what Bob wants to get out of the directory. Bob wants to get a list of all of the people in his organization, Example.Com, who have email addresses that begin with the letter m. From this information, we can construct a search.

First, Bob wants to know about everyone in the Example.Com organization. In the directory, this is everything under the Example.Com entry: dc=example,dc=com. Also, since we know that Bob wants all of the email addresses that begin with m, not just one layer down; we know that Bob wants to search the entire subtree under dc=example,dc=com. So we have:

Next, we want to know what attributes Bob wants the server to return. The DN will be automatically returned. Other than that, Bob is concerned only with the attribute that stores the email address. Email addresses are stored in the mail attribute. We could also grab any number of attributes, such as the user's name (cn) and telephone number (telephoneNumber). So we have:

Finally, we need to create a filter from Bob's criteria. Bob wants all of the entries where the email address starts with the letter m.

Here is the search filter:

This simple filter is composed of four parts:

This type of search is called a substring search, because the filter provides only part of the string, and requests that the server respond with any entries that match the substring (according to the pattern supplied).

What if Bob also needed all of the users with email addresses that started with n? We could run two separate searches, or we could create a more elaborate filter:

(|(mail=m*)(mail=n*))

This filter is composed of two subfilters: (mail=m*) and (mail=n*). The first matches only mail addresses that start with m, while the second matches only addresses that start with n. These two subfilters are disjoined using the pipe (|) symbol. That means that an OR operation will be performed, and the filter will match a record if the record matches either (mail=m*) or (mail=n*).

The syntax may seem a little unusual at first, as the operator (the OR) comes before the two filters are listed.

Just to make things more interesting, let's say that Bob wants to restrict the list to only people whose offices have room numbers of 300 or above. We can simply add one more sub-filter to our list, and we will have the results that Bob is looking for:

To visualize this a little better let's add some line breaks and spaces:

Now it should be a little easier to see how this filter is interpreted. In the innermost level, mail addresses are considered matches if they start with m OR n. Now, these matches are only returned if they also have a room number greater than or equal to 300. They must match either (mail=m*) OR (mail=n*), AND, in addition, must also have (roomNumber >= 300).

Once Bob performs the search, with the base DN, scope, attributes, and filter, he will receive a response from the server that will contain a list of records that look something like this:

The search returns everything in appearing in the subtree below the DN dc=example,dc=com that matches our filter. The returned records only have the DN and the attributes that we specified: mail, cn, and telephoneNumber.

In our most complex filter, we used the roomNumber attribute. Why isn't it present in the records above? Even though it was used in the filter the attribute value would not be returned in the response unless we requested it.

Before going on, there is one last thing to mention about searching. During a search the entire request is checked against the list of access controls.

If an ACL specifies that Bob does not have access to the telephoneNumber attribute, then the search will return the same DNs but without the telephoneNumber attribute. Similarly, if an ACL denied Bob access to the records of certain people in the directory, then the server would send back the results for only those that Bob does have permission to see.

The server will not give Bob any indication that some information has been withheld because of an ACL.

In our illustration of Bob's search for email addresses we covered only binding and searching. Of course, LDAP supports adding, modifying, and deleting, as well. All three of these also require that the user first bind. And all three of these are also subject to ACL restrictions.

Modification acts on a particular record, specified by DN. Any number of changes can be done on a single record in one modification request.

For a particular record, a modification operation can add, replace, or remove attributes. And it can combine operations in the same request. That is, it can remove one attribute and replace another attribute in one request. Let's see these attributes:

There are a few operations that clients can call, but that tend to be used less than binding, searching, adding, modifying, and deleting. Three that we will look at just briefly are ModifyDN, Compare, and Extended Operation.

SLAPD and SLURPD are the two daemons included in the OpenLDAP suite. Above, we looked at the SLAPD server. Now we will turn to the second daemon.

SLURPD, the Stand-alone LDAP Update Replication Daemon, is used less frequently than SLAPD, and is on its way to obsolescence. SLURPD provides one way of keeping multiple copies of an LDAP directory synchronized (see the discussion in Chapter 1). Basically it works by tracking the changes (additions, deletions, modifications) to a master SLAPD directory server. When a change is made to the master directory, SLURPD sends updates to all of the subordinate slave servers.

The SLURPD program, slurpd, is located at /usr/sbin (or /usr/local/libexec, if you compiled from source). In configurations where SLURPD is used, slurpd is typically started immediately after slapd. SLURPD does not have its own configuration file. It searches the slapd.conf file for configuration information.

In Chapter 7 we will look at the technology that will likely replace SLURPD: the LDAP Sync Replication capability that is built into recent (OpenLDAP 2.2 and later) versions of SLAPD.