Authentifizierung mit einem LDAP-Server: Verschlüsselung mit SSL

Die Nutzer einer Application Express-Anwendung mit Hilfe eines LDAP-Servers zu authentifizieren, ist nicht besonders schwierig: Dazu gibt es ein vorgefertigtes Authentifizierungsschema; es müssen lediglich vier Angaben gemacht werden.

  • LDAP-Servername oder IP-Adresse
  • LDAP-Port
  • Den LDAP Distinguished Name String, also eine Maske für den LDAP-Anmeldenamen
  • Und optional: Die Username Edit Function, welche den vom Anwender angegebenen Nutzernamen u.U. umformatiert
Einrichtung des Authentifizierungsschemas "LDAP-Server"

Abbildung 1: Einrichtung des Authentifizierungsschemas "LDAP-Server"

Wird eine Anwendung mit einem solchen Authentifizierungsschema versehen, kann sich jeder im LDAP-Verzeichnis eingetragene Nutzer anmelden. Diese Authentifizerung nutzt jedoch keinerlei Verschlüsselungsmechanismen: Username und Passwort werden also im Klartext über das Netzwerk gesendet - dies ist in vielen Fällen (naheliegenderweise) nicht erwünscht. Erwartet wird dagegen eine verschlüsselte Kommunikation zwischen Application Express und dem LDAP-Server.

Das in APEX standardmäßig vorhandene LDAP-Authentifizierungsschema reicht in diesen Fällen nicht aus, da es keine verschlüsselte Kommunikation beherrscht. Das PL/SQL-Paket DBMS_LDAP (welches im Hintergrund von APEX verwendet wird), kann dagegen sehr wohl mit verschlüsselten Verbindungen arbeiten. Um diese Fähigkeit in APEX nutzen zu können, muss ein eigenes, benutzerdefiniertes Authentifizierungsschema erzeugt werden. Dieser Tipp zeigt auf, wie das für SSL gemacht wird. Passend dazu gibt es einen ähnlichen Tipp, der zeigt, wie man einen LDAP-Login mit einer zusätzlichen Tabelle im Parsing-Schema der APEX-Anwendung kombinieren kann.

Wenn das Paket DBMS_LDAP in Ihrer Datenbank nicht vorhanden ist, muss es zunächst eingespielt werden. Dazu muss der DBA als SYS das Skript catldap.sql im Verzeichnis $ORACLE_HOME/rdbms/admin laufen lassen.

LDAP und SSL: Grundsätzliches

SSL ist mitunter mehr als nur Verschlüsselung - vielfach kommen Aspekte der Authentifizierung hinzu. Grundlage ist die Einsicht, dass eine Verschlüsselung der Kommunikation nicht hilfreich ist, wenn man sich nicht über die Identität des Servers "auf der anderen Seite" klar ist. Zunächst ist es also wichtig, zu verstehen, welche Variante der SSL-Authentifizierung der LDAP-Server verwendet.

  • Keine Authentifizerung (Methode "1")
    In diesem Fall ist keine besondere Einrichtung des Datenbankservers nötig. Die Übertragungen werden verschlüsselt, es findet aber keinerlei Authentifizierung des LDAP-Servers oder des Clients statt. Dies ist die unsicherste Variante, denn man könnte fragen, was eine Verschlüsselung nutzt, wenn man sich über die Identität seines Gegenübers nicht im Klaren ist.
  • Serverseitige Authentifizerung (Methode "2")
    In diesem Fall weist sich der LDAP-Server gegenüber dem Datenbankserver per SSL-Zertifikat aus. Damit die Datenbank das Zertifikat prüfen kann, muss ein Oracle Wallet auf dem Datenbankserver eingerichtet werden.
  • Beiderseitige Authentifizerung (Methode "3")
    Nun muss sich auch der Datenbankserver gegenüber dem LDAP-Server ausweisen; es wird ebenfalls ein Oracle Wallet benötigt - zusätzlich muss darin nun noch ein SSL-Zertifikat für den Datenbankserver enthalten sein. Dieses sendet der Datenbankserver dann an den LDAP-Server, um sich "auszuweisen"; parallel dazu weist sich auch der LDAP-Server mit einem Zertfikat gegenüber dem Datenbankserver aus. Dies ist die sicherste Variante.

