umbau 1.0
This commit is contained in:
@ -96,12 +96,33 @@ def _plain_key_pem() -> str:
|
||||
).decode()
|
||||
|
||||
|
||||
# Teil D Schritt 4 (Achse B): connect_to_host()/load_private_key_for_host()
|
||||
# loesen Zugangsdaten seither benutzerabhaengig auf -- _make_db() seedet
|
||||
# daher immer einen Benutzer (TEST_USER_ID) samt Gruppe, und bei with_key=True
|
||||
# zusaetzlich eine group_ssh_key_grants-Freigabe dieser Gruppe fuer den
|
||||
# angelegten Schluessel (ohne die wuerde resolve_credential_for_user_on_host()
|
||||
# keinen Treffer finden, siehe app/rbac.py).
|
||||
TEST_USER_ID = 1
|
||||
TEST_USER_GROUP_ID = 1
|
||||
|
||||
|
||||
def _make_db(tmp_path, *, host_username=None, key_username="l4u", fingerprint=FINGERPRINT,
|
||||
host_key=PUBLIC_KEY, with_key=True) -> str:
|
||||
path = str(tmp_path / "jumphost.sqlite3")
|
||||
db = sqlite3.connect(path)
|
||||
_apply_migrations(db)
|
||||
db.execute("INSERT INTO host_groups (id, name, tenant_id) VALUES (1, 'gruppe', 1)")
|
||||
db.execute(
|
||||
"INSERT INTO users (id, username, password_hash) VALUES (?, 'p12-user', 'x')",
|
||||
(TEST_USER_ID,),
|
||||
)
|
||||
db.execute(
|
||||
"INSERT INTO user_groups (id, name) VALUES (?, 'p12-team')", (TEST_USER_GROUP_ID,),
|
||||
)
|
||||
db.execute(
|
||||
"INSERT INTO user_group_members (user_group_id, user_id) VALUES (?, ?)",
|
||||
(TEST_USER_GROUP_ID, TEST_USER_ID),
|
||||
)
|
||||
db.execute("INSERT INTO host_groups (id, name) VALUES (1, 'gruppe')")
|
||||
db.execute(
|
||||
"INSERT INTO hosts (id, host_group_id, hostname, address, protocol, port, os_type, "
|
||||
"ssh_host_key_fingerprint, ssh_host_key, ssh_username) "
|
||||
@ -110,11 +131,15 @@ def _make_db(tmp_path, *, host_username=None, key_username="l4u", fingerprint=FI
|
||||
)
|
||||
if with_key:
|
||||
db.execute(
|
||||
"INSERT INTO ssh_keys (id, label, private_key_enc, public_key, key_type, tenant_id, username) "
|
||||
"VALUES (1, 'testkey', ?, 'ssh-ed25519 AAAA', 'ed25519', 1, ?)",
|
||||
"INSERT INTO ssh_keys (id, label, private_key_enc, public_key, key_type, username) "
|
||||
"VALUES (1, 'testkey', ?, 'ssh-ed25519 AAAA', 'ed25519', ?)",
|
||||
(encrypt_secret(_plain_key_pem().encode(), associated_data=b"ssh_private_key"), key_username),
|
||||
)
|
||||
db.execute("INSERT INTO host_ssh_key_map (host_id, ssh_key_id) VALUES (1, 1)")
|
||||
db.execute(
|
||||
"INSERT INTO group_ssh_key_grants (user_group_id, ssh_key_id) VALUES (?, 1)",
|
||||
(TEST_USER_GROUP_ID,),
|
||||
)
|
||||
db.commit()
|
||||
db.close()
|
||||
return path
|
||||
@ -206,7 +231,7 @@ async def test_verbindung_ohne_hinterlegten_hostkey_wird_abgelehnt(tmp_path, mon
|
||||
monkeypatch.setattr(asyncssh, "connect", _fake_connect)
|
||||
conn = FakeConnection(_make_db(tmp_path, fingerprint=None, host_key=None))
|
||||
with pytest.raises(HostKeyNotPinnedError):
|
||||
await connect_to_host(conn, 1)
|
||||
await connect_to_host(conn, 1, user_id=TEST_USER_ID)
|
||||
|
||||
|
||||
async def test_abweichender_hostkey_bricht_vor_der_anmeldung_ab(tmp_path, monkeypatch):
|
||||
@ -227,7 +252,7 @@ async def test_abweichender_hostkey_bricht_vor_der_anmeldung_ab(tmp_path, monkey
|
||||
|
||||
conn = FakeConnection(_make_db(tmp_path))
|
||||
with pytest.raises(HostKeyMismatchError) as excinfo:
|
||||
await connect_to_host(conn, 1)
|
||||
await connect_to_host(conn, 1, user_id=TEST_USER_ID)
|
||||
assert excinfo.value.expected == FINGERPRINT
|
||||
assert versuche == []
|
||||
|
||||
@ -249,7 +274,7 @@ async def test_verbindung_nutzt_benutzernamen_der_zugangsdaten(tmp_path, monkeyp
|
||||
monkeypatch.setattr(asyncssh, "get_server_host_key", _fake_get_host_key, raising=False)
|
||||
|
||||
conn = FakeConnection(_make_db(tmp_path, host_username="alterWertAmHost", key_username="l4u"))
|
||||
await connect_to_host(conn, 1)
|
||||
await connect_to_host(conn, 1, user_id=TEST_USER_ID)
|
||||
# Der Name aus den Zugangsdaten gewinnt gegen den Altwert am Host.
|
||||
assert aufrufe["username"] == "l4u"
|
||||
|
||||
@ -270,7 +295,7 @@ async def test_hostkey_wechsel_nach_der_pruefung_beendet_die_sitzung(tmp_path, m
|
||||
|
||||
conn = FakeConnection(_make_db(tmp_path))
|
||||
with pytest.raises(HostKeyMismatchError):
|
||||
await connect_to_host(conn, 1)
|
||||
await connect_to_host(conn, 1, user_id=TEST_USER_ID)
|
||||
assert verbindung.aborted is True
|
||||
|
||||
|
||||
@ -290,7 +315,7 @@ async def test_altbestand_ohne_gespeicherten_hostkey_wird_nachgetragen(tmp_path,
|
||||
monkeypatch.setattr(asyncssh, "get_server_host_key", _fake_get_host_key, raising=False)
|
||||
|
||||
conn = FakeConnection(_make_db(tmp_path, host_key=None))
|
||||
await connect_to_host(conn, 1)
|
||||
await connect_to_host(conn, 1, user_id=TEST_USER_ID)
|
||||
(stored,) = conn.raw.execute("SELECT ssh_host_key FROM hosts WHERE id = 1").fetchone()
|
||||
assert stored == PUBLIC_KEY
|
||||
|
||||
@ -323,9 +348,13 @@ def _rdp_host(**overrides):
|
||||
|
||||
|
||||
def test_rdp_params_nehmen_benutzernamen_der_zugangsdaten():
|
||||
# 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(
|
||||
_rdp_host(rdp_username="alt", rdp_domain="ALTEDOMAENE"),
|
||||
"geheim", username="Administrator", domain="CONTOSO",
|
||||
"geheim", username="Administrator", domain="CONTOSO", session_id=1,
|
||||
)
|
||||
assert params["username"] == "Administrator"
|
||||
assert params["domain"] == "CONTOSO"
|
||||
@ -333,20 +362,22 @@ def test_rdp_params_nehmen_benutzernamen_der_zugangsdaten():
|
||||
|
||||
|
||||
def test_rdp_params_fallback_auf_altwert_am_host():
|
||||
params = build_rdp_params(_rdp_host(rdp_username="alt", rdp_domain="D"), "geheim")
|
||||
params = build_rdp_params(
|
||||
_rdp_host(rdp_username="alt", rdp_domain="D"), "geheim", session_id=1,
|
||||
)
|
||||
assert (params["username"], params["domain"]) == ("alt", "D")
|
||||
|
||||
|
||||
def test_rdp_params_ohne_benutzernamen_meldet_zugangsdaten():
|
||||
with pytest.raises(GuacamoleProtocolError) as excinfo:
|
||||
build_rdp_params(_rdp_host(), "geheim")
|
||||
build_rdp_params(_rdp_host(), "geheim", session_id=1)
|
||||
assert "Zugangsdaten" in str(excinfo.value)
|
||||
|
||||
|
||||
def test_rdp_params_brauchen_die_hostspalte_nicht_mehr():
|
||||
"""Ein Hostdatensatz ohne rdp_username ist kein Fehler mehr -- der Name
|
||||
kommt jetzt von woanders."""
|
||||
params = build_rdp_params(_rdp_host(), "geheim", username="svc")
|
||||
params = build_rdp_params(_rdp_host(), "geheim", username="svc", session_id=1)
|
||||
assert params["username"] == "svc"
|
||||
|
||||
|
||||
@ -362,7 +393,7 @@ def _pre_0010_db(tmp_path) -> sqlite3.Connection:
|
||||
|
||||
def test_migration_uebernimmt_eindeutige_ssh_benutzernamen(tmp_path):
|
||||
db = _pre_0010_db(tmp_path)
|
||||
db.execute("INSERT INTO host_groups (id, name, tenant_id) VALUES (1, 'g', 1)")
|
||||
db.execute("INSERT INTO host_groups (id, name) VALUES (1, 'g')")
|
||||
for host_id in (1, 2):
|
||||
db.execute(
|
||||
"INSERT INTO hosts (id, host_group_id, hostname, address, protocol, port, os_type, ssh_username) "
|
||||
@ -370,8 +401,8 @@ def test_migration_uebernimmt_eindeutige_ssh_benutzernamen(tmp_path):
|
||||
(host_id,),
|
||||
)
|
||||
db.execute(
|
||||
"INSERT INTO ssh_keys (id, label, private_key_enc, public_key, key_type, tenant_id) "
|
||||
"VALUES (1, 'k', X'00', 'pub', 'ed25519', 1)"
|
||||
"INSERT INTO ssh_keys (id, label, private_key_enc, public_key, key_type) "
|
||||
"VALUES (1, 'k', X'00', 'pub', 'ed25519')"
|
||||
)
|
||||
db.execute("INSERT INTO host_ssh_key_map (host_id, ssh_key_id) VALUES (1, 1), (2, 1)")
|
||||
db.commit()
|
||||
@ -386,7 +417,7 @@ def test_migration_raet_nicht_bei_mehrdeutigen_benutzernamen(tmp_path):
|
||||
jede automatische Wahl geraten -- also bleibt das Feld leer und der
|
||||
Fallback greift weiter."""
|
||||
db = _pre_0010_db(tmp_path)
|
||||
db.execute("INSERT INTO host_groups (id, name, tenant_id) VALUES (1, 'g', 1)")
|
||||
db.execute("INSERT INTO host_groups (id, name) VALUES (1, 'g')")
|
||||
for host_id, name in ((1, "root"), (2, "l4u")):
|
||||
db.execute(
|
||||
"INSERT INTO hosts (id, host_group_id, hostname, address, protocol, port, os_type, ssh_username) "
|
||||
@ -394,8 +425,8 @@ def test_migration_raet_nicht_bei_mehrdeutigen_benutzernamen(tmp_path):
|
||||
(host_id, name),
|
||||
)
|
||||
db.execute(
|
||||
"INSERT INTO ssh_keys (id, label, private_key_enc, public_key, key_type, tenant_id) "
|
||||
"VALUES (1, 'k', X'00', 'pub', 'ed25519', 1)"
|
||||
"INSERT INTO ssh_keys (id, label, private_key_enc, public_key, key_type) "
|
||||
"VALUES (1, 'k', X'00', 'pub', 'ed25519')"
|
||||
)
|
||||
db.execute("INSERT INTO host_ssh_key_map (host_id, ssh_key_id) VALUES (1, 1), (2, 1)")
|
||||
db.commit()
|
||||
@ -407,7 +438,7 @@ def test_migration_raet_nicht_bei_mehrdeutigen_benutzernamen(tmp_path):
|
||||
|
||||
def test_migration_uebernimmt_rdp_benutzer_und_domaene(tmp_path):
|
||||
db = _pre_0010_db(tmp_path)
|
||||
db.execute("INSERT INTO host_groups (id, name, tenant_id) VALUES (1, 'g', 1)")
|
||||
db.execute("INSERT INTO host_groups (id, name) VALUES (1, 'g')")
|
||||
db.execute(
|
||||
"INSERT INTO hosts (id, host_group_id, hostname, address, protocol, port, os_type, "
|
||||
"rdp_username, rdp_domain) "
|
||||
|
||||
Reference in New Issue
Block a user