HomeHowTo › Basic OpenLDAP Installation & Configuration

Basic OpenLDAP Installation & Configuration

I’m not a huge fan of LDAP because I don’t like the handling of it, but if a directory service is needed it’ll most probably be an OpenLDAP, so sometimes one just has to deal with it. I’ll use this article to document the basic installation and configuration process of OpenLDAP and I’m going to do this on Ubuntu 14.04 LTS. This article can be understood as a very basic quick start guide.

 

1. Essential Knowledge About OpenLDAP

LDAP stands for Lightweight Directory Access Protocol and is based on the X.500 standard which defines the structure of directory services. The primary use of directory services is storing user- and object data in a central system and make this data available to other applications (often for authentication or as an address book). In contrast to relational database management systems (RDBMS) directory services are specifically optimized for read access.

The directory is built as a tree structure. The whole tree is referred to as the DIT (Directory Information Tree). At the very top of this tree is the (invisible) RootDSE which is the Directory Service Entry point. Then follows a BaseDN (Base Distinguished Name) that looks like a domain name and can consist of multiple components (i.e. dc=example,dc=com). But in contrast to domain names (i.e. example.com) an LDAP DN has to be spelled in attribute/value pairs (attribute1=value1,…,attributeN=valueN). Beneath the BaseDN any desired structure of OUs (Organizational Units) can be created to represent the company structure. At the very bottom would be the actual resources (persons, user/service accounts or any other objects) with their properties.

LDAP Directory Overview

LDAP Directory Overview

 

 

 

 

 

 

 

A DN (Distinguished Name) identifies one specific object in the tree (i.e. uid=postfix,ou=services,dc=example,dc=com). An RDN (Relative Distinguished Name) is one part of a DN (i.e. uid=postfix). dc (domain component) is an “allround”-attribute that can be used instead of specific attributes like o (organization) and c (country) to create general structures (the example above could also be created as uid=postfix,ou=services,o=example,c=com). Attributes (uid, ouo, c, dc) are part of objectClasses which in turn are defined by schemas.

The OpenLDAP daemon (server) is not configured through a classic config file; the configuration is stored in the directory itself. Changes to the configuration, the tree structure or objects are described in LDIF files (LDAP Data Interchange Format) and then added to the directory.

 

2. OpenLDAP Installation

Become root, update the software repository and upgrade your system:

1
2
3
sudo -i
apt-get update
apt-get upgrade

Install the OpenLDAP daemon (slapd) and the LDAP configuration tools (ldap-utils). During installation you’ll have to define a password for the LDAP Administrator account. Then check if slapd is running:

1
2
apt-get install slapd ldap-utils
lsof -Pni :389

OpenLDAP is now ready to use.

 

3. OpenLDAP Default Configuration

The configuration can be found in /etc/ldap. Here’s a short explanation of the existing files/folders:

sasl2/ Used for SASL authentication. Initially empty and unconfigured.
schema/ Contains the included schema and ldif files.
slapd.d/ The LDAP server’s configuration storage.
slapd.d/cn=config Contains the server configuration and directory databases.
slapd.d/cn=config/cn=schema Contains the currently loaded schemas.
ldap.conf Used to define system-wide defaults for LDAP clients.

Initially there’s one directory configured, which can be found in /etc/ldap/slapd.d/cn=config/
olcDatabase={1}hdb.ldif
. If you open the file in a text editor, you can see that this directory is called “dc=nodomain“. The administrator account for this directory is “cn=admin,dc=nodomain” (olcRootDN) with the password that you provided during installation (olcRootPW).

The actual database, that is automatically built from this configuration, is stored in /var/lib/ldap.

 

4. Custom Directory Creation

Now that slapd is running, you can set up your own directory. This can be done by hand (writing and importing LDIF files) or – on Ubuntu – with the Debian Packet Manager (dpkg). I like it simple, so I’m going to chose the second option. This however should only be used for a first-time setup.

1
dpkg-reconfigure slapd
Omit OpenLDAP server configuration? No This will start the configuration wizard.
DNS domain name: example.com Name of your directory (this will result in a BaseDN of the form dc=example,dc=com).
Organization name: example Name of your organization.
Administrator password: secret New password for the LDAP Administrator (cn=admin,dc=example,dc=com).
Database backend to use: HDB Based on Oracle Berkeley Database (BDB) but more effective.
Remove database when slapd is purged? No Keep the database if OpenLDAP is uninstalled.
Move old database? Yes Remove the old database so that it does not interfere with the new configuration.
Allow LDAPv2 protocol? No Unless specifically needed, LDAPv2 should be disabled.

