Unterschiedliche Anmeldeverfahren

In dieser Dokumentation werden verschiedene Anmeldeverfahren sowie Protokolle untersucht und erläutert. Ziel ist es, ein Verständnis für die verschiedenen Methoden der Authentifizierung und deren Anwendungen zu vermitteln.

Authentifizierung und Autorisierung

Authentifizierung

Authentifizierung ist der Prozess, bei dem die Identität eines Benutzers überprüft wird, um sicherzustellen, dass er tatsächlich derjenige ist, der er vorgibt zu sein. Dies erfolgt typischerweise durch die Überprüfung von Anmeldeinformationen wie Benutzername und Passwort oder durch den Einsatz von biometrischen Merkmalen wie Fingerabdruck oder Gesichtserkennung. Das Ziel der Authentifizierung ist es, sicherzustellen, dass nur autorisierte Benutzer auf geschützte Ressourcen zugreifen können.

Autorisierung

Autorisierung bestimmt, welche Aktionen ein authentifizierter Benutzer auf einer Ressource ausführen darf. Sie erfolgt nach erfolgreicher Authentifizierung und basiert auf den Berechtigungen oder Rollen, die einem Benutzer zugewiesen sind. Dies kann bedeuten, dass ein Benutzer Lese- oder Schreibzugriff auf eine Ressource hat oder dass bestimmte Funktionen oder Daten nur für bestimmte Benutzer zugänglich sind. Das Ziel der Autorisierung ist es, sicherzustellen, dass Benutzer nur diejenigen Aktionen ausführen können, für die sie autorisiert sind.

Anmeldemöglichkeiten

Unterschiedliche Anmeldemöglichkeiten bieten Benutzern verschiedene Wege, um sich bei einem System anzumelden. Diese können in drei Hauptkategorien eingeteilt werden: das, was der Benutzer weiß, was der Benutzer hat und was der Benutzer ist.

  • Was der Benutzer weiß (z.B. E-Mail und Passwort): Diese Methode erfordert vom Benutzer, dass er sich an Informationen erinnert, die nur er kennen sollte, wie beispielsweise ein Passwort oder einen Benutzernamen. Dies ist die traditionellste Form der Anmeldung und wird auf vielen Websites und in Anwendungen verwendet.

  • Was der Benutzer hat (z.B. E-Mail/SMS OTP): Hierbei muss der Benutzer zusätzlich zu seinem Passwort einen weiteren Faktor besitzen, wie beispielsweise ein Mobiltelefon, auf das ein Einmalpasswort (OTP) gesendet wird. Dies erhöht die Sicherheit, da ein potenzieller Angreifer sowohl das Passwort als auch den zweiten Faktor benötigt, um sich anzumelden.

  • Was der Benutzer ist (z.B. Fingerabdruck): Biometrische Authentifizierungsmethoden basieren auf den physischen Merkmalen des Benutzers, wie Fingerabdruck, Gesichtserkennung oder Iris-Scan. Diese Methode bietet eine hohe Sicherheit und Benutzerfreundlichkeit, da der Benutzer keine Passwörter oder zusätzlichen Geräte benötigt.

Multi-Faktor-Authentifizierung (MFA)

Die Multi-Faktor-Authentifizierung (MFA) kombiniert zwei oder mehr der oben genannten Anmeldemethoden, um die Sicherheit weiter zu erhöhen. Indem sie mehrere Faktoren miteinander verbindet, schützt sie das System effektiver vor unbefugtem Zugriff.

Unter den verschiedenen untersuchten Protokollen für die Mehrfaktor-Authentifizierung (MFA) sticht das Time-Based One-Time Password (TOTP) als eine solide Lösung zur Erhöhung der Sicherheit digitaler Zugänge hervor. Im Wesentlichen als Methode für die Zwei-Faktor-Authentifizierung (2FA) konzipiert, hat sich TOTP als wirksam erwiesen, um Benutzerkonten in einer Vielzahl von Online-Anwendungen und -Diensten zu schützen. Es wird weitgehend als sekundäre Authentifizierungsmethode neben den traditionellen Benutzername-Passwort-Kombinationen verwendet.

