LDAP
Willemers Informatik-Ecke

Konzept

Plattformübergreifender Netzwerkverzeichnisdienst

LDAP (Lightweight Data Access Protocol) kann als plattformübergreifender Netzwerkverzeichnisdienst bezeichnet werden.

Besonders häufig trifft man LDAP für die Verwaltung von Benutzerkonten an. LDAP lässt sich in die Authentifierung der meisten Systeme einbinden und ist mit allen denkbaren Plattormen kombinierbar.

Organisation der Daten

In einem Verzeichnis befinden sich gleichartige Daten. Beispielsweise bestehen die Einträge in einem Telefonbuch aus Namen und Nummern. Ein Eintrag muss also einen Namen und eine Telefonnummer haben, kann zusätzlich gern eine Adresse haben.

Das Schema beschreibt die Struktur der Einträge. Die Struktur ist mit der Klasse in der objektorientierten Programmierung vergleichbar. Ein Eintrag entspräche einer Instanz oder einem Objekt.

Jeder Eintrag (Entry) muss zu einer strukturellen Objektklasse gehören. Daneben gibt es abstrakte Objektklassen als Überklassen und Auxiliärklassen, die zusätzliche Nebeneigenschaften verleihen.

Ein Entry muss eindeutig über einen dn (Distingiushed Name) gekennzeichnet sein. Er bezeichnet den vollständigen Ort in den Verzeichnissen. Zusammen mit der LDAP-URL ist die DN dann weltweit eindeutig.

dn: ou=People,dc=wirdomain,dc=de

Installation und Konfiguration eines OpenLDAP-Servers

Installation

Unter Linux steht das Paket slapd als OpenLDAP-Server zur Verfügung. Die Installation erfolgt unter einem Debian, Ubuntu oder Linux-Mint-System mit dem folgenden Befehl als Administrator.

server # apt-get install slapd ldapscripts

Die Installation fragt nach dem Passwort für den Administratorzugang von LDAP. Wie üblich bei Passworteingaben, muss dieses wiederholt werden.

In den Beispielen heißt der Server-Host server. Das Zeichen # wird als Administratorprompt angezeigt. Ein $ für einen normalen Anwenderbefehl.

Unter Debian erreichen Sie den Administratorprompt mit dem Befehl su - , bei Unbuntu und Linux Mint können Sie Sie den Befehl sudo -s verwenden.

Konfiguration

Im nächsten Schritt erfolgt die Konfiguration. Sie können den Server am einfachsten einrichten, wenn Sie das Tool dpkg-reconfigure auf das Paket slapd anwenden.
server # dpkg-reconfigure slapd
Nun werden Sie im Dialog durch die Konfiguration des LDAP-Servers geführt.
OpenLDAP-Server-Konfiguration auslassen?
Die erste Frage ist etwas originell, denn Sie werden gefragt, ob Sie die Konfiguration auslassen wollen.
Antwort: Nein.
DNS-Domäne
Als Basis für das LDAP-Verzeichnis wird die DNS-Domäne verwendet, und so wird Ihnen die Domäne des Rechners vorgeschlagen.
Eingabe: wirdomain.de
Organisation
Nun wird der Name der Organisation erfragt, die die Basis DN des LDAP-Verzeichnisses werden soll.
Eingabe: wirorg
Administrator-Passwort
Im nächsten Schritt wird das Administratorpasswort eingegeben und zur Prüfung von Tippfehlern wiederholt.
Datenbank-Backend
Nun wird nach dem zu verwendenden Datenbank-Backend gefragt. Sie können den Vorschlag übernehmen.
Entfernen der Datenbank
Es wird gefragt, ob die Datenbank entfernt werden soll, wenn slapd vollständig gelöscht wird.
Antwort: Nein
Protokoll LDAPv2 (in neueren Versionen nicht mehr)
Zu guter Letzt werden Sie gefragt, ob Sie das LDAPv2-Protokoll erlauben wollen. Auch wenn Sie persönlich eher zur Toleranz neigen, sollten Sie das ablehnen, sofern Sie nicht explizit ältere Anwendungen haben, die diese Version noch fordern.

