Merge branch 'phase/029-betriebsdoku'
Prüfung / pruefung (push) Canceled after 0s

This commit is contained in:
2026-09-19 00:51:16 +02:00
14 changed files with 473 additions and 9 deletions
+9
View File
@@ -17,6 +17,15 @@ und dieses Projekt folgt [Semantic Versioning](https://semver.org/lang/de/).
### Sicherheit
## [0.19.0] – 2026-09-19
### Hinzugefügt
- `docs/betrieb/`: Inbetriebnahme, Reverse Proxy (nginx Proxy Manager und netbird), OIDC mit authentik und Sicherung – jeweils Schritt für Schritt (#029)
### Behoben
- Die OIDC-Rückkehradresse berücksichtigte die im Dashboard eingetragene Adresse nicht, sondern nur `APP_URL` (#029)
- Beim Einlösen des OIDC-Codes wurde hinter einem Reverse Proxy die interne Adresse verwendet; der Tausch wäre am Anbieter gescheitert (#029)
## [0.18.0] – 2026-09-19
### Hinzugefügt
+6 -2
View File
@@ -2,7 +2,7 @@
## Zeitübersicht
**Gesamt:** 14 h 23 min
**Gesamt:** 15 h 03 min
| Issue | Zeit |
|---|---|
@@ -34,6 +34,7 @@
| #026 Auslieferung | 0 h 40 min |
| #027 Rollen und Benutzerverwaltung | 1 h 20 min |
| #028 Passkeys | 0 h 45 min |
| #029 Einrichtungsdokumentation | 0 h 40 min |
| Meilenstein | Zeit |
|---|---|
@@ -56,7 +57,7 @@
## 2026-09-17 · Sitzung 1 · 19:36–laufend
**Issue:** #001–#007 (Meilensteine v0.1.0 bis v0.4.0)
**Version:** 0.18.0
**Version:** 0.19.0
### Erledigt
- Auftrag gelesen, Rückfragen gestellt
@@ -158,6 +159,9 @@
- Dabei aufgefallen: Neu angelegte OIDC-Konten hätten die Modellvorgabe ADMIN geerbt – behoben, mit eigener Einstellung und Test
- Passkeys (#028): passwortlos, mehrere je Konto, Aufgabe in einem kurzlebigen Cookie. Nur über HTTPS nutzbar – die Seite sagt es, statt still zu scheitern
- Einrichtungsdokumentation (#029): Beim Aufschreiben des OIDC-Wegs fielen zwei Fehler auf, die nur hinter einem Reverse Proxy auftreten – Rückkehradresse und Code-Einlösung nahmen die interne Adresse. Beides behoben
- Erkenntnis: Eine Anleitung Schritt für Schritt aufzuschreiben findet Fehler, die kein Test findet, weil sie nur in einer bestimmten Betriebsform auftreten
### Nächster Schritt
- #016 Benutzerhandbuch mit Screenshots, danach #017 Favicons und #019 CI-Pipeline
- Für 1.0.0 fehlt noch: PMG (kein Host verfügbar) und der Fall „aktive Subscription auf PBS“ (#023)
+11 -1
View File
@@ -122,13 +122,23 @@ sie sich mit eigenen Tokens ausweisen.
- **Lokaler Zugang:** E-Mail und Passwort aus dem Seed (`ADMIN_EMAIL`, `ADMIN_PASSWORD`). Fünf Fehlversuche
je Kennung und Viertelstunde, danach Sperre (einstellbar unter *Einstellungen → System*).
Benutzer sperren oder Passwort setzen: `npm run benutzer -- sperren <email>`.
- **OIDC (z. B. authentik):** `OIDC_ISSUER`, `OIDC_CLIENT_ID`, `OIDC_CLIENT_SECRET` setzen. Rückkehradresse
- **Passkey:** passwortlos über WebAuthn, mehrere je Konto, Verwaltung unter *Meine Passkeys*. Setzt HTTPS voraus (außer `localhost`).
- **OIDC (z. B. authentik):** `OIDC_ISSUER`, `OIDC_CLIENT_ID`, `OIDC_CLIENT_SECRET` setzen – Schritt für Schritt in [docs/betrieb/authentik.md](docs/betrieb/authentik.md). Rückkehradresse
ist `<APP_URL>/api/auth/oidc/callback`. Ohne diese Werte erscheint nur der lokale Zugang – der bleibt
absichtlich immer nutzbar, falls der Anmeldedienst ausfällt. Unter *Einstellungen → System* lässt sich
einschränken, welche E-Mail-Domänen zugelassen sind und ob unbekannte Konten angelegt werden dürfen.
- **`APP_SECRET`** (mindestens 32 Zeichen) signiert die Sitzungs-Cookies. Ändert sich der Wert, sind alle
Sitzungen ungültig.
## Einrichtung im Betrieb
| Anleitung | Inhalt |
|---|---|
| [Inbetriebnahme](docs/betrieb/inbetriebnahme.md) | von null zum meldenden Host, in der richtigen Reihenfolge |
| [Reverse Proxy](docs/betrieb/reverse-proxy.md) | HTTPS mit nginx Proxy Manager, privates Netz mit netbird |
| [authentik](docs/betrieb/authentik.md) | Anmeldung über OIDC, samt Fehlerbildern |
| [Sicherung](docs/betrieb/sicherung.md) | was gesichert wird – und wie man es zurückspielt |
## Einstellungen
Die meisten Betriebswerte stehen unter *Einstellungen → System* und wirken sofort: Dashboard-Adresse,
+3
View File
@@ -24,6 +24,9 @@ auch mit Hosts hinter NAT.
---
> **Einrichtung statt Bedienung?** Reverse Proxy, OIDC und Sicherung stehen in
> [docs/betrieb/](../betrieb/README.md). Dieses Handbuch beschreibt die tägliche Arbeit.
## 1. Installation
### Mit Docker
+13
View File
@@ -0,0 +1,13 @@
# Betrieb
Anleitungen für alles, was rund um ProxLedger eingerichtet wird.
| Dokument | Inhalt |
|---|---|
| [inbetriebnahme.md](inbetriebnahme.md) | Von null zum laufenden Dashboard – Docker oder LXC, erster Agent, erste Zuordnung |
| [reverse-proxy.md](reverse-proxy.md) | HTTPS mit nginx Proxy Manager, privates Netz mit netbird |
| [authentik.md](authentik.md) | Anmeldung über OIDC |
| [sicherung.md](sicherung.md) | Was gesichert werden muss und wie man es zurückspielt |
Für die tägliche Arbeit **mit** ProxLedger ist das [Handbuch](../anleitung/README.md) gedacht.
Was gegen Angriffe getan wird (und was bewusst nicht), steht in [sicherheit.md](../sicherheit.md).
+118
View File
@@ -0,0 +1,118 @@
# Anmeldung über authentik (OIDC)
ProxLedger kann die Anmeldung an einen OIDC-Anbieter abgeben. Getestet ist authentik; mit jedem
anderen Anbieter, der OpenID Connect Discovery beherrscht, funktioniert es genauso.
**Der lokale Zugang bleibt daneben immer bestehen.** Das ist Absicht: Fällt authentik aus, kommt man
trotzdem noch ins Dashboard.
---
## 1. In authentik: Provider anlegen
*Applications → Providers → Create → OAuth2/OpenID Provider*
| Feld | Wert |
|---|---|
| Name | `ProxLedger` |
| Authorization flow | der übliche (z. B. *default-provider-authorization-implicit-consent*) |
| Client type | **Confidential** |
| Client ID | übernehmen, wird gleich gebraucht |
| Client Secret | übernehmen, wird gleich gebraucht |
| Redirect URIs | `https://proxledger.firma.de/api/auth/oidc/callback` |
| Scopes | `openid`, `email`, `profile` |
| Signing Key | ein vorhandenes Zertifikat auswählen |
Zur Rückkehradresse zwei Hinweise, an denen die meisten Einrichtungen scheitern:
- Sie muss **wortgleich** übereinstimmen – einschließlich `https`, Portangabe und ohne Schrägstrich am
Ende. ProxLedger bildet sie aus der Dashboard-Adresse unter *Einstellungen → System*, ersatzweise aus
`APP_URL`.
- authentik erlaubt auch reguläre Ausdrücke. Für eine einzelne Installation ist die genaue Adresse die
bessere Wahl; ein zu weiter Ausdruck öffnet eine Umleitung auf fremde Ziele.
## 2. In authentik: Application anlegen
*Applications → Applications → Create*
| Feld | Wert |
|---|---|
| Name | `ProxLedger` |
| Slug | `proxledger` |
| Provider | der eben angelegte |
Der Slug bestimmt die Discovery-Adresse:
```
https://authentik.firma.de/application/o/proxledger/.well-known/openid-configuration
```
Diese Adresse **ohne** den Teil `/.well-known/openid-configuration` ist der Aussteller
(`OIDC_ISSUER`) – also `https://authentik.firma.de/application/o/proxledger/`.
Prüfen lässt sie sich mit:
```bash
curl -fsS https://authentik.firma.de/application/o/proxledger/.well-known/openid-configuration | head
```
Wer darf sich anmelden, entscheidet in authentik die **Policy-Bindung** an der Application
(*Applications → ProxLedger → Policy / Group / User Bindings*). Ohne Bindung darf jeder, der bei
authentik ein Konto hat.
## 3. In ProxLedger: Werte eintragen
In die `.env` (Docker) oder `/opt/proxledger/.env` (LXC):
```bash
OIDC_ISSUER="https://authentik.firma.de/application/o/proxledger/"
OIDC_CLIENT_ID="…"
OIDC_CLIENT_SECRET="…"
OIDC_NAME="authentik" # Beschriftung des Knopfes auf der Anmeldeseite
APP_URL="https://proxledger.firma.de"
```
Danach neu starten:
```bash
docker compose up -d # Docker
systemctl restart proxledger # LXC
```
Auf der Anmeldeseite erscheint jetzt **Mit authentik anmelden**.
## 4. Rollen festlegen
ProxLedger liest **keine** Gruppen aus authentik. Wer sich zum ersten Mal anmeldet, bekommt die Rolle
aus *Einstellungen → System → Rolle für neue OIDC-Konten* – Vorgabe ist **Techniker**. Die endgültige
Rolle vergibt ein Administrator unter *Einstellungen → Benutzer*.
Das ist bewusst so: Eine Gruppenzuordnung, die stillschweigend Administratorrechte verteilt, ist
schwerer zu überblicken als eine Liste, in der jeder Zugang sichtbar ist.
Zwei Einstellungen helfen dabei, den Kreis klein zu halten:
- **Erlaubte E-Mail-Domänen** – etwa `firma.de`. Alles andere wird abgewiesen, auch wenn die Anmeldung
bei authentik geklappt hat.
- **Unbekannte OIDC-Anmeldungen legen ein Konto an** – abgeschaltet kommt nur herein, wer hier bereits
ein Konto hat. Dann legt man Konten vorab an (ohne Passwort) und die Anmeldung läuft trotzdem über
authentik.
## 5. Prüfen
1. Abmelden, dann **Mit authentik anmelden**.
2. Unter *Einstellungen → Protokoll* steht `anmeldung.erfolgreich` mit `weg: oidc`.
3. Unter *Einstellungen → Benutzer* steht das Konto mit der vergebenen Rolle und der Anmeldeart `OIDC`.
## Wenn es nicht klappt
| Meldung | Ursache |
|---|---|
| „Die Anmeldung über den Anbieter hat nicht geklappt.“ | Sammelmeldung – die Einzelheiten stehen im Protokoll des Containers (`docker compose logs web`). |
| authentik zeigt *Redirect URI Error* | Die Adresse stimmt nicht wortgleich. Häufig: `http` statt `https`, Schrägstrich am Ende, oder die interne statt der öffentlichen Adresse. |
| `invalid_client` | Client-ID oder -Secret falsch, oder der Provider steht auf *Public* statt *Confidential*. |
| Anmeldung klappt, aber ProxLedger meldet „keine E-Mail-Adresse“ | Der Scope `email` fehlt am Provider. |
| Nach der Anmeldung landet man auf einer unerreichbaren Adresse | `APP_URL` bzw. die Dashboard-Adresse zeigt nicht auf die öffentliche Adresse. |
Siehe auch: [Reverse Proxy](reverse-proxy.md) – ohne HTTPS gibt es weder sinnvolle OIDC-Anmeldung noch
Passkeys.
+81
View File
@@ -0,0 +1,81 @@
# Inbetriebnahme
Der kürzeste Weg von null zu einem Dashboard, das Hosts meldet. Rechnen Sie mit einer halben Stunde.
## Reihenfolge
Die Reihenfolge ist nicht beliebig – zwei Schritte hängen an der endgültigen Adresse:
1. Dashboard installieren
2. **Adresse festlegen** (Reverse Proxy, DNS)
3. OIDC einrichten (falls gewünscht)
4. Passkeys anlegen
5. Agents ausrollen
Wer Schritt 4 oder 5 vorzieht, macht sie nach einem Adresswechsel noch einmal: Passkeys gelten nur für
die Domäne, unter der sie entstanden sind, und die Adresse steckt im Installations-Einzeiler.
## 1. Installieren
**Docker** (beliebiger Host mit Docker):
```bash
git clone <repo> proxledger && cd proxledger
cp .env.example .env
# Pflicht: APP_SECRET, POSTGRES_PASSWORD, ADMIN_PASSWORD, APP_URL
docker compose up -d
```
**LXC auf Proxmox**, zwei Möglichkeiten:
```bash
bash deploy/lxc-installer.sh # Container mit Docker darin
```
```bash
# Nach Art der Proxmox VE Helper-Scripts, ohne Docker:
bash -c "$(curl -fsSL https://<git>/ProxLedger/raw/branch/main/deploy/community-scripts/ct/proxledger.sh)"
```
Der erste Administrator entsteht beim Einrichten aus `ADMIN_EMAIL` und `ADMIN_PASSWORD`; beim
LXC-Weg stehen die erzeugten Zugangsdaten in `/opt/proxledger/.credentials`.
**`APP_SECRET` gehört sofort in die Sicherung.** Er signiert die Sitzungen und verschlüsselt die
gespeicherten Zugangsdaten für SMTP und Webhooks. Ohne ihn sind beide unbrauchbar.
## 2. Adresse festlegen
Siehe [reverse-proxy.md](reverse-proxy.md). Danach unter *Einstellungen → System* die **Adresse des
Dashboards** eintragen – sie landet im Installations-Einzeiler und in den Benachrichtigungen.
## 3. Anmeldung einrichten
- Optional OIDC: [authentik.md](authentik.md)
- Weitere Konten unter *Einstellungen → Benutzer* (Administrator, Techniker, Kunde)
- Jeder legt sich unter *Meine Passkeys* einen Passkey an – danach entfällt das Passwort
## 4. Agents ausrollen
1. *Einstellungen → Agent-Tokens* → Enrollment-Token erzeugen (mit Kundenbindung spart es den
Zuordnungsschritt)
2. Auf jedem Proxmox-Host als root:
```bash
curl -fsSL https://proxledger.firma.de/install.sh | bash -s -- --token <ENROLL_TOKEN>
```
3. **In einem Cluster auf jedem Knoten** – jeder Knoten hat eine eigene Subscription. Das Dashboard
warnt von selbst, wenn ein Knoten fehlt.
4. Danach den Enrollment-Token widerrufen.
## 5. Benachrichtigungen
*Einstellungen → Benachrichtigungen*: SMTP-Zugang oder Webhook eintragen, Testnachricht schicken,
Zusammenfassung auf täglich oder wöchentlich stellen.
## Prüfliste
- [ ] `https://…/api/gesundheit` antwortet mit 200
- [ ] Anmeldung klappt, die Adresszeile bleibt auf der öffentlichen Adresse
- [ ] Ein Host meldet sich (*Hosts* zeigt ihn mit Ablaufdatum)
- [ ] Testnachricht ist angekommen
- [ ] Sicherung läuft und wurde **einmal zurückgespielt** ([sicherung.md](sicherung.md))
- [ ] `APP_SECRET` liegt an einem zweiten Ort
+144
View File
@@ -0,0 +1,144 @@
# HTTPS einrichten: nginx Proxy Manager oder netbird
ProxLedger spricht selbst kein HTTPS – davor gehört ein Reverse Proxy. Ohne ihn fehlen drei Dinge:
- **Passkeys** funktionieren nur im sicheren Kontext (HTTPS oder `localhost`).
- Das Sitzungs-Cookie bekommt kein `Secure`-Kennzeichen.
- Die Agent-Kommunikation läuft unverschlüsselt durchs Netz.
Fertige Beispiele für nginx, Caddy und Traefik liegen unter [`deploy/reverse-proxy/`](../../deploy/reverse-proxy/).
Dieses Dokument beschreibt die beiden Wege, die in der Praxis am häufigsten vorkommen.
---
## Weg A: nginx Proxy Manager
### 1. Proxy Host anlegen
*Hosts → Proxy Hosts → Add Proxy Host*, Reiter **Details**:
| Feld | Wert |
|---|---|
| Domain Names | `proxledger.firma.de` |
| Scheme | `http` |
| Forward Hostname / IP | IP des Docker-Hosts oder des LXC |
| Forward Port | `3000` |
| Cache Assets | aus |
| Block Common Exploits | an |
| Websockets Support | **an** |
Reiter **SSL**: *Request a new SSL Certificate*, dazu **Force SSL** und **HTTP/2 Support**.
### 2. Kopfzeilen ergänzen
Reiter **Advanced**, in das Feld *Custom Nginx Configuration*:
```nginx
# Ohne diese Angaben baut ProxLedger seine Weiterleitungen aus der internen Adresse
# (etwa http://172.18.0.4:3000) – im Browser landet man dann im Nichts.
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# Rechnungs-PDFs sind größer als die Standardgrenze von 1 MB.
client_max_body_size 12m;
```
### 3. In ProxLedger eintragen
```bash
APP_URL="https://proxledger.firma.de"
```
und unter *Einstellungen → System* dieselbe Adresse als **Adresse des Dashboards**. Sie steht danach
im Installations-Einzeiler für die Agents und ist die Grundlage für Passkeys und OIDC.
### 4. Prüfen
```bash
curl -fsS -o /dev/null -w "%{http_code}\n" https://proxledger.firma.de/api/gesundheit
curl -fsSI https://proxledger.firma.de/login | grep -i "content-security-policy\|strict-transport"
```
Danach einmal anmelden und darauf achten, dass die Adresszeile auf `proxledger.firma.de` bleibt.
---
## Weg B: netbird (kein offener Port)
netbird spannt ein privates Netz über WireGuard. ProxLedger ist dann **nur** für Geräte im Netz
erreichbar – kein Port im Internet, kein Zertifikat von außen nötig.
Das passt gut zu diesem Werkzeug: Die Oberfläche braucht niemand aus dem Internet, und die Proxmox-
Hosts stehen ohnehin meist in Kundennetzen mit netbird oder VPN.
### Aufbau
```
Proxmox-Host (netbird-Client) ──┐
Proxmox-Host (netbird-Client) ──┼── netbird-Netz ──► ProxLedger (netbird-Client, Port 3000)
Arbeitsplatz (netbird-Client) ──┘
```
### 1. netbird auf dem ProxLedger-Host
```bash
curl -fsSL https://pkgs.netbird.io/install.sh | sh
netbird up --setup-key <SETUP-KEY>
netbird status # zeigt die vergebene Adresse, z. B. 100.x.y.z
```
### 2. netbird auf jedem Proxmox-Host
Gleiche Schritte. Danach von dort prüfen:
```bash
curl -fsS -o /dev/null -w "%{http_code}\n" http://100.x.y.z:3000/api/gesundheit
```
### 3. Zugriff einschränken
In der netbird-Verwaltung eine Access-Policy anlegen: Gruppe `proxmox-hosts` darf Gruppe
`proxledger` auf Port 3000 erreichen, sonst nichts. Damit können die Hosts melden, aber nicht
untereinander sprechen.
### 4. HTTPS trotzdem einrichten
netbird verschlüsselt den Transport – der Browser weiß davon aber nichts, und **Passkeys bleiben ohne
HTTPS gesperrt**. Zwei Möglichkeiten:
- **Empfohlen:** Zusätzlich einen kleinen Reverse Proxy im netbird-Netz betreiben (nginx oder Caddy)
mit einem Zertifikat für einen internen Namen, ausgestellt über DNS-01 – dafür muss nichts nach
außen offen sein.
- Oder ein eigenes CA-Zertifikat verteilen. Dann brauchen auch die Agents das CA-Zertifikat:
`curl … | bash -s -- --token … --ca-cert /pfad/zur/ca.crt`.
Wer auf Passkeys verzichtet, kann ProxLedger im netbird-Netz auch schlicht über `http://100.x.y.z:3000`
betreiben. In dem Fall `APP_URL` auf genau diese Adresse setzen – sonst setzt ProxLedger ein
`Secure`-Cookie, das der Browser über `http` verwirft, und die Anmeldung läuft ins Leere.
---
## Beides zusammen
Der häufigste Aufbau in der Praxis:
| Zugang | Weg |
|---|---|
| Oberfläche für Mitarbeiter und Kunden | nginx Proxy Manager mit Let's-Encrypt-Zertifikat |
| Agents aus Kundennetzen | netbird, oder dieselbe öffentliche Adresse |
Wichtig ist nur, dass die Agents dieselbe Adresse erreichen, die im Installations-Einzeiler steht.
Ändert sich die Adresse später, genügt der Einzeiler erneut auf jedem Host – die Zuordnung bleibt
erhalten, weil sie an der Maschinenkennung hängt, nicht an der Adresse.
## Merkposten
1. **Adresse zuerst festlegen, dann Passkeys anlegen.** Ein Passkey gilt nur für die Domäne, unter der
er registriert wurde.
2. **`APP_URL` und die Dashboard-Adresse müssen auf die öffentliche Adresse zeigen** – daraus entstehen
Weiterleitungen, OIDC-Rückkehradresse und der Agent-Einzeiler.
3. **`client_max_body_size` nicht vergessen**, sonst scheitert das Hochladen von Rechnungs-PDFs mit
einem nichtssagenden 413.
+40
View File
@@ -0,0 +1,40 @@
# Sicherung und Wiederherstellung
## Was gesichert werden muss
| Sache | Wo | Ohne sie |
|---|---|---|
| Datenbank | PostgreSQL | alles weg: Hosts, Kunden, Laufzeiten, Rechnungen |
| `APP_SECRET` | `.env` | alle Sitzungen ungültig, SMTP- und Webhook-Zugangsdaten unlesbar |
| Hochgeladene PDFs | `/data/uploads` (Docker-Volume) bzw. `/opt/proxledger/data/uploads` | Rechnungsanhänge fehlen |
Die Agents brauchen **keine** Sicherung: Sie registrieren sich neu, und die Zuordnung hängt an der
Maschinenkennung, nicht an einem Token.
## Sichern
```bash
bash deploy/backup.sh # Datenbank und Uploads
```
Beim LXC-Weg reicht zusätzlich die gewohnte Proxmox-Sicherung des Containers.
## Zurückspielen
```bash
# Docker
docker compose down
docker compose up -d postgres
gunzip -c sicherung.sql.gz | docker compose exec -T postgres psql -U proxledger proxledger
docker compose up -d
```
Danach die `.env` mit **demselben** `APP_SECRET` zurücklegen wie zum Zeitpunkt der Sicherung. Ein
anderer Wert lässt die gespeicherten Zugangsdaten unlesbar werden; das Dashboard sagt das beim
nächsten Versand deutlich, aber die Werte müssen dann neu eingetragen werden.
## Das Wichtigste
**Eine Sicherung, die nie zurückgespielt wurde, ist keine Sicherung.** Spielen Sie sie einmal in eine
leere Testumgebung ein und melden Sie sich dort an. Erst dann wissen Sie, dass Sicherung und
`APP_SECRET` zusammenpassen.
+30
View File
@@ -0,0 +1,30 @@
# #029 Einrichtungsdokumentation
**Status:** erledigt
**Meilenstein:** v0.19.0
**Labels:** doku
**Geschätzt:** 3 h **Tatsächlich:** 0 h 40 min
## Ziel
Anleitungen für alles, was rund um ProxLedger eingerichtet wird: HTTPS, OIDC mit authentik, Sicherung –
und die richtige Reihenfolge, in der das geschehen muss.
## Aufgaben
- [x] `docs/betrieb/inbetriebnahme.md` – von null zum meldenden Host
- [x] `docs/betrieb/reverse-proxy.md` – nginx Proxy Manager und netbird
- [x] `docs/betrieb/authentik.md` – OIDC Schritt für Schritt, mit Fehlerbildern
- [x] `docs/betrieb/sicherung.md` – sichern und **zurückspielen**
- [x] Verweise aus README und Handbuch
## Beim Schreiben gefunden
Zwei Stellen taugten für einen Betrieb hinter einem Reverse Proxy nicht:
1. Die **OIDC-Rückkehradresse** kam allein aus `APP_URL` und übersah die Dashboard-Adresse aus den
Einstellungen. Wer nur letztere gesetzt hatte, bekam vom Anbieter einen *Redirect URI Error*.
2. Beim **Einlösen des Codes** wurde die Adresse der eingehenden Anfrage verwendet – hinter einem
Proxy also die interne. Der Anbieter hat aber die öffentliche hinterlegt; der Tausch wäre
gescheitert. Jetzt wird dieselbe öffentliche Adresse gebildet wie für die Weiterleitungen.
## Entscheidung
Die Reihenfolge steht bewusst am Anfang der Inbetriebnahme: **Adresse festlegen, dann Passkeys und
Agents.** Ein Passkey gilt nur für die Domäne, unter der er entstanden ist, und die Adresse steckt im
Installations-Einzeiler. Wer das übergeht, macht beides zweimal.
+2 -1
View File
@@ -32,4 +32,5 @@ Details und Architektur: [../architektur.md](../architektur.md). Zeiten werden a
| [#026](026-auslieferung.md) | Auslieferung finalisieren | erledigt | v0.17.0 | 3 h | 0 h 40 min |
| [#027](027-rollen-benutzerverwaltung.md) | Rollen und Benutzerverwaltung | erledigt | v0.18.0 | 6 h | 1 h 20 min |
| [#028](028-passkeys.md) | Anmeldung mit Passkeys | erledigt | v0.18.0 | 4 h | 0 h 45 min |
| | **Summe** | | | **143 h** | **14 h 23 min** |
| [#029](029-betriebsdokumentation.md) | Einrichtungsdokumentation | erledigt | v0.19.0 | 3 h | 0 h 40 min |
| | **Summe** | | | **146 h** | **15 h 03 min** |
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "proxledger",
"version": "0.18.0",
"version": "0.19.0",
"private": true,
"scripts": {
"dev": "next dev",
+6 -1
View File
@@ -26,7 +26,12 @@ export async function GET(request: Request) {
}
try {
const angaben = await anmeldungAbschliessen(einstellungen, new URL(request.url), pruefwert, zustand);
// Hinter einem Reverse Proxy ist `request.url` die interne Adresse. Der Anbieter hat aber die
// öffentliche als Rückkehradresse hinterlegt – mit der internen scheitert der Tausch des Codes.
const angekommen = new URL(request.url);
const oeffentlich = eigeneAdresse(request, `${angekommen.pathname}${angekommen.search}`, dashboardUrl);
const angaben = await anmeldungAbschliessen(einstellungen, oeffentlich, pruefwert, zustand);
const benutzer = await mitOidcAnmelden(angaben.subject, angaben.email, angaben.name);
const { sitzungsdauerStunden } = await systemEinstellungen();
+9 -3
View File
@@ -1,4 +1,5 @@
import * as client from "openid-client";
import { einstellungen as systemEinstellungen } from "@/server/einstellungen";
/**
* Anmeldung über OIDC (getestet mit authentik). Die Einrichtung erfolgt über Umgebungsvariablen,
@@ -28,8 +29,13 @@ export function oidcEinstellungen(): OidcEinstellungen | null {
};
}
export function rueckkehrAdresse(): string {
const basis = (process.env.APP_URL ?? "http://localhost:3000").replace(/\/$/, "");
/**
* Adresse, an die der Anbieter zurückschickt. Sie muss beim Anbieter **wortgleich** hinterlegt sein.
* Vorrang hat die eingetragene Dashboard-Adresse, dann `APP_URL` (#029).
*/
export async function rueckkehrAdresse(): Promise<string> {
const { dashboardUrl } = await systemEinstellungen();
const basis = (dashboardUrl || process.env.APP_URL || "http://localhost:3000").replace(/\/$/, "");
return `${basis}/api/auth/oidc/callback`;
}
@@ -55,7 +61,7 @@ export async function anmeldungStarten(einstellungen: OidcEinstellungen): Promis
const zustand = client.randomState();
const url = client.buildAuthorizationUrl(konfig, {
redirect_uri: rueckkehrAdresse(),
redirect_uri: await rueckkehrAdresse(),
scope: "openid email profile",
code_challenge: herausforderung,
code_challenge_method: "S256",