Laravel und LDAP

1405_Laravel_LDAP

Nutzer und deren Passwörter liegen bereits fix und fertig im Active Directory der Domäne und nun ist es daran sich diese Daten elegant mit Laravel zur Authentifizerung der User zu nutze zu machen. Mit wenig Aufwand kann die eingebaute Nutzerauthentifizerung von Laravel mit LDAP aufgebohrt werden.

Zunächst braucht man ein funktionierendes Active Directory und muss für die Kommunikation mittels LDAP die Option extension=php_ldap.dll in der php.ini  aktivieren. Nach einem Neustart sollte der Apache nun LDAP sprechen können.

Update: Der hier beschriebene Weg bezieht sich auf die veraltete Version 4.1 des PHP-Framworks Laravel.

Die offizielle Dokumentation verrät uns den ersten Schritt, die Erweiterung des AuthManagers mittels der extend-Methode und erwartet wird die Rückgabe eines UserProviderInterfaces bzw. unserer Implementierung dieses. Der erste Parameter ist der Name des drivers, in unserem Fall „ldap“, welchen wir hier und in der /app/config/auth.php angeben.

Auth::extend('ldap', function($app) {
    return new LdapUserProvider(Config::get('auth.model'));
});

Der beste Platz dafür ist am Ende der /app/start/global.php

So weit so gut, was muss unser LdapUserProvider denn nun alles können und welche weitern Datentypen gibt es zu beachten? Ein Blick auf die Dokumentation oder die API zeigt die folgenden drei Methoden

interface UserProviderInterface {

  public function retrieveById($identifier);
  public function retrieveByCredentials(array $credentials);
  public function validateCredentials(UserInterface $user, array $credentials);

}

Wir brauchen also zusätzlich noch eine Implementierung des UserInterface, welches bereits im Ordner /app/models/ vorhanden ist und auf den Namen „User“ hört. In unserer lokalen Datenbank erzeugen wir eine Tabelle „users“ mit den Spalten, ‚id‘, ‚username‘, ‚remember_token‘ und den timestamps ‚created_at‘ und ‚updated_at‘. Eine Spalte für das Passwort wird nicht benötigt, da wir ja mittels LDAP authentifizieren wollen.

Schauen wir uns die Implementierung des mitgelieferten EloquentUserProvider einmal an, stellen wir fest, dass die ersten beiden Methoden retrieveById und retrieveByCredentials bereits solide umgesetzt sind. Und was man nicht besser machen kann, sollte man nicht nachbauen oder kopieren. Überhaupt ist die dynamische Methode für die Erzeugung des Models anhand eines String-Parameters sehr nützlich. Einzig den Hasher benötigen wir für die LDAP-Validierung nicht. Also erweitert unser LdapUserProvider einfach den EloquentUserProvider und wir überschreiben die dritte Methode validateCredentials

class LdapUserProvider extends EloquentUserProvider {

  public function __construct($model)
  {
    $this->model = $model;
  }

  public function validateCredentials(UserInterface $user, array $credentials)
  {
    $server = Config::get('auth.ldap_server');
    $domain = Config::get('auth.ldap_domain');
    $username = $credentials['username'];
    $password = $credentials['password'];

    $result = false;

    if ($connect=@ldap_connect($server))
    {
      ldap_set_option($connect, LDAP_OPT_PROTOCOL_VERSION, 3);
      ldap_set_option($connect, LDAP_OPT_REFERRALS, 0);
      if ($bind=@ldap_bind($connect, $username.$domain, $password))
      {
        $result = true;
      }
    }
    ldap_close($connect);

    return $result;
  }
}

Der Nutzername einer Domänenanmeldung enthält meist einen Suffix in der Form @domainname, welchen wir kurzerhand zusammen mit dem URL des LDAP-Servers in der /app/config/auth.php abspeichern. Der Server-URL hat dabei das Format: ldap://128.128.128.128

Im Detail: wir erstellen eine Verbindung mittels ldap_connect und versuchen dann ein ldap_bind mit Verbindung, Benutzernamen und Passwort. Das kann alles mit den Rechten eines Domänennutzers geschehen und mehr kann unsere Verbindung auch nicht, schlägt ein Teil der Prozedur fehl, schlägt die Anmeldung des Benutzers fehl. Ohne Rückmeldung was eigentlich schief gelaufen ist.

In unserer Login-Prozedur müssen wir nun nur noch die attempt-Methode des AuthManager verwenden um unseren Nutzer mittels LDAP anmelden zu können.

...
if (Auth::attempt($credentials))
{
  return Redirect::intended('/');
}
...

Zusammengefasst, benötigen wir eine Erweiterung des AuthManagers um einen Treiber („ldap“), welcher über die auth.config der Application mitgeteilt wird. Weiter eine Implementierung des Illuminate/Auth/UserProviderInterface und letztlich ein Eloquent-User-Model, welches zusätzlich als UserInterface fungiert.

Entscheidend ist einzig die validateCredentials-Methode, diese entscheidet ob die eingegebenen Daten korrekt sind und der Nutzer den geschützten Bereich der Webseite betreten darf. Auf diesem Wege ist es z.B. einfach möglich, sagen wir einen „dummy“-driver für die Entwicklungsumgebung anzulegen. Denn unter Umständen ist der LDAP-Server nicht überall erreichbar oder man möchte ihn einfach nicht mit unnötigen Anfragen belasten. Hierfür eignen sich die Environment-Einstellungen hervorragend.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.