Kontrolle

Der Befehl slapcat liefert die voreingestellten Werte des Servers.
server # slapcat
Die Ausgabe zeigt die Konfiguration an. Hier ein paar Ausschnitte:
dn: dc=wirdomain,dc=de
objectClass: top
objectClass: dcObject
objectClass: organization
o: wirorg
dc: wirdomain

dn: cn=admin,dc=wirdomain,dc=de

Basisklassen und Verzeichnisstruktur

LDAP stellt netzwerkweit einen Verzeichnisbaum zur Verfügung. Dieser Baum bildet die Struktur, in der weitere Strukturen gedeihen und Daten abgelegt werden können. Damit nicht jede Anwendung bei null anfangen muss, werden bei LDAP Basisobjektklassen vordefiniert, die Sie in Ihren Objekten aufgreifen. Diese Objektklassen lauten:

Kürzel Objektklasse
c Country, also Land
l Location
o Organisation
ou Organisatorische Einheit (organizationalUnit)
dc Domain Component
cn Datenblatt (commonName)

Die Daten werden bei LDAP in einer Struktur abgelegt. Die Grundstruktur ist vorgegeben und unterliegt gewissen Regeln:

Benutzerkonto für Login

Um einen Benutzereintrag für einen Linux-Login anzulegen, muss eine eigene organizationalUnit angelegt werden. Diese nennen wir people.

Organisationseinheit (ou) einfügen

Wir fügen nun eine organizationalUnit ein. Dazu wird eine ldif-Datei angelegt, beispielsweise durch den Aufruf des Editors vi mit dem Befehl:
server $ vi ou.ldif
Statt vi kann man natürlich auch den Editor nano verwenden. Der Inhalt der Datei ou.ldif ist:
dn: ou=people,dc=wirdomain,dc=de
objectclass: organizationalUnit
objectclass: top
ou: people
Damit wird die ou people angelegt. Diese wird später benötigt, um die eigentlichen Daten anzuhängen, die dann der ou people angehören.

Mit dem Kommando >ldapadd wird dieser Eintrag dem Verzeichnisbaum hinzugefügt.

server $ ldapadd -x -D cn=admin,dc=wirdomain,dc=de -W -f ou.ldif
Enter LDAP Password: 
adding new entry "ou=people,dc=wirdomain,dc=de"
Durch -W wird das Passwort des Admins verlangt. Nach Ausführen des Befehls wird gemeldet, dass die ou people eingetragen ist. Ohne Eingabe des Passworts wird der Eintrag verweigert.

Der Benutzer tux

Nun kann der Benutzer tux als Mitglied der organizationalUnit people angelegt werden. Bereits vorhanden sind account, posixAccount und shadowAccount.

Es wird eine Datei tuxuser.ldif angelegt, in der der Benutzer tux definiert wird.

server $ vi tux.ldfif
Die erste Zeile der Datei mit dn enthält den Zusammenhang, in den das neue Element gestellt wird. Es gehört zur Domain wirdomain.de und zur Organisationseinheit people. Das Feld uid unterscheidet es von allen anderen Elementen der Organisationseinheit und der Domain.

In der Folgezeile wird der eindeutige Schlüssel des Elements auf tux festgelegt.

Es folgen die Objektklassen, die das Element erbt. So bekommt tux alle Eigenschaften eines POSIX-Accounts und des verborgenen Passworts in der Shadow-Datei.

