Websiteentwicklung: PHP: LDAP

Kurze Einführung in LDAP

Bearbeiten

LDAP ist eine Abkürzung für Lightweight Directory Access Protocol, was soviel heißt wie "Leichtgewichtiges Verzeichnis-Zugriffs-Protokoll". Also ist LDAP das, im Gegensatz zu DAP, weniger komplexe Protokoll, um auf ein "Verzeichnis" zuzugreifen,

Ein Verzeichnisdienst ähnelt in seiner Funktionsweise zwar einer Datenbank, unterscheidet sich aber von traditionellen relationalen Datenbanken in folgenden Punkten:

  • Ein Directory ist mehr auf das Finden und Auslesen von Informationen spezialisiert als auf das Schreiben immer neuer Informationen.

Suchfilter

Bearbeiten

Eine LDAP-DB arbeitet nicht wie eine relationale Datenbank anhand von SQL-Statements, sondern anhand von Suchfilter.

Das Format ist allgemein im RFC 1960 definiert. Hier führen wir dich aber kurz in die wichtigsten Ausdrücke ein.

Hier die Grundsätzlichen Filter:

Exakter Wert Format Beispiel Resultate
Exakter Wert (<attr>=<wert>) (sn=Muster) Alle Personen mit dem Nachnamen Muster
ungefährer Wert (<attr>~=<wert>) (givenname~=Pascal) Alle Personen mit einem Vornamen,
welcher einen ähnlichen Ton hat wie Pascal
(Achtung: Dies ist Server abhängig)
Teilzeichenkette (<attr>=[<begin>]*[<text>]*[<ende>]) (sn=*ust*) Alle Personen, welche im Nachnamen die Sequenz ust enthält.
Grösser gleich (<attr>>=<wert>) (sn>=Muster) Alle Nachnamen, welche im Lexikon an derselben Stelle wie Muster und nach Muster auftritt.
Kleiner gleich (<attr><=<wert>) (sn<=Muster) Alle Nachnamen, welche im Lexikon an derselben Stelle wie Muster und vor Muster auftritt.
Vorhanden (<attr>=*) (sn=*) Alle Einträge mit Nachnamen.

Die Basic-Filter können in jeder beliebigen Form kombiniert werden, wie man in der folgenden Tabelle sehen kann:

Exakter Wert Format Beispiel Resultate
UND (&(<filter1>)(<filter2>)...) (&(givenname=Hans)(sn=Muster)) Einträge mit dem Vornamen Hans UND dem Nachnamen Muster
ODER (|(<filter1>)(<filter2>)...) (|(givenname=Hans)(sn=Muster)) Einträge mit dem Vornamen Hans ODER dem Nachnamen Muster
NICHT (!(<filter1>)) (!(mail=*)) Einträge ohne ein Mail-Attribut

So nun kennst du alle Grundlagen, um deine eigenen Suchfilter zu schreiben. Bedenke aber, dass du nur Attribute, welche der Server kennt, nutzt, denn ansonsten kann dieses die Suche erheblich verlangsamen.

OpenLDAP installieren

Bearbeiten

Um OpenLDAP auf einem Linux Computer zu installieren siehe Linux-Praxisbuch: Lightweight Directory Access Protocol

Siehe http://lucas.bergmans.us/hacks/openldap/

LDAP mit PHP

Bearbeiten

Es gibt eine Vielzahl an Funktion, um auf einer LDAP-Datenbank zu kommunizieren. Hier werden nur die meist gebräuchlichsten erklärt:

  • ldap_connect ([string hostname[, int port]]) - Stellt die Verbindung zu einem LDAP-DB-Server her.
  • ldap_bind(resource link_identifier[, string bind_rdn[, string bind_password]]) - Logged sich beim Server ein, wobei die eigentlichen Userdaten optional sind. Standardmäßig wird man als anonymous eingelogged.
  • ldap_search(resource link_identifier, string base_dn, string filter[, array attributes[, int attrsonly[, int sizelimit[, int timelimit[, int deref]]]]]) - Startet eine Suche in dem vorgegebenen Namespace und mit dem angegebenen Suchfilter.
  • ldap_get_entries(resource link_identifier, resource result_identifier) - Wandelt die Suchresultate in ein Array um.
  • ldap_error(resource link_identifier) - Holt eine Fehlerbeschreibung des zuletzt aufgetretenen Fehlers.
  • ldap_delete(resource link_identifier, string dn) - Löscht einen Eintrag des Verzeichnisses.
  • ldap_rename(resource link_identifier, string dn, string newrdn, string newparent, bool deleteoldrdn) - Ändert den Namen eines Eintrags.
  • ldap_add(resource link_identifier, string dn, array entry) - Fügt einen Eintrag hinzu.
  • ldap_modify(resource link_identifier, string dn, array entry) - Ändert Werte eines Eintrags.
  • ldap_unbind(resource link_identifier) oder ldap_close(resource link_identifier) - Schließt die Verbindung mit dem LDAP-Server.

