Files
mesh-configs/skills/devops/jit-ssh-access-portal/references/safe-e2e-login-testing.md
T

54 lines
2.3 KiB
Markdown

# Sicheres E2E-Testen der Login-/Lockout-Logik (ohne echten User zu zerstören)
Der Bonuspitfall: Tests der Login-/Brute-Force-Logik dürfen den **echten
Benutzeraccount** (`mehlzoerwer`) nicht verändern, sonst ist der echte Login
danach defekt (Skill-Pitfall "E2E-Test mutiert die DB").
## Muster (validiert 2026-08-04)
1. **IP-Lockout-Zweig testen** → mit einem **fremden/leeren Benutzernamen**
laufen lassen. Fremder User trifft nur den In-Memory-`_IP_FAIL`-Zähler,
KEIN DB-Update auf den echten Account:
```bash
for i in $(seq 1 6); do
curl -sk -X POST https://ssh.<domain>.de/ \
-d "username=foo&password=wrong$i"
done
tail portal.log # Versuch 6 → "IP-SPERRE aktiv für <ip>"
```
Prüfen, dass der echte User danach `failed=0, lockout_until=0` ist.
2. **DB-User-Lockout-Zweig testen** → **temporären Test-User** in die DB,
nach dem Test wieder löschen:
```bash
./venv/bin/python -c "
import sqlite3
from werkzeug.security import generate_password_hash
c=sqlite3.connect('portal.db')
c.execute(\"INSERT OR REPLACE INTO users(username,pw_hash,pw_changed,failed,lockout_until)\
VALUES('testuser',?,1,0,0)\", (generate_password_hash('TestPass123!'),))
c.commit(); c.close()"
```
Dann 5x falsches PW für `testuser` → DB zeigt `failed=5, lockout_until=<ts>`,
Log zeigt "USER-SPERRE aktiv".
3. **WICHTIG — In-Memory-IP-Sperre leert nur beim Service-Restart**:
Nach Test 1 ist die Test-IP noch 15 min in `_IP_FAIL` gesperrt. Vor dem
Testen des zweiten Zweigs `systemctl restart sshportal` (leert den
In-Memory-Zähler), sonst kommen die neuen Requests gar nicht bis zur DB.
4. **Aufräumen** (immer, in einer Transaktion committen):
```bash
c.execute('DELETE FROM users WHERE username=?', ('testuser',))
c.execute('UPDATE users SET failed=0, lockout_until=0 WHERE username=?', ('mehlzoerwer',))
c.commit()
```
## Fallstricke
- `sqlite3`-CLI fehlt oft auf dem VPS → über das venv-Python lesen
(`./venv/bin/python -c "..."`), nicht `sqlite3 portal.db`.
- DB-Schema kann Alt-Spalten haben → `dict(row)` schlägt beim Print fehl
("length 11; 2 is required"); explizite Spalten im SELECT wählen.
- Desktop-`dict(rows)`-Print ist nur Reporting, nicht Teil des Deletes — ein
Traceback dort heißt NICHT, dass der Delete fehlgeschlagen ist.