Insbesondere bildet TOTP die Grundlage für Authentifizierungs-Apps wie Google Authenticator, Authy und andere, die Benutzern eine einfache und zuverlässige Möglichkeit bieten, zeitbasierte Einmalpasswörter zu generieren und zu verwenden. Diese Apps bieten den Benutzern eine zusätzliche Sicherheitsebene, indem sie einen zweiten Authentifizierungsfaktor hinzufügen, der oft in der Verwendung eines mobilen Geräts des Benutzers zur Generierung von TOTP-Codes besteht.

Die weit verbreitete Umsetzung von TOTP als Methode für die Zwei-Faktor-Authentifizierung unterstreicht seine Relevanz und Zuverlässigkeit in der modernen Cybersecurity-Landschaft. Seine zeitbasierte Natur gewährleistet, dass die generierten Codes nur für kurze Zeitfenster gültig sind, was es Angreifern erschwert, Konten zu kompromittieren, selbst wenn sie Zugriffsdaten erhalten haben.

Einführung TOTP (Time-Based One-Time Password)

Das TOTP (Time-Based One-Time Password)-Protokoll ist ein Verfahren zur Generierung von zeitbasierten Einmalpasswörtern, das speziell für die Zwei-Faktor-Authentifizierung (2FA) und andere Formen der Multifaktor-Authentifizierung (MFA) entwickelt wurde. TOTP ist eine Erweiterung des HMAC-Based One-Time Password (HOTP) Algorithmus.

  • Methode: Besitz des Benutzers

  • Typ: Zwei-Faktor-Authentifizierung (2FA)

  • Funktionsweise: Kombiniert das Wissen (Benutzername/Passwort) mit dem Besitz (Gerät des Benutzers)

Funktionsweise von TOTP:

  1. Generierung des Tokens:

    • Das Token hat normalerweise eine Gültigkeitsdauer von 60 Sekunden.

    • Es erfordert einen gemeinsamen geheimen Schlüssel zwischen Server und Gerät des Benutzers.

  2. Algorithmus:

    • Basierend auf der Erweiterung HMAC-Based One-Time Password.

    • Verwendet einen gemeinsamen geheimen Schlüssel und die aktuelle Zeit, um die Tokens zu generieren.

    • Der Algorithmus wurde in der RFC 6238 veröffentlicht.

  3. Generierung des Tokens:

    • Der Benutzer erhält einen gemeinsamen geheimen Schlüssel, oft als QR-Code, während der Registrierung auf der Authentifizierungsanwendung (z.B. Google Authenticator).

    • Wenn der Benutzer sich mit diesem gemeinsamen geheimen Schlüssel auf einer Anwendung registriert, generiert die Anwendung gültige Tokens für einen bestimmten Zeitraum und eine spezifische Anwendung.

  4. Berechnung des Tokens:

    • Der Benutzer nimmt die aktuelle Zeit (z.B. die Unix-Zeit) und teilt sie in Zeitintervalle, normalerweise 30 Sekunden, auf.

    • Dieser Wert wird in einen hexadezimalen Wert mit 16 Zeichen (8 Byte) umgewandelt.

    • Der gemeinsame geheime Schlüssel und die Nachricht (hexadezimaler Wert) werden verwendet, um den HMAC-Hash unter Verwendung des HMAC-SHA1-Algorithmus zu berechnen.

    • Aus dem HMAC-Hash werden die ersten 4 Byte vom bestimmten Byte des Offsets genommen.

    • Diese Bytes werden verarbeitet, um eine ganze Zahl zu erhalten.

    • Schließlich wird das Token generiert, indem diese ganze Zahl modulo 10^n genommen wird, wobei n die gewünschte Länge des Tokens ist.

Anwendungen:

  • Beispiele für Anwendungen, die 2FA mit TOTP verwenden, sind die Desktop- und mobile Wallet-App von Trinity.

  • Apps wie Google Authenticator und Authy bieten eine Anwendung, die TOTP-Token zur Authentifizierung auf anderen Apps generiert.