Noch detailliertere Erklärungen der drei Varianten finden Sie in der Metalink-Note 263700.1. Welche der Varianten Sie verwenden können, hängt vom Setup des LDAP-Servers ab; das müssen Sie also ggfs. mit dem Administrator abstimmen. Ist dieser auf Variante "1" eingerichtet, können Sie auch nur diese nutzen. Ist der LDAP-Server dagegen für Variante "2" konfiguriert, können Sie sowohl Methode "1" als auch "2" nutzen. Erwartet der Server dagegen auch ein Client-Zertifikat (Variante "3"), so müssen Sie dieses auch liefern; Sie können dann also ebenfalls nur Methode "3" nutzen. Die Varianten "2" und "3" erfordern die Einrichtung eines Oracle Wallet auf dem Datenbankserver.

Oracle Wallet auf dem Datenbankserver einrichten

Starten Sie zum Einrichten eines Wallets den Oracle Wallet Manager. Auf Linux- oder Unix-Systemen geben Sie dazu auf der Kommandozeile owm ein; auf Windows-Systemen wählen Sie den Wallet Manager aus dem Startmenü aus (Abbildung 2). Verwenden Sie hierzu den Betriebssystem-User, unter dem die Prozesse der Oracle-Datenbank laufen (normalerweise "oracle"). Wenn Sie einen anderen User verwenden, müssen Sie anschließend sicherstellen, dass der Nutzer, unter dem die Datenbankprozesse laufen, die Wallet-Datei lesen kann.

Oracle Wallet Manager

Abbildung 2: Oracle Wallet Manager

Wählen Sie im Wallet Manager aus der Menüzeile zunächst Wallet, dann Neu aus. Geben Sie Ihrem Wallet dann ein Passwort und achten Sie dabei auf die Vorgaben (Abbildung 3). Merken Sie sich das Passwort.

Passwort für das neue Wallet vergeben

Abbildung 3: Passwort für das neue Wallet vergeben

Das neue Wallet wird dann erstellt und ist im ersten Schritt noch leer. (Abbildung 4).

Das Wallet wurde erstellt

Abbildung 4: Das Wallet wurde erstellt

Wenn Sie mit der Authentifizerungsvariante "2", also nur der serverseitigen Authentifizierung arbeiten möchten, können Sie in dem in Abbildung 4 dargestellten Dialog auf Nein klicken. Wenn sich Ihr Datenbankserver auch gegenüber dem LDAP-Server ausweisen muss (Methode "3"), klicken Sie auf Ja, um eine Zertifikatsanforderung zu erstellen.

Beim Ausfüllen der Zertifikatsanforderung (Abbildung 5) kommt es darauf an, wie SSL-Zertifikate in Ihrem Unternehmen ausgegeben werden. Typischerweise wird die Zertifikatsanforderung dann an eine "ausgebende Stelle" (Certificate Authority) gesendet - diese erstellt dann das Zertifikat, welches dann ins Oracle Wallet importiert werden kann. Beachten Sie bitte, dass Sie diesen Schritt nur dann benötigen, wenn Sie die gegenseitige Authentifizierung (Methode "3") nutzen möchten. Klicken Sie ansonsten im Dialog der Zertifikatsanforderung auf Abbrechen.

Ein neues Zertifikat (für den Datenbankserver) anfordern

Abbildung 5: Ein neues Zertifikat (für den Datenbankserver) anfordern

