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.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
The samples cover a progressive enhancement from a simple starting point as described below:
Step 1: common or garden variety name and address directory with no security (anonymous read and limited write access).
Step 2: addition of a security policy - anonymous read to certain fields, secure access to others and limited secure write access.
Step 3: addition of two more branches to the hierarchy - a shared but secure customer branch and an equipment branch.
Step 4: addition of a new objectclass and some attributes.
Step 5: enhancement to single sign on (SSO) to support Samba, FTP, Apache and email (courier in this case).
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.
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.
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 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:
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.
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 # NO REFERRALS # DON'T bother with ARGS file unless you feel strongly # slapd scripts stop scripts need this to work pidfile /var/run/slapd.pid # 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 moduleload back_bdb.la # 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 example.com # 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).
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.
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.
There is no backend directive, which is not strictly necessary, even though some documentation suggests it is. Add it if you like typing.
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.
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:
## DEFINE DIT ROOT/BASE/SUFFIX #### ## 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 mail: email@example.com mail: firstname.lastname@example.org mail: email@example.com description: swell guy ou: Human Resources
Get sample file as text (use save as in your browser).
<warning> We incorrectly defined dn: dc=example,dc=com above as dn: dc=example.com 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>
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.
We use some terminology to simplify the description of certain LDIF concepts.
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.
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'.
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.
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.
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.
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.
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.
The space following the : (colon) on each line is VITAL.
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.
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.
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.
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.
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/slapd.sh start # confirm slapd is running ps ax | grep slapd # (you should see the slapd process entry if it has been started successfully)
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://ldaphost.example.com -x -D "cn=jimbob,dc=example,dc=com" -f /tmp/createdit.ldif -w dirtysecret
The ldaphost.example.com 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!
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 mail: firstname.lastname@example.org mail: email@example.com mail: firstname.lastname@example.org 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 mail: email@example.com mail: firstname.lastname@example.org mail: email@example.com 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://ldaphost.example.com -x -D "cn=jimbob,dc=example,dc=com" -f /tmp/addentry.ldif -w dirtysecret
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 mail: firstname.lastname@example.org mail: email@example.com - # 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).
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.
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.
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.
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.
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://ldaphost.example.com -x -D "cn=jimbob,dc=example,dc=com" -f /tmp/modentry.ldif -w dirtysecret
The ldaphost.example.com 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.
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.
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.
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 ldaphost.example.com 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.
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.
3 ldap objects
4 install ldap
7 replica & refer
10 ldap api
14 ldap tools
notes & info
rfc's & x.500
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