Das TOTP-Protokoll erhöht die Sicherheit der Zugangsdaten, indem es es für Angreifer schwieriger macht, auf das Benutzerkonto zuzugreifen, selbst wenn sie die grundlegenden Zugangsdaten erhalten.

Beschreibung der Versuche:

Versuch 01: TOTP mit Javascript
Verzeichnis: 1_TOTP_JS

Für diesen Versuch wurde ein Express-Server und eine einfache SQLite3-Datenbank eingerichtet, um eine Registrierung, einen Login und eine Verifizierung unter Verwendung von Time-Based One-Time Passwords (TOTP) zu ermöglichen. Dadurch soll die Funktionsweise der Zwei-Faktor-Authentifizierung (2FA) demonstriert werden. Die Benutzeroberfläche wird mit Hilfe von HTML und Bootstrap5 angezeigt.

Im Grundlegenen ist der Versuch so aufgebaut:

Importieren der erforderlichen Module:
Die Anwendung importiert die benötigten Module wie Express, Body-Parser, Speakeasy für die TOTP-Generierung und sqlite3 für die Datenbankinteraktion.

Konfiguration des Servers:
Der Server wird konfiguriert, um statische Dateien aus dem “public” Verzeichnis zu bedienen und JSON- und URL-kodierte Anfragen zu verarbeiten.

Datenbankinitialisierung:
Eine SQLite-Datenbank wird eingerichtet und eine “users” Tabelle wird erstellt, um Benutzerinformationen wie Benutzername, E-Mail, Passwort, TOTP-Geheimnis und Token zu speichern.

Registrierung von Benutzern:
Der Server stellt Endpunkte bereit, um Benutzer zu registrieren und ihre Informationen in der Datenbank zu speichern. Beim Registrieren wird ein TOTP-Geheimnis für den Benutzer generiert.

Anmeldung von Benutzern:
Benutzer können sich anmelden, indem sie ihren Benutzernamen und ihr Passwort eingeben. Die Anwendung überprüft, ob der Benutzername vorhanden ist und ob das Passwort korrekt ist. Wenn ja, wird ein TOTP-Token generiert und in der Datenbank gespeichert.

Verifizierung von TOTP-Token:
Benutzer können ihr TOTP-Token überprüfen, indem sie es zusammen mit ihrem Benutzernamen an den Server senden. Die Anwendung überprüft, ob das empfangene Token mit dem in der Datenbank gespeicherten übereinstimmt und leitet den Benutzer entsprechend weiter.

Zurücksetzen der Datenbank:
Ein zusätzlicher Endpunkt zum Zurücksetzen der Datenbank wird bereitgestellt, um alle Einträge in der Benutzertabelle zu löschen.

Server starten:
Der Server wird gestartet und auf Port 3000 gehört.

Versuch 02: TOTP mit Python
Verzeichnis : 1_TOTP

Im Rahmen dieses Anwendungsfalls wird ein Base-32 codierter geheimer Schlüssel zwischen dem Client und dem Server ausgetauscht. Der Client generiert ein 6-stelliges Token und sendet es sofort nach der Generierung mittels einer Post HTTP-Anfrage an den Server. Das Token hat eine Lebensdauer von 30 Sekunden, was bedeutet, dass es nach 30 Sekunden ungültig wird. Dabei wird das Token in die Nachricht integriert. Der Server verifiziert die empfangene Antwort und vergleicht das erhaltene Token mit dem intern generierten Token. Im Falle einer Übereinstimmung antwortet der Server mit dem HTTP-Statuscode 200, andernfalls mit dem Statuscode 403. Bei einer erfolgreichen Authentifizierung erhält der Client eine positive Rückmeldung, andernfalls eine negative.

Nachfolgend sind die Anweisungen zur Ausführung des Codes beschrieben:

  1. Starten Sie die Datei MyToTPServer.py: Dadurch wird ein Server auf localhost:8000 gestartet.

  2. Führen Sie die Datei MyToTPclient.py aus: Der Client wird eine Nachricht an den Server senden und die Ausgabe des Servers wird auf der Konsole angezeigt.