dn: uid=tux, ou=people, dc=wirdomain, dc=de
uid: tux
objectClass: account
objectClass: posixAccount
objectClass: top
objectClass: shadowAccount
userPassword: {SSHA}HbmCTHfuA/RBrrxWhsB4SGDcI18Md6dw
shadowLastChange: 13167
shadowMax: 99999
shadowWarning: 0
uidNumber: 1500
gidNumber: 1000
homeDirectory: /home/tux
loginShell: /bin/bash
cn: Tux Pinguin
Der Eintrag für das userPassword kann mit dem Befehl slappasswd erzeugt werden. Der Befehl verwendet für die Verschlüsselung standardmäßig SSHA. Da es sich um einen Hash handelt, kann das Ergebnis bei jedem Aufruf anders sein.
server $ slappasswd -s geheim
{SSHA}HbmCTHfuA/RBrrxWhsB4SGDcI18Md6dw
Die LDIF-Datei kann mit dem folgenden Befehl in die LDAP-Struktur eingefügt werden.
server # ldapadd -x -D "cn=admin,dc=wirdomain,dc=de" -W -f tux.ldif 
Enter LDAP Password: 
adding new entry "uid=tux, ou=people, dc=wirdomain, dc=de"
Mit dem Befehl slapcat können alle Inhalte des LDAP-Servers betrachtet werden, auch die der ou people und des people tux. Der Befehl slapcat muss als Superuser des Systems eingegeben werden.

Passwort setzen

Damit ist der Benutzer tux angelegt. Gern würde tux auch sein Passwort nachträglich ändern. Und auch hier können Sie ihm helfen.
server # ldappasswd -x -D cn=admin,dc=wirdomain,dc=de -W -S uid=johannes,ou=people,dc=wirdomain,dc=de
New password: 
Re-enter new password: 
Enter LDAP Password: 
server #

Objektklassen

Bestimmte Objektklassen kommen immer wieder vor und sind bereits vordefiniert. Als Beispiel befindet sich eine Objektklasse person (und andere) im Verzeichnis /etc/ldap/schema in den Dateien core.schema und core.ldif.

In der Datei core.schema ist unter MUST festgelegt, dass ein Objekt vom Typ person immer folgende Felder definieren muss:

Zusätzlich können beispielsweise noch folgende Felder begelegt werden. Sie stehen unter MAY in der Datei core.schema. Wird also person als objectClass benutzt, muss cn und sn definiert sein, die anderen Felder können optional hinzugefügt werden.

Operationen auf einem LDAP-Server

Ein LDAP-Server stellt mehrere Operationen auf seinen Verzeichnissen zur Verfügung. Zwischen Client und LDAP-Server wird folgender Kommunikationsablauf stattfinden.
  1. Der Client baut eine Verbindung zum LDAP-Server auf (bind).
  2. Der Client authentifiziert sich (optional, es gibt auch anonyme Operationen, je nach Regeln des LDAP-Servers)
  3. Der Client sendet seine Operation.
  4. Der Server sendet seine Ergebnisse
  5. Der Client schließt die Verbindung (unbind).

Datenoperationen mit den LDAP-Tools

LDAP-Daten können über die LDAP-Tools ausgelesen und gespeichert werden.

Einfügen von LDIF-Dateien mit ldapadd

Sie werden befüllt, indem LDIF-Dateien importiert werden. LDIF-Dateien können Sie mit einem normalen Editor bearbeiten.

Der Aufbau eines Eintrags in der LDIF-Datei folgt diesem Muster:

dn: <Distinguished Name>
<Attribut>: <Wert>
[ <Attribut>: <Wert> ]*

Diese Dateien können mit dem Befehl ldapadd in die Datenbank übernommen werden.

ldapadd <Optionen> -D <Admin-Bezeichnung> -f <LDIF-Datei>

Suchen mit ldapsearch

Für die Suche nach Einträgen wird das Kommando ldapsearch aufgerufen. Um den Eintrag für tux zu suchen, lautet der Befehl:
ldapsearch -x -LLL "(uid=tux)" cn homeDirectory
-x
Vereinfacht die Anmeldung.
-LLL
reduziert die Ausgaben auf die relevanten Daten.
-H
Angabe des Hosts, auf dem sich der LDAP-Server befindet. Ohne weitere Angabe wird in der Datei /etc/ldap/ldap.conf unter BASE nachgesehen.
-b
Hinter -b wird die Ausgangsbasis für die Suche angegeben. Typischerweise gibt es hier eine Kombination aus ou=eineou,dc=einedomain,dc=net.
(Filter)
In Klammern werden die Filter angesetzt. So wird hier nach tux gesucht. Es können für die Suche auch Wildcards verwendet werden.
Feldangaben
Am Ende werden durch Leerzeichen voneinander getrennt die Felder angegeben, die angezeigt werden sollen. Wird keine Liste angegeben, werden alle Felder angezeigt.

