connect fix 3

This commit is contained in:
2026-08-20 23:35:42 +02:00
parent fc32b1e4ef
commit bf2a02679d
14 changed files with 956 additions and 49 deletions

View File

@ -23,7 +23,12 @@ from app.rbac import user_has_role_for_host
from app.recordings.recorder import SessionRecorder
from app.security import active_sessions
from app.security.audit import write_audit_event
from app.ssh_proxy.proxy import HostNotConfiguredError, connect_to_host, load_host
from app.ssh_proxy.proxy import (
HostNotConfiguredError,
PrivateKeyUnusableError,
connect_to_host,
load_host,
)
logger = logging.getLogger("jumphost.ssh_proxy.ws")
router = APIRouter()
@ -50,6 +55,10 @@ async def _pump_ssh_to_ws(process: asyncssh.SSHClientProcess, websocket: WebSock
async def ssh_terminal(websocket: WebSocket, host_id: int):
user = await get_current_user_ws(websocket)
if user is None:
# Auch die Ablehnungen VOR dem Sitzungsbeginn gehoeren protokolliert:
# bisher schloss dieser Pfad das Socket kommentarlos, im
# Verbindungslog war der Fehlversuch dadurch unsichtbar.
logger.warning("SSH-Verbindung abgelehnt: keine gueltige Sitzung (host_id=%s)", host_id)
await websocket.close(code=4401)
return
@ -57,6 +66,10 @@ async def ssh_terminal(websocket: WebSocket, host_id: int):
if not user.is_admin and not await user_has_role_for_host(
conn, user_id=user.id, host_id=host_id, role_name="ssh_connect"
):
logger.warning(
"SSH-Verbindung abgelehnt: Benutzer %s hat keine Berechtigung 'ssh_connect' fuer Host %s",
user.username, host_id,
)
await websocket.close(code=4403)
return
@ -66,6 +79,7 @@ async def ssh_terminal(websocket: WebSocket, host_id: int):
try:
host = await load_host(conn, host_id)
except HostNotConfiguredError as exc:
logger.warning("SSH-Verbindung abgelehnt (host_id=%s): %s", host_id, exc)
await websocket.send_json({"type": "error", "message": str(exc)})
await websocket.close(code=4404)
return
@ -125,8 +139,27 @@ async def ssh_terminal(websocket: WebSocket, host_id: int):
# Best-Effort-Fehlermeldung an einen ggf. bereits getrennten Client;
# der eigentliche Fehler ist bereits oben geloggt (logger.warning).
logger.debug("Fehlermeldung konnte nicht mehr an Client gesendet werden", exc_info=True)
except HostNotConfiguredError:
except PrivateKeyUnusableError as exc:
# Der haeufigste Grund, warum eine SSH-Sitzung nie zustande kam: der
# hinterlegte Private Key ist passphrasegeschuetzt und die Passphrase
# fehlt oder passt nicht. asyncssh wirft dafuer einen KeyImportError
# (ein ValueError, KEIN asyncssh.Error), der frueher an allen
# Handlern vorbei bis aus der Route hinauslief -- der Browser sah nur
# ein wortloses Verbindungsende. Der Text ist bewusst konkret und
# nennt die Stelle im Adminbereich, an der es zu beheben ist.
logger.warning("SSH-Sitzung %s: Schluessel unbrauchbar: %s", session_id, exc)
end_reason = "error"
try:
await websocket.send_json({"type": "error", "message": str(exc)})
except Exception:
logger.debug("Fehlermeldung konnte nicht mehr an Client gesendet werden", exc_info=True)
except HostNotConfiguredError as exc:
logger.warning("SSH-Sitzung %s abgebrochen: %s", session_id, exc)
end_reason = "error"
try:
await websocket.send_json({"type": "error", "message": str(exc)})
except Exception:
logger.debug("Fehlermeldung konnte nicht mehr an Client gesendet werden", exc_info=True)
except asyncio.CancelledError:
# Zwangs-Beendigung durch einen Superadmin ueber die Sessionview
# (POST /admin/sessions/{id}/terminate, siehe app/security/active_sessions.py).