Passkeys

Eine weitere Art der Implementierung von Authentifizierung mit mehreren Faktoren sind FIDO-Passkeys. Diese wurden von der Fast Identity Online (FIDO) Alliance entwickelt, um das konventionelle Passwort-basierte System zu ersetzen und die Sicherheit von Online-Konten zu verbessern.

FIDO-Passkeys sind kryptografische Schlüssel, die auf einem physischen Gerät wie einem USB-Token oder einem NFC-fähigen Smartphone gespeichert sind. Sie dienen als eine Art digitaler Ausweis für den Benutzer. Wenn sich ein Benutzer bei einem Dienst anmeldet, sendet der Dienst eine Herausforderung an das Gerät des Benutzers. Das Gerät verwendet den auf ihm gespeicherten privaten Schlüssel, um die Herausforderung zu signieren und sie an den Dienst zurückzusenden. Der Dienst überprüft dann die Signatur mithilfe des öffentlichen Schlüssels, der dem Benutzerkonto zugeordnet ist. Wenn die Signatur gültig ist, wird der Benutzer authentifiziert und kann auf das Konto zugreifen.

Die Verwendung von FIDO-Passkeys bietet mehrere Vorteile:

  • Schutz vor Phishing: Da die Passkeys nicht anfällig für Phishing-Angriffe sind, wird die Sicherheit erhöht.

  • Schutz vor Replay-Angriffen: Da jede Anmeldung eine neue Herausforderung erzeugt, können aufgezeichnete Anmeldeinformationen nicht wiederverwendet werden.

  • Stärkere Sicherheit: Die physische Präsenz des Geräts ist erforderlich, um sich anzumelden, was die Sicherheit erhöht, da ein Angreifer nicht nur das Passwort kennen, sondern auch physischen Zugriff auf das Gerät haben müsste.

Die Funktionsweise sieht man am besten beim WebAuthn Playground, der intern die SimpleWebAuthn library benutzt.

HTTP Basic Authentication

HTTP Basic Authentication ist eine einfache Methode zur Authentifizierung von Benutzern über das Hypertext Transfer Protocol (HTTP). Es ist eine der ältesten Formen der Authentifizierung im Web und wird immer noch häufig verwendet.

  1. Aufforderung zur Anmeldung: Wenn ein Benutzer auf eine geschützte Ressource zugreifen möchte, fordert der Server den Benutzer zur Anmeldung auf, indem er eine HTTP 401 Unauthorized-Antwort zurückgibt.

  2. Übermittlung von Anmeldeinformationen: Der Benutzer sendet dann seine Anmeldeinformationen (Benutzername und Passwort) an den Server. Dies geschieht normalerweise über einen Dialog im Browser, der den Benutzer auffordert, seine Anmeldeinformationen einzugeben.

  3. Übertragung von Anmeldeinformationen: Die Anmeldeinformationen werden normalerweise als Teil des HTTP-Header-Felds Authorization übertragen. Das Authorization-Header-Feld enthält den Benutzernamen und das Passwort, die Base64-codiert sind. Die Codierung ist jedoch nicht gleichbedeutend mit Verschlüsselung und bietet nur eine minimale Sicherheit.

Zum Beispiel könnte der Authorization-Header so aussehen:

Authorization: Basic QWxhZGRpbjpPcGVuU2VzYW1l

Hier ist QWxhZGRpbjpPcGVuU2VzYW1l der Base64-codierte String Aladdin:OpenSesame, wobei Aladdin der Benutzername und OpenSesame das Passwort ist.

  1. Authentifizierung auf Serverseite: Der Server entschlüsselt die Base64-codierte Zeichenfolge und überprüft, ob die Anmeldeinformationen korrekt sind. Wenn die Anmeldeinformationen gültig sind, gewährt der Server dem Benutzer Zugriff auf die angeforderte Ressource und sendet eine HTTP 200 OK-Antwort zurück. Andernfalls sendet der Server eine erneute HTTP 401 Unauthorized-Antwort.

