Aus Linux-Magazin 07/2008

LDAP-Anbindung in PHP-Anwendungen auf- oder nachrüsten

Egal ob man eine eigene Webanwendung schreibt oder nachträglich eine freie Lösung aufbohren will: Die Benutzerinformationen in einem LDAP-Verzeichnis zu speichern schafft Login-Synergien und bringt Konsistenz in die eigene IT-Landschaft. Fehlt nur die LDAP-Authentifizierung.

LDAP hat sich als Standard für Benutzer- und Adresseninformationen etabliert und arbeitet in diesem Bereich effizienter als eine Datenbank. PHP bringt außerdem eine Schnittstelle für die Kommunikation mit dem Verzeichnisdienst mit, die einige Webanwendung für die Benutzerauthentifizierung einsetzen – leider jedoch nicht die Mehrheit. Dieser Artikel erläutert, wie sich eine LDAP-Anbindung selbst programmieren lässt.

Die installierte PHP-Version muss mit der Option »–with-ldap« kompiliert sein oder die LDAP-Extension als Erweiterung einbinden. Ob dies der Fall ist, zeigt die Ausgabe der Funktion »phpinfo()« (siehe Abbildung 1). Im PHP-Erweiterungs-Repository PEAR [1] gibt es außerdem die Klasse »auth()«, die den Umgang mit LDAP erleichtert [2]. Sie unterstützt nicht nur LDAP, sondern auch eine Authentifizierung über Datenbanken oder Passwortdateien und weitere Datenquellen. In Listing 1 ist zu sehen, wie der Entwickler LDAP auswählt.

Zeile 2 bindet die PEAR-Erweiterung ein. Zeile 9 erzeugt das für die Authentifizierung erforderliche PHP-Objekt mit den Parametern aus dem Array »$optionen[]«. Das sind die Adresse und der Port des LDAP-Servers (»localhost«, »389«), die eingesetzte Version des LDAP-Protokolls und die LDAP-Basisdomäne »dc=j-hoch-3,dc=de«.

Abbildung 1: Eine Extension bindet PHP an LDAP an, »phpinfo()« gibt Auskunft, ob die Erweiterung geladen oder einkompiliert ist.

Abbildung 1: Eine Extension bindet PHP an LDAP an, »phpinfo()« gibt Auskunft, ob die Erweiterung geladen oder einkompiliert ist.

Listing 1:
»Auth.php«

01 <?php
02   require_once "Auth.php";
03   $optionen = array('host' => 'localhost',
04                     'port' => '389',
05                     'version'= 3,
06                     'basedn' => 'dc=j-hoch-3, dc=de',
07                     'userattr' => 'uid',
08                     'useroc' => 'person');
09   $auth = new Auth('LDAP', $optionen, $loginFunction = 'Funktionsname', $showLogin = true);
10   //Starte Authentifizierung
11   $auth->start();
12 
13   if($auth->getAuth()){
14     //Quelltext für authentifizierte Benutzer
15   }
16   else{
17     //Quelltext für nicht authentifizierte Benutzer
18   }
19 
20   //Nutzer ausloggen
21   $auth->logout();
22 ?>

Spezialfall

In Zeile 8 teilt »’useroc’ => ‘person’« dem Auth-Objekt mit, dass es die Attribute der LDAP-Objektklasse »person« für die Suche verwenden soll. Es überschreibt die Standardeinstellung, bei der »PEAR::Auth« in der Objektklasse »posixAccount« sucht, die die Felder »gidNumber«, »homeDirectory« und »uidNumber« voraussetzt. Da eine Webanwendung diese nicht benötigt, vergleicht die Authentifizierung im Beispiel stattdessen das Feld »uid« (User ID). Auch der Common Name (»cn«) oder der Search Name (»sn«) kämen in Frage.

Hat der Parameter »$showLogin« in Zeile 9 den Wert »true«, erzeugt die PEAR-Erweiterung automatisch ein Login-Formular, wenn der Benutzer noch nicht eingeloggt ist. Über eine Funktion, die den HTML-Code für das Formular erzeugt, lässt sich dessen Aussehen steuern. Dabei ist darauf zu achten, dass das Formular Benutzername und Password per »$POST« über die Formularfelder »username« und »password« zurückgibt.

Listing 2 zeigt eine LDIF-Datei (LDAP Directory Interchange Format), dem Format, in dem LDAP seine Daten ablegt.Sie enthält zwei Beispielbenutzer, unter anderem mit den für die Authentifizierung nötigen Informationen. Im Beispiel speichern »dn:dc«, »uid« und »userpassword« die Login-Daten.

Listing 2:
LDIF-Datei

01 dn: cn=Falko Benthin,ou=editors,dc=j-hoch-3,dc=de
02 objectclass: top
03 objectclass: person
04 cn: Falko Benthin
05 sn: Benthin
06 uid: fbenthin
07 ou: editors
08 mail: fbenthin@j-hoch-3.de
09 l: Potsdam
10 postalcode: 14467
11 userpassword: geheim1
12 
13 dn: cn=Hans Hein,ou=editors,dc=j-hoch-3,dc=de
14 objectclass: top
15 objectclass: person
16 cn: Hans Hein
17 sn: Hein
18 uid: hhein
19 ou: editors
20 mail: hhein@j-hoch-3.de
21 l: Potsdam
22 postalcode: 14467
23 userpassword: geheim2

