connect fix 3
This commit is contained in:
78
README.md
78
README.md
@ -252,13 +252,89 @@ Mandanten-Admin sein zu muessen (neue Dependency
|
||||
`GET /admin/hosts/{id}/credentials`, Dashboard zeigt einen "Zugangsdaten"-
|
||||
Knopf bei Hosts mit dieser Rolle).
|
||||
|
||||
## Phase 10: SSH-Key-Passphrasen und funktionsfaehige RDP-Sitzungen
|
||||
|
||||
Behebt die Ursachen dafuer, dass weder SSH- noch RDP-Sitzungen zustande kamen.
|
||||
|
||||
**SSH -- passphrasegeschuetzte Schluessel (Migration 0009,
|
||||
`ssh_keys.passphrase_enc`).** `asyncssh.import_private_key()` wurde ohne
|
||||
Passphrase aufgerufen; ein mit `ssh-keygen` ueblich erzeugter, verschluesselter
|
||||
Schluessel liess sich damit prinzipiell nicht laden
|
||||
(`KeyImportError: Passphrase must be specified to import encrypted private
|
||||
keys`). Weil dieser Fehler ein `ValueError` und *kein* `asyncssh.Error` ist,
|
||||
lief er an allen Fehlerbehandlungen der WebSocket-Route vorbei -- der Browser
|
||||
sah nur ein wortloses Verbindungsende. Neu:
|
||||
|
||||
* Beim Anlegen und Rotieren eines Schluessels kann eine Passphrase angegeben
|
||||
werden. Sie wird wie das Schluesselmaterial selbst mit dem KEK
|
||||
(AES-256-GCM) verschluesselt gespeichert und ueber keinen Endpunkt jemals
|
||||
zurueckgegeben -- die Liste zeigt nur `has_passphrase`.
|
||||
* Zu einem **bereits hinterlegten** Schluessel laesst sich die Passphrase
|
||||
nachtragen (Adminbereich -> Zugangsdaten -> SSH-Key bearbeiten). Sie wird
|
||||
dabei sofort gegen das gespeicherte Schluesselmaterial geprueft; passt sie
|
||||
nicht, wird nichts gespeichert.
|
||||
* Jeder Upload wird sofort gegen asyncssh validiert: ein unbrauchbarer
|
||||
Schluessel wird mit HTTP 400 und Klartextbegruendung abgelehnt, statt erst
|
||||
beim ersten Verbindungsversuch eines Benutzers aufzufallen.
|
||||
* Scheitert das Laden trotzdem, meldet die Sitzung jetzt `PrivateKeyUnusableError`
|
||||
mit verstaendlichem Text an Terminal und Dateitransfer statt kommentarlos
|
||||
abzubrechen.
|
||||
|
||||
**RDP -- vier unabhaengige Fehler, die jede Sitzung verhinderten.**
|
||||
|
||||
1. `static/js/rdp.js` haengte die Verbindungsparameter an die Tunnel-URL an --
|
||||
`Guacamole.WebSocketTunnel.connect(data)` haengt aber selbst noch
|
||||
`"?" + data` an. Daraus wurde `...&dpi=96?undefined`; FastAPI wies den
|
||||
WebSocket wegen der ungueltigen Query noch vor dem Routenhandler ab, und
|
||||
im Verbindungslog erschien **kein einziger Eintrag**. Die Parameter werden
|
||||
jetzt an `connect()` uebergeben.
|
||||
2. guacamole-common-js oeffnet den Socket immer mit dem Subprotokoll
|
||||
`guacamole`. Der Server bestaetigte es nicht, woraufhin der Browser die
|
||||
Verbindung nach RFC 6455 sofort wieder verwarf. `websocket.accept()` setzt
|
||||
es jetzt.
|
||||
3. `load_host()` selektierte `rdp_username`, `rdp_domain`, `rdp_require_nla`
|
||||
und `clipboard_enabled` nicht -- `build_rdp_params()` baute daraus eine
|
||||
`connect`-Instruktion **ohne Benutzernamen** (Anmeldung am Ziel scheitert,
|
||||
der Client haengt in "Warte auf Server ..."), und die Zwischenablage war
|
||||
unabhaengig von der Hostkonfiguration immer gesperrt. Fehlt jetzt eine der
|
||||
Angaben, meldet der Server das im Klartext statt still eine kaputte
|
||||
Verbindung aufzubauen.
|
||||
4. `ignore-cert` war hart auf `false` verdrahtet. Windows-Ziele ohne eigene
|
||||
PKI weisen sich mit einem selbstsignierten Zertifikat aus, guacd/FreeRDP
|
||||
bricht dann vor dem ersten Bild ab. Neu: `hosts.rdp_ignore_cert`
|
||||
(Migration 0009, Default: ignorieren) mit Checkbox im Host-Formular.
|
||||
|
||||
Ausserdem im Guacamole-Protokoll behoben: die Laengenangaben zaehlen
|
||||
**Zeichen**, nicht Bytes (so ist das Protokoll definiert, und so zaehlen guacd
|
||||
und guacamole-common-js). Zuvor stand dort die UTF-8-Bytelaenge -- ein
|
||||
einziger Umlaut, etwa in einem RDP-Passwort oder in der Zwischenablage,
|
||||
verschob den gesamten nachfolgenden Datenstrom. Tunnelinterne Instruktionen
|
||||
(leerer Opcode: `ping`, Tunnel-UUID) werden nicht mehr an guacd
|
||||
durchgereicht, ein `ping` wird gespiegelt, und der Server sendet die
|
||||
Tunnel-UUID als erste Instruktion -- sonst blieb der Client bis zum ersten
|
||||
Bild in "Warte auf Server ..." und lief bei einem langsamen RDP-Handshake in
|
||||
den 15-Sekunden-Timeout.
|
||||
|
||||
**Sichtbarkeit.** Saemtliche Abbruchpfade *vor* dem eigentlichen
|
||||
Sitzungsbeginn (fehlende Berechtigung, unbekannter Host, falsches Protokoll,
|
||||
fehlendes RDP-Passwort) schlossen den Socket bisher kommentarlos. Sie
|
||||
protokollieren jetzt und geben den Grund als WebSocket-Close-Reason mit, den
|
||||
`rdp.js` direkt anzeigt.
|
||||
|
||||
### Nach dem Deployment zu tun
|
||||
|
||||
1. Migration 0009 laeuft beim Start automatisch.
|
||||
2. Zu jedem bereits hinterlegten, passphrasegeschuetzten SSH-Key die
|
||||
Passphrase nachtragen (Adminbereich -> Zugangsdaten -> SSH-Key bearbeiten).
|
||||
3. Bei RDP-Hosts pruefen, dass ein RDP-Benutzername gesetzt ist.
|
||||
|
||||
## Tests
|
||||
|
||||
```bash
|
||||
pytest -q
|
||||
```
|
||||
|
||||
68 Tests (vorher 61) decken ab: Argon2id/TOTP-Grundfunktionen, Audit-Hash-Chain
|
||||
78 Tests (vorher 68; `tests/test_phase10.py` kam hinzu) decken ab: Argon2id/TOTP-Grundfunktionen, Audit-Hash-Chain
|
||||
(inkl. Manipulationserkennung und Trigger-Durchsetzung), RBAC-Logik inkl.
|
||||
Ablaufdaten, den vollstaendigen Login-Flow (Passwort -> TOTP-Enrollment ->
|
||||
Session-Cookie -> geschuetzte Endpunkte) gegen die echte FastAPI-App, 17
|
||||
|
||||
Reference in New Issue
Block a user