Es ist wichtig zu beachten, dass HTTP Basic Authentication die Anmeldeinformationen bei jedem HTTP-Request überträgt. Die Anmeldeinformationen werden vom Browser zwischengespeichert, so dass sie nicht bei jeder Anfrage erneut eingegeben werden müssen. Dies macht HTTP Basic Authentication weniger benutzerfreundlich als andere Authentifizierungsmethoden wie Sessions oder Cookies. Auch die Sicherheit ist begrenzt, da die Anmeldeinformationen zwar Base64-codiert, aber nicht verschlüsselt sind, und somit potenziell von Dritten abgefangen werden könnten.

SSO-Protokolle

Single Sign-On (SSO)-Protokolle ermöglichen es Benutzern, sich einmalig bei einem System anzumelden und dann nahtlos auf mehrere verbundene Systeme zuzugreifen, ohne sich erneut anmelden zu müssen. Die drei gängigsten SSO-Protokolle sind OAuth2, OpenID Connect und Security Assertion Markup Language (SAML).

OAuth2

OAuth2 ist ein Autorisierungsframework, das es Benutzern ermöglicht, Anwendungen den Zugriff auf ihre Ressourcen zu gestatten, ohne ihre Anmeldeinformationen weiterzugeben. Es wird häufig für die Autorisierung von Drittanbieteranwendungen verwendet. Benutzer autorisieren Anwendungen, auf ihre geschützten Ressourcen zuzugreifen, indem sie Zugriffs-Token an die Anwendung ausgeben. Diese Tokens können zeitlich begrenzt sein und verschiedene Berechtigungsstufen haben.

  1. Der Client beantragt beim Autorisierungsserver Zugriff auf die geschützten Ressourcen des Benutzers. Dies geschieht über eine Autorisierungsanfrage, die den Typ der angeforderten Berechtigung (Scope), die Identität des Clients und gegebenenfalls andere Informationen enthält.

  2. Der Autorisierungsserver leitet den Benutzer zur Authentifizierung weiter.

  3. Nach erfolgreicher Authentifizierung erhält der Benutzer die Möglichkeit, dem Client den Zugriff auf seine Ressourcen zu gewähren oder abzulehnen. Wenn der Benutzer zustimmt, gibt der Autorisierungsserver dem Client ein Autorisierungstoken zurück.

  4. Der Client verwendet das Autorisierungstoken, um beim Autorisierungsserver ein Zugriffstoken anzufordern. Dieses Zugriffstoken wird verwendet, um auf die geschützten Ressourcen des Benutzers zuzugreifen.

  5. Der Client verwendet das Zugriffstoken, um auf die geschützten Ressourcen zuzugreifen. Das Zugriffstoken enthält Informationen über die vom Benutzer gewährten Berechtigungen und hat eine begrenzte Gültigkeitsdauer.

sequenceDiagram participant User participant Client participant AuthorizationServer participant ResourceServer User->>Client: Visit App Client->>AuthorizationServer: Redirect to Auth Server AuthorizationServer->>User: Redirect to Login Page User->>AuthorizationServer: Access Grant AuthorizationServer->>Client: Redirect with Auth code Client->>AuthorizationServer: Request for Access Token with Auth code AuthorizationServer->>AuthorizationServer: Validation AuthorizationServer->>Client: Receive Access Token Client->>ResourceServer: Request Resource with Access Token ResourceServer->>ResourceServer: Validate Access Token ResourceServer->>Client: Grant Access to Resource

OpenID Connect

OpenID Connect ist eine Authentifizierungsschicht, die auf OAuth2 aufbaut und eine standardisierte Methode zur Verifizierung der Identität eines Benutzers bereitstellt. Es ermöglicht es einem Benutzer, sich bei einer Anwendung mit einer ID von einem Identity Provider (IdP) anzumelden. Der IdP bestätigt die Identität des Benutzers gegenüber der Anwendung und stellt ein ID-Token aus, das Informationen über den Benutzer enthält.