Der Aufruf der Methode »$auth->start()« in Zeile 11 von Listing 1 instanziiert das Auth-Objekt und authentifiziert einen Benutzer. Dazu führt die Methode eine anonyme Bindung mit dem LDAP-Server durch und prüft, ob es zu dem mit »username« übergebenen Wert unter dem für »userattr« festgelegten Feld einen Eintrag im LDAP-Verzeichnis gibt. Ist genau eine Person mit dem entsprechenden Eintrag vorhanden, versucht »Auth::start()« eine authentifizierte Bindung mittels des Distinguished Name und des im Formular übergebenen Passworts.

Stimmen alle Angaben überein, gilt die PHP-Session des Seitenbesuchers von nun an als authentifiziert. »$auth->getAuth()« liefert so lange den Status »true«, bis die Benutzersession über den in »php.ini« eingestellten Timeout verfällt oder der Benutzer aus der Session heraus »$auth->logout()« aufruft. Die Klassenvariable »$username« enthält den Benutzernamen, den Webanwendungen zur Laufzeit meist häufig abfragen.

Weiter geht’s

Mit dem PEAR-Modul Auth ist also in PHP mit geringem Aufwand eine Authentifizierung gegen LDAP realisierbar. Damit ist die Aufgabe, eine Webanwendung für den LDAP-Einsatz aufzurüsten, aber noch nicht erledigt: Im PHP-Code sind jene Stellen durch Aufruf der Methode »getAuth()« zu ersetzen, in denen die Webanwendung in der für sie spezifischen Art prüft, ob der Benutzer angemeldet ist. Gleiches gilt auch für sämtliche Stellen, an denen die Software den Benutzernamen aus der Datenbank ausliest.

Wie hoch der Aufwand im konkreten Fall ausfällt, hängt davon ab, wie systematisch die Anwendung programmiert ist. Benutzt sie für die Authentifizierung durchgängig eine Funktion oder Methode, dann hält er sich in Grenzen, Eingriffe sind nur an wenigen Stellen im Code nötig. Zuverlässig sollte dies immer der Fall sein, wenn die Anwendung mehrere Datenbank-Backends unterstützt und diese also zwangsläufig über eine Abstraktionsschicht anspricht. E

Ein Debugger, der es erlaubt, den Code im Schrittmodus ablaufen zu lassen, ist ein gutes Mittel, um eine Anwendung zu verstehen. Am komfortabelsten geht dies in PHP mit Eclipse, den Erweiterungen PHP-Development-Tools [3] und dem kostenlosen Executable Debugger von Zend ([4], Abbildung 2). Eine freie Version gibt es von dem Debugger DBG [5], Xdebug ist unter der PHP-License verfügbar [6].

Abbildung 2: Eclipse, die PHP-Development-Tools und der Zend-Debugger bieten zusammen eine gute Starthilfe, um den Code einer PHP-Webanwendung zu verstehen.

Abbildung 2: Eclipse, die PHP-Development-Tools und der Zend-Debugger bieten zusammen eine gute Starthilfe, um den Code einer PHP-Webanwendung zu verstehen.

Ein reales Beispiel

Listing 3 zeigt als Beispiel den Nicht-LDAP-Code, mit dem die Bilddatenbank Photo Organizer 2.33 [7] prüft, ob der Benutzer bereits eingeloggt ist. Der Code steht in der Datei »site.php«, die viele Photo-Organizer-Dateien via Include einbinden, und zeigt, wonach ein Entwickler bei einer Anpassung des Quellcode suchen sollte: Photo Organizer nutzt für die Benutzersessions ein eigenes Cookie (Zeile 1). Der restliche Code stellt eine Datenbankabfrage nach Filterung der Daten mit »pg_escape_string()« dar.

Listing 3: Session-Management in
Photo Organizer

01 if (isset($_COOKIE[$po_cookie])) {
02     $session_id = pg_escape_string($_COOKIE[$po_cookie]);
03 
04     $res = pg_query($dbh, "SELECT identifier, type, preferences, username, first_name, last_name, password
05                              FROM users
06                             WHERE session_id='$session_id'");
07     if (($res != FALSE) && pg_num_rows($res)) {
08         $row = pg_fetch_assoc($res);
09       $po_user['id'] = $row['identifier'];
10       $po_user['type'] = $row['type'];
11       $po_user['session'] = $session_id;
12       $po_user['prefs'] = $row['preferences'];
13       $po_user['username'] = $row['username'];
14       $po_user['first_name'] = $row['first_name'];
15       $po_user['last_name'] = $row['last_name'];
16       $po_user['password'] = $row['password'];
17     }
18   }

Andere Anwendungen nutzen die PHP-eigene Session-Funktion, die entweder mit Cookies oder mit Parametern in der URL arbeitet. Eine solche Session startet mit »session_start()« oder über die Ini-Option »session.auto_start«, die sich auch zur Laufzeit setzen lässt.

Infos

[1] PEAR: [http://pear.php.net]

[2] PHP-PEAR::auth-Paket: [http://pear.php.net/package/Auth/]

[3] Eclipse PDT: [http://www.eclipse.org/pdt/]

[4] Zend-Debugger: [http://www.zend.com/en/community/pdt#debugger]

[5] DBG: [http://dd.cron.ru/dbg/]

[6] Xdebug: [http://xdebug.org]

[7] Photo Organizer: [http://po.shaftnet.org]

LINUX-MAGAZIN KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Readly Logo
E-Mail Benachrichtigung
Benachrichtige mich zu:
0 Kommentare
Älteste
Neuste Beste Bewertung
Inline Feedbacks
Alle Kommentare anzeigen
Nach oben