A basic OpenLDAP server in under 15 minutes

January 28, 2010 - 2 comments

Tested under Debian Lenny

This howto is basic, as in “no security involved”. I may come up with a second part to this guide about securing OpenLDAP with TLS, if I ever find the time.
Meanwhile see http://www.openldap.org/doc/admin23/security.html for the security aspect of things.

In this example, I’ll create a tree following this scheme : dc=my,dc=domain,dc=tld.
It’s really up to you how you organize your tree, it’s really for organizational purposes. You can limit your tree to a single root branch, for example dc=myname.

Install OpenLDAP server and some useful utilities :

# apt-get install slapd ldap-utils

You should be prompted for a password, if not create it from the command line :

# slappasswd
New password:
Re-enter new password:
{SSHA}vFk3EP4SSW0RDm4yEKD

Edit /etc/ldap/slapd.conf :

You should copy the password obtained with slappasswd under the rootpw option.

include         /etc/ldap/schema/core.schema
include         /etc/ldap/schema/cosine.schema
include         /etc/ldap/schema/nis.schema
include         /etc/ldap/schema/inetorgperson.schema
pidfile         /var/run/slapd/slapd.pid
argsfile        /var/run/slapd/slapd.args
loglevel        none
modulepath	/usr/lib/ldap
moduleload	back_hdb
sizelimit 500
tool-threads 1
backend		hdb
database        hdb
suffix          "dc=my,dc=domain,dc=tld"
rootdn          "cn=admin,dc=my,dc=domain,dc=tld"
rootpw		"{SSHA}vFk3EP4SSW0RDm4yEKD"
directory       "/var/lib/ldap"
dbconfig set_cachesize 0 2097152 0
dbconfig set_lk_max_objects 1500
dbconfig set_lk_max_locks 1500
dbconfig set_lk_max_lockers 1500
index           objectClass eq
lastmod         on
checkpoint      512 30
access to attrs=userPassword,shadowLastChange
        by dn="cn=admin,dc=my,dc=domain,dc=tld" write
        by anonymous auth
        by self write
        by * none
access to dn.base="" by * read
access to *
        by dn="cn=admin,dc=my,dc=domain,dc=tld" write
        by * read

“cn=admin,dc=my,dc=domain,dc=tld” is the database admin. This is what you will use as credential when you need to modify something in the database.

Then edit /etc/ldap/ldap.conf :

This is the configuration for the LDAP client.

HOST 127.0.0.1
BASE dc=my,dc=domain,dc=tld
URI ldap://localhost

Now create a directory that will contain some initial configuration files.

# mkdir /etc/ldap/LDIF

In this directory create the following files :

1_base.ldif (the base of our LDAP tree) :

dn: dc=my,dc=domain,dc=tld
dc: my
objectClass: domain

2_group.ldif (this will be the branch that will host our groups) :

dn: ou=Groups,dc=my,dc=domain,dc=tld
ou: Groups
objectClass: organizationalUnit

3_dev.ldif (this is our first group) :

dn: cn=dev,ou=Groups,dc=my,dc=domain,dc=tld
cn: dev
gidNumber: 30000
memberUid: user1
objectClass: posixGroup
objectClass: top
description: developers

4_people.ldif (this is the branch hosting users) :

dn: ou=People,dc=my,dc=domain,dc=tld
ou: People
objectClass: organizationalUnit

5_user1.ldif (this is our first user) :

dn: uid=user1,ou=People,dc=my,dc=domain,dc=tld
uid: user1
cn: John Doe
displayName: John Doe
givenName: Doe
sn: Doe
objectClass: inetOrgPerson
userPassword: pass
mail: johndoe@domain.tld

When we are done, we can restart OpenLDAP and create the tree and import some data :

# /etc/init.d/slapd restart
# cd /etc/ldap/LDIF
# for i in `ls`; do ldapadd -x -D "cn=admin,dc=my,dc=domain,dc=tld" -W -f $i ; done