Einfaches Beispiel: Registrierung bei Spotify (Client) mit dem Google Konto (IdP).
spotify_oidc

OIDC Prozess am Beispiel: https://openidconnect.net/

OIDC Spezifikation: https://openid.net/specs/openid-connect-basic-1_0.html

Beteiligte Agenten bei OpenID Connect

  • Resource Owner (auch Nutzer): der Eigentümer der Daten beim IdP.

  • Relying Party (auch Client): App welcher den Nutzer mittels OpenID Connect authentifizieren will.

  • OpenID Provider (auch IdP, z.B. Google): ein Anbieter, welcher das OpenID Connect Protokoll implementiert hat und entsprechende Endpunkte bereitstellt.

    • Authorisierungsserver: Server beim IdP mit Endpunkt für Authentifizierung und Endpunkt für Tokenausgabe.

    • Ressourcenserver: Server beim IdP für die Ausgabe von Nutzerdaten.

Ablauf eines Authentifizierungsprozesses

sequenceDiagram participant User participant Client participant AuthorizationServer participant ResourceServer User->>Client: (1) Visit App, choose OIDC login Client->>AuthorizationServer: (2) Redirect to Auth Server AuthorizationServer->>User: (3) Redirect to Login Page User->>AuthorizationServer: (4) Access Grant AuthorizationServer->>Client: (5) Redirect with Auth code Client->>AuthorizationServer: (6) Request for Access Token & ID Token with Auth code AuthorizationServer->>AuthorizationServer: (6) Validation AuthorizationServer->>Client: (6) Receive Access Token & ID Token Client->>Client: (7) Login with ID Token Data
  1. Der Benutzer initiiert den Authentifizierungsprozess, indem er bei einer OIDC-fähigen Client-Anwendung die Anmeldeoption eines IdP (wie Google) wählt.

  2. Die Anwendung sendet dann eine Autorisierungsanfrage an den Autorisierungsserver des Identity Providers, ähnlich wie im OAuth 2.0 Protokoll.
    Der Client sendet folgende Parameter an den IdP:

    • respone_type=code
      Die Antwort soll einen Code enthalten der Zugriff auf den ID Token und den Access Token gibt.

    • client_id=abcd1234
      Die ID welche den Client beim IdP identifiziert.

    • redirect_uri=https://client.xyz/callback
      Die URI zu der die Antwort gesendet werden soll.

    • scope=openid profile
      Der “openid” Wert informiert den Authorisierungsserver, dass es hier um eine openID Anfrage geht.
      Der “profile” Wert ist optional und fragt Nutzerdaten wie Name und Geburtsdatum an.

  3. Der Authorisierungsserver authentifiziert den Nutzer (z.B. durch ein Login-fenster) und fragt, ob der Nutzer den Client die angefragten Ressourcen freigeben will.

  4. Der Nutzer authentifiziert sich und authoriziert die Anfrage des Clients.

  5. Der IdP sendet einen Auth-code an den Client.

  6. Der Client sendet den Auth-code an den Token-Endpunkt des Authorisierungsservers und erhält eine Antwort der u.a. den Access Token und ID Token beinhaltet.

    • Das ID-Token enthält Nutzerdaten und Informationen vom gesamten Authentifizierungsprozess. Es wird von der Client-Anwendung verwendet, um die Identität des Benutzers zu überprüfen.

    • Das Zugriffstoken wird verwendet, um auf geschützte Ressourcen zuzugreifen, ähnlich wie im OAuth 2.0-Protokoll. Es wird normalerweise mit dem ID-Token zusammen ausgegeben und hat eine begrenzte Gültigkeitsdauer.

  7. Die Client-Anwendung kann mit den gelieferten Daten aus dem ID Token den Nutzer in der Client-anwendung authentifizieren und einloggen. Das ID Token kann beispielsweise so aussehen:

