Softwareentwickler / Software Developer
LDAP Authentifizierung Java

LDAP in Java | Authentifizierung und Autorisierung

Im Rahmen meines Abschlussprojektes habe ich eine Anwendung umgesetzt, bei der sich ein Benutzer bei der Anmeldung gegen das firmeninterne Active Directory authentifizieren muss. Zudem wird die Autorisierung auf bestimmte Bereiche in der Anwendung über AD-Gruppen vorgenommen. Im ersten Teil möchte ich vorstellen, wie sich das mit Java umsetzen lässt.

Authentifizierung und Autorisierung

Zum Einstieg möchte ich zumindest kurz darauf eingehen, was diese beiden Begriffe bedeuten und wie sie sich unterscheiden. Bei der Authentifizierung meldet der Benutzer sich an einer Anmeldung an und weist nach, dass es sich auch um die vorgegebene Person handelt, zum Beispiel durch die Eingabe eines Passworts. Die Autorisierung hingegen wird eingesetzt, um dem Benutzer Rechte einzuräumen, bestimmte Bereiche der Anwendung sehen zu können.

Implementierung der Authentifierzung

Für beide der hier vorgestellten Schritte werden keine externen Bibliotheken benötigt, sondern die verwendeten Klassen und Interfaces befinden sich alle im Package javax.naming.*.Um eine Authentifierung durchzuführen, müssen zu Beginn verschiedene Werte in eine Hashtable eingefügt werden. Darin befinden sich dann die Informationen, wie der Name des aktuellen Benutzers ist und wie eine Verbindung zum LDAP-Server hergestellt werden kann. Anschließend wird diese Hashtable dann an der Konstuktor eines InitialDirContexts weitergereicht. Wird im Anschluss dessen keine NamingException geworfen, war die Anmeldung erfolgreich, eingegebener Benutzername und Passwort stimmen also mit den Daten des LDAP-Servers überein. Die Methode könnte dann also wie folgt aussehen:

public Optional authentifiziereBenutzer(Benutzer benutzer)
    throws AuthentifizierungException
{
  try
  {
    Hashtable<String, String> env = new Hashtable<>();
    env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
    env.put(Context.PROVIDER_URL, "ldap://ldap.example.de");
    env.put(Context.SECURITY_PRINCIPAL, benutzer.getName());
    env.put(Context.SECURITY_CREDENTIALS, benutzer.getKennwort());
    DirContext ctx = new InitialDirContext(env);
    return Optional.of(benutzer);
  }
  catch (NamingException e)
  {
    throw new AuthentifizierungException("Benutzername oder Passwort falsch");
  }
}

Implementierung der Autorisierung

Da die Verwaltung von Berechtigungen in meinem Unternehmen zentral im Active Directory über die Zuordnung zu verschiedenen Gruppen vorgenommen werden soll, muss ich für den angemeldeten Benutzer prüfen, ob dieser der jeweils notwendigen Gruppe zugeordnet ist. Dafür habe ich die Methode benutzerIstInGruppe(Benutzer benutzer, List<String> gruppen) angelegt, die einen bool’schen Wert zurückliefert. Hier muss ich jetzt zwei Schritte durchführen. Zuerst müssen die Attribute des Benutzers ausgelesen werden, in diesem konkreten Fall benötigte ich die Werte für das “memberOf”-Attribut. Danach muss ich in diesem Ergebnis suchen und überprüfen, ob eine der angegebenen Gruppen Teil des Ergebnisses ist.

Zum Ermitteln der Attribute befülle ich zuerst einmal die Hashtable wie im obigen Code-Snippet und erzeuge den DirContext. Hier darf nach erfolgreicher Authentifierierung eigentlich keine NamingException mehr auftreten. Diesen Teil habe ich aufgrund der Dopplung in eine eigene Methode ausgelagert, die mir den gefüllten Hashtable zurück gibt. Am DirContext kann dann die search-Methode aufgerufen werden. Dieser übergebe ich den Pfad, wo die Benutzer abgelegt sind, einen Such-String, um eindeutig den AD-Benutzer zu finden, sowie ein Objekt der Klasse SearchControls. Dieses habe ich zuvor initialisiert und an diesem neben dem Such-Scope (z.B. nur im angebenen Pfad oder auch alle Unterordner) auch die zu ermittelnden Attribute festgelegt. Als Ergebnis erhält man eine NamingEnumeration.

Mit einer while-Schleife lässt sich über die gesuchten Attribute iterieren. In jedem Durchgang werden die Attribute ausgelesen und mit den erwarteten Gruppen abgeglichen. In meinem Code habe ich die folgende Methode noch einmal auseinandergezogen, hier stelle ich den Code aber zur Vereinfachung als ganzes dar.

public boolean benutzerHatBerechtigung(Benutzer benutzer, List gruppen)
{
  // Schritt 1
  DirContext ctx = new InitialDirContext(getLdapVariablen(benutzer));
  SearchControls ctls = new SearchControls();
  ctls.setReturningAttributes(suchAttribute);
  ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);

  NamingEnumeration ergebnis = 
    ctx.search(
      ACTIVE_DIRECTORY_BENUTZER_PFAD,
      "(&(objectclass=user)(sAMAccountName=" + benutzer.getName() + "))",
      ctls);
  
  // Schritt 2
  while (antwort.hasMoreElements())
  {
    SearchResult ergebnis = antwort.nextElement();
    Attributes attribute = ergebnis.getAttributes();
    String gruppenString = attribute.get("memberOf").toString().split(":")[1];
    return Arrays.asList(gruppenString.split(", "))
      .stream()
      .map(gruppe -> gruppe.substring(3, gruppe.indexOf(",")).replace("=", ""))
      .anyMatch(gruppe -> gruppen.contains(gruppe));
  }
}

Fazit

Wie man sieht, lässt sich eine solche Anbindung an das Active Directory über das LDAP-Protokoll mit recht wenig Code und relativ einfach umzusetzen. Anstatt eine extra Datenbank mit allen Benutzern und deren Berechtigungen pflegen zu müssen, kann ich mich einfach an das AD hängen. Dazu benötige ich nicht einmal externe Bibliotheken, sondern es lässt sich alles mit “Bordmitteln” von Java machen.

Schreibe einen Kommentar

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

4 Gedanken zu “LDAP in Java | Authentifizierung und Autorisierung”