Directory Zugriffe

Bearbeiten

Verzeichnislein, Verzeichnislein an der Wand wo wohnt cn=Hans Muster;ou=contacts,o=master,c=ch im kleinen Land?!?

Nun diese Frage kann ein kleiner LDAP-Zugriff beantworten und dies sogar sehr schnell, auch wenn es mehrere 10000 Einträge gibt.

Mit Server Verbinden

Bearbeiten

Aber zuerst müssen wir auf das Directory verbinden (und falls nötig uns authentisieren, damit wir lesen können):

 //
 // Notiz: Für Windows 2003 AD kann es erforderlich sein, den Port (2. Argument) 
 // für ldap_connect( $ldaphost, 3268 ) vom Standardwert (nichts angegeben)
 // auf 3268 zu ändern. (knito)
 //
 //''ldap.master.org'' ist der DNS-Name des LDAP-Servers
 $ldaphost = 'ldap.master.org';
 $ldapconn = ldap_connect($ldaphost) or die("Could not connect to $ldaphost");
 //''username'' und ''passwort'' sind optional, default ist anonymous-login
 if (ldap_bind($ldapconn, "username", "passwort")) {
   echo "Die Verbindung zu $ldaphost war erfolgreich";
 }

Der Verbindungsaufbau wird in den weiteren Beispielen nicht weiter beschrieben, um Platz zu sparen,

Nun, da wir mit dem Server verbunden sind, können wir dem Server unsere Frage stellen:

 /*
  * ''$ldapconn'' ist die Verbindung zum LDAP-Server vom ersten Beispiel
  */
 
 $results = ldap_search($ldapconn, "ou=contacts,o=master,c=ch", "cn=Hans Muster");
 /* Wie der Filter (letztes Argument) aufgebaut ist, siehe [[#Suchfilter|hier]]
  * 
  * Die optionalen Argumente sind:
  * ''attributes'' - Nur diese Attribute sollen zurückgegeben werden, z.B. ''array("cn", "givenname", "sn")
  * ''attrsonly'' - ''1'' für nur die Attributtypen, ''0'' (default) 
  * ''sizelimit'' - Die maximale Anzahl an Einträgen, welche zurückgegeben werden sollen.
  * ''timelimit'' - Die maximale Zeit, welche für die Suche genutzt werden darf.
  * ''deref'' - Bestimmt, wie Aliase behandelt werden sollen, bei dieser Suche.
  *  -LDAP_DEREF_NEVER - (default) Aliase werden nie aufgelöst. Mögliche Werte:
  *  -LDAP_DEREF_SEARCHING - Aliase sollen während der Suche aufgelöst werden, aber nicht dann, wenn das Basisobjekt der Suche ermittelt wird.
  *  -LDAP_DEREF_FINDING - Aliase sollen aufgelöst werden, wenn das Basisobjekt ermittelt wird, aber nicht während der Suche.
  *  -LDAP_DEREF_ALWAYS - Aliase sollen immer aufgelöst werden. 
  */
 
 // und nun die gefundenen Einträge verarbeiten
 $entries = ldap_get_entries($ldapconn, $results);
 echo "Es wurden ".$entries["count"]." Einträge gefunden";
 if ($results != false) {
   foreach($entries as $entry) {
     //Gibt den eindeutigen Bezeichner (CommonName) des Eintrags aus.
     echo $entry["cn"][0]." (".$entry["cn"]["count"].")&lt;br&gt;\n";
   }
 }

Neuer Eintrag

Bearbeiten

Du hast einen hübschen Typen/eine schöne Frau kennengelernt und möchtest diese Person (Axel Muster) nun auch in deiner Datenbank speichern. Nach dem Verbinden zur Datenbank aufgebaut hast, muss nur eine einzelne Methode aufgerufen werden:

 ldap_add($ldapconn, "cn=Axel Muster,ou=contacts,o=master,c=ch", 
   array(
     "cn" => array("Axel Muster"), //CommonName
     "givenname" => array("Axel"), //Vorname
     "sn" => array("Muster"), //Nachname (SurName)
     "objectclass" => array("pabPerson", "inetOrgPerson", "organizationalPerson", "person", "top"), //Eintrag typen
     "telephonenumber" => array("784'351'92'34"), //Telefonnummer
     "mobile" => array())); //Handy-Nummer

Umbenennen

Bearbeiten

