aboutsummaryrefslogtreecommitdiff
path: root/ssh/server_test.go
diff options
context:
space:
mode:
authorNicola Murino <nicola.murino@gmail.com>2024-04-03 11:21:09 +0200
committerGopher Robot <gobot@golang.org>2024-04-04 14:49:27 +0000
commitb92bf9480d25521fc2b8965f86fe152bdfb43f28 (patch)
tree287bfb7662f815c0f393cd0ac05ad3bf93149704 /ssh/server_test.go
parent6f79b5a20cd106b083a02ec17482450d25a1a8f3 (diff)
downloadgo-x-crypto-b92bf9480d25521fc2b8965f86fe152bdfb43f28.tar.xz
ssh: respect MaxAuthTries also for "none" auth attempts
Only the first "none" auth attempt is allowed without penality Change-Id: Ibe776e968ba406445eeb94e8f1959383b88c98f7 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/575995 Reviewed-by: Filippo Valsorda <filippo@golang.org> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> Auto-Submit: Nicola Murino <nicola.murino@gmail.com> Commit-Queue: Nicola Murino <nicola.murino@gmail.com> Reviewed-by: Than McIntosh <thanm@google.com>
Diffstat (limited to 'ssh/server_test.go')
-rw-r--r--ssh/server_test.go129
1 files changed, 129 insertions, 0 deletions
diff --git a/ssh/server_test.go b/ssh/server_test.go
index a9b2bce..5b47b9e 100644
--- a/ssh/server_test.go
+++ b/ssh/server_test.go
@@ -5,8 +5,10 @@
package ssh
import (
+ "errors"
"io"
"net"
+ "strings"
"sync/atomic"
"testing"
"time"
@@ -62,6 +64,133 @@ func TestClientAuthRestrictedPublicKeyAlgos(t *testing.T) {
}
}
+func TestMaxAuthTriesNoneMethod(t *testing.T) {
+ username := "testuser"
+ serverConfig := &ServerConfig{
+ MaxAuthTries: 2,
+ PasswordCallback: func(conn ConnMetadata, password []byte) (*Permissions, error) {
+ if conn.User() == username && string(password) == clientPassword {
+ return nil, nil
+ }
+ return nil, errors.New("invalid credentials")
+ },
+ }
+ c1, c2, err := netPipe()
+ if err != nil {
+ t.Fatalf("netPipe: %v", err)
+ }
+ defer c1.Close()
+ defer c2.Close()
+
+ var serverAuthErrors []error
+
+ serverConfig.AddHostKey(testSigners["rsa"])
+ serverConfig.AuthLogCallback = func(conn ConnMetadata, method string, err error) {
+ serverAuthErrors = append(serverAuthErrors, err)
+ }
+ go newServer(c1, serverConfig)
+
+ clientConfig := ClientConfig{
+ User: username,
+ HostKeyCallback: InsecureIgnoreHostKey(),
+ }
+ clientConfig.SetDefaults()
+ // Our client will send 'none' auth only once, so we need to send the
+ // requests manually.
+ c := &connection{
+ sshConn: sshConn{
+ conn: c2,
+ user: username,
+ clientVersion: []byte(packageVersion),
+ },
+ }
+ c.serverVersion, err = exchangeVersions(c.sshConn.conn, c.clientVersion)
+ if err != nil {
+ t.Fatalf("unable to exchange version: %v", err)
+ }
+ c.transport = newClientTransport(
+ newTransport(c.sshConn.conn, clientConfig.Rand, true /* is client */),
+ c.clientVersion, c.serverVersion, &clientConfig, "", c.sshConn.RemoteAddr())
+ if err := c.transport.waitSession(); err != nil {
+ t.Fatalf("unable to wait session: %v", err)
+ }
+ c.sessionID = c.transport.getSessionID()
+ if err := c.transport.writePacket(Marshal(&serviceRequestMsg{serviceUserAuth})); err != nil {
+ t.Fatalf("unable to send ssh-userauth message: %v", err)
+ }
+ packet, err := c.transport.readPacket()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(packet) > 0 && packet[0] == msgExtInfo {
+ packet, err = c.transport.readPacket()
+ if err != nil {
+ t.Fatal(err)
+ }
+ }
+ var serviceAccept serviceAcceptMsg
+ if err := Unmarshal(packet, &serviceAccept); err != nil {
+ t.Fatal(err)
+ }
+ for i := 0; i <= serverConfig.MaxAuthTries; i++ {
+ auth := new(noneAuth)
+ _, _, err := auth.auth(c.sessionID, clientConfig.User, c.transport, clientConfig.Rand, nil)
+ if i < serverConfig.MaxAuthTries {
+ if err != nil {
+ t.Fatal(err)
+ }
+ continue
+ }
+ if err == nil {
+ t.Fatal("client: got no error")
+ } else if !strings.Contains(err.Error(), "too many authentication failures") {
+ t.Fatalf("client: got unexpected error: %v", err)
+ }
+ }
+ if len(serverAuthErrors) != 3 {
+ t.Fatalf("unexpected number of server auth errors: %v, errors: %+v", len(serverAuthErrors), serverAuthErrors)
+ }
+ for _, err := range serverAuthErrors {
+ if !errors.Is(err, ErrNoAuth) {
+ t.Errorf("go error: %v; want: %v", err, ErrNoAuth)
+ }
+ }
+}
+
+func TestMaxAuthTriesFirstNoneAuthErrorIgnored(t *testing.T) {
+ username := "testuser"
+ serverConfig := &ServerConfig{
+ MaxAuthTries: 1,
+ PasswordCallback: func(conn ConnMetadata, password []byte) (*Permissions, error) {
+ if conn.User() == username && string(password) == clientPassword {
+ return nil, nil
+ }
+ return nil, errors.New("invalid credentials")
+ },
+ }
+ clientConfig := &ClientConfig{
+ User: username,
+ Auth: []AuthMethod{
+ Password(clientPassword),
+ },
+ HostKeyCallback: InsecureIgnoreHostKey(),
+ }
+
+ serverAuthErrors, err := doClientServerAuth(t, serverConfig, clientConfig)
+ if err != nil {
+ t.Fatalf("client login error: %s", err)
+ }
+ if len(serverAuthErrors) != 2 {
+ t.Fatalf("unexpected number of server auth errors: %v, errors: %+v", len(serverAuthErrors), serverAuthErrors)
+ }
+ if !errors.Is(serverAuthErrors[0], ErrNoAuth) {
+ t.Errorf("go error: %v; want: %v", serverAuthErrors[0], ErrNoAuth)
+ }
+ if serverAuthErrors[1] != nil {
+ t.Errorf("unexpected error: %v", serverAuthErrors[1])
+ }
+}
+
func TestNewServerConnValidationErrors(t *testing.T) {
serverConf := &ServerConfig{
PublicKeyAuthAlgorithms: []string{CertAlgoRSAv01},