The dc=nodomain has now been replaced with dc=example,dc=com.

 

5. A First Test

You can query the directory as follows:

1
2
3
4
5
6
7
ldapsearch -x -W -D cn=admin,dc=example,dc=com -b dc=example,dc=com -LLL

# x = simple bind/authentication
# W = ask for password
# D = user DN
# b = search base
# LLL = omit comments

This query should return two DNs: your directory (dc=example,dc=com) and your admin account (cn=admin,dc=example,dc=com).

If you don’t want to type the user DN and the search base for every query, you can put these into ~/.ldaprc:

1
2
BASE    dc=example,dc=com
BINDDN  cn=admin,dc=example,dc=com

Then you can just run

1
ldapsearch -x -W -LLL

To filter the result:

1
2
ldapsearch -x -W -LLL 'cn=admin'
ldapsearch -x -W -LLL '(&(objectClass=simpleSecurityObject)(cn=admin))'

A trailing + can be added to also show metadata.

 

6. Directory Modification

There are three ways to make changes and add entries to the directory:

  1. Modifying the config in /etc/ldap/slapd.d directly (not recommended!)
  2. Using the ldap-utils (ldapadd, ldapdelete, ldapmodify, …)
  3. Using a graphical user interface (i.e. Apache Directory Studio)

Using the ldap-utils is probably the best way, especially for script and batch operations (see chapter 12 & 13 for a quick overview). To get started, I’m going to use a graphical interface.

 

7. Apache Directory Studio Installation

Since it is written in Java, you need to install a Java Runtime Environment:

1
apt-get install default-jre

Then download the appropiate version (32 or 64 bit) from https://directory.apache.org/studio/
download/download-linux.html
, extract it to /root/ADS/ and run it:

1
2
3
tar -xvzf /ApacheDirectoryStudio-*.tar.gz -C /root/
mv /root/ApacheDirectoryStudio-* /root/ADS
/root/ADS/ApacheDirectoryStudio

 

8. Connecting To The Directory With ADS

Create a new connection in the connection window (bottom left corner) using the following parameters:

Apache Directory Studio Connection  Apache Directory Studio Connection

Optionally create a second connection for the cn=config tree (only works after step 9):

Apache Directory Studio Connection   Apache Directory Studio Connection   Apache Directory Studio Connection

 

9. Add A RootDN To The Config Tree

To connect and make changes to cn=config (which contains the LDAP configuration) an admin user and password has to be created. This can be done with an LDIF file (/etc/ldap/own_ldifs/configroot.ldif):

1
2
3
4
5
6
7
8
9
dn: olcDatabase={0}config,cn=config
changetype: modify
add: olcRootDN
olcRootDN: cn=admin,cn=config

dn: olcDatabase={0}config,cn=config
changetype: modify
add: olcRootPW
olcRootPW: {SSHA}juW1dDVtEV+KTwp5a6nTUO3GBs16mdAg

The password can be generated with slappasswd. Then import the LDIF as follows:

1
sudo ldapadd -Y EXTERNAL -H ldapi:/// -f configroot.ldif

 

10. Load an Additional Schema

Go into the schema directory and add your custom schema (in this case the postfix-book.schema):

1
2
3
cd /etc/ldap/schema
wget http://www.postfix-buch.com/download/postfix-book.schema.gz
gunzip postfix-book.schema.gz

To load a schema with ldapadd, it has to be in LDIF format, so it must be converted first. The conversion can be done with slapcat. You’ll need a config file and an output directory:

1
2
3
cd /etc/ldap/schema
mkdir ldif_output
touch schema_convert.conf

The schema_convert.conf file contains the schema to be converted (and any dependencies):

1
2
3
4
5
include /etc/ldap/schema/core.schema
include /etc/ldap/schema/cosine.schema
include /etc/ldap/schema/nis.schema
include /etc/ldap/schema/inetorgperson.schema
include /etc/ldap/schema/postfix-book.schema

Start the conversion:

1
slapcat -f schema_convert.conf -F ./ldif_output/ -n0

Copy the corresponding output file to /etc/ldap/schema:

1
cp /etc/ldap/schema/ldif_output/cn\=config/cn\=schema/cn\=\{4\}postfix-book.ldif /etc/ldap/schema/postfix-book.ldif

