Demystifying LDAP Data

More Than You Could Ever Possibly Want to Know About LDAP Data

In response to some great feedback collected on my previous article on Demystifying LDAP, my editor has given me the okay to skip the coding and instead dive head first into explaining why the data in a directory server looks the way it does, where objectclasses and attributes come from, why an entry will have multiple objectclass attributes, and all kinds of other details that seem like minutiae until you face a problem as a developer or an administrator that you cannot solve without a solid grasp of how a directory manages data.

It's a non-trivial topic space, really. However, I believe that the content of this article evaporates all of the unnecessarily verbose theory and leaves behind something you can (I hope!) refer back to in times of need.

What Are Objectclasses?

Objectclasses are prototypes for entries that will actually exist in your directory server. The objectclass definition (which uses ASN.1 syntax) specifies which attributes may or must be used by LDAP entries declared as instances of a particular objectclass.

Get it? Let me explain it backward, in the way that most people get into LDAP: you want to store information about people. The most common attributes associated with people are:

These attributes are great for setting up an office whitepages server that users can refer to for information about people in their office. The key now is finding out which objectclass definitions either require or allow for the use of these attributes. When I started with LDAP, I researched this by perusing the actual schema files that come with most (if not all) directory servers. These files are human-readable.

Object Class Definitions

My previous article mentioned that each user in the directory is an object which has one or more attributes. Here's the definition of the inetOrgPerson objectclass, which is a good place to start:

objectclass     ( 2.16.840.1.113730.3.2.2
NAME 'inetOrgPerson'
DESC 'RFC2798: Internet Organizational Person'
SUP organizationalPerson
audio $ businessCategory $ carLicense $ departmentNumber $
displayName $ employeeNumber $ employeeType $ givenName $
homePhone $ homePostalAddress $ initials $ jpegPhoto $
labeledURI $ mail $ manager $ mobile $ o $ pager $
photo $ roomNumber $ secretary $ uid $ userCertificate $
x500uniqueIdentifier $ preferredLanguage $
userSMIMECertificate $ userPKCS12 )

I'll go over each line of the entry here, but don't get flustered! Some of it will sound foreign to you until you create your first user entry.

The first line states that what follows is an objectclass definition, as opposed to an attributetype definition. The long number is the ASN.1 number assigned to the objectclass. If you create your own objectclasses, this number is significant; it's where you use your organization's IANA Enterprise Number to identify any objectclasses that you create.

The NAME line should be self explanatory. It is the name that will appear in your users' entries to state that the user is of type inetOrgPerson. This line gives you license to use any of the attributes in the objectclass definition to describe the user.

The DESC line is usually a useful description that can help you use this object in a way appropriate to the intent of the definer. You don't want to use objectclasses in a completely unorthodox way, because when you reach out to others for help, they'll find themselves asking you more questions than you ask them, which is often a sign that you've gone off in the wrong direction.

The SUP line is critical, and the theory is tough to describe without getting pretty verbose. SUP is short for SUPERIOR, and it names another objectclass from which this objectclass inherits. In this case, the superior or parent objectclass is organizationalPerson. The organizationalPerson class inherits from the person objectclass, which inherits from an objectclass called top. If an objectclass has no other superiors, it is always a child of the top objectclass.

It's an inheritance chain. You need to understand it, because some LDAP servers strictly enforce it, and if you violate it in the creation of your entries, the directory server will unceremoniously spit them back at you.

The MAY line is actually a block. That block (between parentheses) contains a list, delimited with the $ symbol, of all of the attributes that MAY be used to describe an object declared of the type inetOrgPerson.

Defining a Valid Entry

Enough chat. Here's a very simple inetOrgPerson entry, which I hope will lend itself nicely to an expanded explanation of some of this gibberish:

dn: cn=jonesy,dc=linuxlaboratory,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
displayName: Brian K. Jones
givenName: Brian
sn: Jones
uid: 101
roomNumber: 101B
homePhone: 609-555-1212
title: System/Network Administrator
telephoneNumber: 609-111-1111
cn: jonesy

The first line of this entry is the DN, or distinguished name. It uniquely identifies this entry across the entire directory hierarchy.

The next four lines lay out the inheritance chain that I mentioned earlier. I have the most interest in the inetOrgPerson object, but because that inherits from organizationalPerson, which inherits from person, which inherits from top, I had to name those objects here as well. I've done it starting with top and listing the descendants in order, like a family tree. You're free to list them out of order if you like.