{
 "clientID": "kbyuFDidLLm280LIwVFiazOqjO3ty8KH",
 "created_at": "2024-04-02T12:16:41.546Z",
 "email": "bota.nicolas@gmail.com",
 "email_verified": true,
 "identities": [
  {
   "connection": "Username-Password-Authentication",
   "provider": "auth0",
   "user_id": "660bf7290cd378686326f1c6",
   "isSocial": false
  }
 ],
 "name": "bota.nicolas@gmail.com",
 "nickname": "bota.nicolas",
 "picture": "https://s.gravatar.com/avatar/76f1da0a655e948e3e1907d2d4f4238f?s=480&r=pg&d=https%3A%2F%2Fcdn.auth0.com%2Favatars%2Fbo.png",
 "updated_at": "2024-04-02T13:54:11.777Z",
 "user_id": "auth0|660bf7290cd378686326f1c6",
 "user_metadata": {},
 "app_metadata": {},
 "iss": "https://samples.auth0.com/",
 "sub": "auth0|660bf7290cd378686326f1c6",
 "aud": "kbyuFDidLLm280LIwVFiazOqjO3ty8KH",
 "iat": 1712066093,
 "exp": 1712102093
}

SAML (Security Assertion Markup Language)

SAML ist ein XML-basiertes SSO-Protokoll, das die Authentifizierung und Autorisierung zwischen verschiedenen Sicherheitsdomänen ermöglicht. Es wird häufig in Unternehmensumgebungen und bei der Integration von Diensten verschiedener Anbieter eingesetzt. SAML arbeitet mit einer Struktur von vertrauenswürdigen Identitätsanbietern und Service Providern. Der Identitätsanbieter authentifiziert den Benutzer und stellt eine SAML-Antwort aus, die eine Aussage über die Identität des Benutzers enthält. Der Service Provider verarbeitet diese Aussage und gewährt dem Benutzer Zugriff auf die geschützten Ressourcen.

  1. Ein Benutzer versucht auf eine geschützte Ressource bei einem Service Provider (SP) zuzugreifen. Der SP leitet den Benutzer an den Identity Provider (IdP) weiter, der für die Authentifizierung des Benutzers verantwortlich ist.

  2. Der IdP authentifiziert den Benutzer. Dies kann durch verschiedene Mechanismen erfolgen, wie z. B. die Eingabe von Benutzername und Passwort, die Verwendung von Multi-Faktor-Authentifizierung usw.

  3. Nach erfolgreicher Authentifizierung erstellt der IdP eine SAML-Assertion. Diese Assertion ist ein XML-Dokument, das Informationen über den authentifizierten Benutzer enthält, wie z. B. Benutzer-ID, Name, Rollen usw. Die Assertion wird digital signiert, um ihre Integrität und Authentizität zu gewährleisten.

  4. Der IdP leitet die SAML-Assertion an den SP weiter. Dies geschieht normalerweise über den Browser des Benutzers, der die Weiterleitung der Assertion an den SP initiiert.

  5. Der SP empfängt die SAML-Assertion und überprüft ihre Signatur, um sicherzustellen, dass sie vom gültigen IdP stammt und nicht manipuliert wurde. Nach erfolgreicher Überprüfung verwendet der SP die in der Assertion enthaltenen Informationen, um den Benutzer zu authentifizieren und ggf. Autorisierungsentscheidungen zu treffen.

sequenceDiagram participant User participant Client participant SP participant IdP User ->> Client: Visit App Client ->> SP: Request Protected Resource SP ->> IdP: Redirect to IdP for Authentication IdP->>User: Redirect to Login Page User->>IdP: Access Grant IdP -->> Client: Authentication Response (SAML Assertion) Client ->> SP: Provide SAML Assertion SP ->> SP: Validate SAML Assertion SP ->> Client: Serve Resource

Beispiele

Für die folgenden Beispiele wurde der REserver server benutzt.

HTTP Basic

In diesem Beispiel wird für /basic/ Anfragen der folgende Händler aufgerufen. Dieser Händler überprüft ob in der Anfrage der Authorization Header gesetzt ist. Falls dies nicht der Fall ist wird HTTP Status Code 401 an den Client geschickt. Der Client bzw. der Browser wertet diesen Code aus und zeigt dem User ein Dialog an für die Eingabe von Benutzername und Passwort. Der Browser macht mit diesen Daten erneut die selbe Anfrage, aber dieses Mal mit dem Authorization Header. Der Händler extrahiert Benutzername und Passwort aus dem Header und überprüft ob die Daten richtig sind.