Zum Abschluß müssen Sie Ihr Wallet speichern (Abbildung 6). Sie können jedes Verzeichnis auf dem Datenbankserver nutzen, der Eigentümer der Oracle-Software (oracle) muss nur Lese- und Schreibprivilegien haben. Merken Sie sich den Pfad und schließen Sie den Oracle Wallet Manager.

Wallet speichern

Abbildung 6: Wallet speichern

Anschließend finden Sie im ausgewählten Verzeichnis die in Abbildung 7 dargestellten Dateien.

Die Dateien des Oracle Wallet

Abbildung 7: Die Dateien des Oracle Wallet

Nun können Sie auf Betriebssystem-Ebene einen ersten Test wagen. Nutzen Sie dazu das auf dem Datenbankserver vorhandene Kommandozeilenwerkzeug ldapbind (liegt in $ORACLE_HOME/bin) wie folgt:

  • Methode "1": Nur Verschlüsselung
    $ ldapbind -h ldap.domain.com -p 636 -U 1 -D {LDAP-Anmelde-DN} -w {LDAP-Passwort}
    
  • Methoden "2": Serverseitige Authentifizierung
    $ ldapbind -h ldap.domain.com -p 636 -U 2 -W {Wallet-Verzeichnis} -P {Wallet-Passwort} -D {LDAP-Anmelde-DN} -w {LDAP-Passwort}
    
  • Methoden "3": Beidseitige Authentifizierung
    $ ldapbind -h ldap.domain.com -p 636 -U 3 -W {Wallet-Verzeichnis} -P {Wallet-Passwort} -D {LDAP-Anmelde-DN} -w {LDAP-Passwort}
    

Das Wallet-Verzeichnis wird in einer bestimmten Form erwartet. Auf Unix- oder Linux-Systemen sieht das wie folgt aus:

file:/pfad/zum/wallet/verzeichnis

Auf Windows-Systemen ist die Notation so:

file:D:\pfad\zum\wallet\verzeichnis

Wenn bind successful ausgegeben wird, funktioniert die Kommunikation. Dann kann eine PL/SQL-Authentifizierungsfunktion als Basis eingerichtet werden.

PL/SQL-Authentifizierungsfunktion einrichten

Wichtig beim Erstellen ist die Signatur der Funktion: Sie muss Nutzernamen und Passwort als VARCHAR2-Parameter entgegennehmen und das Ergebnis als BOOLEAN zurückliefern. Der Name ist dagegen frei wählbar.

create or replace FUNCTION USERNAME_PASSWORD_CHECK (
  p_username in varchar2, 
  p_password in varchar2
) return boolean as
  v_login_result  boolean := false;
  v_ldap          raw(32);
  v_ldapres       binary_integer;
  v_un            varchar2(100);
