mail us  |  mail this page

contact us
training  | 
tech stuff  | 

Chapter 5. OpenLDAP Samples

This section is designed to be a paint-by-numbers set of implementations with links to back-up information. By taking the links you might learn something - you have been warned.

This section will create a single LDAP directory implementation that will be progressively enhanced one-step-at-a-time.

Before you begin - if you don't already have an LDAP browser get one now. There are plenty of Open Source ones available. An LDAP Browser is a specialized LDAP Client which allows generic access and exploration of an LDAP directory. It is an invaluable tool. You are blind without one. As a minimum the LDAP Browser should be capable of binding as either anonymous or using a specific DN, exporting LDIF files and searching - if it can add entries and attributes and import from LDIF so much the better. You can of course, assuming you like high levels of pain, use command line utilities such as ldapadd, ldapsearch. But then again you can also bang your head against a wall - repeatedly. Entirely your choice.


5.1 Simple Directory

5.1.1 Designing the DIT
5.1.2 Select the STRUCTURAL objectClass
5.1.3 slapd.conf File
5.1.4 LDIF File
5.1.5 Loading the LDIF
5.1.6 Adding New Entries using LDIF
5.1.7 Modifying Entries using LDIF
5.1.8 Just Fooling Around

5.2 Securing the Directory

5.2.1 Security Policy
5.2.2 Adding Groups
5.2.3 ACL slapd.conf Access Definitions
5.2.4 Testing the ACL

5.3 Expanded Hierarchy

5.3.1 Requirement
5.3.2 Implementation
5.3.3 LDIF
5.3.4 ACL slapd.conf Access Definitions
5.3.5 Testing the ACL

5.4 Creating & Adding Objects

5.4.1 Requirement
5.4.2 Implementation
5.4.3 Attribute Definitions
5.4.4 objectClass & Schema Definition
5.4.5 ACL slapd.conf Access Definitions
5.4.6 LDIF
5.4.7 Testing the Changes

5.5 Single Sign On
5.6 Referral and Replication

The samples cover a progressive enhancement from a simple starting point as described below:

  1. Step 1: common or garden variety name and address directory with no security (anonymous read and limited write access).

  2. Step 2: addition of a security policy - anonymous read to certain fields, secure access to others and limited secure write access.

  3. Step 3: addition of two more branches to the hierarchy - a shared but secure customer branch and an equipment branch.

  4. Step 4: addition of a new objectclass and some attributes.

  5. Step 5: enhancement to single sign on (SSO) to support Samba, FTP, Apache and email (courier in this case).

  6. Step 6: distribution of control (referrals) and implementation of a single stealth master (replication).

Note: OpenLDAP is in the process of moving from a textual configuration file (slapd.conf) to on-line configuration (OLC or cn=config). As of OpenLDAP version series 2.4 slapd.conf is still supported by OpenLAP and most distributions continue to ship using slapd.conf files. Others have decided to ship using OLC (cn=config), some even tell you they have done this and provide special tools and scripts to "make life easier". If your installation is in this latter category then you need to do three things: Read any documentation provided with your distributions OpenLDAP implementation; get thoroughly familiar with OLC (cn=config); curse quietly - your initial learning curve just got a bit steeper. Though you can always revert to classic slapd.conf configuration and migrate to OLC in your own time (read this section carefully to understand the process). The sample sections contain notes and explanations to cover slapd.conf or OLC (cn=config) configuration.

5.1 Simple Directory

We start with a simple name and address directory application which is not secured. There are about 6 million things that can go wrong when you start with any new application as complex as LDAP. We have omitted security to reduce the possible errors to around 3 million. Do not place any sensitive data in this application, security - even trivial security - is essential for any directory application. Security is however an add-on; it does not affect the data content of the directory - it can be retro-fitted at any time.

Up Arrow

5.1.1 Designing the DIT

This is actually a very important step and you can spend the rest of your life designing your DIT. People even write books about the subject. There are some generally accepted practices that we have documented but they may not work in your specific case. Take them for what they are - a starting point for your own thinking on the subject.

We have elected to follow the classic RFC 2377 format and use a dc format for the DIT root.