Löschen mit ldapdelete

Einträge können durch ldapdelete gelöscht werden.
ldapdelete -D "cn=admin,dc=wirdomain,dc=de" -W "cn=tux"
Die Option -W wird dazu führen, dass der Aufrufer nach seinem LDAP-Passwort fragt.

LDAP-Tools

jxplorer

apt install jxplorer
Start über das Menü. Als Verbindung localhost angeben. Im Baum wirdomain anwählen.

PHP-LDAP-Admin

Das Paket phpldapadmin stellt ein Web-Interface für einen LDAP-Server zur Verfügung.

LAT: LDAP Administration Tool

Das Paket lat stellt ein grafisches Tool zur Verfügung, mit dem man einen LDAP-Server auch remote warten kann. Es ist möglich, Elemente einzugeben oder die bestehenden Strukturen anzuschauen.

Das Programm wird in den Linux-Desktops unter der Rubrik Internet in das Programmmenü installiert.

Beispiel eines Login-Servers für Linux-Clients

Im folgenden Beispiel soll ein LDAP-Server für Login-Daten eingerichtet werden. Daneben wird ein Linux-PC als Client so konfiguriert, dass er eine Anmeldung für alle Benutzer erlaubt, die im LDAP-Server eingetragen sind.

Installation des LDAP-Servers

# apt update
# apt install slapd
Das Passwort für den LDAP-Administrator muss zwei Mal eingegeben werden. Es folgt die Konfiguration.
# dpkg-reconfigure slapd
Nun stellt der Konfigurator Fragen: Wir testen das Ganze noch einmal kurz mit einer LDAP-Anfrage.
# ldapsearch -x

Was wird gebraucht?

Um einen Benutzer anzumelden, wird ein Benutzername, eine Gruppe und ein Passwort benötigt.

Anlegen einer Gruppe für alle User auf dem LDAP-Server

Heutzutage legt Linux für jeden Benutzer eine eigene Gruppe an, dabei wird diese in den seltensten Fällen wirklich benötigt. Im Beispiel ziehen wir uns auf die gute alte Zeit zurück, wo alle Benutzer, die sich anmelden konnten zur derselben Gruppe gehörten und die hieß users. Diese Gruppe findet sich heute noch auf jedem Linux-Rechner und hat die Gruppen-ID (gid) 100.

Die Kommunikation zwischen dem Client und Server geschieht mit einem Datenblock, der im LDIF (LDAP Data Interchange Format) versandt wird. Damit der Block nicht bei jedem Befehl eingetippt werden muss, hat es sich eingebürgert, den Datenblock in einer Datei einzutippen und diese zu versenden.

Wir erstellen dazu eine Datei oc-users.ldif mit einem LDIF-Paket.
dn: cn=users,dc=willemer,dc=edu
objectClass: posixGroup
cn: users
gidNumber: 100
Die Abkürzungen in der LDIF bedeuten: Als Datenelementstruktur wird die vordefinierte objectClass posixGroup herangezogen. Diese enthält beispielsweise das Attribut gidNumber.

Der Inhalt der Datei oc-users.ldif wird mit dem LDAP-Tool ldapadd an den Server gesendet.

# ldapadd -x -D cn=admin,dc=willemer,dc=edu -W -f oc-users.ldif 
Enter LDAP Password: 
adding new entry "cn=users,dc=willemer,dc=edu"

Wir testen, ob die Gruppe users existiert.

Mit dem Befehl ldapsearch kann man den LDAP-Server abfragen.
ldapsearch -x -b "dc=willemer,dc=edu"
Das liefert einige Menge Zeilen Text, darunter auch folgende:
...
# users, willemer.edu
dn: cn=users,dc=willemer,dc=edu
objectClass: posixGroup
cn: users
gidNumber: 100
...
Oder man sucht direkt nach dem Eintrag users durch den folgenden Befehl:
ldapsearch -x -b "cn=users,dc=willemer,dc=edu"