Eine gute Kollegin (Nadine Schindel) hat nun geheiratet und übernimmt den Namen ihres Ehemanns (Fabian Wickihalder), nun möchtest du diesen Eintrag auch in deiner Datenbank aktualisieren:

 ldap_rename($ldapconn, 
   "cn=Nadine Schindel,ou=contacts,o=master,c=ch", //Der alte Eintrag, welcher gemoved/umbenannt werden soll.
   "cn=Nadine Wickihalder,ou=contacts,o=master,c=ch", //Der neue Name des alten Eintrags.
   "ou=contacts,o=master,c=ch", //Da wir diesen Eintrag nicht in einen anderen Namespace verschieben, bleibt dies gleich.
   true); //Der alte Eintrag soll gelöscht werden (false, wäre beibehalten).

Aktualisieren

Bearbeiten

Jemand (Hans Muster) hat seine Natel-Nummer geändert und nun werden wir diese kleine Information nachtragen

 ldap_modify($ldapconn, "cn=Hans Muster;ou=contacts,o=master,c=ch", array("mobile" => array("435'245'45'56")))

Löschen

Bearbeiten

Ein schlimmer Streit ist zwischen dir und einem Kollegen vorgekommen und du willst nichts mehr von dieser Person wissen, also löscht du seinen Eintrag (cn=Hans Muster;ou=contacts,o=master,c=ch)

 ldap_delete($ldapconn, "cn=Hans Muster;ou=contacts,o=master,c=ch")

Specials

Bearbeiten

phpLDAPAdmin

Bearbeiten

phpLDAPAdmin ist das LDAP-Equivalent zu phpMyAdmin, welches aber für MySQL-Datenbanken geschrieben wurde. Die Benutzeroberfläche ist gut organisiert, so dass keine weitere Ausführung nötig ist.

Installation

  1. Die php-sources von sourceforge herunterladen (http://phpldapadmin.sourceforge.net/download.php)
  2. .tar.gz bzw. .zip File entpacken
  3. Das Entpackte in einen Ordner verschieben, welcher durch den Webserver zugreifbar ist (Oft htdocs oder bei MacOSX Sites)
  4. LDAP-Server-Zugriff konfigurieren
  5. FERTIG

Konfiguration

Hier eine kleine Hilfestellung, wie man das LDAP-Tool phpLDAPAdmin konfiguriert.

TODO: Konfiguration beschreiben

Bilder in der LDAP-DB

Bearbeiten

In diesem kleinen Spezial behandeln wir, welche Bedingungen erfüllt werden müssen, um ein Bild in der Datenbank speichern zu können und wie man solch ein Bild wieder ausliest.

Da du denkst eine LDAP-DB ist genau das was du brauchst, um die Mitglieder deines Vereins zu verwalten, hast du eine Directory erstellt. Hier hast du die Möglichkeit, um die Daten in deiner Datenbank noch zu erweitern: Speichere ein Bild, z.B. von den wichtigsten Personen deines Vereins, in die DB. Dies ist ganz einfach:

Die Bedingungen

Die Attribute, in welchen man ein Bild speichern könnte, muss mit der ldapSyntax Binary (1.3.6.1.4.1.1466.115.121.1.5) bezeichnet sein.

Das einfachste ist aber, wenn man das Attribut jpegPhoto von einen der Objekt-Klassen document, inetOrgPerson, pabPerson, pilotObject benutzt.

Bild speichern

 /*
  * ''$dn'' repräsentiert die DN worin das Bild gespeichert werden kann.
  * ''$data'' repräsentieren die JPG-Daten, welche z.B. mit ''fread'' aus einem File gelesen wurden.
  */
 
  $ldapconn = $ldap_connect("ldap.master.org");
  if ($ldapconn && $ldap_bind($ldapconn, "username", "passwort")) { //username und passwort sind optional
   $res = ldap_modify($ldapconn, $dn, array("jpegPhoto" => $data));
   if (!$res) {
    echo "Fehler beim speichern des Bildes: ".ldap_error();
   } else {
    echo "Bild erfolgreich in $dn gespeichert.";
   }
  }

''' Bild auslesen '''

 /*
  * Zur DB Verbinden...
  * ''$dn'' repräsentiert die DN des Eintrags
  */
 
 $ldapconn = ldap_connect("ldap.master.org");
 if ($ldapconn && ldap_bind($ldapconn, "username", "password")) { //username und password sind optional
  $search_result = ldap_read($ldapconn, $dn, 'objectClass=*');
  $entry = ldap_first_entry($ldapconn, $search_result);
  $entry = ldap_get_values_len($ldapconn, $entry, "jpegPhoto");
  $jpeg_data = $entry[0];
 }