Finally, in the postfix-book.ldif, the following changes need to be made:

  • dn: cn=postfix-book,cn=schema,cn=config
  • cn: postfix-book
  • Remove the metadata starting from structuralObjectClass

Then add it to the directory as follows:

1
sudo ldapadd -Y EXTERNAL -H ldapi:/// -f postfix-book.ldif

The new attributes of PostfixBookMailAccount are available from now on.
If not, try a restart (/etc/init.d slapd restart).

 

11. Security

To control the directory access (–> who may access which parts of the directory?) ACLs can be created in the cn=config tree — see steps 8 and 9 on how to connect to it. ACLs are saved under olcDatabase={1}hdb in the olcAccess attribute (there can be more than one of those). The following screenshot shows an “allow everything” ACL, which will allow anyone write access to the whole directory:

ldap_acl_allow_everything

 

 

 

 

 

 

This ACL however should only be used for testing purposes.

Here is an example ACL that defines some more specific permissions:

Check the LDAP documentation for an in-depth look at ACLs.

 

12. LDIF Examples

a) Adding an OU by LDIF File

Create an addou.ldif with the following content to add an OU called “people”:

Then add it to the directory using this command:

 

b) Adding Users by LDIF File

Create a userimport.ldif with the following content to add a single user (the value for userPassword can be generated with slappasswd):

Then add it using this command:

 

c) Reset a User-Password by LDIF File

Create a pwreset.ldif with the following content to reset the password of a user account (the value for userPassword can be generated with slappasswd):

Then add the changes to the directory using this command:

 