We will also organise the address book hierarchy under people and use an ou attribute for department. So we will end up with a DIT structure that looks like this:

LDAP Sample DIT - using RFC 2377 domain as root and people as second level in hierarchy

Up Arrow

5.1.2 Selecting the STRUCTURAL objectClass

Much wailing and gnashing of teeth usually accompanies selecting the primary objectclass. This is an essential LDAP ritual so start practising now.

However, the most generally useful objectclass for common or garden variety directories is inetorgperson since it has a BIG hierarchy with lots of attributes (follow its SUPerior hierarchy links). If we are missing something - we can add it later and Step 4 does exactly that. The decision is made; the case is closed for now.

Up Arrow

5.1.3 slapd.conf File

This is a sample slapd.conf that will let us get started using the Oracle Berkeley DataBase (BDB) backend (the OpenLDAP historically recommended database - it's currently mdb):

###### SAMPLE 1 - SIMPLE DIRECTORY ############
# NOTES: inetorgperson picks up attributes and objectclasses
#        from all three schemas
# NB: RH Linux schemas in /etc/openldap
include		/usr/local/etc/openldap/schema/core.schema
include		/usr/local/etc/openldap/schema/cosine.schema
include		/usr/local/etc/openldap/schema/inetorgperson.schema

# NO SECURITY - no access clause
# defaults to anonymous access for read
# only rootdn can write


# DON'T bother with ARGS file unless you feel strongly
# slapd scripts stop scripts need this to work
pidfile /var/run/

# enable a lot of logging - we might need it
# but generates huge logs
loglevel 	-1 

# MODULELOAD definitions
# not required (comment out) before version 2.3

# NO TLS-enabled connections

# backend definition not required

# bdb database definitions
# replace example and com below with a suitable domain
# If you don't have a domain you can leave it since
# is reserved for experimentation or change them to my and inc

database bdb
suffix "dc=example, dc=com"

# root or superuser
rootdn "cn=jimbob, dc=example, dc=com"
rootpw dirtysecret
# The database directory MUST exist prior to running slapd AND 
# change path as necessary
directory	/var/db/openldap/example-com

# Indices to maintain for this directory
# unique id so equality match only
index	uid	eq
# allows general searching on commonname, givenname and email
index	cn,gn,mail eq,sub
# allows multiple variants on surname searching
index sn eq,sub
# sub above includes subintial,subany,subfinal
# optimise department searches
index ou eq
# if searches will include objectClass uncomment following
# index objectClass eq
# shows use of default index parameter
index default eq,sub
# indices missing - uses default eq,sub
index telephonenumber

# other database parameters
# read more in slapd.conf reference section
cachesize 10000
checkpoint 128 15

Get sample file as text (use save as in your browser).


  1. You can customise BDB database specific parameters. The default values shown above for cachesize and checkpoint give us a reasonable configuration and can recover from the most common database write failures. If you even remotely care about performance you need to thoroughly understand configuration of BDB and experiment with it.

  2. Security is defined using access directives. Their absence in this case allows anonymous read (no authentication required) and no writing. Since the above definition includes rootdn and rootpw directives, we can write to the directory using this dn and experiment with binding when creating entries.

  3. There is no backend directive, which is not strictly necessary, even though some documentation suggests it is. Add it if you like typing.

  4. The selected indexes (indices) have optimized certain forms of access. You can still search using an attribute that is not indexed - it will just take longer.

Up Arrow

5.1.4 LDIF File

The LDIF below will create the DIT structure and add a single people entry - a later LDIF will add a further two entries. An LDAP browser can be used to add further entries, search the directory and do all the other fun stuff.

The LDIF will be added using the ldapadd utility with OpenLDAP (slapd) running. If you have lots of data records ready to rock n' roll then go ahead and build your LDIF and put as much into the directory as you want. If you really have a lot of data (>1,000) you may want to use the slapadd method to load the records for performance reasons.

Before we create the LDIF file we have to figure the data that MUST be present - in our case this also provides the minimal data to keep the examples short. So a quick browse of the inetorgperson objectclass hierarchy finds all the MUST entries. From our inspection only attributes cn and sn are mandatory. The following LDIF will set up our initial hierarchy and a single entry under people:

## uses RFC 2377 format
## replace example and com as necessary below
## or for experimentation leave as is

## dcObject is an AUXILLIARY objectclass and MUST
## have a STRUCTURAL objectclass (organization in this case)
# this is an ENTRY sequence and is preceded by a BLANK line

dn: dc=example,dc=com
dc: example
description: My wonderful company as much text as you want to place 
 in this line up to 32K continuation data for the line above must 
 have <CR> or <CR><LF> i.e. ENTER works 
 on both Windows and *nix system - new line MUST begin with ONE SPACE
objectClass: dcObject
objectClass: organization
o: Example, Inc.

## FIRST Level hierarchy - people 
## uses mixed upper and lower case for objectclass
# this is an ENTRY sequence and is preceded by a BLANK line

dn: ou=people, dc=example,dc=com
ou: people
description: All people in organisation
objectclass: organizationalunit

## SECOND Level hierarchy
## ADD a single entry under FIRST (people) level
# this is an ENTRY sequence and is preceded by a BLANK line
# the ou: Human Resources is the department name

dn: cn=Robert Smith,ou=people,dc=example,dc=com
objectclass: inetOrgPerson
cn: Robert Smith
cn: Robert J Smith
cn: bob  smith
sn: smith
uid: rjsmith
userpassword: rJsmitH
carlicense: HISCAR 123
homephone: 555-111-2222
description: swell guy
ou: Human Resources

Get sample file as text (use save as in your browser).


  1. <warning> We incorrectly defined dn: dc=example,dc=com above as dn: in versions of this guide prior to 0.1.2 which successfully loaded in OpenLDAP 2.0 and 2.1 but was rejected by OpenLDAP 2.2 (error 64). </warning>

  2. When entries are added they commence with the line starting 'dn:'. In general, any attribute may be used for this purpose as long as 'dn:' is unique and, to save excessive searching, it will typically be the DN most frequently used to access the entry. In the case of the last entry in the above LDIF the value cn=Robert Smith,ou=people,dc=example,dc=com is used implying that cn= will be the most frequently used DN to access entries. However, if the entry will be used for authentication then this DN MUST be that used with any secure Bind Operation. In this case a DN of uid=rjsmith,ou=people,dc=example,dc=com may be more appropriate. While this initial or 'creation' DN has no special terminology within the LDAP standards, when used for authentication it is sometimes referred to as the Principal DN. For more on this topic.

  3. We use some terminology to simplify the description of certain LDIF concepts.

  4. As noted in the comments version: is not strictly necessary. If present it must be (currently) set to 1 to indicate version 1 of the LDIF format. It was included in the orginal version (ouch!) simply because it should be a Good Thing™. Future versions may be not be compatible or may impose stricter validation - it's best to get into good habits. During our testing we noticed that certain brain-dead versions of OpenLDAP choked on the version statement with failure messages suggesting that no DN exists and it was removed.

  5. Comments are indicated by a # in the first column only. The following line interprets # as content:

    cn: my name #this is my name

    The resulting cn attribute will contain 'my name #this is my name'.

  6. There must be at LEAST one BLANK line between entries (before the lines starting with dn:). This is VERY important - strange errors will result otherwise.

  7. CONTINUATION lines are assumed if the line finishes with a line separator (a <CR> or <Cr><LF> sequence) and the next line starts with EXACTLY ONE SPACE.

  8. The above file uses attribute names that inconsistently use upper and lower case letters - specifically, that ghastly pseudo-hungarian (CamelCase or even Camel case) notation for objectClass and all lower case letters for objectclass. Both work. Which style you adopt is up to you.

  9. The line cn: bob smith contains multiple apparent errors. There are two spaces between 'bob' and 'smith' and both use lower case. Neither apparent error has any effect on the effectiveness of the directory because the attribute cn (child of the name attribute) uses a case insensitive matchingrule and LDAP does some interesting things on searching.

  10. In a lot of documentation you will see objectclass: top, as well as an insistence on defining all the objectclasses in the hierarchy. Since OpenLDAP 2.0 this has not been necessary whether you continue to do it will be defined by your system requirements or the buzz you get from typing lots of stuff.

  11. The space following the : (colon) on each line is VITAL.

  12. In a lot of documentation you will see an entry defined for the rootdn (the superuser) in the LDIF file (in the example slapd.conf this is rootdn "cn=jimbob,dc=example,dc=com"). As long as rootpw is supplied in the slapd.conf file this is unnecessary and potentially dangerous since it exposes this entry to external access. We advise strongly against doing this, and provide a detailed discussion on this topic.

  13. We have used multiple cn values to allow the maximum chance of finding the person by name. We used an index parameter of eq,sub (in the slapd.conf file) on the cn attribute. Whether you do this or not is a matter of policy and preference. You could just assume that sn is the basic parameter of search to find someone, but in that case you may want to index using approx for a sounds-like search. The choice of Robert Smith on the dn: line (dn: cn=Robert Smith,dc=example,dc=com) is purely arbitrary and it could have been any one of the cn values.

  14. Each of these entries is implicity using a changetype: add directive which would immediately follow the dn: line and which is defaulted - we will see use of the changetype LDIF directive later.

  15. Some of attributes we have added may look a little bizarre but they will be used in later examples to illustrate certain points. You can add any other attributes of the objectclass hierarchy you choose to the LDIF.

The majority of directory systems can be constructed using the above subset of the full LDIF file vocabulary.

Up Arrow

5.1.5 Loading the LDIF File

To load an LDIF file we will need a running OpenLDAP server (slapd), so we should start it now, if it is not already running, with a command resembling the following:

[redhat] /etc/rc.d/init.d/ldap start
[bsd] /usr/local/etc/openldap/ start

# confirm slapd is running
ps ax | grep slapd
# (you should see the slapd process entry if it has been started successfully)

Note: slapd daemon command line options.

Assuming we save the above LDIF as createdit.ldif in our /tmp directory we load the LDIF file using ldapadd with a command like this (line below is split for HTML formatting reasons only and should be on a single line):

ldapadd -H ldap:// -x -D "cn=jimbob,dc=example,dc=com" 
 -f /tmp/createdit.ldif -w dirtysecret

The should be replaced with whatever hostname your LDAP directory is located on. If the ldap host is the same system as the one from which the command is issued the -H and parameter can be omitted. The -x indicates we do not use SASL security and is required since OpenLDAP 2.x. The -D is the binding and is required because we defined a rootdn and have no other access statements - the superuser gets to do everything. The -w followed by the password is, to say the least, insecure but currently so is the whole directory!

Up Arrow

5.1.6 Adding Entries using LDIF

The following LDIF shows how we add additional entries using LDIF.

version: 1

## ADD a single entry to people level

dn: cn=John Smith,ou=people,dc=example,dc=com
objectclass: inetOrgPerson
cn: John Smith
cn: John J Smith
sn: Smith
uid: jsmith
userpassword: jSmitH
carlicense: HISCAR 124
homephone: 555-111-2223
ou: Sales

## ADD another single entry to people level

dn: cn=Sheri Smith,ou=people,dc=example,dc=com
objectclass: inetOrgPerson
cn: Sheri Smith
sn: smith
uid: ssmith
userpassword: sSmitH
carlicense: HERCAR 125
homephone: 555-111-2225
ou: IT

Get sample file as text (use save as in your browser).

Assuming we save the above LDIF as addentry.ldif in our /tmp directory we load the LDIF file using ldapadd with a command like this (line below is split for HTML formatting reasons only and should be on a single line):

ldapadd -H ldap:// -x -D "cn=jimbob,dc=example,dc=com" 
 -f /tmp/addentry.ldif -w dirtysecret

Up Arrow

5.1.7 Modifying Entries

The following LDIF shows how we modify entries using LDIF - its usually quicker to use your LDAP Browser but if you have bulk changes LDIF is quicker.

version: 1

## MODIFY the Robert Smith entry

dn: cn=Robert Smith,ou=people,dc=example,dc=com
changetype: modify
add: telephonenumber
telephonenumber: 555-555-1212
telephonenumber: 212
replace: uid
uid: rjosmith
replace: mail
# adds using URL format
add: jpegphoto
jpegphoto: < file://path/to/jpeg/file.jpg
delete: description

Get sample file as text (use save as in your browser).


  1. The changetype: modify tells OpenLDAP we are going to make mods to the entry. It could also have been changetype: delete which will delete the whole entry.

  2. add: attribute tells OpenLDAP we are going to add the attribute which immediately follows it. In this case we add telephonenumber attributes (which are attributes of the organizationalPerson objectclass) to the entry.

  3. replace: attribute tells OpenLDAP we are going replace the attribute which immediately follows it. In this case we replace both uid and mail attributes. In the case of mail we originally added three mail values, replace will delete all the attributes and add the two from this LDIF. The Robert Smith entry will, at the end of the operation, have only two mail attributes - the ones we modified using this LDIF.

  4. The line jpegphoto: < file://path/to/jpeg/file.jpg tells OpenLDAP to read the contents of the file (specified by a full path descriptor). The < in this case is preceded by a space and MUST be immediately followed by a space (Note this is not the format defined in RFC 2849 examples 5 and 6 but works). If you don't have a handy JPEG lying around (it can be anything) edit out the two lines.

  5. The line delete: description tells OpenLDAP to delete the description attribute - we decided that Mr. Robert Smith was not such a swell guy.

Assuming we save the above LDIF as modentry.ldif in our /tmp directory we load the LDIF file using ldapadd with a command like this (line below is split for HTML formatting reasons only and should be on a single line):

ldapadd -H ldap:// -x -D "cn=jimbob,dc=example,dc=com" 
 -f /tmp/modentry.ldif -w dirtysecret

The should be replaced with whatever hostname your LDAP directory is located on. The .ldif file name qualifier is not a requirement just a convention we happen to use, it could have been called modentry.file or whatever.

Up Arrow

5.1.8 Just Fooling Around

Now you can experiment with the basic LDAP structure. We suggest you use this opportunity to get thoroughly familiar with LDAP operations before moving on.

  1. Use an LDAP browser or LDIF files to add further entries or attributes to the existing entries. You must bind using cn=jimbob,dc=example,dc=com (rootdn or superuser and its associated rootpw) when writing to the directory.

  2. Use ldapsearch or your LDAP Browser to search on various criteria.

  3. Historical Note: Once upon a time browsers of the Mozilla family (for instance FireFox) or MS Explorer (5+) used to support LDAP URLs of the following format:


    The should be replaced with whatever hostname your LDAP directory is located on and replace any other references to example and com to reflect your implementation.

Up Arrow

Step 2 - Securing the Directory

Go to Arrow

Problems, comments, suggestions, corrections (including broken links) or something to add? Please take the time from a busy life to 'mail us' (at top of screen), the webmaster (below) or info-support at zytrax. You will have a warm inner glow for the rest of the day.


tech info
guides home
1 objectives
big picture
2 concepts
3 ldap objects
4 install ldap
5 samples
6 configuration
7 replica & refer
8 ldif
9 protocol
10 ldap api
11 howtos
12 trouble
13 performance
14 ldap tools
15 security
notes & info
ldap resources
rfc's & x.500
ldap objects
change log

Creative Commons License
This work is licensed under a Creative Commons License.

If you are happy it's OK - but your browser is giving a less than optimal experience on our site. You could, at no charge, upgrade to a W3C STANDARDS COMPLIANT browser such as Firefox




Icons made by Icomoon from is licensed by CC 3.0 BY
share page via facebook tweet this page


email us Send to a friend feature print this page Display full width page Decrease font size Increase font size



Debian Linux


GNU-Free SW Foundation


Open Source Initiative
Creative Commons


Ibiblio - Library
Open Book Project
Open Directory


CSS Technology SPF Record Conformant Domain
Copyright © 1994 - 2017 ZyTrax, Inc.
All rights reserved. Legal and Privacy
site by zytrax
Hosted by
web-master at zytrax
Page modified: December 11 2017.