connect fix 4

This commit is contained in:
2026-08-21 06:14:10 +02:00
parent bf2a02679d
commit 5e506c9921
17 changed files with 1266 additions and 162 deletions

View File

@ -162,7 +162,13 @@ async def open_tunnel(
return GuacdTunnel(reader, writer, connection_id)
def build_rdp_params(host: dict, password: str) -> dict[str, str]:
def build_rdp_params(
host: dict,
password: str,
*,
username: str | None = None,
domain: str | None = None,
) -> dict[str, str]:
"""Baut die Parameter-Map fuer die connect-Instruktion aus dem Host-Datensatz.
Sicherheitsdefaults (siehe Konzept 6.3/6.7): NLA wird erzwungen sofern
@ -171,17 +177,19 @@ def build_rdp_params(host: dict, password: str) -> dict[str, str]:
ohne interne PKI praesentiert jedes Windows-Ziel ein selbstsigniertes
Zertifikat, guacd/FreeRDP bricht dann bereits vor dem ersten Bild ab.
`username`/`domain` kommen aus rdp_credentials (Migration 0010) -- der
Benutzername gehoert zur Anmeldung, nicht zum Zielsystem. Fehlen sie, wird
auf hosts.rdp_username/rdp_domain zurueckgegriffen (Altbestand).
WICHTIG: `host` muss aus app.ssh_proxy.proxy.load_host() stammen. Diese
Funktion liest rdp_username/rdp_domain/rdp_require_nla/clipboard_enabled/
rdp_ignore_cert -- genau diese Spalten hat load_host() frueher NICHT
selektiert, wodurch hier still ein leerer Benutzername in die
connect-Instruktion ging und die Anmeldung am Zielsystem zwangslaeufig
scheiterte. Fehlt eine der Spalten jetzt trotzdem, ist das ein
Programmierfehler und soll auffallen statt still zu einer kaputten
Verbindung zu fuehren.
Funktion liest rdp_require_nla/clipboard_enabled/rdp_ignore_cert -- genau
diese Spalten hat load_host() frueher NICHT selektiert, wodurch hier still
eine unbrauchbare connect-Instruktion entstand. Fehlt eine der Spalten
jetzt trotzdem, ist das ein Programmierfehler und soll auffallen statt
still zu einer kaputten Verbindung zu fuehren.
"""
missing = [
key for key in ("rdp_username", "rdp_require_nla", "clipboard_enabled", "rdp_ignore_cert")
key for key in ("rdp_require_nla", "clipboard_enabled", "rdp_ignore_cert")
if key not in host
]
if missing:
@ -189,20 +197,25 @@ def build_rdp_params(host: dict, password: str) -> dict[str, str]:
f"Hostdatensatz unvollstaendig, fehlende Felder: {', '.join(missing)}"
)
username = (host.get("rdp_username") or "").strip()
if not username:
# Benutzername/Domaene kommen seit Migration 0010 aus den Zugangsdaten
# (rdp_credentials). Der Wert am Host wird nur noch als Fallback fuer
# Datensaetze gelesen, die vor der Migration angelegt wurden.
effective_username = (username or "").strip() or (host.get("rdp_username") or "").strip()
if not effective_username:
raise GuacamoleProtocolError(
"Fuer diesen Host ist kein RDP-Benutzername hinterlegt "
"(Adminbereich -> Server -> RDP-Benutzer)."
"Fuer diesen Host ist kein RDP-Benutzername hinterlegt. Der Benutzername "
"gehoert zu den Zugangsdaten (Adminbereich -> Zugangsdaten -> "
"RDP/Windows-Passwoerter)."
)
effective_domain = (domain or "").strip() or (host.get("rdp_domain") or "").strip()
clipboard_enabled = bool(host.get("clipboard_enabled"))
return {
"hostname": host["address"],
"port": str(host["port"]),
"username": username,
"username": effective_username,
"password": password,
"domain": host.get("rdp_domain") or "",
"domain": effective_domain,
"security": "nla" if host.get("rdp_require_nla", True) else "any",
"ignore-cert": "true" if host.get("rdp_ignore_cert", True) else "false",
"disable-audio": "true",

View File

@ -174,8 +174,12 @@ async def rdp_tunnel(
)
return
# username/domain stehen seit Migration 0010 bei den Zugangsdaten und nicht
# mehr am Host -- der Benutzername gehoert zur Anmeldung, nicht zur
# Beschreibung des Zielsystems.
cred_cursor = await conn.execute(
"SELECT password_enc FROM rdp_credentials WHERE host_id = ?", (host_id,)
"SELECT password_enc, username, domain FROM rdp_credentials WHERE host_id = ?",
(host_id,),
)
cred_row = await cred_cursor.fetchone()
if cred_row is None:
@ -221,7 +225,9 @@ async def rdp_tunnel(
# riss ein Fehler hier VOR jeglicher Protokollierung durch und die
# Sitzung verschwand spurlos (schwarzer Bildschirm, kein Log-Eintrag).
password = decrypt_secret(cred_row[0], associated_data=b"rdp_password")
params = build_rdp_params(host, password.decode())
params = build_rdp_params(
host, password.decode(), username=cred_row[1], domain=cred_row[2]
)
tunnel = await open_tunnel(
guacd_host=settings.guacd_host, guacd_port=settings.guacd_port,
protocol="rdp", params=params, screen_width=width, screen_height=height, dpi=dpi,