22 Comments.[ Leave a comment ]

  1. Hi, thank you for this topic, it will be helpfull !

    I am trying to setup Postfix to work with OpenLDAP. So first I would like LDAP to work correctly. I followed you article here (without the web interface part) and I am stuck when trying to add a user.

    Here is what I have done:

    For credential check purposes, I tried following query:
    ldapsearch -x -W -D cn=admin,dc=myDomain,dc=com -b dc=myDomain,dc=com -LLL

    It lists:

    dn: dc=myDomain,dc=com
    objectClass: top
    objectClass: dcObject
    objectClass: organization
    o: myDomain.com
    dc: myDomain

    dn: cn=admin,dc=myDomain,dc=com
    objectClass: simpleSecurityObject
    objectClass: organizationalRole
    cn: admin
    description: LDAP administrator
    userPassword:: superHash=

    === I created the LDAP schema

    Dowloaded the postfix-book schema to /etc/ldap/schema:
    wget http://www.postfix-buch.com/download/postfix-book.schema.gz

    Once downloaded, unziped the archive to the ldap schema directory:
    gunzip postfix-book.schema.gz

    Made a new directory to store the converted file:
    mkdir /etc/ldap/schema/ldif_out

    Then created the file /etc/ldap/schema/schema-convert and added following lines:
    include /etc/ldap/schema/core.schema
    include /etc/ldap/schema/cosine.schema
    include /etc/ldap/schema/nis.schema
    include /etc/ldap/schema/inetorgperson.schema
    include /etc/ldap/schema/postfix-book.schema

    Once done, I converted the schema files to an ldif file:
    slaptest -f schema-convert -F /etc/ldap/schema/ldif_out/

    Edited the file /etc/ldap/schema/ldif_out/cn\=config/cn\=schema/cn\=\{4\}postfix-book.ldif to delete the 7 last line and make following changes:
    dn: cn=postfix-book,cn=schema,cn=config
    cn: postfix-book

    To finish I imported the converted ldif file to the schema directory:
    ldapadd -x -W -D cn=admin,cn=config -f /etc/ldap/schema/ldif_out/cn\=config/cn\=schema/cn\=\{4\}postfix-book.ldif

    Successfully imported !

    === When I try to add a user

    Created the file userimport.ldif and inserted following lines:

    dn: uniqueIdentifier=frank,ou=people,dc=myDomain,dc=com
    objectClass: organizationalPerson
    objectClass: person
    objectClass: top
    objectClass: PostfixBookMailAccount
    objectClass: extensibleObject
    cn: Frank Moses
    givenName: Frank Moses
    mail: frank@myDomain.com
    mailEnabled: TRUE
    mailGidNumber: 5000
    mailHomeDirectory: /my/mailbox/frank@myDomain.com
    mailQuota: 10240
    mailStorageDirectory: maildir:/my/mailbox/frank@myDomain.com
    mailUidNumber: 5000
    sn: Some
    uniqueIdentifier: frank
    userPassword: {MD5}mysuperpasswordhash==

    BUT… When I try to add user:
    ldapadd -W -D “cn=admin,dc=myDomain,dc=com” -f userimport.ldif

    I Have following error that I am stuck on for a few days allready:

    adding new entry “uniqueIdentifier=frank,ou=people,cn=myDomain,cn=com”
    ldap_add: Server is unwilling to perform (53)
    additional info: no global superior knowledge

    I don’t know why it doesn’t work, but I think that I am making a mistake with the OU or a CN somewhere…

    If ever you have any idea, you will be welcome.
    Thank you

  2. I just noticed that I did not mention to create the OU “people”. Is it possible that you don’t have this? I created it within the graphical editor.

  3. Hi,

    Well that’s what I thought, but I can’t find the exact content of the ldif file to add the people OU. As I want to do this all by hand (to make scripts later on) I avoid using an interface.

    Do you have any idea ? (I am searching allready but if you have the correct answer it is much better).

    Thank you

  4. The LDIF content to create an OU should be this:

    dn: ou=people,dc=myDomain,dc=com
    changetype: add
    objectClass: organizationalUnit
    objectClass: top
    ou: people

  5. Hi,

    Yes I had created such a OU file, but when I tried to import it with:
    ldapadd -x -W -D cn=admin,cn=config -f /etc/ldap/LDIF/peopleOuAdd.ldif

    But I stumble upon this error that seems to be linked with my permissions (as cn=admin,cn=config):

    adding new entry “ou=people,dc=myDomain,dc=com”
    ldap_add: Insufficient access (50)
    additional info: no write access to parent

    Do you have any idea about what I am doing wrong ? Because this OU is new, it does not depend on another particular tree, I don’t get why I have this error.

    Thanks

  6. Hi,

    Sorry, my mistake, I wasn’t using correct user 😉
    Importing OU people should be done with:

    ldapadd -W -D cn=admin,dc=myDomain,dc=com -f /etc/ldap/LDIF/peopleOuAdd.ldif

  7. There might be something wrong with your ACL (olcAccess in config tree).

  8. Regarding your previous message, which user should be able to query information on “ou=people,dc=acs-tmp,dc=com” ?

    Because admin has (for sure) all rights. Example of query for user f.moses:
    ldapsearch -W -D “cn=admin,dc=myDomain,dc=com” -b “ou=people,dc=myDomain,dc=com” -P 3 -LLL “(&(mail=f.moses@myDomain.com)(mailEnabled=TRUE))”

    Which works and returns user info from OU “people”.

    But for security reasons, I see that in your postfix conf file (ldap_virtual_recipients.cf) you use a user “uid=postfix,ou=services,dc=myDomain,dc=com” to do the queries.

    Did you create that user ? Because I saw that in your ACL your autorize “ou=services,dc=example,dc=com” to read
    I applied the ACLS but if I want to run a read/write test I then have no idea about the “uid=postfix,ou=services,dc=myDomain,dc=com” user’s credentials…

  9. Sorry, my question wasn’t clear.

    I fact I found out that you created a OU “services” and some users “postfix”, “dovecot” etc…
    Do you have the exact structure of the OU and users ?

  10. Here are two screenshots showing the structure of my OUs and users:

    http://acidx.net/wordpress/wp-content/uploads/2014/06/mailserver_ldap_config_01.png
    http://acidx.net/wordpress/wp-content/uploads/2014/06/mailserver_ldap_config_02.png

    I created those extra users in the service OU (postfix, dovecot, …) so that I don’t have to use the admin credentials in any config files of Postfix and Dovecot. Also, those users only get read access, which allows them to perform lookup queries but doesn’t allow them to change anything.

    With the admin user you should be able to add OUs and users since the admin has write access. You should try the “allow everything” ACL (“{0}to * by * write”) to see if works at all. If it does work with this, there is definitely something wrong with your current ACL.

  11. Great !

    It means you have created an OU “services” with this ldif structure:

    dn: ou=services,dc=myDomain,dc=com
    changetype: add
    objectClass: organizationalUnit
    objectClass: top
    ou: services

    And services with following ldif structure:

    dn: uid=postfix,ou=services,dc=myDomain,dc=com
    objectClass: account
    objectClass: simpleSecurityObject
    objectClass: top
    uid: postfix
    userPassword: HASH==

    And then an ACL ldif file (to allow write only to admin, read only to “services” and nothing for others) with:

    olcAccess: {0}to dn.subtree=”dc=myDomain,dc=com” attrs=userPassword
    by self write
    by dn.base=”cn=admin,dc=myDomain,dc=com” write
    by dn.children=”ou=services,dc=myDomain,dc=com” read
    by anonymous auth
    by * none

    olcAccess: {1}to dn.subtree=”dc=myDomain,dc=com”
    by self read
    by dn.base=”cn=admin,dc=myDomain,dc=com” write
    by dn.children=”ou=services,dc=myDomain,dc=com” read
    by * none

    With previous LDIF files everything is fine, just like in your example.
    Mybe you can add it to your Topic for people trying do it by hand… 😉

    MFG,
    [GvD]

  12. Thanks for the feedback! I’ll try to add that information to the article some time.

    By the way: Please be aware that this example doesn’t use TLS encryption. This means, that LDAP queries (including passwords) and replies are transferred in cleartext.

  13. Hi,

    You are welcome ! Yes, I know, I will add it soon and send you the steps to follow to secure servicesLDAP exchanges (if you want to add them).

    Best regards,
    [GvD]

  14. Hi,

    I have a little change regarding the ACL lidfi file I gave previously. In fact using the one I sent will make the LDAP having troubles (non admin loose all rights).

    The correct content should be:

    dn: olcDatabase={1}hdb,cn=config
    changetype: modify
    replace: olcAccess
    olcAccess: {0}to dn.subtree=”dc=myDoamin,dc=com” attrs=userPassword
    by self write
    by dn.base=”cn=admin,dc=myDoamin,dc=com” write
    by dn.children=”ou=services,dc=myDoamin,dc=com” read
    by anonymous auth
    by * none
    olcAccess: {1}to attrs=userPassword,shadowLastChange
    by self write
    by anonymous auth
    by dn=”cn=admin,dc=myDoamin,dc=com” write
    by * none
    olcAccess: {2}to dn.subtree=”dc=myDoamin,dc=com”
    by self read
    by dn.base=”cn=admin,dc=myDoamin,dc=com” write
    by dn.children=”ou=services,dc=myDoamin,dc=com” read
    by * none
    olcAccess: {3}to dn.base=”” by * none

    And you can import it with:
    ldapadd -Y EXTERNAL -H ldapi:/// -f .ldif

  15. Hi,

    I get an error when I try to add a user with your suggested code in userimport.ldif.
    The error message is “warning according to the schema attribute uniqueidentifier is not allowed”

    Thnaks

  16. Hi, I’m not sure about this but it might be due to a broken schema/database. uniqueIdentifier should be available through the extensibleObject auxiliary class.

  17. dividschmivid

    hi, i’m following this tutorial as part of your email tutorial. i’ve installed an ldap server before, but without sasl. when i tried to add the configroot.ldif file after changing the password i get this…

    ldap_sasl_interactive_bind_s: Unknown authentication method (-6) additional info: SASL(-4): no mechanism available:

    i am ssh’d in from another machine on my lan.i tried using just ldap:/// and not ldapi:/// since that is how i ran dpkg-reconfigure
    any ideas?

  18. Hello dividschmivid,

    admittedly I don’t entirely understand that whole ldap/ldapi/sasl part, but I think the problem might be that

    ldapadd -Y EXTERNAL -H ldapi:/// -f configroot.ldif

    is not executed as root. I have changed the corresponding part in section 9. There is now a sudo in front of that command.

  19. Nice tutorial… if I’ve been able to use it.
    Step 4, you choose the “easy” solution with dpkg-reconfigure, which does not exist on many Linux distros.
    Thanks anyway.

  20. Hi thank you very much for this tutorial! It helped a lot. I just wanted to ask if you might know how to activate ldaps and deactivate ldap unencrypted. I have searched some tutorials and tried them, but did not get very far. Maybe you could also point me in a direction where I could find something.

    Thanks in advance,

    Mohammed Ajil

  21. Hi, sry I can’t help with the configuration of ldaps. Haven’t implemented that yet.

  22. sudo ldapadd -Y EXTERNAL -H ldapi:/// -f postfix-book.ldif
    SASL/EXTERNAL authentication started
    SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
    SASL SSF: 0
    adding new entry “cn={4}postfix-book”
    ldap_add: Server is unwilling to perform (53)
    additional info: no global superior knowledge

Leave a Comment

Captcha Captcha Reload