POSIX-User anlegen

Die Gruppe haben wir. Um einen User anzulegen, benötigen wir aber auch ein Passwort, aber nicht im Klartext, sondern gehasht. Um einen solchen Hash zu erzeugen, gibt es den Befehl slappasswd.
linux@mintmate:~$ slappasswd 
New password: 
Re-enter new password: 
{SSHA}fL402skgIMWc45mGL4PNq5LyJ1Waqqso
Dieses Passwort kopieren wir in die LDIF für den User hinter userPassword. Wir erzeugen wieder ein LDIF in einer Datei user-paul.ldif.
dn: uid=paul,dc=willemer,dc=edu
objectClass: inetOrgPerson
objectClass: posixAccount
uid: paul
cn: Paul
sn: Willemer
uidNumber: 2002
gidNumber: 100
userPassword: {SSHA}fL402skgIMWc45mGL4PNq5LyJ1Waqqso
homeDirectory: /home/paul
Der Benutzer paul wird mit dem Befehl ldapadd angelegt.
# ldapadd -x -D cn=admin,dc=willemer,dc=edu -W -f user-paul.ldif 
Enter LDAP Password: 
adding new entry "uid=paul,dc=willemer,dc=edu"
Kontrolle:
$ ldapsearch -x -b "uid=paul,dc=willemer,dc=edu"
# paul, willemer.edu
dn: uid=paul,dc=willemer,dc=edu
objectClass: inetOrgPerson
objectClass: posixAccount
uid: paul
cn: Paul
sn: Willemer
uidNumber: 2002
gidNumber: 100
homeDirectory: /home/paul
Wir haben nun definiert: Woher weiß LDAP etwas über posixAccount und inetOrgPerson?

Objektklasse posixAccount

objectclass ( 1.3.6.1.1.1.2.0 NAME 'posixAccount'
        DESC 'Abstraction of an account with POSIX attributes'
        SUP top AUXILIARY
        MUST ( cn $ uid $ uidNumber $ gidNumber $ homeDirectory )
        MAY ( userPassword $ loginShell $ gecos $ description ) )
Das Feld sn (für surname) nimmt unser Accout aus inetOrgPerson. Die Objektklasse inetOrgPerson findet sich in der Datei
/etc/ldap/schema/inetorgperson.schema
objectclass ( 2.16.840.1.113730.3.2.2 NAME 'inetOrgPerson'
        DESC 'RFC2798: Internet Organizational Person'
    SUP organizationalPerson
    STRUCTURAL
        MAY (
                audio $ businessCategory $ carLicense $ departmentNumber $
                displayName $ employeeNumber $ employeeType $ givenName $
                homePhone $ homePostalAddress $ initials $ jpegPhoto $
                labeledURI $ mail $ manager $ mobile $ o $ pager $
                photo $ roomNumber $ secretary $ uid $ userCertificate $
                x500uniqueIdentifier $ preferredLanguage $
                userSMIMECertificate $ userPKCS12 )
        )
Hier gibt es aber kein Feld sn. Aber die Klasse ermöglicht es, den Objekten Felder wie mail, mobile, photo oder roomNumber hinzuzufügen. inetOrgPerson hat als Superklasse organizationalPerson, erbt also alle ihre Attribute. Auch in organizationalPerson gibt es kein sn:
objectclass ( 2.5.6.7 NAME 'organizationalPerson'
        DESC 'RFC2256: an organizational person'
        SUP person STRUCTURAL
        MAY ( title $ x121Address $ registeredAddress $ destinationIndicator $
                preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
                telephoneNumber $ internationaliSDNNumber $
                facsimileTelephoneNumber $ street $ postOfficeBox $ postalCode $
                postalAddress $ physicalDeliveryOfficeName $ ou $ st $ l ) )