You should be prompted for the admin password as much as you have LDIF files in the directory.
If you didn’t name your file 1_base.ldif, 2_group.ldif, etc. the command may fail as it may try to add a group or user before creating its branch.

Now you should be able to query the LDAP tree :

# ldapsearch -x
# extended LDIF
#
# LDAPv3
# base <dc=my,dc=domain,dc=tld> (default) with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#

# my.domain.tld
dn: dc=my,dc=domain,dc=tld
dc: my
objectClass: domain

# Groups, my.domain.tld
dn: ou=Groups,dc=my,dc=domain,dc=tld
ou: Groups
objectClass: organizationalUnit

# People, my.domain.tld
dn: ou=People,dc=my,dc=domain,dc=tld
ou: People
objectClass: organizationalUnit

# user1, People, my.domain.tld
dn: uid=user1,ou=People,dc=my,dc=domain,dc=tld
uid: user1
cn: John Doe
displayName: John Doe
givenName: Doe
sn: Doe
objectClass: inetOrgPerson
mail: johndoe@domain.tld

# dev, Groups, my.domain.tld
dn: cn=dev,ou=Groups,dc=my,dc=domain,dc=tld
cn: dev
gidNumber: 30000
memberUid: user1
objectClass: posixGroup
objectClass: top
description: developers

# search result
search: 2
result: 0 Success

# numResponses: 6
# numEntries: 5

This command requires /etc/ldap/ldap.conf. If you don’t have ldap.conf configured you’d have to type the whole command :

# ldapsearch -x -b "dc=my,dc=domain,dc=tld" -H ldap://server

Now, you can authenticate several services against your new LDAP server.
For example, web authentication in Apache.. Take a look at http://www.wains.be/index.php/2010/01/26/apache-simple-authentication-and-ldap-authentication-examples/

You also may want to install PHP LDAP Admin for managing your LDAP database through a web GUI :

# apt-get install phpldapadmin

Then go to http://server/phpldapadmin and authentify with cn=admin,dc=my,dc=domain,dc=tld and your rootpw.

Apache : simple authentication and LDAP authentication examples

January 26, 2010 - No comment

Simple authentication :

Users credentials are stored in a file created with htpasswd command

<Location /dir/>
AuthType Basic
AuthName "Authentication"
AuthUserFile /etc/apache2/passwd-file
Require user username1 username2
</Location>

If we want to allow all users in passwd-file, use :
Require valid-user

LDAP user authentication :

We allow user1 and user2 found in the branch ou=People,dc=domain,dc=tld

<Location /dir/>
AuthName "Authentication"
AuthType Basic
AuthBasicProvider ldap
AuthzLDAPAuthoritative on
AuthLDAPURL ldap://127.0.0.1/ou=People,dc=domain,dc=tld
Require ldap-user user1 user2
</Location>

LDAP group authentication :

We allow all users in the group “support”, users are defined in that group under the memberUid field

<Location /dir/>
AuthName "Authentication"
AuthType Basic
AuthBasicProvider ldap
AuthzLDAPAuthoritative on
AuthLDAPURL ldap://127.0.0.1/ou=People,dc=domain,dc=tld
AuthLDAPGroupAttribute memberUid
AuthLDAPGroupAttributeIsDN off
Require ldap-group cn=support,ou=Groups,dc=domain,dc=tld
</Location>

Combination of users and group :

<Location /dir/>
AuthName "Authentication"
AuthType Basic
AuthBasicProvider ldap
AuthzLDAPAuthoritative on
AuthLDAPURL ldap://127.0.0.1/ou=People,dc=domain,dc=tld
AuthLDAPGroupAttribute memberUid
AuthLDAPGroupAttributeIsDN off
Require ldap-group cn=support,ou=Groups,dc=domain,dc=tld
Require ldap-attribute gidNumber=10000
Require ldap-user user1 user3 user5
</Location>

See also :

- Conditional web authentication : http://www.wains.be/index.php/2007/01/27/apache-conditional-http-authentication/

