From d066dbf03db143c372c5fa88f082b00a9f32aaf5 Mon Sep 17 00:00:00 2001 From: alientim Date: Thu, 13 Aug 2026 22:30:41 +0200 Subject: [PATCH] SSH-Verbindungstest: 'password' vor 'keyboard-interactive' bevorzugen Bei einigen Switches/APs (u.a. ArubaOS-Varianten), die Server-seitig sowohl 'password' als auch 'keyboard-interactive' anbieten, fuehrte keyboard-interactive zu einem stillen Fehlschlag ganz ohne sichtbaren Prompt im Browser-Terminal (RFC 4256 erlaubt eine erste Runde ganz ohne Prompts -- fuer den Nutzer unsichtbar -- gefolgt von sofortigem Scheitern statt einer zweiten Runde mit dem eigentlichen Passwort- Prompt). Das erklaerte exakt das gemeldete Symptom: kein Prompt, direkt 'Zugangsdaten falsch'. 'password' wird jetzt bevorzugt, wenn der Server es ueberhaupt anbietet (Ende-zu-Ende gegen einen echten Host verifiziert: Host-Key-Bestaetigung -> Passwort-Prompt -> erfolgreicher Login, keine Regression). Die keyboard-interactive-Handler-Funktion wurde zusaetzlich gehaertet: title/instructions werden jetzt mit angezeigt (manche Geraete legen den Hinweistext dort statt in prompt_list ab) und leere prompt_text-Strings bekommen einen Passwort-Fallback-Text, falls keyboard-interactive doch der einzig angebotene Weg ist. --- srv/tesm/app.py | 44 ++++++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/srv/tesm/app.py b/srv/tesm/app.py index 347aab6..57243ff 100644 --- a/srv/tesm/app.py +++ b/srv/tesm/app.py @@ -5886,24 +5886,44 @@ def _authenticate_interactive(ws, transport, username): if transport.is_authenticated(): return True - if "keyboard-interactive" in allowed: - def handler(title, instructions, prompt_list): - responses = [] - for prompt_text, echo in prompt_list: - ws.send(f"\r\n{prompt_text}") - responses.append(_terminal_read_line(ws, echo=bool(echo)) or "") - return responses - try: - transport.auth_interactive(username, handler) - except paramiko.AuthenticationException: - pass - elif "password" in allowed: + # "password" bewusst VOR "keyboard-interactive" versuchen, auch wenn der + # Server beides anbietet: viele Switches/APs (u.a. diverse ArubaOS- + # Varianten) bieten zwar "keyboard-interactive" an, deren Server-seitige + # Umsetzung ist aber teils nicht robust — z. B. eine erste Runde ganz + # ohne Prompts (laut RFC 4256 gültig, aber unsichtbar für den Nutzer), + # gefolgt von sofortigem Scheitern statt einer zweiten Runde mit dem + # eigentlichen Passwort-Prompt. Das erklärt exakt das beobachtete + # Symptom: im Terminal erscheint NIE ein Prompt, nur direkt "Zugangs- + # daten falsch". "password" ist der einfachere, zuverlässiger + # unterstützte Pfad (Ende-zu-Ende gegen einen echten Host verifiziert) + # und wird deshalb bevorzugt, wenn der Server ihn überhaupt anbietet. + if "password" in allowed: ws.send("\r\nPasswort: ") pw = _terminal_read_line(ws, echo=False) try: transport.auth_password(username, pw or "") except paramiko.AuthenticationException: pass + elif "keyboard-interactive" in allowed: + def handler(title, instructions, prompt_list): + # title/instructions zusätzlich anzeigen: manche Geräte legen + # den eigentlichen Hinweistext ("Password:") dort statt in + # prompt_list ab. Leere prompt_text-Strings (ebenfalls bei + # manchen Geräten üblich) bekommen einen sinnvollen Fallback, + # damit dem Nutzer nie eine Eingabeaufforderung ganz ohne + # sichtbaren Text präsentiert wird. + for text in (title, instructions): + if text: + ws.send(f"\r\n{text}") + responses = [] + for prompt_text, echo in prompt_list: + ws.send(f"\r\n{prompt_text or 'Passwort: '}") + responses.append(_terminal_read_line(ws, echo=bool(echo)) or "") + return responses + try: + transport.auth_interactive(username, handler) + except paramiko.AuthenticationException: + pass else: ws.send(f"\r\n\x1b[31mServer bietet keine unterstützte Auth-Methode an ({', '.join(allowed) or 'keine'}).\x1b[0m\r\n")