umbau 1.0

This commit is contained in:
2026-09-02 20:30:44 +02:00
parent afe6719f51
commit 5c95b21be7
77 changed files with 10733 additions and 1914 deletions

View File

@ -186,6 +186,14 @@ async def test_load_private_key_for_host_uses_stored_passphrase(client):
from app.security.crypto import encrypt_secret
conn = get_db()
from app.security.passwords import hash_password
cursor = await conn.execute(
"INSERT INTO users (username, password_hash) VALUES ('p10-user', ?)",
(hash_password("Correct-Horse-Battery-Staple-P10"),),
)
user_id = cursor.lastrowid
cursor = await conn.execute("INSERT INTO host_groups (name) VALUES ('p10-group')")
hg_id = cursor.lastrowid
cursor = await conn.execute(
@ -205,17 +213,31 @@ async def test_load_private_key_for_host_uses_stored_passphrase(client):
await conn.execute(
"INSERT INTO host_ssh_key_map (host_id, ssh_key_id) VALUES (?, ?)", (host_id, key_id)
)
# Teil D Schritt 4 (Achse B): load_private_key_for_host() loest seither
# NICHT mehr blind ueber den Host auf, sondern nur noch fuer einen
# Benutzer, dessen Gruppe den Schluessel ueber group_ssh_key_grants
# freigegeben bekommen hat (siehe Docstring von
# load_ssh_key_credential_for_host in app/ssh_proxy/proxy.py).
cursor = await conn.execute("INSERT INTO user_groups (name) VALUES ('p10-team')")
group_id = cursor.lastrowid
await conn.execute(
"INSERT INTO user_group_members (user_group_id, user_id) VALUES (?, ?)", (group_id, user_id)
)
await conn.execute(
"INSERT INTO group_ssh_key_grants (user_group_id, ssh_key_id) VALUES (?, ?)", (group_id, key_id)
)
await conn.commit()
# Mit hinterlegter Passphrase laedt der Schluessel.
assert await load_private_key_for_host(conn, host_id) is not None
assert await load_private_key_for_host(conn, host_id, user_id=user_id) is not None
# Ohne sie: klare Meldung statt eines nach aussen durchschlagenden
# KeyImportError (das war der gemeldete Abbruch ohne Fehlermeldung).
await conn.execute("UPDATE ssh_keys SET passphrase_enc = NULL WHERE id = ?", (key_id,))
await conn.commit()
with pytest.raises(PrivateKeyUnusableError) as excinfo:
await load_private_key_for_host(conn, host_id)
await load_private_key_for_host(conn, host_id, user_id=user_id)
assert "passphrasegeschuetzt" in str(excinfo.value).lower()
@ -257,25 +279,33 @@ def test_build_rdp_params_passes_username_and_cert_policy():
"rdp_domain": "CORP", "rdp_require_nla": True, "clipboard_enabled": True,
"rdp_ignore_cert": True,
}
params = build_rdp_params(host, "geheim")
# Bug-Fix (FORTSETZUNG_Teil_C.md Abschnitt 3 Punkt 2): build_rdp_params()
# verlangt inzwischen session_id als Pflicht-Keyword-Argument (echte
# Signaturerweiterung, app/rdp_proxy/guacd_client.py) -- fuer diese Tests
# ist der konkrete Wert irrelevant, ein beliebiger int reicht.
params = build_rdp_params(host, "geheim", session_id=1)
assert params["username"] == "Administrator"
assert params["domain"] == "CORP"
assert params["security"] == "nla"
assert params["ignore-cert"] == "true"
assert params["disable-copy"] == "false"
strict = build_rdp_params(dict(host, rdp_ignore_cert=False, clipboard_enabled=False), "geheim")
strict = build_rdp_params(
dict(host, rdp_ignore_cert=False, clipboard_enabled=False), "geheim", session_id=1,
)
assert strict["ignore-cert"] == "false"
assert strict["disable-copy"] == "true" and strict["disable-paste"] == "true"
# Kein Benutzername -> klare Meldung statt stiller Fehlanmeldung am Ziel
with pytest.raises(GuacamoleProtocolError):
build_rdp_params(dict(host, rdp_username=""), "geheim")
build_rdp_params(dict(host, rdp_username=""), "geheim", session_id=1)
# Unvollstaendiger Hostdatensatz (der alte load_host()-Zustand)
with pytest.raises(GuacamoleProtocolError):
build_rdp_params({k: host[k] for k in ("id", "hostname", "address", "port",
"file_transfer_enabled")}, "geheim")
build_rdp_params(
{k: host[k] for k in ("id", "hostname", "address", "port", "file_transfer_enabled")},
"geheim", session_id=1,
)
# ---------------------------------------------------------------------------