Watch-Auth gegen minerva: api_key in users.toml ist bcrypt-Hash, Server vergleicht Plaintext #1

Closed
opened 2026-05-20 16:42:44 +02:00 by Brummel · 1 comment
Owner

Beobachtung

Watch-Requests gegen http://minerva.lan:3000 werden immer mit 401 Unauthorized abgewiesen, egal welcher Klartext-Wert als X-API-Key-Header gesendet wird.

Ursache

Server-Auth (server/src/auth.rs:46-52) macht einen Plaintext-HashMap-Lookup:

let api_key = parts.headers.get(API_KEY_HEADER) ...;
let slug = config.api_keys.get(api_key).ok_or(AppError::Unauthorized)?;

config.api_keys ist ein HashMap<plaintext_key, slug>, gebaut in server/src/config.rs:238-255 direkt aus dem Klartext-Wert in users.toml. Es findet kein bcrypt::verify statt.

Auf minerva (/opt/stacks/doctate-server/config/users.toml) stehen aber bcrypt-Hashes ($2b$12$…) im api_key-Feld. Damit landet der Hash-String selbst als HashMap-Key. Die Watch sendet im Header den Klartext, der niemals matched.

Der hash-password-Helper (server/src/bin/hash-password.rs:149) patcht ausschliesslich web_password; api_key war nie für bcrypt vorgesehen.

Reproduktion

curl -i -H "X-API-Key: irgendwas" http://minerva.lan:3000/api/oneliners
# → 401 (Klartext matched nicht den bcrypt-String in der HashMap)

Fix

  1. /opt/stacks/doctate-server/config/users.toml editieren: api_key-Felder durch frische Klartext-Werte ersetzen (z.B. openssl rand -base64 24), pro User ein eigener Wert.
  2. Container neu laden.
  3. Verifikation: curl -H "X-API-Key: <klartext>" http://minerva.lan:3000/api/oneliners200.

Folge-Härtung im Server-Code: siehe das idea-Issue zum Sanity-Check.

## Beobachtung Watch-Requests gegen `http://minerva.lan:3000` werden immer mit `401 Unauthorized` abgewiesen, egal welcher Klartext-Wert als `X-API-Key`-Header gesendet wird. ## Ursache Server-Auth (`server/src/auth.rs:46-52`) macht einen Plaintext-`HashMap`-Lookup: ```rust let api_key = parts.headers.get(API_KEY_HEADER) ...; let slug = config.api_keys.get(api_key).ok_or(AppError::Unauthorized)?; ``` `config.api_keys` ist ein `HashMap<plaintext_key, slug>`, gebaut in `server/src/config.rs:238-255` direkt aus dem Klartext-Wert in `users.toml`. Es findet **kein** `bcrypt::verify` statt. Auf minerva (`/opt/stacks/doctate-server/config/users.toml`) stehen aber bcrypt-Hashes (`$2b$12$…`) im `api_key`-Feld. Damit landet der Hash-String selbst als HashMap-Key. Die Watch sendet im Header den Klartext, der niemals matched. Der `hash-password`-Helper (`server/src/bin/hash-password.rs:149`) patcht ausschliesslich `web_password`; `api_key` war nie für bcrypt vorgesehen. ## Reproduktion ```bash curl -i -H "X-API-Key: irgendwas" http://minerva.lan:3000/api/oneliners # → 401 (Klartext matched nicht den bcrypt-String in der HashMap) ``` ## Fix 1. `/opt/stacks/doctate-server/config/users.toml` editieren: `api_key`-Felder durch frische Klartext-Werte ersetzen (z.B. `openssl rand -base64 24`), pro User ein eigener Wert. 2. Container neu laden. 3. Verifikation: `curl -H "X-API-Key: <klartext>" http://minerva.lan:3000/api/oneliners` → `200`. Folge-Härtung im Server-Code: siehe das `idea`-Issue zum Sanity-Check.
Brummel added the BLOCKERbug labels 2026-05-20 16:42:44 +02:00
Author
Owner

Resolved 2026-05-20.

Fix angewendet

/opt/stacks/doctate-server/config/users.toml auf minerva editiert:

  • admin (Brummel): bcrypt-Hash → frischer Klartext-Wert (openssl rand -base64 24)
  • krey (Dr. Krey): bcrypt-Hash → frischer Klartext-Wert (separat generiert)
  • web_password-Felder unangetastet (bcrypt korrekt für Browser-Login)

Backup unter users.toml.pre-issue1.bak. Container via docker compose restart neu gestartet.

Verifikation

curl -H 'X-API-Key: <brummel-key>' http://minerva.lan:3000/api/oneliners → 200
curl -H 'X-API-Key: <krey-key>'    http://minerva.lan:3000/api/oneliners → 200
curl -H 'X-API-Key: bogus'         http://minerva.lan:3000/api/oneliners → 401

Klartext-Werte

Leben jetzt nur in lokal-gitignored Build-Profilen unter clients/wearos/profiles.d/brummel-minerva.sh und krey-minerva.sh (gebaut im Rahmen von #3). Das Server-users.toml-Schema hat dieselbe Klartext-Erwartung — kein Schema-Drift mehr.

Follow-up #4 (Server-Sanity-Check, der bcrypt-aussehende api_keys beim Start rejected) bleibt offen — fängt künftige Konfigurationsfehler dieser Art ab, bevor sie wieder zwei Stunden Debugging kosten.

Resolved 2026-05-20. ## Fix angewendet `/opt/stacks/doctate-server/config/users.toml` auf minerva editiert: - `admin` (Brummel): bcrypt-Hash → frischer Klartext-Wert (`openssl rand -base64 24`) - `krey` (Dr. Krey): bcrypt-Hash → frischer Klartext-Wert (separat generiert) - `web_password`-Felder unangetastet (bcrypt korrekt für Browser-Login) Backup unter `users.toml.pre-issue1.bak`. Container via `docker compose restart` neu gestartet. ## Verifikation ``` curl -H 'X-API-Key: <brummel-key>' http://minerva.lan:3000/api/oneliners → 200 curl -H 'X-API-Key: <krey-key>' http://minerva.lan:3000/api/oneliners → 200 curl -H 'X-API-Key: bogus' http://minerva.lan:3000/api/oneliners → 401 ``` ## Klartext-Werte Leben jetzt nur in lokal-gitignored Build-Profilen unter `clients/wearos/profiles.d/brummel-minerva.sh` und `krey-minerva.sh` (gebaut im Rahmen von #3). Das Server-`users.toml`-Schema hat dieselbe Klartext-Erwartung — kein Schema-Drift mehr. Follow-up #4 (Server-Sanity-Check, der bcrypt-aussehende `api_key`s beim Start rejected) bleibt offen — fängt künftige Konfigurationsfehler dieser Art ab, bevor sie wieder zwei Stunden Debugging kosten.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Brummel/doctate#1