Inheritance Overload!

Here's the rule: every LDAP entry must use a STRUCTURAL objectclass. Furthermore, it can have only one STRUCTURAL objectclass. While it's true that every objectclass in the example entry is STRUCTURAL, only one has top as its parent. All of the others are descendants of that objectclass. I've played by the rules here, and LDAP servers will not spit this back at you.



There are applications that can cause you headaches, however. Some application developers include a schema that you can use with your LDAP server to add attributes to an entry for use by that application. Evolution and Mozilla used to (and may still) distribute schemas that defined evolutionPerson and zillaPerson, respectively, as STRUCTURAL objectclasses. This alone is not a problem. The real problem comes when you want to use both of these schemas--you can't, because both of the objectclasses, in addition to being STRUCTURAL, also have inetOrgPerson as their parent objectclass. This creates a fork in the inheritance chain, and is unacceptable to strict LDAP directories:

/ \
evolutionPerson zillaPerson

In short, you can't define an entry which uses two STRUCTURAL objectclasses that share a parent. These schemas should really declare the objectclasses as AUXILIARY, which would fix this issue. As long as you have an object defined using one STRUCTURAL objectclass, you can use any number of AUXILIARY objectclasses to add more attributes to your entries. Also note that you can use either one of these schemas with your existing entries. It's only when you try to employ both that you create a fork in the chain.

Where's the Beef?

With all of that definition in mind, now it's possible to consider the really important information: the attributes. The interesting ones describe, in human terms, who this person is and how to reach him. Most of these attributes, such as roomNumber and givenName, come from the MAY section of the inetOrgPerson objectclass. Where did cn and sn come from?

The answer is from the person objectclass. Just like inetOrgPerson, the person definition has a MAY block, but it also has a MUST block which contains the attributes cn and sn. This means that any entry defined using this objectclass must have values set for these attributes. Here's the person objectclass definition:

objectclass ( NAME 'person'
DESC 'RFC2256: a person'
MUST ( sn $ cn )
MAY ( userPassword $ telephoneNumber $ seeAlso $ description ) )

My earlier example also chose to use the telephoneNumber attribute, which is perfectly legal.

How do you know what cn and sn are?

In every case I've ever seen, the definitions of the attributes named in an objectclass definition are in the very same file as the objectclass itself. They're very readable as well. Here's the definition of sn:

attributetype ( NAME ( 'sn' 'surname' )
DESC 'RFC2256: last (family) name(s) for which the entity is known
SUP name )

sn is an alias for surname. I could've written the attribute as surname, if I liked. The description indicates that the purpose of this attribute is to indicate the user's last name.

There is another major point worth noting about this particular attribute definition. As you might've guessed, it has to do with the SUP line. In this case, the superior to this attribute type is name:

attributetype ( NAME 'name'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX{32768} )

See those EQUALITY, SUBSTR, and SYNTAX lines? EQUALITY and SUBSTR define the method the LDAP server will use to figure out if an incoming value is an exact match, or a substring match (respectively) for the value of this attribute in an entry. The SYNTAX line points to a syntax definition used to check that new values added by an administrator, or old values updated by an administrator, conform to the syntax definition pointed to by the very long ASN.1 number. The long number is just a reference point for looking up the definition, as are the strings next to the EQUALITY and SUBSTR keywords. RFC 4517 defines their meanings. As well, the handy Schema Browser tool can look up almost anything you see in any standard schema.

I told you all of that so I could tell you this: you won't see any of those lines in the sn attribute because it inherits all of that information from its SUP attribute, which is name. Because name doesn't inherit anything from anywhere, all of that information must be present in its definition.

Before You Fall Asleep

That's a good bit to chew on. Hopefully, you've come away with the ability to peruse the schema files, which will give you a greater understanding of how your directory works, and why. It also explains a good number of errors you'll get from you server, including any form of objectclass violation error.

I must caution you strongly against using this information to implement shiny new custom objectclasses and attributes. Many people have worked very hard to create standardized, published schemas for general use. It would benefit you, your firm, and anyone who may come after you to consult the Schema Browser tool, a few schema files, and maybe one or two RFCs to figure out if what you need actually exists in a published schema before taking off and blazing your own ASN.1-littered trail.