BEGIN
  begin
    -- LDAP-Handle initialisieren ...
    v_ldap := DBMS_LDAP.INIT(
      HOSTNAME => 'ldapserver.mydomain.com'
     ,PORTNUM  => 636
    );

    -- SSL aufsetzen - Beispiel für Methode "1"
    v_ldapres := DBMS_LDAP.OPEN_SSL(
      LD              => v_ldap
     ,SSLWRL          => null
     ,SSLWALLETPASSWD => null
     ,SSLAUTH         => 1
    );

    -- SSL aufsetzen - Beispiel für Methoden "2" und "3" auf Unix/Linux
    v_ldapres := DBMS_LDAP.OPEN_SSL(
      LD              => v_ldap
     ,SSLWRL          => 'file:/pfad/zum/Oracle/Wallet/Verzeichnis'
     ,SSLWALLETPASSWD => '{Oracle-Wallet-Passwort}'
     ,SSLAUTH         => 2 -- hier ggfs. "3" einsetzen
    );

    -- SSL aufsetzen - Beispiel für Methoden "2" und "3" auf Windows
    v_ldapres := DBMS_LDAP.OPEN_SSL(
      LD              => v_ldap
     ,SSLWRL          => 'file:D:\pfad\zum\Oracle\Wallet\Verzeichnis'
     ,SSLWALLETPASSWD => '{Oracle-Wallet-Passwort}'
     ,SSLAUTH         => 2 -- hier ggfs. "3" einsetzen
    );

    -- Hier wird der LDAP-"Distinguished Name" (DN) für das Login 
    -- zusammengesetzt; dies muss natürlich an die jeweilige Umgebung 
    -- angepasst werden.

    v_un := 'cn='||wwv_flow_custom_auth_std.ldap_dnprep(upper(p_username))||', dc=mydomain, dc=com';

    -- Der LDAP-Login-Versuch wird nur durchgeführt, wenn das
    -- Passwort NOT NULL ist - ansonsten nimmt der LDAP-Server
    -- an, dass ein "anonymous bind" vorliegt und wird jeden
    -- Versuch mit leerem Passwort "durchlassen"

    if p_password is not null then 

      -- Login-Versuch am LDAP-Server ...
       v_ldapres := DBMS_LDAP.SIMPLE_BIND_S(
        LD     => v_ldap,
        DN     => v_un,
        PASSWD => p_password
      );
  
      -- Bei Erfolg: wieder abmelden!
      v_ldapres := DBMS_LDAP.UNBIND_S(
        LD => v_ldap
      );
  
      -- Alles erfolgreich: Ergebnis auf "true" setzen
      v_login_result := true;
    else 
      v_login_result := false;
    end if;
  exception
    -- Bei Login-Misserfolg ... Ergebnis auf "false" setzen
    when others then
      v_login_result := false;
  end;

  return v_login_result;
END;
/

Wenn Sie den Code betrachten, erkennen Sie sehr gut die wesentlichen Abschnitte. Nach dem Initialisieren der LDAP-Umgebung (DBMS_LDAP.INIT) erfolgt das Aufsetzen der SSL-Umgebung mit DBMS_LDAP.OPEN_SSL (Sie brauchen natürlich nur einen Aufruf). Hier wird die Authentifizierungsvariante mit "1", "2" oder "3" festgelegt. Bei den Varianten "2" und "3" müssen zusätzlich noch Angaben zum Oracle Wallet gemacht werden; die Notation des Verzeichnisses erfolgt analog zu den Tests mit dem ldapbind-Werkzeug.

Ist die SSL-Sitzung erfolgreich aufgesetzt, werden Username und Passwort gegen den LDAP-Server geprüft. Dazu wird mit dem PL/SQL-Paket DBMS_LDAP ein Login (Bind) und unmittelbar danach ein Logout (Unbind) durchgeführt. Dieser Code läuft bei korrektem Benutzernamen und Passwort einwandfrei durch, bei falschen Angaben wird eine Exception ausgelöst.

PL/SQL-Funktion als APEX-Authentifizierungsschema aufsetzen

Legen Sie nun ein neues Authentifizierungschema an. Navigieren Sie dazu zu den Gemeinsamen Komponenten, dort zu den Authentfizierungsschemas und klicken Sie dort auf Erstellen. Wählen Sie im folgenden Dialog Völlig neu aus (Abbildung 8).

Erstellen eines Authentifizierungsschemas "Völlig neu"

Abbildung 8: Erstellen eines Authentifizierungsschemas "Völlig neu"

Geben Sie Ihrem Authentifizierungsschema einen Namen und (optional) eine Beschreibung.

Namen und Beschreibung für das Authentifizierungsschema festlegen

Abbildung 9: Namen und Beschreibung für das Authentifizierungsschema festlegen

Übernehmen Sie nun bis zum Dialog Ungültiges Session-Ziel die Defaults. Dort wählen Sie die Seite 101 aus - die Application Express Integrierte Anmeldeseite ist nicht zu empfehlen (Abbildung 10).

Seite "101" als Login-Seite auswählen

Abbildung 10: Seite "101" als Login-Seite auswählen