- Source for this post : http://www.linux.com/archive/feature/120050?theme=print

Keith in his post is wrong about the “Satisfy Any” option, as explained in Apache documentation : http://httpd.apache.org/docs/2.0/mod/core.html#satisfy :

This directive is only useful if access to a particular area is being restricted by both username/password and client host address. In this case the default behavior (All) is to require that the client passes the address access restriction and enters a valid username and password. With the Any option the client will be granted access if they either pass the host restriction or enter a valid username and password.

He seems to explain that the “Satisfy Any” option is necessary when using several “Require” arguments. That’s incorrect, all Require arguments are evaluated by default and must pass checks to give access to the resource.

Postfix + virtual users/groups/aliases stored in LDAP

January 25, 2010 - No comment

This will just explain the configuration files needed for Postfix to check against the LDAP server.

We want to be able to send emails to username@domain.tld
We also want to have aliases for our users, for example : firstname.lastname@domain.tld pointing to username@domain.tld
Finally, we want groups to act as a mailing list, forwarding emails to members of the group, for example : support@domain.tld

LDAP tree

dc=domain,dc=tld
|-------ou=Aliases,dc=domain,dc=tld
|---------------cn=support,ou=Aliases,dc=domain,dc=tld
|
|		cn : support
|		description : alias support
|		gidNumber : 50000
|		mailRoutingAddress : support@domain.tld
|		memberUid : it (this is a group with a inetLocalMailRecipient class and a mailRoutingAddress field defined)
|		memberUid : username3 (this is a user account)
|
|-------ou=Groups,dc=domain,dc=tld
|---------------cn=it,ou=Groups,dc=domain,dc=tld
|
|		cn : it
|		description : IT dept group
|		gidNumber : 40000
|		mailRoutingAddress : it@domain.tld
|		memberUid : username1
|		memberUid : username2
|
|-------ou=Users,dc=domain,dc=tld
|---------------uid=username1,ou=Users,dc=domain,dc=tld

		cn : username1
		gecos : John Doe
		gidNumber : 10000
		homeDirectory : /home/username1
		mail : john.doe@domain.tld
		mailLocalAddress : john.doe
		uid : username1
		[...]

Postfix configuration

For this to work, we must define “append_at_myorigin = yes” in main.cf
For group/alias emails to work, the group must have the inetLocalMailRecipient class and mailRoutingAddress defined

So we basically add in main.cf :
virtual_alias_maps = ldap:/etc/postfix/ldap-account.cf, ldap:/etc/postfix/ldap-group.cf, ldap:/etc/postfix/ldap-alias.cf

It means that Postfix will check ldap-account.cf first, then ldap-group.cf and finally ldap-alias.cf.

So we create those files :

ldap-account.cf (for virtual users) :

server_host = localhost
port = 389
version = 3
search_base = ou=Users,dc=domain,dc=tld
scope = sub
# we search through the Users base for the recipient email address (%s)
query_filter = (mail=%s)
# if we find anything under ou=Users,dc=domain,dc=tld, we deliver to the account specified under "uid"
# so basically, if we send an email to john.doe@domain.tld, we will find an entry, finally delivering the email to uid username1
result_attribute = uid

ldap-alias.cf (for virtual aliases) :

server_host = localhost
port = 389
version = 3
scope = sub
# we search through the Aliases base...
search_base = ou=Aliases,dc=domain,dc=tld
# ...for the recipient email address (%s) specified under mailRoutingAddress field
query_filter = mailRoutingAddress=%s
# If we find anything, return memberUid, that can be accounts, groups, or aliases
result_attribute = memberUid

ldap-group.cf (for virtual groups) :

server_host = localhost
port = 389
version = 3
scope = sub
# Same as aliases, but in a different base
search_base = ou=Groups,dc=domain,dc=tld
query_filter = mailRoutingAddress=%s
result_attribute = memberUid

OpenLDAP password protection, security and authentication

July 13, 2007 - No comment

yolinux.com has a great guide about password protection, security and authentication for OpenLDAP.

