connect fix 4
This commit is contained in:
@ -811,13 +811,13 @@ async def get_host_detail(
|
||||
if row is None:
|
||||
raise HTTPException(status.HTTP_404_NOT_FOUND, "Host nicht gefunden")
|
||||
keys_cursor = await conn.execute(
|
||||
"SELECT sk.id, sk.label FROM host_ssh_key_map m JOIN ssh_keys sk ON sk.id = m.ssh_key_id "
|
||||
"WHERE m.host_id = ?",
|
||||
"SELECT sk.id, sk.label, sk.username FROM host_ssh_key_map m "
|
||||
"JOIN ssh_keys sk ON sk.id = m.ssh_key_id WHERE m.host_id = ?",
|
||||
(host_id,),
|
||||
)
|
||||
ssh_keys = [{"id": k[0], "label": k[1]} for k in await keys_cursor.fetchall()]
|
||||
ssh_keys = [{"id": k[0], "label": k[1], "username": k[2]} for k in await keys_cursor.fetchall()]
|
||||
rdp_row = await (await conn.execute(
|
||||
"SELECT updated_at FROM rdp_credentials WHERE host_id = ?", (host_id,)
|
||||
"SELECT updated_at, username, domain FROM rdp_credentials WHERE host_id = ?", (host_id,)
|
||||
)).fetchone()
|
||||
return {
|
||||
"id": row[0], "hostname": row[1], "address": row[2], "protocol": row[3], "port": row[4],
|
||||
@ -829,6 +829,10 @@ async def get_host_detail(
|
||||
"ssh_keys": ssh_keys,
|
||||
"rdp_credentials_set": rdp_row is not None,
|
||||
"rdp_credentials_updated_at": rdp_row[0] if rdp_row else None,
|
||||
# Benutzername/Domaene gehoeren seit Migration 0010 zu den
|
||||
# Zugangsdaten; sie werden hier nur zur Anzeige mitgeliefert.
|
||||
"rdp_credentials_username": rdp_row[1] if rdp_row else None,
|
||||
"rdp_credentials_domain": rdp_row[2] if rdp_row else None,
|
||||
}
|
||||
|
||||
|
||||
@ -955,17 +959,28 @@ async def set_rdp_credentials(
|
||||
conn = get_db()
|
||||
if admin.is_any_admin:
|
||||
await _assert_host_in_scope(conn, _scope(admin), host_id)
|
||||
username = (payload.username or "").strip() or None
|
||||
if username is None:
|
||||
raise HTTPException(
|
||||
status.HTTP_400_BAD_REQUEST,
|
||||
"Bitte den Windows-Benutzernamen mit angeben -- er gehoert zu den "
|
||||
"Zugangsdaten und wird fuer die Anmeldung am Ziel gebraucht.",
|
||||
)
|
||||
domain = (payload.domain or "").strip() or None
|
||||
encrypted = encrypt_secret(payload.password.encode(), associated_data=b"rdp_password")
|
||||
await conn.execute(
|
||||
"INSERT INTO rdp_credentials (host_id, password_enc, updated_at) "
|
||||
"VALUES (?, ?, strftime('%Y-%m-%dT%H:%M:%fZ','now')) "
|
||||
"INSERT INTO rdp_credentials (host_id, password_enc, username, domain, updated_at) "
|
||||
"VALUES (?, ?, ?, ?, strftime('%Y-%m-%dT%H:%M:%fZ','now')) "
|
||||
"ON CONFLICT(host_id) DO UPDATE SET password_enc = excluded.password_enc, "
|
||||
"username = excluded.username, domain = excluded.domain, "
|
||||
"updated_at = excluded.updated_at",
|
||||
(host_id, encrypted),
|
||||
(host_id, encrypted, username, domain),
|
||||
)
|
||||
await write_audit_event(
|
||||
conn, event_type="rdp_credentials_set", user_id=admin.id, client_ip=_client_ip(request),
|
||||
details={"host_id": host_id},
|
||||
# Benutzername/Domaene sind keine Geheimnisse (das Passwort schon) und
|
||||
# gehoeren ins Audit-Log.
|
||||
details={"host_id": host_id, "username": username, "domain": domain},
|
||||
)
|
||||
await conn.commit()
|
||||
return {"status": "ok"}
|
||||
@ -1011,18 +1026,20 @@ async def get_host_credentials(
|
||||
if host_row is None:
|
||||
raise HTTPException(status.HTTP_404_NOT_FOUND, "Host nicht gefunden")
|
||||
keys_cursor = await conn.execute(
|
||||
"SELECT sk.id, sk.label FROM host_ssh_key_map m JOIN ssh_keys sk ON sk.id = m.ssh_key_id "
|
||||
"WHERE m.host_id = ?",
|
||||
"SELECT sk.id, sk.label, sk.username FROM host_ssh_key_map m "
|
||||
"JOIN ssh_keys sk ON sk.id = m.ssh_key_id WHERE m.host_id = ?",
|
||||
(host_id,),
|
||||
)
|
||||
ssh_keys = [{"id": k[0], "label": k[1]} for k in await keys_cursor.fetchall()]
|
||||
ssh_keys = [{"id": k[0], "label": k[1], "username": k[2]} for k in await keys_cursor.fetchall()]
|
||||
rdp_row = await (await conn.execute(
|
||||
"SELECT updated_at FROM rdp_credentials WHERE host_id = ?", (host_id,)
|
||||
"SELECT updated_at, username, domain FROM rdp_credentials WHERE host_id = ?", (host_id,)
|
||||
)).fetchone()
|
||||
return {
|
||||
"host_id": host_id, "ssh_keys": ssh_keys,
|
||||
"rdp_credentials_set": rdp_row is not None,
|
||||
"rdp_credentials_updated_at": rdp_row[0] if rdp_row else None,
|
||||
"rdp_credentials_username": rdp_row[1] if rdp_row else None,
|
||||
"rdp_credentials_domain": rdp_row[2] if rdp_row else None,
|
||||
}
|
||||
|
||||
|
||||
@ -1034,7 +1051,7 @@ async def list_rdp_credentials(admin: CurrentUser = Depends(require_admin_or_sco
|
||||
scope = _scope(admin)
|
||||
tenant_filter, params = scope.sql_filter("hg.tenant_id")
|
||||
cursor = await conn.execute(
|
||||
"SELECT h.id, h.hostname, h.address, hg.name, rc.updated_at "
|
||||
"SELECT h.id, h.hostname, h.address, hg.name, rc.updated_at, rc.username, rc.domain "
|
||||
"FROM hosts h JOIN host_groups hg ON hg.id = h.host_group_id "
|
||||
"LEFT JOIN rdp_credentials rc ON rc.host_id = h.id "
|
||||
f"WHERE h.protocol = 'rdp'{tenant_filter} ORDER BY h.hostname",
|
||||
@ -1045,6 +1062,7 @@ async def list_rdp_credentials(admin: CurrentUser = Depends(require_admin_or_sco
|
||||
{
|
||||
"host_id": r[0], "hostname": r[1], "address": r[2], "host_group_name": r[3],
|
||||
"credentials_set": r[4] is not None, "updated_at": r[4],
|
||||
"username": r[5], "domain": r[6],
|
||||
}
|
||||
for r in rows
|
||||
]
|
||||
@ -1274,9 +1292,9 @@ async def create_ssh_key(
|
||||
)
|
||||
cursor = await conn.execute(
|
||||
"INSERT INTO ssh_keys (label, owner_user_id, private_key_enc, public_key, key_type, "
|
||||
"tenant_id, passphrase_enc) VALUES (?, ?, ?, ?, ?, ?, ?)",
|
||||
"tenant_id, passphrase_enc, username) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
(payload.label, payload.owner_user_id, encrypted, payload.public_key, payload.key_type,
|
||||
tenant_id, passphrase_enc),
|
||||
tenant_id, passphrase_enc, (payload.username or "").strip() or None),
|
||||
)
|
||||
new_id = cursor.lastrowid
|
||||
await write_audit_event(
|
||||
@ -1284,6 +1302,9 @@ async def create_ssh_key(
|
||||
details={
|
||||
"id": new_id, "label": payload.label, "key_type": payload.key_type,
|
||||
"has_passphrase": bool(payload.passphrase),
|
||||
# Der Anmeldename ist kein Geheimnis und im Audit-Log ausdruecklich
|
||||
# erwuenscht: er beantwortet "wer hat sich womit angemeldet".
|
||||
"username": (payload.username or "").strip() or None,
|
||||
},
|
||||
)
|
||||
await conn.commit()
|
||||
@ -1297,7 +1318,7 @@ async def list_ssh_keys(admin: CurrentUser = Depends(require_admin_or_scope("ssh
|
||||
tenant_filter, params = scope.sql_filter("sk.tenant_id")
|
||||
cursor = await conn.execute(
|
||||
"SELECT sk.id, sk.label, sk.owner_user_id, sk.key_type, sk.created_at, sk.rotated_at, "
|
||||
"sk.expires_at, sk.tenant_id, t.name, (sk.passphrase_enc IS NOT NULL) "
|
||||
"sk.expires_at, sk.tenant_id, t.name, (sk.passphrase_enc IS NOT NULL), sk.username "
|
||||
"FROM ssh_keys sk JOIN tenants t ON t.id = sk.tenant_id "
|
||||
f"WHERE 1=1{tenant_filter} ORDER BY sk.id",
|
||||
params,
|
||||
@ -1311,6 +1332,9 @@ async def list_ssh_keys(admin: CurrentUser = Depends(require_admin_or_scope("ssh
|
||||
# Nur die Tatsache, NIE die Passphrase selbst -- kein Endpunkt
|
||||
# dieser Anwendung gibt jemals Klartext-Geheimnisse zurueck.
|
||||
"has_passphrase": bool(r[9]),
|
||||
# Anmeldename des Zielsystems (Migration 0010). Kein Geheimnis --
|
||||
# er wird angezeigt, damit erkennbar ist, welcher Zugang das ist.
|
||||
"username": r[10],
|
||||
}
|
||||
for r in rows
|
||||
]
|
||||
@ -1371,6 +1395,10 @@ async def update_ssh_key(
|
||||
fields.append("label = ?"); values.append(payload.label)
|
||||
if "owner_user_id" in payload.model_fields_set:
|
||||
fields.append("owner_user_id = ?"); values.append(payload.owner_user_id)
|
||||
if "username" in payload.model_fields_set:
|
||||
# Gleiche Semantik wie bei passphrase: Weglassen = unveraendert,
|
||||
# explizites null/"" = entfernen.
|
||||
fields.append("username = ?"); values.append((payload.username or "").strip() or None)
|
||||
if rotating:
|
||||
encrypted = encrypt_secret(payload.private_key_pem.encode(), associated_data=b"ssh_private_key")
|
||||
fields += ["private_key_enc = ?", "public_key = ?", "key_type = ?",
|
||||
@ -1396,6 +1424,7 @@ async def update_ssh_key(
|
||||
"id": key_id, "rotated": rotating,
|
||||
"passphrase_changed": bool(rotating or passphrase_given),
|
||||
"has_passphrase": bool(passphrase),
|
||||
"username_changed": "username" in payload.model_fields_set,
|
||||
},
|
||||
)
|
||||
await conn.commit()
|
||||
|
||||
Reference in New Issue
Block a user