RJ Systems
Linux System Administration
Home Tech Linux Links Consulting







Valid XHTML 1.0!

Valid CSS!

IPv6 test

OpenLDAP provider on Debian squeeze

Introduction

Back in the mid 1980s, before the Internet and its TCP/IP protocol suite became popular, two standards organizations, the ITU-T (then known as the CCITT) and the ISO, were busy developing their own standards for network communications. They had already produced the OSI Transport service, which was an advance in network communications, and also X.400; a collection of data communication standards for what was basically an e-mail service. However, more standards needed to be defined before any of this could be used as part of a global communications system.

The two organizations were looking for solutions. The ITU-T was hoping to develop a white pages service that would return either people's phone numbers or X.400 O/R addresses, while the ISO mostly wanted a name server service for OSI applications. Not wanting to duplicate each other's efforts, they decided to pool their resources. Together they produced a set of networking standards in 1988, called X.500, for what was described as a directory service.

X.500 is an elaborate collection of protocols, specifications and definitions centered around the concept of a single, distributed, replicated, global Directory Information Tree (DIT), capable of storing all kinds of information that would be accessible via the Directory Access Protocol (DAP). The whole system would take off as soon as organizations everywhere started to publish their own directory information, or subsets thereof, in the global DIT. Unfortunately, this never happened, perhaps because most organizations considered their own directory information to be too valuable, or too confidential, to be made available to the world at large in the form of an X.500 directory sub-tree.

However, the concept of a private DIT, and a DAP with which to access it, was regarded as worthy enough in its own right. It just needed to be simplified somewhat. To this end, the Lightweight Directory Access Protocol (LDAP) was defined in 1993 (RFC-1487), giving clients access to an X.500-based DIT via TCP/IP without incurring the costly resource requirements associated with the X.500 DAP. The third and current version of LDAP was published in 1997 (RFC-2251), with a technical specification (RFC-3377) following in 2002.

First released 1998, OpenLDAP is the popular open source implementation of LDAP. With it, anyone can create their own DIT and, unfettered by vendor limitations, decide for themselves what to use it for. All kinds of information can be stored in it − anything from host configuration data to names and addresses − and accessed from anywhere using the many different LDAP-compatible applications.

A DIT is a hierarchically organized collection of entries, each identified by a Distinguished Name (DN); a unique, comma-separated list of components that provide the path to an entry, or object, from the top of the tree. For example, the DN of the root of a DIT for Example Corp. could be dc=example,dc=com, while the DN of someone employed there might be cn=JoeSmith,ou=People,dc=example,dc=com. The Relative Distinguished Name (RDN) of this entry is cn=JoeSmith. Notice how each DN consists of multiple key=value pairs. The keys in these example DNs stand for Common Name (cn), Organizational Unit (ou) and Domain Component (dc).

All LDAP entries are typed, meaning that each DN belongs to an objectClass that identifies the type of information it represents. In turn, each entry consists of multiple attributes that also consist of key=value pairs, each of which is defined by a certain attributeType. These objectClasses and attributeTypes are defined in schema files. This allows an LDAP administrator to decide which schema files to include, based on the needs of the applications that will be using the DIT.

In this example, OpenLDAP is installed on a host running Debian 6.0 (squeeze). If followed properly, the step-by-step process should produce a provider server with a new DIT. Actually, OpenLDAP used to refer to master and slave servers, but this has been depricated in favor of, respectively, provider and consumer servers, since the differences between them are not as distinct as they once were. This is because some consumers may now also act as providers for other LDAP hosts.

Before the actual OpenLDAP installation process can begin, it will first be necessary to install Debian squeeze on a new host called ldaps1.example.com. A DNS server must also be available on the network with a zone file to which forward and reverse mappings can be added for this host, as well as an alias for it called ldaps.example.com. After the initial installation of the operating system, make sure these packages are installed on the system as well:

~# apt-get install ssh nmap

Now the installation process for the OpenLDAP provider server can begin:


1. Package installation

On the new host, ldaps1.example.com, start by installing these two packages:

~# apt-get install slapd ldap-utils

A total of eight packages are installed as a result, including six dependencies:

ldap-utils              2.4.23-7                   OpenLDAP utilities
libltdl7                2.2.6b-2                   A system independent dlopen wrapper for GNU libtool
libperl5.10             5.10.1-16                  shared Perl library
libslp1                 1.2.1-7.8                  OpenSLP libraries
odbcinst                2.2.14p2-1                 Helper program for accessing odbc ini files
odbcinst1debian2        2.2.14p2-1                 Support library for accessing odbc ini files
slapd                   2.4.23-7                   OpenLDAP server (slapd)
unixodbc                2.2.14p2-1                 ODBC tools libraries