Source : yolinux.com

Mirror : http://www.wains.be/mirrors/yolinux.com/openldap-password/

CentOS : secure OpenLDAP traffic with SSL

I’ll consider you already have a database running.
I’ll only review how to set up the SSL certificate and key and what to change in the config files.

OpenLDAP, Evolution and Microsoft Outlook HOWTO

December 17, 2006 - No comment

Matthew Feldt was kind enough to put up a guide explaining how to set up OpenLDAP as an addressbook compatible with Evolution and Microsoft Outlook.

Please visit his page here : http://www.feldt.com/work/projects/openLDAP/

A mirror of his page is available here : http://www.wains.be/mirrors/feldt.com/

The guide works for CentOS/RHEL 4.4.

Thanks Matthew for that very well written howto !

For your information, LDAP support in Outlook is terrible. No autocompletion available.. pretty much like IMAP support.. “terrible on purpose” ™

openldap not listening on port 389

September 18, 2006 - 1 comment

For some reason openldap stopped running and listening on port 389 after our server had a problem…

The database files (BDB type) were actually corrupted…

This is how to fix the issue and recover the DB :

- install db4-utils (under RedHat)
- cd /var/lib/ldap (or whatever directory in which the DB files are located)
- /etc/init.d/ldap stop
- run /usr/sbin/slapd_db_recover in the directory
- /etc/init.d/ldap start

The server was up again after fixing the DB

OpenLDAP log

OpenLDAP logs via syslogd LOCAL4 so to stream the log you will need to add a line like this to syslog.conf (normally /etc/syslog.conf):

local4.* /var/log/ldap.log

The above command will log all levels of local4 (OpenLDAP) output to the defined file. In many systems you need to create an empty log file before logging will be visible.

The OpenLDAP logging level is set using the following command:

loglevel number

The possible values for number are:
loglevel Logging description
-1 enable all debugging
0 no debugging
1 trace function calls
2 debug packet handling
4 heavy trace debugging
8 connection management
16 print out packets sent and received
32 search filter processing
64 configuration file processing
128 access control list processing
256 stats log connections/operations/results
512 stats log entries sent
1024 print communication with shell backends
2048 print entry parsing debugging

An OpenLDAP addressbook/directory for Thunderbird

April 1, 2006 - 20 comments

This guide will help you setting up an LDAP directory under RHEL 4/CentOS 4 systems, 100 % compatible with Mozilla Thunderbird 1.5. Management of the LDAP directory will be done with phpLdapAdmin.

1. Install the needed packages
# yum install openldap-servers openldap-clients

2. Download the LDAP schema for Thunderbird
# wget http://www.wains.be/pub/thunderbird.schema -O /etc/openldap/schema/thunderbird.schema

3. Create the directory tree in which the database will be stored
# mkdir /var/lib/ldap/local

4. Change ownership
# chown ldap:ldap /var/lib/ldap/local

5. Make sure LDAP will start at boot
# chkconfig --level 345 ldap on

6. open tcp port 389 under iptables
# iptables -A INPUT -p tcp --dport 389 -j ACCEPT
# iptables-save > /etc/sysconfig/iptables

7. Make a backup of the default config
# mv /etc/openldap/slapd.conf /etc/openldap/slapd.conf.bak

8. Create and edit /etc/openldap/slapd.conf :

include         /etc/openldap/schema/core.schema
include         /etc/openldap/schema/cosine.schema
include         /etc/openldap/schema/inetorgperson.schema
#include         /etc/openldap/schema/nis.schema
include         /etc/openldap/schema/thunderbird.schema

# bind_v2 will allow compatibility with older Thunderbird clients (tested under v0.4 & v0.5)
allow bind_v2

pidfile         /var/run/slapd.pid
argsfile        /var/run/slapd.args

database bdb
suffix "dc=domain,dc=be"
rootdn "cn=AddressManager,dc=domain,dc=be"
rootpw secret

directory /var/lib/ldap/local

