|This article/section is a stub — probably a pile of half-sorted notes, is not well-checked so may have incorrect bits. (Feel free to ignore, fix, or tell me)|
LDAP is a simple string-based database setup.
Standards and Acronyms
LDAP follows the ITU-T X.500 series of standards that define a particular type of hierarchical information directory, ways of referencing parts, and protocols that access it.
LDAP is a simplified version of the fairly complex DAP protocol (X.511). (Other things that follow X.500 to some degree: Microsoft's Active Directory, Novell Directory Services, DCE, others.)
Note that LDAP is a binary protocol (apparently ASN.1 BER)(verify). Readable entries are in the LDIF  interchange format, also used in some DSML (Directory Services Markup Language) is an XML interchange format for LDAP.
LDAP is served on TCP port 389 and/or 636. Port 636 serves the SSL-wrapped variant, which is recommended as the password is sent in plain text. (Note that some servers do both plain and SSL versions on a single port, or even on both)
LDAP model and concepts
LDAP inherits various concepts from X.500, including:
- directory: a tree of entries
- entry: consists of a
- a Distinguished Name (DN), and
- a set of attributes
Attributes are pretty free-form variable:value pairs, in which variables may appear more than once (For ease in coding, this is usually seen as mapping from a variable name to a list of values).
As a somewhat advanced feature, a directory may contain entries that are references to other servers that actually store a subtree. In some setups, this is transparently handled, while in others the LDAP client is responsible for connecting to, resolving in, and fetching from that additional server.
Rough analogies for the technical-minded:
- a directory server is analogous to a filesystem
- a DN is an absolute path,
- an RDN (see explanation below) is a directory entry
- attributes are attached to files (and/but also directories)
- cross-server references are similar to symlinks
(X.500) name references
The tree and its paths are made out of units of DN and RDN - comparable to absolute directory paths and directory entries in the context of another directory (DN).
For example, in the following LDIF formatted entry (this example copied from the wikipedia article):
dn: cn=John Doe,dc=example,dc=com cn: John Doe givenName: John sn: Doe telephoneNumber: +1 888 555 6789 telephoneNumber: +1 888 555 1234 mail: firstname.lastname@example.org manager: cn=Barbara Doe,dc=example,dc=com objectClass: inetOrgPerson objectClass: organizationalPerson objectClass: person objectClass: top
- The full DN is .
- When seen as an element in a context:
- the context DN is
- The RDN in that context is
It is usual to structure the name rather like DNS host/domains (from specific to general, something like a path from right to left). This is generally easy to read, and means LDAP directories can often be merged sensibly-enough.
Common elements (it seems that most of these come from convention-by-copy):
- cn: Common Name, often (unique) usernames, not real names, to avoid duplicates and strange-character problems.
- dc: Domain Component (used if fashioned after DNS domains)
- ou: Organizational Unit (e.g. Sales or Staff) often one or two
- o: Organization/company (organization's name and/or domain)
- c: Country (regularly a ccTLD)
There are a bunch more,
(Particularly) In X.509 certificates, you may also see l for locality (often taken to mean city, and st may be used for state), and OU seems somewhat abused.
The organization of any directory's data may not be obvious, and may change over time; ask your LDAP admin for details.
In practice, X.500 naming is usually awkward; the model is strange, meaning real use is pretty arbitrary.
- search base / base object: the of the entry to search
- scope is one of:
- base object: the entry at the DN
- single level: immediate children of the DN (note: excluding the entry directly at the DN)
- whole subtree: the entire subtree starting at (and including) the base DN.
- filter: tests fields (prefix operator syntax, allows wildcards)
- attributes: which attributes to return in result entries (optional, default is usually all)
Additional options may include things like:
- derefAliases - whether and how to follow alias entries (entries which refer to other entries),
- sizeLimit, timeLimit - max number of entries, and max search time.
- typesOnly - return attribute types only, not attribute values.
Rights and authentication
LDAP has rights management.
Authenticating is called binding; a client tries to bind to a specific user's DN using a password (plain-text in the protocol, hence the SSL suggestion).
There also exist anonymous binds - essentially guest logins. If you leave the DN and password empty (and, in some cases, if you leave only the password empty(verify)) servers will assu me an anonymous bind.
When used for authentication, it is common to allow users to read only their own information, and for their entries to be invisible to anonymous binds. Write access is usually not for owning users, and only for administrators.
It is not uncommon to have proxy usernames, to be able to give read-only access to some set of information, particularly for programs, particularly if you just want to look up some user details without having to have them log them in first. Ask your administrator.
Login system, practical issues
You probably want to split an LDAP based login system into two parts, authentication and (optional) fetching of detais.
The authentication is often:
- connect to the server (note some common server types have peculiarities - google around when you run into trouble)
- decide on a user's DN (you could search for it, but this is heavy on the server as even most commercial LDAP servers seem to be impressively stupid; knowledge of the organization means you can hardcode this for speed, or make this part of your app configuration)
- bind against that DN. This will fail if the login is incorrect, and under some other conditions.
(In accordance with general security rules, you may want to be relatively vague in your login failure errors. For example, say that the login is incorrect, not that the username or password is incorrect, since it is easy to reveal that an username exists and only the password is wrong. Many LDAP interfaces, particularly the ones you piece together yourself, do not prevent brute forcing, which means this is DoS sensitive, so don't invite it.)
Fetching user details (say, user's name, email, department, whatnot) should probably be separated. Sometimes this information will be in the same location and you may be authorized to read them (the just-bound user's own record). But it may just as well be in another container, and/or require different authentication (an application's being given read access via its own login is not unusual)
So this can mean
- (as applicable) a bind elsewhere to be able to read this information
- a search (that preferably looks for exactly the one record you want)
- often for cn=username under some given DN,
- using that DN as the base (and choosing the minimal search that works, e.g. one-deep, to be nice to the server)
- could filter on the username, just to be sure
- could ask for a filtered set of the record's attributes (although few fields are large enough for this to make any difference to speed or lookup efficiency)
- You should get exactly one record, and get its data in some sort of attribute-value list or dictionary/map, depending on your LDAP library.
Since attribute names used may be local to any system, general-purpose LDAP code may wish to allow for remapping of attribute names via configuration somehow.
- eDirectory (Novell)
- Active Directory (Microsoft)
- "Turn your world LDAP-tastic"
- Wikipedia: Lightweight Directory Access Protocol
- online java applet browser