Last modified July 16, 2022
If we go into
details, the LDAP protocol is of the client server type, the server
contains the database, and the client consults the database,
the protocol provides the bases for this communication between
the client and the server (standardized by the IETF by
RFC2251), and the commands necessary for the client to search,
create, modify or delete data. LDAP is of course
secure for the transfer and access to data, with encryption
tools such as SSL and authentication.
In addition, LDAP provides tools
so that LDAP servers can communicate with each other, so we have
the possibility of creating mirror servers that can
synchronize, or simply link the servers together, the servers
automatically redirecting requests that do not concern them.
There are many
examples of LDAP applications :
- employee databases,
- product databases,
- databases for certain
applications, example:
* all the
information containing the users of your network (password,
shell, homedirectory, ...) can be in the database, so we have
many more possibilities than a simple /etc/passwd file , authentication can therefore use LDAP rather than passwd or shadow or even NIS . Your users
will thus be able to change their password and some of their
attributes from a web interface.
* application or
environment preferences ( netscape , KDE graphical environment, ...) are saved in the
database, so the user can move from one machine to another and
find his preferences.
This page is an introduction to LDAP, it does not cover certain aspects such as links with other databases (duplication, mirror, ...), security (access control, SSL, ...). Its only purpose is to set up a simply configured LDAP server so that you can make your "first steps" in the field. For more information, refer to Laurent Mirtain 's excellent page.
To use an LDAP database from a PHP script, see my Apache page.
The principle is therefore the same as in C++, we find a tree structure, with the top class at the root , all the other object classes derive from this generic class, each class inherits the properties of a parent class and has additional attributes compared to the latter.
objectclass (2.5.6.6 NAME
'person'
DESC 'RFC2256: a
person'
SUP top
STRUCTURAL
MUST (sn $cn)
MAY (userPassword
$telephoneNumber $seeAlso $description))
MUST corresponds to the mandatory attributes and MAY to the
optional ones
objectClass is the name of the class which itself descends from
the top class
sn corresponds to surname
cn corresponds to common name
I'll let you guess the
meaning of the other attributes.
We see that it is necessary to provide the attributes sn (surname) and cn (common name), the password ( userPassword ), the telephone number ( telephoneNumber ), the links ( seeAlso ) and the description are optional.
The attributes are defined in the same file, the syntax is as follows for telephoneNumber for example:
attributetype ( 2.5.4.20
NAME 'telephoneNumber'
DESC 'RFC2256: Telephone Number'
EQUALITY telephoneNumberMatch
SUBSTR telephoneNumberSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.50{32} )
I will present the syntax later, we can initially limit ourselves to the available attributes. To create a breizhPerson object class derived from person , with the mandatory title attribute in addition and the optional arguments ou (workgroup) and l (location). We will type in the core.schema file just after the definition of the person class
objectclass (2.5.6.6.2 NAME
'breizhPerson' SUP person STRUCTURAL
MUST
(title)
MAY (or
$l))
# $OpenLDAP:
pkg/ldap/servers/slapd/slapd.conf,v 1.8.8.6 2001/04/20
23:32:43 kurt Exp $
#
# See slapd.conf(5) for
details on configuration options.
# This file should NOT be
world readable.
#
# Modified by Christian
Zoffoli <czoffoli@linux-mandrake.com>
# Version 0.2
include
/usr/share/openldap/schema/core.schema
include
/usr/share/openldap/schema/cosine.schema
include
/usr/share/openldap/schema/corba.schema
include
/usr/share/openldap/schema/inetorgperson.schema
include
/usr/share/openldap/schema/java.schema
include
/usr/share/openldap/schema/krb5-kdc.schema
include
/usr/share/openldap/schema/kerberosobject.schema
include
/usr/share/openldap/schema/misc.schema
include
/usr/share/openldap/schema/nis.schema
include
/usr/share/openldap/schema/openldap.schema
include
/usr/share/openldap/schema/autofs.schema
include
/usr/share/openldap/schema/samba.schema
include
/usr/share/openldap/schema/kolab.schema
include
/usr/share/openldap/schema/evolutionperson.schema
include
/usr/share/openldap/schema/calendar.schema
include
/usr/share/openldap/schema/sudo.schema
include
/usr/share/openldap/schema/dnszone.schema
include
/usr/share/openldap/schema/dhcp.schema
include
/etc/openldap/schema/local.schema
# Define global ACLs to
disable default read access and provide default
# behavior for samba/pam
use
include
/etc/openldap/slapd.access.conf
# Do not enable referrals
until AFTER you have a working directory
# service AND an
understanding of referrals.
#referral
ldap://root.openldap.org
pidfile
/run/ldap/slapd.pid
argsfile
/run/ldap/slapd.args
modulepath
/usr/lib64/openldap
# database backend modules
available:
moduleload
back_mdb.la
# To allow TLS-enabled
connections, create /etc/ssl/openldap/ldap.pem
# and uncomment the
following lines.
#TLSCertificatePath /etc/ssl/openldap/
#TLSCACertificateFile /etc/ssl/cacert.pem
TLSCACertificateFile
/etc/pki/tls/certs/ldap.pem
######################################################################
# database definitions
#####################################################################
database mdb
suffix "dc=kervao,dc=fr"
rootdn
"cn=Manager,dc=kervao,dc=fr"
# Cleartext passwords,
especially for the rootdn, should
# be avoided. See
slappasswd(8) and slapd.conf(5) for details.
# Use of strong
authentication encouraged.
rootpw secret
# The database directory
MUST exist prior to running slapd AND
# should only be
accessible by the slapd/tools. Mode 700 recommended,
directory where the database is located
directory /var/lib/ldap
# Tuning settings, please
see the man page for slapd-bdb for more information
# as well as the DB_CONFIG
file in the database directory
# commented entries are at
their defaults
# In-memory cache size in
entries
#cachesize 1000
# Checkpoint the bdb
database after 256kb of writes or 5 minutes have passed
# since the last
checkpoint
checkpoint 256 5
# Indices to maintain
index objectClass eq
# persion-type searches
index
cn,mail,surname,givenname eq,subinitial
# nss_ldap exact searches:
index
uidNumber,gidNumber,memberuid,member,uniqueMember eq
# username completion via
nss_ldap needs uid indexed sub:
index uid eq,subinitial
# samba:
index
sambaSID,sambaDomainName,displayName eq
# autofs:
#index nisMapName eq
# bind sdb_ldap:
#index
zoneName,relativeDomainName eq
# sudo
#index sudoUser eq
# syncprov
#index entryCSN,entryUUID
eq
# Replicas running
syncrepl as non-rootdn need unrestricted size/time limits:
limits
group="cn=Replicator,ou=Group,dc=example,dc=com"
size=unlimited
time=unlimited
# Basic ACL (deprecated in
favor of ACLs in /etc/openldap/slapd.access.conf)
access to
attrs=userPassword
by self
write
by
anonymous auth
by
dn="cn=Manager,dc=kervao,dc=fr" write
by * none
#
access to *
by
dn="cn=Manager,dc=kervao,dc=fr" write
by * read
The LDAP database was created by default under /var/lib/ldap
The ldap.conf file may initially be empty or even nonexistent.
The administrator password is secret in clear text, if you don't like it and want to encrypt it, you will have to type
slappasswd
we enter our password
New password:
Re-enter new password:
and here is the result
{SSHA}vNCYRQthN6u3OqcTAJ4lt/9vIhjsFmI
Instead of
rootpw secret
In slapd.conf, you will therefore put:
rootpw {SSHA}vNCYRQthN6u3OqcTAJ4lt/9vIhjsFmI
After=syslog.target
[Service]
Type=forking
PIDFile=/run/ldap/slapd.pid
Environment="SLAPDURLLIST=ldap:///ldapi:///"
"LDAP_USER=ldap" "LDAP_GROUP=ldap"
"SLAPDSYSLOGLOCALUSER=local4" "SLAPDSYSLOGLEVEL=0"
EnvironmentFile=/etc/sysconfig/slapd
ExecStartPre=/usr/share/openldap/scripts/ldap-config check
ExecStart=/usr/sbin/slapd
-u ${LDAP_USER} -g ${LDAP_GROUP} -h ${SLAPDURLLIST} -l
${SLAPDSYSLOGLOCALUSER} -s ${SLAPDSYSLOGLEVEL}
[Install]
WantedBy=multi-user.target
now so that the service is
launched at each boot of the machine you will have to type
systemctl
enable slapd.service
here is the result
Created symlink from /etc/systemd/system/multi-user.target.wants/slapd.service to /usr/lib/systemd/system/slapd.service.
to launch it now just type
systemctl start
slapd.service
and to know his condition
systemctl status slapd.service
here is the result
● slapd.service - OpenLDAP Server Daemon
Loaded: loaded (/usr/lib/systemd/system/slapd.service;
disabled; vendor preset: disabled)
Active: active (running) since Sat 2022-07-16 11:24:49 CEST;
2h 13min ago
Process: 3267
ExecStartPre=/usr/share/openldap/scripts/ldap-config check
(code=exited, status=0/SUCCESS)
Process: 3302 ExecStart=/usr/sbin/slapd -u ${LDAP_USER} -g
${LDAP_GROUP} -h ${SLAPDURLLIST} -l ${SLAPDSYSLOGLOCALUSER}
-s ${SLAPDSYSLOGLEVEL} (code=exited, status=0/SUCCESS)
Main PID:
3303 (slapd)
Tasks: 3 (limit: 9283)
Memory: 3.1M
CPU: 57ms
CGroup: /system.slice/slapd.service
└─3303 /usr/sbin/slapd -u ldap -g ldap -h ldap:/// ldapi:///
-l local4 -s 0
Jul 16 11:24:48
server-slapd.kervao.fr systemd[1]: Starting OpenLDAP Server
Daemon...
Jul 16 11:24:48
server-slapd.kervao.fr su[3274]: (to ldap) root on none
Jul 16 11:24:49
slapd-server.kervao.fr su[3274]: pam_unix(su:session):
session opened for user ldap by (uid=0)
Jul 16 11:24:49
slapd-server.kervao.fr su[3274]: pam_unix(su:session):
session closed for user ldap
Jul 16 11:24:49
server-slapd.kervao.fr ldap-config[3267]: Checking the
configuration file /etc/openldap/slapd.conf: [ OK ]
Jul 16 11:24:49
server-slapd.kervao.fr systemd[1]: Started OpenLDAP Server
Daemon.
This
will prevent us from making a mistake like this.slapd[5803]: main: TLS init def ctx failed:
-1
TLSCACertificateFile /etc/pki/CA/cacert.pem
TLSCertificateFile
/etc/pki/CA/private/cakey.pem
TLSCertificateKeyFile /etc/pki/CA/cacert.pem
/etc/pki/tls/certs/
) with 644
rights.
chmod 644 ldapcrt.pem
We edit the file
/etc/openldap/ldapd.conf
and thus
modify
# SSL/TSL
configuration. With CA-signed certs, TLS_REQCERT
should be
# "demand", with the CA certificate accessible
#TLS_REQCERT
([demand],never,allow,try)
# We ship with allow by default as some LDAP clients
(e.g. evolution) have
# no interactive SSL configuration
TLS_REQCERT allow
# CA Certificate locations
# Use the default self-signed cert generated by
openldap-server postinstall
# by default
TLS_CACERT
/etc/pki/tls/certs/ldap.pem
The syntax of the LDIF format is as follows:
dn : description of the distinguished name
objectclass : original object class
...
objectclass : derived object class
type attribute: value
...
For example, we will use the
breizPerson class defined above to describe a new person Veronique Hoarau that we will add to the directory. She belongs to
the service ( organizationalUnit ) staff, this same service belonging to the organization kervao.fr
Or the entree.ldif file
dn: dc=kervao, dc=fr
objectClass: dcObject
objectClass: organization
dc: kervao
o: kervao.fr
dn: ou=staff, dc=kervao, dc=fr
objectclass: organizationalUnit
ou: staff
dn: cn=Veronique Hoarau, ou=staff, dc=kervao, dc=fr
objectclass: person
objectclass: breizhPerson
cn: Veronique Hoarau
sn: Hoarau
title: madame
dc=fr
|
dc=kervao
|
------------------------------------------------------------------------------------------------------------
|
|
|
|
ou=staff
ou=informatique
ou=production
ou=achat
|
------------------------------------------------------------------
|
|-b 'dc=kervao, dc=fr' '(objectclass=*)'
cn=Veronique
Hoarau
cn=Olivier Hoarau
At the level of the definition of the person:
objetclass : person defines the parent class of the breizPerson class,
objetclass : breizPerson class describing the person,
cn and sn are mandatory attributes,
title is a mandatory attribute
We will add the record using the following syntax (as a simple user):
ldapadd -x -D "administrator dn description" -W -f ldif-file-name
Concrete example:
l dapadd -x -D "cn=Manager, dc=kervao, dc=fr" -W -f
entree.ldif
Enter LDAP Password: secret
adding new entry
"dc=kervao, dc=fr"
adding new entry "ou=staff, dc=kervao, dc=fr"
adding new entry "cn=Veronique Hoarau, ou=staff, dc=kervao, dc=fr"
To subsequently add another record in the staff group , it will no longer be necessary to add the definition of the group and the organization. Either the entree.ldif file
dn: cn=Olivier Hoarau,
ou=staff, dc=kervao, dc=fr
objectclass: person
objectclass: breizhPerson
cn: Olivier Hoarau
sn: Hoarau
title: monsieur
Then we type the command:
ldapadd -x -D "cn=Manager,
dc=kervao, dc=fr" -W -f entree.ldif
Enter LDAP Password:
adding new entry
"cn=Olivier Hoarau, ou=staff, dc=kervao, dc=fr"
ldapsearch -x -b 'dc=kervao, dc=fr' '(objectclass=*)'
This is the result
# extended LDIF
#
# LDAPv3
# base <dc=kervao,
dc=fr> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#
# kervao.fr
dn: dc=kervao,dc=fr
objectClass: dcObject
objectClass: organization
dc: kervao
o: kervao.fr
# staff, kervao.fr
dn:
ou=staff,dc=kervao,dc=fr
objectClass:
organizationalUnit
ou: staff
# Veronique Hoarau, staff,
kervao.fr
dn: cn=Veronique
Hoarau,ou=staff,dc=kervao,dc=fr
objectClass: person
objectClass: breizhPerson
cn: Veronique Hoarau
sn: Hoarau
title: madame
# Olivier Hoarau, staff,
kervao.fr
dn: cn=Olivier
Hoarau,ou=staff,dc=kervao,dc=fr
objectClass: person
objectClass: breizhPerson
cn: Olivier Hoarau
sn: Hoarau
title: monsieur
# search result
search: 2
result: 0 Success
# numResponses: 5
# numEntries: 4
dn: cn=Veronique Hoarau,
ou=staff, dc=kervao, dc=fr
add: l
title: bureau36
Then we type
ldapmodify -x -D
"cn=Manager, dc=kervao, dc=fr" -W -f modif.ldif
Enter LDAP Password:secret
modifying entry
"cn=Veronique Hoarau, ou=staff, dc=kervao, dc=fr"
dn: cn=Veronique Hoarau,
ou=staff, dc=kervao, dc=fr
changetype: modify
replace: title
title: mademoiselle
Then we type
ldapmodify -x -D
"cn=Manager, dc=kervao, dc=fr" -W -f modif.ldif
Enter LDAP Password:secret
modifying entry
"cn=Veronique Hoarau, ou=staff, dc=kervao, dc=fr"
dn: cn=Veronique Hoarau,
ou=staff, dc=kervao, dc=fr
delete: l
Then we type
ldapmodify -x -D
"cn=Manager, dc=kervao, dc=fr" -W -f modif.ldif
Enter LDAP Password:secret
modifying entry
cn=Veronique Hoarau, ou=staff, dc=kervao, dc=fr
dn: cn=Veronique Hoarau,
ou=staff, dc=kervao, dc=fr
changetype: delete
Then we type:
ldapmodify -x -D
"cn=Manager, dc=kervao, dc=fr" -W -f modif.ldif
Enter LDAP Password:secret
deleting entry cn=Veronique
Hoarau, ou=staff, dc=kervao, dc=fr
ATTENTION You cannot delete a mandatory attribute like title for the breizhPerson class .
The principle is to export a database on server A to reimport it on server B. To export a database on server A, type
slapcat > base.ldif
Now we return to server B on which we will have recovered the base.ldif file, we will first stop slapd by typing
systemctl stop slapd
then to import
slapadd -l base.ldif
here is the result
62d2baf8
/etc/openldap/slapd.conf: line 185: rootdn is always granted
unlimited privileges.
62d2baf8
/etc/openldap/slapd.conf: line 189: rootdn is always granted
unlimited privileges.
_####################
100.00% eta none elapsed none
fast!
Closing DB...
Be careful if the base already contains duplicate pre-existing elements, it will cause an error like this
62d2b3b7
/etc/openldap/slapd.conf: line 185: rootdn is always granted
unlimited privileges.
62d2b3b7
/etc/openldap/slapd.conf: line 189: rootdn is always granted
unlimited privileges.
_# 8.38% eta 27s elapsed
02s spd 155.6 /s 62d2b3b9 mdb_id2entry_put: mdb_put failed:
MDB_KEYEXIST: Key/data pair already exists(-30799)
"dc=kervao,dc=fr"
62d2b3b9 =>
mdb_tool_entry_put: id2entry_add failed: err=-30799
62d2b3b9 =>
mdb_tool_entry_put: txn_aborted! MDB_KEYEXIST: Key/data pair
already exists (-30799)
slapadd: could not add
entry dn="dc=kervao,dc=fr" (line=1): txn_aborted!
MDB_KEYEXIST: Key/data pair already exists (-30799)
.# 8.38% eta 27s elapsed
02s spd 0.0 /s
Closing DB..
In this case, you will have to clean up the database by simply deleting it.
rm -f /var/lib/ldap/*
we restart slapd to create a minimal base
systemctl start slapd
then we cut it to type
slapadd -l base.ldif
we then restart slapd
systemctl start slapd
Just add the -Z option to switch to encrypted connection, with debug mode in addition (-d 1), you should get this kind of message
TLS trace:
SSL_connect:before SSL initialization
TLS trace:
SSL_connect:SSLv3/TLS write client hello
TLS trace:
SSL_connect:SSLv3/TLS write client hello
TLS trace:
SSL_connect:SSLv3/TLS read server hello
TLS trace:
SSL_connect:TLSv1.3 read encrypted extensions
TLS certificate
verification: depth: 0, err: 0, subject:
/CN=serveur-slapd.kervao.fr/OU=default ldap cert for
server-slapd.kervao.fr/emailAddress=root@serveur-slapd.kervao.fr,
issuer: /CN=serveur-slapd.kervao.fr/OU=default ldap cert for
server-slapd.kervao.fr/emailAddress=root@serveur-slapd.kervao.fr
TLS trace:
SSL_connect:SSLv3/TLS read server certificate
TLS trace:
SSL_connect:TLSv1.3 read server certificate verify
TLS trace:
SSL_connect:SSLv3/TLS read finished
TLS trace:
SSL_connect:SSLv3/TLS write change cipher spec
TLS trace:
SSL_connect:SSLv3/TLS write finished
ldap_sasl_bind
ldap_send_initial_request
ldap_send_server_request
(...)
TLS trace: SSL_connect:SSL
negotiation finished successfully
TLS trace: SSL_connect:SSL
negotiation finished successfully
TLS trace:
SSL_connect:SSLv3/TLS read server session ticket
TLS trace: SSL_connect:SSL
negotiation finished successfully
TLS trace: SSL_connect:SSL
negotiation finished successfully
TLS trace:
SSL_connect:SSLv3/TLS read server session ticket
(...)
ldap_free_connection 1 1
ldap_send_unbind
ber_flush2: 7 bytes to sd
3
TLS trace: SSL3 alert
write:warning:close notify
ldap_free_connection:
actually freed
there is an error with the certificate which is self-signed but as we put TLS_REQCERT allow in the ldap.conf file it is not blocking. On the server side it gives this
Jul 16
14:26:32 slapd-server.kervao.fr slapd[5289]: conn=1001 fd=11
ACCEPT from IP=127.0.0.1:37634 (IP=0.0.0.0:389)
Jul 16 14:26:32
slapd-server.kervao.fr slapd[5289]: conn=1001 op=0 EXT
oid=1.3.6.1.4.1.1466.20037
Jul 16 14:26:32
server-slapd.kervao.fr slapd[5289]: conn=1001 op=0 STARTTLS
Jul 16 14:26:32
server-slapd.kervao.fr slapd[5289]: conn=1001 op=0 RESULT
oid= err=0 text=
Jul 16 14:26:32
server-slapd.kervao.fr slapd[5289]: conn=1001 fd=11 TLS
established tls_ssf=256 ssf=256
Jul 16 14:26:32
slapd-server.kervao.fr slapd[5289]: conn=1001 op=1 BIND
dn="" method=128
Jul 16 14:26:32
slapd-server.kervao.fr slapd[5289]: conn=1001 op=1 RESULT
tag=97 err=0 text=
Jul 16 14:26:32
server-slapd.kervao.fr slapd[5289]: conn=1001 op=2 SRCH
base="dc=kervao,dc=fr" scope=2 deref=0
filter="(objectClass=*)"
Jul 16 14:26:32
server-slapd.kervao.fr slapd[5289]: conn=1001 op=2 SEARCH
RESULT tag=101 err=0 nentries=4 text=
Jul 16 14:26:32
server-slapd.kervao.fr slapd[5289]: conn=1001 op=3 UNBIND
Jul 16 14:26:32
server-slapd.kervao.fr slapd[5289]: conn=1001 fd=11 closed
[ Back to FUNIX home page ] |