Introduction

Given the following schema: Lets suppose that we want to get the address of the user Nick Tesla. In the case of MySQL, it would be accomplished by a query like this:

SELECT user.cn, ou.Address
FROM User u, OrgUnit ou
WHERE u.cn = "Nick Tesla"
AND ou.name = u.EduPersonOrgUnitDN
This objective, can be easily completed in SQL by using a JOIN operation (an implicit inner join in this example), in order to combine the resulting sets that we are interested in. In the case of LDAP, this is simply not possible. In many textbooks and presentations, this is described as one of the major "common problems" with LDAP, actually!


LDAP is not Relational

The role and purpose of SQL databases is mainly to store large amounts of data and encapsulate business logic, which results in complex queries running concurrently. On the other hand, the main role of LDAP databases is that of authentication and address books, which concludes to many quick read requests. The main benefits of LDAP are its blinding speed and the interoperability offered by the enforcement of strict standards. But for all its advantages and for all intents ant purposes, LDAP is not relational. (A simple -yet good- explanation can be found here. A detailed analysis -from the developers of OpenLDAP themselves- can be found here)


LDAP and Best Practice Schemas

Once upon a time, it was common practice to have a single ldap tree hierarchy, which would branch on the basis of organizations and then hang all the users under their respective organizational unit -schema 1- . Over the years, this was deemed inefficient (for a variety of reasons, such as moving entries or even entire subtrees due to changes in persons and/or organizational units, data replication and redundancy etc). The basic pattern of the best practice which emerged, is to hold all the people under a single arc -a.k.a. subtree- (such as ou=people) and organizations under another arc (such as ou=departments) -schema 2- .


The CAS Dereference Plugin

The dereference plugin, is a pre op search plugin, provided by the control (see also) of the same name, with the experimental oid (see also) 1.3.6.1.4.1.4203.666.5.16 (for more information, you can read the corresponding RFC). With the usage of this plugin, a service can discover and retrieve extra attributes, not available in the main user object, with a single operation. In any other case, more steps would have to be added. Either by talking to the LDAP server itself -which would mean that the LDAP server itself must be available- or by talking to another service which would publish these extra attributes. These mechanisms, help to further the use of application isolation strategies and the streamlined use of the LDAP service.

For example, given these entries:

dn: cn=Nick Tesla,ou=people,dc=example,dc=org
objectClass: inetOrgPerson
cn: Nick Tesla
sn: Tesla
uid: nt
eduPersonOrgUnitDN: cn=Faculty,ou=groups,dc=example,dc=org
dn: cn=Faculty,ou=groups,dc=example,dc=org
objectClass: groupOfNames
cn: Faculty
member: cn=Nick Tesla,ou=people,dc=example,dc=org
address: Panepistimioupolis Athens
A search could be performed with a Dereference request control value specified as:
{ eduPersonOrgUntiDN.address, uid }
and the "cn=Faculty" entry would be returned with the response control value -alongside the main entry's ("cn=Nick Tesla") attributes- :
{ { address, Panepistimoupolis Athens,
{ { uid, [nt] } } } }


The Dereference Plugin Illustrated in CLI

Lets demonstrate how the dereference plugin works by an example.
Suppose you have the following simple ldap query:

ldapsearch -h example.com -b personID=001,ou=faculty,dc=example,dc=com uid=001
Which would yield the following results (in extended ldif format):
# extended LDIF
#
# LDAPv3
# base <personID=001,ou=faculty,dc=example,dc=com> with scope subtree
# filter: uid=001
# requesting: ALL
#

# 001, faculty, example.com
dn: personID=001,ou=faculty,dc=example,dc=com
personID: 001
FacultyDepartment:: Physics
FacultyDepartmentID: 1856
ou:: Physics
givenName:: Nick
uid: 001
cn:: Nick Tesla
personAffiliation: inventor extraordinaire
eduPersonOrgUnitDN: ou=1856,ou=units,dc=example,dc=com

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1
The same query, by adding a dereference control value in order to get the cn, ou and address attributes of the eduPersonPrimaryOrgUnit DN, would become like this:
ldapsearch -h example.com -b personID=001,ou=faculty,dc=example,dc=com uid=001 -E "deref=eduPersonPrimaryOrgUnitDN:cn,ou,address"
And produce results like this:
# extended LDIF
#
# LDAPv3
# base <personID=001,ou=faculty,dc=example,dc=com> with scope subtree
# filter: uid=001
# requesting: ALL
# with dereference control
#

# 001, faculty, example.com
dn: personID=001,ou=people,dc=example,dc=com
control: 1.3.6.1.4.1.4203.666.5.16 false MIHSMIHPBBllZHVQZXJzb25QcmltYXJ5T3JnV
 W5pdEROBB5vdT00MTgsb3U9dW5pdHMsZGM9Z3VuZXQsZGM9Z3KggZEwYAQCY24xWgRYzqDOoc6fzp
 POoc6RzpzOnM6RIM6VzprOms6bzpfOo86ZzpHOo86kzpnOms6XzqMgzpzOn86lzqPOmc6azpfOoyD
 Oms6RzpkgzqjOkc6bzqTOmc6azpfOozALBAJvdTEFBAM0MTgwIAQQYnVzaW5lc3NDYXRlZ29yeTEM
 BApkZXBhcnRtZW50
# eduPersonOrgUnitDN: <cn:=Physics>;<ou=1856>;<address=Panepistimioupolis Athens>;ou=1856,ou=units,dc=example,dc=com

# 001, faculty, example.com
dn: personID=001,ou=faculty,dc=example,dc=com
personID: 001
FacultyDepartment:: Physics
FacultyDepartmentID: 1856
ou:: Physics
givenName:: Nick
uid: 001
cn:: Nick Tesla
personAffiliation: professor
eduPersonOrgUnitDN: ou=1856,ou=units,dc=example,dc=com

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1