index objectClass                       eq,pres
index ou,cn,mail,surname,givenname      eq,pres,sub
#index uidNumber,gidNumber,loginShell    eq,pres
#index uid,memberUid                     eq,pres,sub
#index nisMapName,nisMapEntry            eq,pres,sub

9. Start the ldap service :
[root@server](1034)# service ldap start
Checking configuration files for : config file testing succeeded
Starting slapd: [ OK ]

10. Make sure ldap is running (IMPORTANT : if slapd crashes, you’d still get an OK when starting the service) :
[root@server](1036)# service ldap status
slapd (pid 2299) is running...

11. Create directory_def.ldif (directory structure) :
dn: dc=domain,dc=be
objectclass: top
objectclass: dcObject
objectclass: organization
dc: domain
o: Name of your company

12. Create directory.ldif (directory data) :
dn: cn=John Doe,dc=domain,dc=be
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
givenName: John
sn: Doe
cn: John Doe
mail: john.doe@domain.be

Contacts should be separated by a blank line

13. Inject the directory structure :

ldapadd -xv -D "cn=AddressManager,dc=domain,dc=be" -f directory_def.ldif -W

ldap_initialize( <default> )
Enter LDAP Password: xxxxxx
add objectclass:
        top
        dcObject
        organization
add dc:
        domain
add o:
        Name of your company
adding new entry "dc=domain,dc=be"
modify complete</default>

14. Inject the data into the directory :
ldapadd -xv -D "cn=AddressManager,dc=domain,dc=be" -f directory.ldif -W

15. Make sure data have been correctly injected :

ldapsearch -x -b "dc=domain,dc=be" "(objectclass=*)"

# extended LDIF
#
# LDAPv3
# base <dc =domain,dc=be> with scope sub
# filter: (objectclass=*)
# requesting: ALL
#

# domain.be
dn: dc=domain,dc=be
objectClass: top
objectClass: dcObject
objectClass: organization
dc: domain
o: Name of your company

# John Doe, domain.be
dn: cn=John Doe,dc=domain,dc=be
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
givenName: John
sn: Doe
cn: John Doe
mail: john.doe@domain.be</dc>

16. Add the ldap addressbook server into Thunderbird :

For some reason, setting LDAP autocompletion into the general configuration did not work.
I had to add the LDAP autocompletion into the account settings

For more info : http://www.stolaf.edu/services/iit/documentation/thunderbird/ldap.html

For domain.be :
Name : domain directory
Hostname : ldap.domain.be
Base DN : dc=domain,dc=be

17. Install phpldapadmin
- yum install php-ldap
- Grab the RPM version of phpldapadmin that fits to your system on rpmfind.net

SRC RPM : ftp://rpmfind.net/linux/fedora/extras/4/SRPMS/phpldapadmin-0.9.8.2-1.fc4.src.rpm
RPM : ftp://rpmfind.net/linux/fedora/extras/4/i386/phpldapadmin-0.9.8.2-1.fc4.noarch.rpm

- Edit /etc/httpd/conf.d/phpldapadmin and allow connection from your IP
- service httpd restart
- Edit /etc/phpldapadmin/config.php and edit these values :

$ldapservers->SetValue($i,'server','name','Thunderbird LDAP Server');
$ldapservers->SetValue($i,'server','host','127.0.0.1');
$ldapservers->SetValue($i,'server','port','389');
$ldapservers->SetValue($i,'server','base',array('dc=domain,dc=be'));
$ldapservers->SetValue($i,'server','auth_type','config');
$ldapservers->SetValue($i,'login','dn','cn=AddressManager,dc=domain,dc=be');
$ldapservers->SetValue($i,'login','pass','secret');

Connect to http://host.domain.be/phpldapadmin/
You should be able to access your LDAP database, please note that this config is not the most secure scheme, you should set a password to access this directory

More info : http://applications.linux.com/article.pl?sid=05/05/18/1248224

Thunderbird can only read into LDAP directories, not write :
https://bugzilla.mozilla.org/show_bug.cgi?id=86405