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);