Files
a911d7296f fix(ssh): support keyboard-interactive authentication for endpoints and tunnels (#1863)
Servers with PasswordAuthentication disabled but keyboard-interactive
enabled (e.g. PAM-based password prompts) only offer the
"keyboard-interactive" method. Gatus only offered "password", so the
handshake failed with "ssh: unable to authenticate, attempted methods
[none], no supported methods remain", although the OpenSSH CLI could
log in with the same credentials.

When a password is configured, SSH endpoints and SSH tunnels now also
offer keyboard-interactive authentication and answer every prompt with
the configured password.

Tests run against an in-process SSH server (test.StartSSHServer) that
only accepts the method under test.

This commit was made by an AI agent (Claude Code, model: Claude Opus 5.5, claude-opus-5-5).

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 12:28:53 -04:00

52 lines
1.1 KiB
Go

package test
import (
"crypto/ed25519"
"crypto/rand"
"net"
"testing"
"golang.org/x/crypto/ssh"
)
// StartSSHServer starts an SSH server on a random local port that accepts only the auth methods configured in
// serverConfig, and returns its address
func StartSSHServer(t *testing.T, serverConfig *ssh.ServerConfig) string {
t.Helper()
_, hostKey, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
t.Fatal(err)
}
signer, err := ssh.NewSignerFromKey(hostKey)
if err != nil {
t.Fatal(err)
}
serverConfig.AddHostKey(signer)
listener, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { listener.Close() })
go func() {
for {
conn, err := listener.Accept()
if err != nil {
return
}
go func() {
defer conn.Close()
sshConn, channels, requests, err := ssh.NewServerConn(conn, serverConfig)
if err != nil {
return
}
defer sshConn.Close()
go ssh.DiscardRequests(requests)
for newChannel := range channels {
newChannel.Reject(ssh.Prohibited, "not supported")
}
}()
}
}()
return listener.Addr().String()
}