// 02/1_Auth/custom_handlers/basic_auth.js

"use strict";

module.exports = (request, response, url) => {
  if (request.headers.authorization) {
    const buffer = Buffer.from(
      /Basic (.*)/.exec(request.headers.authorization)[1],
      "base64"
    );
    const nameAndPassword = buffer.toString("ascii").split(":");
    if (nameAndPassword[0] === "arnaud") {
      return;
    }
  }
  response.writeHead(401, {
    "WWW-Authenticate": 'Basic realm="Private"',
  });
  response.end();
};

HTTP Basic + LDAP

Nun soll der Server die Anmeldedaten nicht selbst überprüfen, sondern lässt diese von einer “dritten Partei” verifizieren. Dazu wird die ldapts library verwendet

Der folgende Händler wird für /oauth/ Anfragen verwendet. Hier werden Benutzername und Passwort an den LDAP Server der THA geschickt, der dann die Verifizierung übernimmt.

// 02/1_Auth/custom_handlers/oauth.js

// --snip--

const nameAndPassword = buffer.toString("ascii").split(":");
const url = "ldaps://ldap1.hs-augsburg.de:636";
const bindDN = `uid=${nameAndPassword[0]},ou=People,dc=FH-Augsburg,dc=de`;
const password = nameAndPassword[1];

const client = new Client({
  url: url,
  timeout: 0,
  connectTimeout: 5000,
  tlsOptions: {
    minVersion: "TLSv1.2",
  },
  strictDN: true,
});

try {
  await client.bind(bindDN, password);
  return;
} catch (ex) {
  console.log(ex);
} finally {
  await client.unbind();
}

client.unbind();

//  --snip--

HTTP Basic + LDAP + 2FA

In dieser Variante wird für die Authentifizierung ein zweiter Faktor verwendet. Der zweite Faktor ist in diesem Fall die E-Mail Adresse des Users. Diese E-Mail Adresse wird vom LDAP Server abgefragt. Anschließend wird über das SMTP-Protokoll eine Mail an den User mit einem Code geschickt. Der Code wird anschließend vom User abgefragt und mit dem generierten Code verglichen.

// 02/1_Auth/custom_handlers/2fa.js

// --snip--

await client.bind(bindDN, password);
const person = await client.search("ou=People,dc=FH-Augsburg,dc=de", {
  filter: `(uid=${nameAndPassword[0]})`,
});
await sendOTP(person.searchEntries[0].mail);

// --snip--

async function sendOTP(mail) {
  const serverHost = "smtp.hs-augsburg.de";
  const serverPort = 25;
  const senderEmail = mail;
  const recipientEmail = mail;
  const emailSubject = "Test Email";
  const emailHead = `From: ${senderEmail}\r\nTo: ${recipientEmail}\r\nSubject: ${emailSubject}\r\n\r\n`;

  const client = net.createConnection(
    { host: serverHost, port: serverPort },
    () => {
      console.log("Connected to SMTP server");
    }
  );

  client.on("error", (err) => {
    console.error("Connection error:", err);
  });

  client.on("connect", async () => {
    client.write(`HELO ${serverHost}\r\n`);
    await sleep();
    client.write(`MAIL FROM: ${senderEmail}\r\n`);
    await sleep();
    client.write(`RCPT TO: ${recipientEmail}\r\n`);
    await sleep();
    client.write("DATA\r\n");
    await sleep();
    client.write(emailHead);
    await sleep();
    const emailBody = "This is your OTP: " + generateOTP();
    client.write(`${emailBody}\r\n.\r\n`);
    await sleep();
    client.write("QUIT\r\n");
  });

  client.on("data", (data) => {
    console.log("Received:", data.toString());
  });

  client.on("end", () => {
    console.log("Disconnected from SMTP server");
  });
}

// --snip--