LDAP directory services are nearly ubiquitous these days. Every sysadmin should know how to work with directories, understand how they are constructed, and have a certain level of familiarity with the LDAP protocol itself. In this, part one of two, we will introduce LDAP and explain how entries and schemas work. Next week, the second part will cover the LDAP protocol, working with LDAP entries, and searching and storing data.
LDAP is actually quite simple, even though it does make use of the ITU X.500 standard—a notoriously complex specification. X.500 directories were accessed via DAP, or Directory Access Protocol. It was large, complex, and unruly, so Lightweight DAP was created. That's almost accurate; in fact, LDBP (Lightweight Directory Browsing Protocol) came first, because all you could do was search. When the functionality to modify entries was implemented, LDAP was born.
A directory can be defined as a set of objects with similar attributes, organized in a hierarchical manner. Sorry, but I must use the old phone book analogy now. In a phone book, an object is a person, and each person has a set of similar attributes: a phone number and perhaps an address. LDAP is the same, but you may make use of many other types of attributes.
LDAP directories are organized in a tree manner, and the design often will reflect organizational or geographic boundaries. X.500 tells us:
- A directory is a tree of directory entries
- An entry contains a set of attributes
- An attribute has a name, and one or more values.
Attributes are defined in a schema, which specifies what types of things can be attributes and whether or not you can multiple values per attribute.
Every entry in a directory has a unique identifier, called the Distinguished Name (DN). The Relative DN (RDN) is part that specifies the current attribute you're dealing with, sort of like a relative path in Unix (./file). The DN, then, would be a full path (/var/lib/file). A sample directory entry's DN, therefore, would look like: cn="john doe",dc=mytree. The RDN is cn="john doe", and the DN is the full path, starting at the top of the tree. A "cn" simply means the "common name" that the entry is referred to as, and "dc" is the "domain component."
You will often see examples of LDAP structures that use DNS names for the domain component, such as: dc=example,dc=com. This is not necessary, but since DNS itself often implies organizational boundaries, it usually makes sense to just use your existing naming structure. One final note about a DN; it changes over time. If you change a DN, you're effectively moving an entry in the tree. Some LDAP servers support unique identifiers that will track the movement of entries, but you often don't need to care. Just know that even though a DN is unique, it changes over time.
A sample directory entry (of a person) looks like this:
dn: cn=John Doe,dc=myplace
cn: John Doe
telephoneNumber: +1 555 555 1234
telephoneNumber: +1 555 555 5555
manager: cn=Bob Smith,dc=example,dc=com
All of the attributes (objects) listed above are associated with the DN; it is a single directory entry. Objects (givenName, sn, etc) are defined by schemas. Every entry must list the objectClass that every attribute is using. For example, organizationalPerson defines what values can live in the attribute called "manager." If the objectClass wasn't listed, the LDAP server wouldn't know what values were allowed, so it wouldn't allow you to define an attribute called manager.
The example above is an LDIF , LDAP Data Interchange Format, entry. That is the entire LDAP entry in text form. You could insert the data into a directory, and in fact, this is exactly what a backup of your directory looks like. It's just text, and that's all there is to an LDAP entry. Well almost: most servers also support aliases and references. An LDAP alias can point to another local entry in the same directory, to avoid duplicating information. A reference will provide a new DN to an LDAP client and tell it to go ask another server. Some LDAP servers even support chained references, where the server will go get the answer and return it to the client; the client never knows a referral has taken place. Regardless, LDAP entries are quite simple.
A schema defines the attribute types that entries can contain, as well as the format of their values. It will specify that: Mail contains a well-formed e-mail address, Photo contains a JPEG image, and uidNumber contains an integer, for example.
Here is an example schema we recently created:
attributeTypes: ( 184.108.40.206.1
DESC 'A pod for people to belong in'
objectClasses: ( 220.127.116.11.1
DESC 'A person who belongs in some pods'
The objectClass is defined, as well as the allowed attributeTypes. Each
schema must have a unique OID (object identifier), which is part of the way
X.500 works (SNMP is the same way). We
created an objectClass called podPerson, gave it a description, an said the
entry must contain a 'cn,' and may contain a 'pod.' The pod attribute can
contain any value, because the only restriction specified is that case doesn't
matter. After loading that scheme into our LDAP server, we could then add a
'pod' attribute to each person entry.
Since LDAP is so lightweight and simple, it is not suitable for a few things. It's very tempting to store tons of data in LDAP, since so many applications can reference LDAP. Unix machines can use LDAP for passwd, shadow, group, netgroup, protocols, and just about everything in nsswitch.conf. LDAP is a database, so print accounting programs, configuration management systems, and just about everything that stores data in a DB will support LDAP. It's fine for most of these things, but LDAP is not ideal for replicating a relational database. The data in LDAP is not ordered, which means you could get results in any order. If your application is querying for only one result at a time, this is fine, but if multiple results are common and order is important, LDAP just won't work.
Join us next week for a look at the protocol, and practical examples of querying and using LDAP data.