# 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](https://opotonniee.github.io/webauthn-playground/), der
intern die [SimpleWebAuthn](https://simplewebauthn.dev/) 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.
1. **Ü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.
1. **Ü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.
1. Der Autorisierungsserver leitet den Benutzer zur Authentifizierung weiter.
1. 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.
1. Der Client verwendet das Autorisierungstoken, um beim Autorisierungsserver
ein Zugriffstoken anzufordern. Dieses Zugriffstoken wird verwendet, um auf
die geschützten Ressourcen des Benutzers zuzugreifen.
1. 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.
```{mermaid}
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).

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
```{mermaid}
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.
1. 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.
1. Der Authorisierungsserver authentifiziert den Nutzer (z.B. durch ein
Login-fenster) und fragt, ob der Nutzer den Client die angefragten Ressourcen
freigeben will.
1. Der Nutzer authentifiziert sich und authoriziert die Anfrage des Clients.
1. Der IdP sendet einen Auth-code an den Client.
1. 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.
1. 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.
1. 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.
1. 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.
1. 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.
1. 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.
```{mermaid}
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](https://github.com/ArnaudBuchholz/reserve) 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.
```javascript
// 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](https://github.com/ldapts/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.
```javascript
// 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.
```javascript
// 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--
```