Aber organizationalPerson erbt von person und hier gibt es endlich sn:
objectclass ( 2.5.6.6 NAME 'person'
        DESC 'RFC2256: a person'
        SUP top STRUCTURAL
        MUST ( sn $ cn )
        MAY ( userPassword $ telephoneNumber $ seeAlso $ description ) )
sn und cn sind also Pflichtfelder (MUST) für person, organizationalPerson und inetOrgPerson. Auszug einer Objektklassenhierarchie
                                           top
                                            |
                              +-------------+-------------------+
                              |             |                   |
                          person           organization   organizationalUnit
                              |
     +------------------------+--------------+
     |                        |              |
organizationalPerson     residentialPerson pilotPerson
     |
inetOrgPerson (RFC2798)

Ein Linux-Client, der sich über LDAP einloggt

Der Client soll den Benutzern, die auf dem LDAP-Server angelegt werden, einen lokalen Login erlauben. Dazu werden NSS und PAM verwendet. Beide benötigen eine LDAP-Library, um mit LDAP konfigurieren zu können.
# apt update
# apt install libnss-ldapd libpam-ldapd
Bei der Installation wird eine Eingabe des LDAP-Servers eingefordert. Hier kann einfach die IP des Servers mit einer LDAP-URL verwendet werden.
ldap://192.168.109.199
Dann fordert die Installation den "Distinguished name of the search base". Hier wird der DN des LDAP-Baums eingetragen, in dem die POSIX-Accounts gespeichert sind.
dc=willemer,dc=edu
Damit wird die Konfiguration automatisch durchgeführt.

Zur Kontrolle schauen wir in die /etc/nslcd.conf

# The location at which the LDAP server(s) should be reachable.
uri ldap://192.168.109.199

# The search base that will be used for all queries.
base dc=willemer,dc=edu
Nun schauen wir noch in die /etc/nsswitch.conf
# /etc/nsswitch.conf
passwd:         files systemd ldap
group:          files systemd ldap
shadow:         files ldap
gshadow:        files
hosts:          files mdns4_minimal [NOTFOUND=return] dns myhostname
networks:       files
Die Datei passwd wird zunächst als Datei in /etc durchsucht. Wenn das nicht klappt, wird systemd gefragt, ansonsten LDAP.

Es bleibt das Problem des Home-Directorys. Für paul gibt es lokal kein Home-Verzeichnis. Es muss angelegt werden, wenn sich paul das erste Mal anmeldet. Das übernimmt PAM (Pluggable Authentication Modules).

Durch Aufruf von pam-auth-update kann PAM konfiguriert werden.

Es erscheint ein Dialog, in dem mehrere Flags aktiviert werden können. Nach einmal Scrollen, aktiviert man Create home directory on login. Nun wird nach dem Einloggen ein Verzeichnis generiert, falls noch keines da ist.

Um das Einloggen zu testen, öffnet man auf dem Client ein neues Terminal.

Dort gibt mal ein:

su - paul
Damit wird paul eingeloggt. Wir geben das Passwort ein und können uns einloggen.

Das Verzeichnis /home/paul existiert (pwd).

Es ist kein Eintrag in /etc/passwd für paul.

Grafisches Login

Prinzipiell funktioniert das natürlich auch beim Einloggen über das grafische Anmeldefenster. Allerdings gibt es ein kleines Hindernis, das mit LDAP nichts zu tun hat. Das Anmeldefenster des Desktops MATE stellt standardmäßig nur eine Liste von Usern für das Einloggen zur Verfügung, die in /etc/password eingetragen sind.

Prinzipiell kann das natürlich auch bei anderen Desktops passieren und es kann dort mit Bordmitteln des Desktops gelöst werden. Bei MATE geht man in das Hauptmenü und wählt:

Systemverwaltung | Anmeldefenster | Benutzer

Es erscheint folgender Dialog:

Dort erlaubt man die manuelle Anmeldung. Nach einem Reboot können dann die Benutzernamen eingetippt werden und damit auch Benutzer, die nicht in der Datei /etc/passwd stehen.

Links