OpenLDAP is the open source implementation of the LDAP protocol to access a directory. Simply put, a directory is a repository of data, much like a database (but with significant differences) that is used to store huge amounts of data. Directories are optimised for fast search and retrieval. Directories are also fairly static — in the sense that the data in a directory is not updated very frequently.
LDAP or “Lightweight Directory Access Protocol” is a protocol used to access directories. OpenLDAP is an open source directory software suite conforming to the LDAP protocol (version 3) and it supports all major platforms. The current version of OpenLDAP is 2.4. There are significant changes in this version compared to v2.3. In this article though, we will cover features that apply to the previous versions as well.
The OpenLDAP software suite consists of a directory server (
openldap-server) and a client (
openldap-clients) to access the directory. To be able to query other LDAP servers, only the
openldap-client is required.
openldap-client package provides popular client tools such as
ldapadd, etc. The
openldap-server software is required if you want to build a directory of your own.
On a RHEL/CentOS/Fedora system, the OpenLDAP RPMS are available as
openldap-clients. A simple check will reveal the RPMs installed in your system. To query the RPM database for the installed OpenLDAP RPMS, run the following command:
[vbg@vbg-work scratch]$ rpm -qa | grep openldap
In my system, the output was as follows:
Installing the OpenLDAP client
To be able to query other LDAP servers, you will need to install the
[root@vbg-work ~]# yum install openldap-clients
With the client software installed, you can access other LDAP servers. There are quite a few LDAP servers on the Internet that allow anonymous querying, which implies querying a server without providing a user name and password, much like in anonymous FTP transactions where you can download files without providing a username/password for authentication.
To query a directory server conforming to the LDAP protocol, use the
ldapsearch command. A list of public LDAP servers can be found here. To test whether your OpenLDAP client software is installed correctly and is able to query remote LDAP servers, you may query any one of the listed servers.
As an example, I chose to query the server
[vbg@vbg-work scratch]$ ldapsearch -x -h x500.bund.de -b "o=bund,c=de"
-h flag above specifies the hostname to be queried. The
-b flag specifies the “base” from which the search should begin and
-x specifies “simple authentication”.
Running the command displays a lot of output on the screen. Redirecting this output to a file will help us in understanding LDAP:
[vbg@vbg-work scratch]$ ldapsearch -x -h x500.bund.de -b "o=bund,c=de" > /tmp/ldapTGH-1.txt ldap_bind: Success (0) additional info: Bind succeeded [vbg@vbg-work scratch]$
stderror output (which was not redirected by the above command) shows that binding (or authenticating and connecting) to the LDAP server was successful. Let us now look at the contents of this file, which contain the output of our query:
[vbg@vbg-work scratch]$ less /tmp/ldapTGH-1.txt # extended LDIF # # LDAPv3 # base with scope subtree # filter: (objectclass=*) # requesting: ALL
The opening line shows us that the output is in the LDIF format. It stands for LDAP Data Interchange Format. LDIF is used to represent LDAP data in text form. An understanding of LDIF is critical to be able to perform successful add/modify/delete/search operations on an LDAP server. LDIF files are useful for:
- adding data to the LDAP directory,
- modifying directory data,
- deleting directory data, and
- pretty much anything that has to do with visualisation of directory data.
The other lines also give us some more meaningful information. Note that all these are preceded with a
# (hash). This means that these are comments, not the results of our query. They just provide additional information. The other important information is the version of the LDAP protocol used for querying (v3), the base of the LDAP tree on which the search operation was performed, and filters applied to refine search results.
A detailed explanation of this is beyond the scope of this article. Maybe in a future article, we can delve deep into the workings of LDAP and uncover its hidden treasures.
Most directories do not allow anonymous writing. To be able to add/modify/delete data, you need to bind to the directory server host with a valid user name and password. Most directories also do not allow anonymous read (or search). Depending on your environment and sensitivity, you may also wish to do away with anonymous read on your directory. This will depend on your LDAP server configuration.
Configuring the LDAP client
If you query a single directory server (within your organisation), typing the hostname and search base on the command line each time might seem like a mundane and irritating task. You can customise the
/etc/openldap/ldap.conf file (on Fedora/RHEL) as shown below to specify an LDAP server and base. The OpenLDAP client utilities read the
Warning: Do not modify the
/etc/ldap.conf file. It is for a different purpose and is accessed by a different set of programs.
To be able to simply query the above server (
x500.bund.de), just specify the following two lines in
HOST x500.bund.de BASE o=bund,c=de
Make sure you comment out all the other lines at this stage. Once you have done this, just execute the
ldapsearch command without the host and the base options:
[vbg@vbg-work scratch]$ ldapsearch -x
This will connect to the server specified in the configuration file and will search from the base mentioned there.
LDAP is a TCP/IP protocol and an LDAP server binds to TCP port 389 by default. When using TLS, the default secure LDAP port is 636. Instead of specifying a host, an LDAP URI can also be used. LDAP URIs are of the form:
The above LDAP search using LDAP URI instead of the hostname can be executed as follows:
[vbg@vbg-work scratch]$ ldapsearch -x -H ldap://x500.bund.de -b "o=bund,c=de"
…and the corresponding entry in
/etc/openldap/ldap.conf will be:
Installing the OpenLDAP server
To query other directory servers is one thing and to be able to create your own directory server to store and serve data is quite another. The first step towards creating your own directory server is installing the required software. In Fedora, a
yum install openldap-servers will do the job.
For the purpose of this article, I will create the
openldap-server on a virtual RHEL 5.4 server and the client will reside on my virtual Fedora 12 host. The details of the test setup are:
- LDAP server hostname: vbg.knafl.org (192.168.122.1) — RHEL 5.4 (64 bit)
- LDAP client hostname: vbg-work.knafl.org (192.168.122.244) — Fedora 12 (32 bit)
The LDAP server software installs the standalone LDAP daemon (
slapd). The version of the OpenLDAP server on RHEL 5.4 is 2.3 (
slapd daemon binds on Port 389 and serves client requests based on its directory data. In Fedora/RHEL systems, the important locations are:
/usr/sbin/slapd— the standalone LDAP daemon binary program
/var/lib/ldap/— the folder containing directory data files
/etc/openldap/slapd.conf— the LDAP server configuration file
/etc/init.d/ldap— init script for the LDAP daemon
It also creates the user and group LDAP. For security purposes, the
slapd daemon runs with the privileges of this user:
[root@vbg ~]# cat /etc/passwd | grep ldap ldap:x:55:55:LDAP User:/var/lib/ldap:/bin/false
Configuring the LDAP server
The main configuration file is
/etc/openldap/slapd.conf. For the init script to be able to read this file, the permissions of this file should be set to 640 and the owner group should be set to “ldap”:
[root@vbg openldap]# ls -l /etc/openldap/slapd.conf -rw-r----- 1 root ldap 3731 Nov 6 2008 /etc/openldap/slapd.conf
Let’s start configuring our very own LDAP server. As always, remember to keep a backup of the main config file — just in case something goes wrong:
[root@vbg openldap]# cp -a slapd.conf slapd.conf.org [root@vbg openldap]# vim /etc/openldap/slapd.conf
include section of this config includes certain files from the schema directory. These files describe the structure of our directory. We will examine these in more detail in another article. For now, to get going quickly, the other important directives in the configuration file are:
database bdb # this defines the database backend used by openldap. In this case - Berkeley Data Base Backend suffix "dc=my-domain,dc=com" # This is the root of the Directory Tree rootdn "cn=Manager,dc=my-domain,dc=com" # This is the Distinguished Name of the superuser of the directory # rootpw secret
For a directory server, the DN and the base suffix are important concepts.
The base suffix of a directory specifies the top of the directory tree (much like “
/” signifies the root of the Linux filesystem). All directory data is stored under this base suffix, much like folders and files in the traditional Linux filesystem. The DN (Distinguished Name) is the unique name of a directory entry (much like file names and directories — which need to be unique within the same parent folder).
LDAP is generally associated with DNS as most organisations would want their domain names mapped to their directory data. Therefore, if my domain name is
knafl.org, this domain context can be represented in the directory as follows:
Therefore, in the directory, the domain
knafl.org can be represented in a hierarchical fashion as:
We need to specify this base in our directory configuration file along with the superuser name and password. The superuser is referred to as
rootdn (the DN of the “root” user). This should also fall under the base of the directory tree and could be referred to by the Common Name (CN) of Manager. Finally, we should set the password of the root user.
We can also set the
rootdn password in clear text. This is a security risk and should be avoided. The password should be stored in an encrypted form. I am only including the “text password” for demo purposes.
#Sample /etc/openldap/slapd.conf database bdb suffix "dc=knafl,dc=org" rootdn "cn=Manager,dc=knafl,dc=org" # Cleartext passwords, especially for the rootdn, should # be avoided. See slappasswd(8) and slapd.conf(5) for details. # Use of strong authentication encouraged. rootpw FOSTERingLinux
Apart from the above, I have made no changes to the default configuration file. Once we have set up the server, we need to start the LDAP daemon. The LDAP service will read the configuration file and start the
[root@vbg openldap]# service ldap start Checking configuration files for slapd: bdb_db_open: Warning - No DB_CONFIG file found in directory /var/lib/ldap: (2) Expect poor performance for suffix dc=knafl,dc=org. config file testing succeeded [ OK ] Starting slapd: [ OK ] [root@vbg openldap]#
To check whether our LDAP is up, we will query our server as follows:
[root@vbg openldap]# ldapsearch -x -h localhost -b "dc=knafl,dc=org" # extended LDIF # # LDAPv3 # base with scope subtree # filter: (objectclass=*) # requesting: ALL # # # search result # search: 2 # result: 32 No such object # # numResponses: 1 # [root@vbg openldap]#
We will receive the “No such object” message from the server. This means that our LDAP server is running, but it could not locate our directory tree or the data.
Now we need to create the base data for our LDAP server. To do that, we need to create an LDIF file and use the client command
First, let us create a simple LDIF file for our directory base and save it in the file
[root@vbg ~]# cat /tmp/ldap-base dn: dc=knafl,dc=org dc: knafl objectClass: top objectClass: domain
Adding the entries to the directory:
[root@vbg ~]# ldapadd -x -D "cn=Manager,dc=knafl,dc=org" -W -f /tmp/ldap-base Enter LDAP Password: adding new entry "dc=knafl,dc=org" [root@vbg ~]#
By default, we require
rootdn privileges to write data in the directory. The
-D flag specifies the user name (DN in LDAP terminology), and
-W specifies that the password will be entered on the command line prompt. Finally,
-f specifies the name of the LDIF file that contains entries to be added to the directory.
Now when we query the directory, we get an output as follows:
root@vbg ~]# ldapsearch -x -h localhost -b "dc=knafl,dc=org" # extended LDIF # # LDAPv3 # base with scope subtree # filter: (objectclass=*) # requesting: ALL # # knafl.org dn: dc=knafl,dc=org dc: knafl objectClass: top objectClass: domain # # search result search: 2 result: 0 Success # numResponses: 2 # numEntries: 1
Thus we have created the base of our directory. Now we need to add more data to it and also beef up the security of the LDAP server.
Let us first add some more data to create an address book. Let us add a section called “addressbook” in our LDAP tree under the base suffix. This section can be denoted as an Organisational Unit (OU). Therefore, our LDIF file will be:
[root@vbg ~]# cat /tmp/addressbook-base.ldif dn: ou=addressbook,dc=knafl,dc=org ou: addressbook objectClass: top objectClass: organizationalUnit
Let us add this OU to our directory:
[root@vbg ~]# ldapadd -x -D "cn=Manager,dc=knafl,dc=org" -W -f /tmp/addressbook-base.ldif Enter LDAP Password: adding new entry "ou=addressbook,dc=knafl,dc=org" [root@vbg ~]#
Now let us add some addressbook entries under the OU “addressbook”. An example of an LDIF file with a user entry might look like the file displayed below:
[root@vbg ~]# cat /tmp/addressbook.ldif dn:cn=Varad Gupta,ou=addressbook,dc=knafl,dc=org cn: Varad Gupta sn: Gupta l: Gurgaon street: M-37, Old DLF Colony, Sector-14 st: Haryana postalCode: 122003 homePhone: 0124 22222222 mobile: 0999999999 mail: email@example.com objectClass: top objectClass: inetOrgPerson [root@vbg ~]#
Add this entry to our directory:
[root@vbg ~]# ldapadd -x -D "cn=Manager,dc=knafl,dc=org" -w FOSTERingLinux -f /tmp/addressbook.ldif adding new entry "cn=Varad Gupta,ou=addressbook,dc=knafl,dc=org" [root@vbg ~]#
-w flag followed by the password of the
rootdn instead of the
-W used earlier. With the
-w option, you can specify the password on the command line instead of being prompted for it.
You can similarly add other entries. Let us now query our directory from the Fedora client host:
[root@vbg ~]# ldapsearch -x -h localhost -b "dc=knafl,dc=org" # extended LDIF # # LDAPv3 # base with scope subtree # filter: (objectclass=*) # requesting: ALL # # knafl.org dn: dc=knafl,dc=org dc: knafl objectClass: top objectClass: domain # addressbook, knafl.org dn: ou=addressbook,dc=knafl,dc=org ou: addressbook objectClass: top objectClass: organizationalUnit # Varad Gupta, addressbook, knafl.org dn: cn=Varad Gupta,ou=addressbook,dc=knafl,dc=org cn: Varad Gupta sn: Gupta l: Gurgaon street: M-37, Old DLF Colony, Sector-14 st: Haryana postalCode: 122003 homePhone: 0124 22222222 mobile: 09999999999 mail: firstname.lastname@example.org objectClass: top objectClass: inetOrgPerson # # search result search: 2 result: 0 Success # numResponses: 5 numEntries: 4 [root@vbg ~]#
In the next article, we will look at how to secure our basic LDAP server — adding an encrypted
rootdn password, implementing access control, disallowing anonymous search, modifying and deleting entries, etc.