During the install process, an administrator password will be requested for slapd. Use piscivorus:

Administrator password: piscivorus
Confirm password: piscivorus

Run the following command to test if the OpenLDAP server is actually running:

~# nmap -p 389 localhost

Starting Nmap 5.00 ( http://nmap.org ) at 2010-10-27 15:05 CEST
Warning: Hostname localhost resolves to 2 IPs. Using 127.0.0.1.
Interesting ports on localhost (127.0.0.1):
PORT    STATE SERVICE
389/tcp open  ldap

Nmap done: 1 IP address (1 host up) scanned in 0.08 seconds
~# _

The ldap service is made available on port 389 by the Standalone LDAP Daemon (slapd). Note that the state of the port is open. To be sure, the LDAP v3 technical specification (RFC-3377) does not mention anything about a backend solution in which to store the database; it is only a description of the network protocol itself. The daemon, slapd, the way it stores its data and the various utilities it comes with are all unique to OpenLDAP.

Perform a quick test by generating an LDAP Data Interchange Format (LDIF) dump of the contents of a the database:

~# slapcat
hdb_db_open: database "dc=example,dc=com": unclean shutdown detected; 
attempting recovery.
hdb_db_open: database "dc=example,dc=com": recovery skipped in read-only 
mode. Run manual recovery if errors are encountered.
dn: dc=example,dc=com
objectClass: top
objectClass: dcObject
objectClass: organization
o: example.com
dc: example
structuralObjectClass: organization
entryUUID: 6c2b7ba6-7614-102f-8dca-2b8c20077bc5
creatorsName: cn=admin,dc=example,dc=com
createTimestamp: 20101027124946Z
entryCSN: 20101027124946.661291Z#000000#000#000000
modifiersName: cn=admin,dc=example,dc=com
modifyTimestamp: 20101027124946Z

dn: cn=admin,dc=example,dc=com
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: admin
description: LDAP administrator
userPassword:: e1NTSEF9NUxZQ0hMd2E4OHgzQzE4d29xeEVkSWFqZVpsWndBT1U=
structuralObjectClass: organizationalRole
entryUUID: 6c2bfc66-7614-102f-8dcb-2b8c20077bc5
creatorsName: cn=admin,dc=example,dc=com
createTimestamp: 20101027124946Z
entryCSN: 20101027124946.664624Z#000000#000#000000
modifiersName: cn=admin,dc=example,dc=com
modifyTimestamp: 20101027124946Z

~# _

If the output looks something like the above, continue with the next step.


2. ldap.conf

Edit /etc/ldap/ldap.conf and add these two lines to the end of the file:

BASE	dc=example,dc=com
URI	ldap://ldaps1.example.com/

This configuration file is used to set system-wide defaults for LDAP clients.


3. cn=config

As of OpenLDAP 2.4.23-3, the slapd runtime configuration is fully LDAP-enabled and the default is to manage it using the standard LDAP operations with data in LDIF. The old slapd.conf format is still supported, but since that file must now be converted to the new slapd-config format to allow runtime changes to be saved, it seems likely that the developers will eventually phase it out. Therefore, this article will focus only on the new configuration method, the main advantage of which is that any changes made are immediately active, so it is no longer necessary to restart slapd after making configuration changes.

The new configuration format uses a slapd backend database that is found in the /etc/ldap/slapd.d/ directory. The configuration is stored as a special LDAP directory with a predefined schema and DIT, the root of which is called cn=config. To get an idea of what this database looks like, run this command:

~# slapcat -b cn=config

This generates an LDIF dump of the contents of the cn=config directory. Much of it consists of schema information. The LDAP configuration directives are attributes of the directory entries (objects) and most them start with the prefix "olc" (OpenLDAP Configuration). Also, some of the objects have names with numbers between curly brackets. This is to compensate for the fact that LDAP databases do not store their contents in any particular order; they are inherently unordered. The numbers constitute a numeric index to ensure a consistent order in the configuration database and thereby preserve all ordering dependencies. The index numbers, however, are generated automatically in the order they are created and usually do not have to be provided.

In this step of the installation process, a few general-purpose modifications will be made to two entries in the runtime DIT: to the cn=config object, which is the root of the configuration directory and contains attributes that are global directives, and to the olcDatabase={1}hdb entry, which is the database definition. To see what they look like at the moment, the attributes of both of these objects can be listed with a single command (see RFC-4515):

~# ldapsearch -LLLQY EXTERNAL -H ldapi:/// -b cn=config \
"(|(cn=config)(olcDatabase={1}hdb))"
dn: cn=config
objectClass: olcGlobal
cn: config
olcArgsFile: /var/run/slapd/slapd.args
olcLogLevel: none
olcPidFile: /var/run/slapd/slapd.pid
olcToolThreads: 1

dn: olcDatabase={1}hdb,cn=config
objectClass: olcDatabaseConfig
objectClass: olcHdbConfig
olcDatabase: {1}hdb
olcDbDirectory: /var/lib/ldap
olcSuffix: dc=example,dc=com
olcAccess: {0}to attrs=userPassword,shadowLastChange by self write by anonymou
 s auth by dn="cn=admin,dc=example,dc=com" write by * none
olcAccess: {1}to dn.base="" by * read
olcAccess: {2}to * by self write by dn="cn=admin,dc=example,dc=com" write by *
  read
olcLastMod: TRUE
olcRootDN: cn=admin,dc=example,dc=com
olcRootPW: {SSHA}ABsCG0bmPL8aRFVEU4NK6zYiU6QvVyPK
olcDbCheckpoint: 512 30
olcDbConfig: {0}set_cachesize 0 2097152 0
olcDbConfig: {1}set_lk_max_objects 1500
olcDbConfig: {2}set_lk_max_locks 1500
olcDbConfig: {3}set_lk_max_lockers 1500
olcDbIndex: objectClass eq

~# _

The -L option used here causes the results to be displayed in LDAP Data Interchange Format (LDIF). A second -L will disable comments, and a third one will prevent the LDIF version from being printed. The default is to use extended LDIF.

Five changes will be made to the cn=config DIT:

1. For the root object, cn=config, the value for olcLogLevel is currently set to none (the Debian default). This prevents slapd from writing almost anything to the syslog. This is okay for production environments, but less desirable for educational purposes, so it is going to be changed to stats (the value recommended by the OpenLDAP project). This way, slapd will log more about what it does to /var/log/syslog.
2.1. For the database definition, olcDatabase={1}hdb,cn=config, an extra equality (eq) index will be added for User ID (uid) objects. olcDbIndex directives are used to specify the attributes on which slapd should maintain indices to optimize directory searches. This new equality index will speed up searches for entries based on exact matches of the uid attribute. At the moment it is not really necessary to add any extra indices, since the dc=example,dc=com directory contains almost no data. However, it is recommended to add an eq index for uid entries, because these are used for storing user account names and later on, as the DIT grows in size, this index can significantly decrease the time it takes for users to log in. This eq will also prevent "bdb_equality_candidates" errors...
2.2. An equality index will also be set for Common Name (cn) objects to prevent "bdb_equality_candidates" errors from appearing in the log file, /var/log/syslog. One such error will otherwise appear in the log for every search for an entry of this type.
2.3. Idem for Organizational Unit (ou) objects.
2.4. Idem for Domain Component (dc) objects.

To make both of the above changes to the cn=config DIT, first create an LDIF file, called ~/olc-mod1.ldif, with the following contents:

# 1.
dn: cn=config
changetype: modify
replace: olcLogLevel
olcLogLevel: stats

# 2.1.
dn: olcDatabase={1}hdb,cn=config
changetype: modify
add: olcDbIndex
olcDbIndex: uid eq
-
# 2.2.
add: olcDbIndex
olcDbIndex: cn eq
-
# 2.3.
add: olcDbIndex
olcDbIndex: ou eq
-
# 2.4.
add: olcDbIndex
olcDbIndex: dc eq

NB: According to the LDIF specification (RFC-2849), lines containing only a "-" character act as a separator between modifications that apply to the same directory entry. Empty lines separate tasks involving different directory entries. Lines that start with a "#" character are considered comments and are ignored.

Apply both of the above changes with this single command:

~# ldapmodify -QY EXTERNAL -H ldapi:/// -f ~/olc-mod1.ldif
modifying entry "cn=config"

modifying entry "olcDatabase={1}hdb,cn=config"

~# _

Repeat the previous ldapsearch command to verify that the changes have been applied. Also, check /var/log/syslog for slapd log output.


4. Basic tree

Create a basic tree structure. First create a file, ~/tree.ldif, with the following contents:

dn: ou=people,dc=example,dc=com
ou: people
objectClass: organizationalUnit

dn: ou=groups,dc=example,dc=com
ou: groups
objectClass: organizationalUnit

Add this information to the LDAP database with the ldapadd command:

~# ldapadd -cxWD cn=admin,dc=example,dc=com -f ~/tree.ldif
Enter LDAP Password: piscivorus
adding new entry "ou=people,dc=example,dc=com"

adding new entry "ou=groups,dc=example,dc=com"

~# _

Five different options are used for this ldapadd command:

-c Continuous operation mode: modifications will continue after any errors are reported. The default is to exit after an error has been reported.
-x Simple authentication. The default is SASL.
-W Prompt the user for simple authentication.
-D <binddn> Specifies the Distinguished Name with which to bind to the LDAP directory.
-f <file> Specifies a file name to use that contains new entry information (as opposed to standard input).

Perform a test. Run an ldapsearch with an anonymous bind (no DN specified) to check that the new organizational units have indeed been added to the database. Check that the output looks like the following and does not contain any obvious errors:

~# ldapsearch -xLLL
dn: dc=example,dc=com
objectClass: top
objectClass: dcObject
objectClass: organization
o: example.com
dc: example

dn: cn=admin,dc=example,dc=com
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: admin
description: LDAP administrator

dn: ou=people,dc=example,dc=com
ou: people
objectClass: organizationalUnit

dn: ou=groups,dc=example,dc=com
ou: groups
objectClass: organizationalUnit

~# _

5. User account

Create a new user account, called ccolumbus. First create a file, ~/ccolumbus.ldif, with the following contents:

dn: cn=ccolumbus,ou=groups,dc=example,dc=com
cn: ccolumbus
gidNumber: 20000
objectClass: top
objectClass: posixGroup

dn: uid=ccolumbus,ou=people,dc=example,dc=com
uid: ccolumbus
uidNumber: 20000
gidNumber: 20000
cn: Christopher
sn: Columbus
objectClass: top
objectClass: person
objectClass: posixAccount
objectClass: shadowAccount
loginShell: /bin/bash
homeDirectory: /home/ccolumbus
userPassword: NewWorld

Add this information to the DIT with the ldapadd command:

~# ldapadd -cxWD cn=admin,dc=example,dc=com -f ~/ccolumbus.ldif
Enter LDAP Password: piscivorus
adding new entry "cn=ccolumbus,ou=groups,dc=example,dc=com"

adding new entry "uid=ccolumbus,ou=people,dc=example,dc=com"

~# _

Run an ldapsearch for the new ccolumbus entry to check if the response seems reasonable and does not contain any errors. The output should look like this:

~# ldapsearch -xLLL uid=ccolumbus
dn: uid=ccolumbus,ou=people,dc=example,dc=com
uid: ccolumbus
uidNumber: 20000
gidNumber: 20000
cn: Christopher
sn: Columbus
objectClass: top
objectClass: person
objectClass: posixAccount
objectClass: shadowAccount
loginShell: /bin/bash
homeDirectory: /home/ccolumbus

~# _

It is possible to test authentication for an LDAP account with the ldapwhoami command:

~# ldapwhoami -xD uid=ccolumbus,ou=people,dc=example,dc=com -w NewWorld
dn:uid=ccolumbus,ou=people,dc=example,dc=com
~$ _

This is also an example of a password that is specified on the command line using the -w option.

Anyway, when using only simple authentication, if no DN is given to bind to and no password is included, the binding will be anonymous:

~# ldapwhoami -x
anonymous
~# _

The same applies to ldapsearch when using simple authentication. In all such cases the principle is the same: authentication and authorization must take place before any such single commands are processed.


6. See also
7. Further reading
  • Eastlake D, Panitz A. 1999. RFC2606 − Reserved Top Level DNS Names. The Internet Society. HTML at the Internet FAQ Archives.
  • Hodges J, Morgan R. 2002. RFC3377 − Lightweight Directory Access Protocol (v3): Technical Specification. The Internet Society. HTML at the Internet FAQ Archives.
  • Smith M, Howes T. 2006. RFC4515 − Lightweight Directory Access Protocol (LDAP): String Representation of Search Filters. The Internet Society. HTML at the Internet FAQ Archives.
  • Wahl M, Howes T, Kille S. 1997. RFC2251 − Lightweight Directory Access Protocol (v3). The Internet Society. HTML at the Internet FAQ Archives.
  • Yeong W, Howes T, Kille S. 1993. RFC1487 − X.500 Lightweight Directory Access Protocol. The Internet Society. HTML at the Internet FAQ Archives.

8. Sources
  • Carter G. 2003. LDAP System Administration. O'Reilly & Associates, Inc. ISBN 1-56592-491-6. 294 pp.
  • Chadwick DW. 1994, 1996. Understanding X.500 − The Directory. HTML at the University of Kent.
  • Ocelic D. 2006-2010. Debian GNU: Setting up OpenLDAP. HTML at Spinlock Solutions.
  • OpenLDAP Project. 2009. OpenLDAP Software 2.4 Administrator's Guide. HTML at OpenLDAP.


Last modified: 2011-01-05, 22:47

©2003-2014 RJ Systems. Permission is granted to copy, distribute and/or modify the
content of this page under the terms of the OpenContent License, version 1.0.