php-Session-Cookies mit Authentifizierung über IServ-LDAP

Authentifizierung einer PHP-Webanwendung über den IServ-LDAP-Server

Jüngst standen wir bei uns am Georg-Büchner-Gymnasium in Seelze vor der Herausforderung, eine eigene PHP-basierte Webanwendung mit PHP-Session-Cookies über den IServ-LDAP authentifizieren zu wollen, um so zu erreichen, dass sich die Nutzerinnen und Nutzer dort mit ihren IServ-Zugangsdaten anmelden können.

Wie sich herausstellte, gab es dabei einige Fallstricke. In diesem Blog-Post werde ich darstellen, was man machen muss, um erfolgreich die Authentifizierung am IServ-LDAP in der PHP-Anwendung durchzuführen.

Als erstes muss man auf dem IServ-Server einen neuen Bind-Benutzer für LDAP anlegen. Dafür muss man in die Datei /etc/iserv/ldapusers folgende Zeile hinzufügen:

gbg-webserver:+userPassword:10.2.31.28

Dabei ist gbg-webserver der Name des Bind-Benutzers und die IP-Adresse ist die unseres Webservers mit der PHP-Anwendung.

Dann muss man mit folgendem Befehl die Konfigurationsänderung sichern:

iconf save /etc/iserv/ldapusers
iservchk

Als nächstes muss man das LDAP-Passwort mit

cat /var/lib/iserv/server-openldap/pwd/gbg-webserver.pwd

vom IServ holen. Jetzt kann man auf dem Testsystem prüfen, ob eine LDAP-Abfrage mit dem soeben eingerichteten Bind-Benutzer und dem Passwort geht. Dafür muss man auf dem Server 10.2.31.28 Folgendes ausführen:

ldapsearch -o ldif-wrap=no -H ldaps://gbg-seelze.eu:10636 -D "cn=gbg-webserver,ou=ldap,dc=gbg-seelze,dc=eu" -w PasswortAusVarLibIservEtc -b "cn=user.name,ou=users,dc=gbg-seelze,dc=eu"

Einer der Fallstricke war, dass IServ standardmäßig LDAP v3 nutzt, wohingegen PHP standardmäßig mit LDAP v2 arbeitet. Die Umsetzung der Abfrage sieht dann in PHP implementiert folgendermaßen aus:

$ds=ldap_connect("ldaps://gbg-seelze.eu:10636");  // must be a valid LDAP server!
if (ldap_set_option($ds,LDAP_OPT_PROTOCOL_VERSION,3))
 {
    echo "Using LDAP v3";
 }else{
    echo "Failed to set version to protocol 3";
      }
 if ($ds) {
    $passwd="PasswortAusVarLibIservEtc";
    $r=ldap_bind_ext($ds, "cn=gbg-webserver,ou=ldap,dc=gbg-seelze,dc=eu", $passwd);
                         //cn=... der User aus /etc/iserv/ldapusers
    if (ldap_parse_result($ds, $r, $errcode, $matcheddn, $errmsg, $referrals, $ctrls)) {
        if ($errcode != 0) {
            die("Error: $errmsg ($errcode)");
                           }
        }
    $sq="(memberOf=*)";
    echo "Searching for $sq";
    $act="erika.mustermann"; // bzw. der zu authentifizierende User
    $sr=ldap_search($ds, "cn=".$act.",ou=users,dc=gbg-seelze,dc=eu",$sq);
    if (ldap_parse_result($ds, $sr, $errcode, $matcheddn, $errmsg, $referrals, $ctrls)) {
        if ($errcode != 0) {
            die("Error: $errmsg ($errcode)");
                           }
        }
    $info = ldap_get_entries($ds, $sr); //hier sollte nur ein Entry rauskommen (keine Wildcards im User erlauben)
    for ($i=0; $i<$info["count"]; $i++) {
//----------------Passworttesten hier!---------------------------------------
      $hashpasswd=explode ("{crypt}",$info[$i]["userpassword"][0])[1];
      if (password_verify('testpasswort', $hashpasswd )) {  //bzw. das zu testende Passwort
       echo 'Password is valid!';
       } else {
        echo 'Invalid password.';
        }
//----------------Gruppenzugehörigkeit hier!------------------------------------
    $memberof=[];
    for ($j=0; $j<$info[$i]["memberof"]["count"]; $j++) {
    $memberof[]= explode(",",explode("cn=",$info[$i]["memberof"][$j])[1])[0];

//----------optimistische Auswertung, hier sollte man sich etwas vor Fehlern schützen----
      }
    }
    print_r($memberof); //$memberof enthält jetzt alle iserv-Gruppenzugehörigkeiten
    ldap_close($ds);