Beim Prozeß vor der Authentifizierung klicken Sie wiederum einfach auf Weiter - die wichtigste Einstellung ist die dann folgende Authentifizerungsfunktion. Wählen Sie hier Meine benutzerdefinierte Funktion für die Authentifizierung verwenden aus und hinterlegen Sie im dann erscheinenden Textfeld "return USERNAME_PASSWORD_CHECK;"; das Schlüsselwort return ist hierbei sehr wichtig (Abbildung 11).

Authentifizierungsfunktion hinterlegen

Abbildung 11: Authentifizierungsfunktion hinterlegen

Übernehmen Sie in den folgenden Dialogen wieder die Defaults, indem Sie stets auf Weiter klicken - im letzten Dialog Abmelde-URL tragen Sie folgende URL ein:

wwv_flow_custom_auth_std.logout?p_this_flow=&APP_ID.&p_next_flow_page_sess=&APP_ID.:1
Abmelde-URL hinterlegen

Abbildung 12: Abmelde-URL hinterlegen

Bestätigen Sie zum Schluß nochmals alle Angaben, in dem Sie in der Übersicht auf die Schaltfläche Schema erstellen klicken. Sie sehen daraufhin alle vorhandenen Schemas in einer Übersicht. Mit Klick auf Aktuelles Element ändern können Sie Ihrer Anwendung das neue Authentifizierungsschema zuweisen (Abbildungen 13 bis 15).

Erstelltes Authentifizierungsschema zuweisen

Abbildung 13: Authentifizierungsschema der Anwendung ändern

Authentifizierungsschema auswählen

Abbildung 14: Authentifizierungsschema auswählen

Änderung des Authentifizierungsschemas bestätigen

Abbildung 15: Änderung des Authentifizierungsschemas bestätigen

Nun können Sie das Authentifizierungsschema testen.

Tasks: Anwendungskomponenten exportieren unter "Gemeinsame Komponenten" Interessant wäre es nun, dieses Authentifizerungssschema auch anderen Application Express-Entwicklern zur Verfügung zu stellen - schließlich werden gerade solche Dinge wie ein LDAP-Login in den meisten Unternehmen zentral gesteuert. Für die PL/SQL-Funktion USERNAME_PASSWORD_CHECK ist das recht einfach - erstellen Sie einfach aus obigem Listing ein SQL-Skript; andere Entwickler spielen es dann via SQL Workshop ein. Allerdings möchten diese das Authentifizierungsschema nicht selbst Schritt für Schritt anlegen müssen; ein einfacher Import soll genügen. Daher empfiehlt es sich, das Authentifizierungsschema als einzelne Komponente zu exportieren. Navigieren Sie dazu wieder zu den Gemeinsamen Komponenten und klicken Sie rechts auf Anwendungskomponenten exportieren.

Im dann folgenden Dialog können Sie einzelne Anwendungskomponenten auswählen und so eine Exportdatei zusammenstellen. Wählen Sie Ihr eben erzeugtes Authentifizierungsschema aus und klicken Sie auf die Schaltfläche Zum Export hinzufügen. Nach gleicher Manier können Sie einzelne Seiten, Wertelisten, Templates und andere Dinge zu diesem Export hinzufügen - Sie können so "Standardkomponenten" für Ihr Unternehmen konfigurieren; jeder Entwickler kann diese Komponenten dann in seinen Workspace laden und für seine Anwendungen verwenden (Abbildung 16).

Komponenten für Export zusammenstellen

Abbildung 16: Komponenten für Export zusammenstellen

Klicken Sie, wenn Sie Ihre Komponenten zusammengestellt haben, auf Weiter und dann auf Komponentenexport (Abbildung 17)

Zusammengestellte Komponenten exportieren

Abbildung 17: Zusammengestellte Komponenten exportieren

Die SQL-Datei enthält die exportierten Komponenten - diese kann nun an andere Entwickler verteilt bzw. zum Download bereitgestellt werden.

Zurück zur Community-Seite