1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
17 type keyboardInteractive map[string]string
19 func (cr keyboardInteractive) Challenge(user string, instruction string, questions []string, echos []bool) ([]string, error) {
21 for _, q := range questions {
22 answers = append(answers, cr[q])
27 // reused internally by tests
28 var clientPassword = "tiger"
30 // tryAuth runs a handshake with a given config against an SSH server
31 // with config serverConfig
32 func tryAuth(t *testing.T, config *ClientConfig) error {
33 c1, c2, err := netPipe()
35 t.Fatalf("netPipe: %v", err)
40 certChecker := CertChecker{
41 IsUserAuthority: func(k PublicKey) bool {
42 return bytes.Equal(k.Marshal(), testPublicKeys["ecdsa"].Marshal())
44 UserKeyFallback: func(conn ConnMetadata, key PublicKey) (*Permissions, error) {
45 if conn.User() == "testuser" && bytes.Equal(key.Marshal(), testPublicKeys["rsa"].Marshal()) {
49 return nil, fmt.Errorf("pubkey for %q not acceptable", conn.User())
51 IsRevoked: func(c *Certificate) bool {
52 return c.Serial == 666
56 serverConfig := &ServerConfig{
57 PasswordCallback: func(conn ConnMetadata, pass []byte) (*Permissions, error) {
58 if conn.User() == "testuser" && string(pass) == clientPassword {
61 return nil, errors.New("password auth failed")
63 PublicKeyCallback: certChecker.Authenticate,
64 KeyboardInteractiveCallback: func(conn ConnMetadata, challenge KeyboardInteractiveChallenge) (*Permissions, error) {
65 ans, err := challenge("user",
67 []string{"question1", "question2"},
72 ok := conn.User() == "testuser" && ans[0] == "answer1" && ans[1] == "answer2"
74 challenge("user", "motd", nil, nil)
77 return nil, errors.New("keyboard-interactive failed")
80 serverConfig.AddHostKey(testSigners["rsa"])
82 go newServer(c1, serverConfig)
83 _, _, _, err = NewClientConn(c2, "", config)
87 func TestClientAuthPublicKey(t *testing.T) {
88 config := &ClientConfig{
91 PublicKeys(testSigners["rsa"]),
93 HostKeyCallback: InsecureIgnoreHostKey(),
95 if err := tryAuth(t, config); err != nil {
96 t.Fatalf("unable to dial remote side: %s", err)
100 func TestAuthMethodPassword(t *testing.T) {
101 config := &ClientConfig{
104 Password(clientPassword),
106 HostKeyCallback: InsecureIgnoreHostKey(),
109 if err := tryAuth(t, config); err != nil {
110 t.Fatalf("unable to dial remote side: %s", err)
114 func TestAuthMethodFallback(t *testing.T) {
115 var passwordCalled bool
116 config := &ClientConfig{
119 PublicKeys(testSigners["rsa"]),
121 func() (string, error) {
122 passwordCalled = true
126 HostKeyCallback: InsecureIgnoreHostKey(),
129 if err := tryAuth(t, config); err != nil {
130 t.Fatalf("unable to dial remote side: %s", err)
134 t.Errorf("password auth tried before public-key auth.")
138 func TestAuthMethodWrongPassword(t *testing.T) {
139 config := &ClientConfig{
143 PublicKeys(testSigners["rsa"]),
145 HostKeyCallback: InsecureIgnoreHostKey(),
148 if err := tryAuth(t, config); err != nil {
149 t.Fatalf("unable to dial remote side: %s", err)
153 func TestAuthMethodKeyboardInteractive(t *testing.T) {
154 answers := keyboardInteractive(map[string]string{
155 "question1": "answer1",
156 "question2": "answer2",
158 config := &ClientConfig{
161 KeyboardInteractive(answers.Challenge),
163 HostKeyCallback: InsecureIgnoreHostKey(),
166 if err := tryAuth(t, config); err != nil {
167 t.Fatalf("unable to dial remote side: %s", err)
171 func TestAuthMethodWrongKeyboardInteractive(t *testing.T) {
172 answers := keyboardInteractive(map[string]string{
173 "question1": "answer1",
174 "question2": "WRONG",
176 config := &ClientConfig{
179 KeyboardInteractive(answers.Challenge),
183 if err := tryAuth(t, config); err == nil {
184 t.Fatalf("wrong answers should not have authenticated with KeyboardInteractive")
188 // the mock server will only authenticate ssh-rsa keys
189 func TestAuthMethodInvalidPublicKey(t *testing.T) {
190 config := &ClientConfig{
193 PublicKeys(testSigners["dsa"]),
197 if err := tryAuth(t, config); err == nil {
198 t.Fatalf("dsa private key should not have authenticated with rsa public key")
202 // the client should authenticate with the second key
203 func TestAuthMethodRSAandDSA(t *testing.T) {
204 config := &ClientConfig{
207 PublicKeys(testSigners["dsa"], testSigners["rsa"]),
209 HostKeyCallback: InsecureIgnoreHostKey(),
211 if err := tryAuth(t, config); err != nil {
212 t.Fatalf("client could not authenticate with rsa key: %v", err)
216 func TestClientHMAC(t *testing.T) {
217 for _, mac := range supportedMACs {
218 config := &ClientConfig{
221 PublicKeys(testSigners["rsa"]),
226 HostKeyCallback: InsecureIgnoreHostKey(),
228 if err := tryAuth(t, config); err != nil {
229 t.Fatalf("client could not authenticate with mac algo %s: %v", mac, err)
235 func TestClientUnsupportedCipher(t *testing.T) {
236 config := &ClientConfig{
242 Ciphers: []string{"aes128-cbc"}, // not currently supported
245 if err := tryAuth(t, config); err == nil {
246 t.Errorf("expected no ciphers in common")
250 func TestClientUnsupportedKex(t *testing.T) {
251 if os.Getenv("GO_BUILDER_NAME") != "" {
252 t.Skip("skipping known-flaky test on the Go build dashboard; see golang.org/issue/15198")
254 config := &ClientConfig{
260 KeyExchanges: []string{"diffie-hellman-group-exchange-sha256"}, // not currently supported
262 HostKeyCallback: InsecureIgnoreHostKey(),
264 if err := tryAuth(t, config); err == nil || !strings.Contains(err.Error(), "common algorithm") {
265 t.Errorf("got %v, expected 'common algorithm'", err)
269 func TestClientLoginCert(t *testing.T) {
270 cert := &Certificate{
271 Key: testPublicKeys["rsa"],
272 ValidBefore: CertTimeInfinity,
275 cert.SignCert(rand.Reader, testSigners["ecdsa"])
276 certSigner, err := NewCertSigner(cert, testSigners["rsa"])
278 t.Fatalf("NewCertSigner: %v", err)
281 clientConfig := &ClientConfig{
283 HostKeyCallback: InsecureIgnoreHostKey(),
285 clientConfig.Auth = append(clientConfig.Auth, PublicKeys(certSigner))
288 if err := tryAuth(t, clientConfig); err != nil {
289 t.Errorf("cert login failed: %v", err)
292 // corrupted signature
293 cert.Signature.Blob[0]++
294 if err := tryAuth(t, clientConfig); err == nil {
295 t.Errorf("cert login passed with corrupted sig")
300 cert.SignCert(rand.Reader, testSigners["ecdsa"])
301 if err := tryAuth(t, clientConfig); err == nil {
302 t.Errorf("revoked cert login succeeded")
306 // sign with wrong key
307 cert.SignCert(rand.Reader, testSigners["dsa"])
308 if err := tryAuth(t, clientConfig); err == nil {
309 t.Errorf("cert login passed with non-authoritative key")
313 cert.CertType = HostCert
314 cert.SignCert(rand.Reader, testSigners["ecdsa"])
315 if err := tryAuth(t, clientConfig); err == nil {
316 t.Errorf("cert login passed with wrong type")
318 cert.CertType = UserCert
320 // principal specified
321 cert.ValidPrincipals = []string{"user"}
322 cert.SignCert(rand.Reader, testSigners["ecdsa"])
323 if err := tryAuth(t, clientConfig); err != nil {
324 t.Errorf("cert login failed: %v", err)
327 // wrong principal specified
328 cert.ValidPrincipals = []string{"fred"}
329 cert.SignCert(rand.Reader, testSigners["ecdsa"])
330 if err := tryAuth(t, clientConfig); err == nil {
331 t.Errorf("cert login passed with wrong principal")
333 cert.ValidPrincipals = nil
335 // added critical option
336 cert.CriticalOptions = map[string]string{"root-access": "yes"}
337 cert.SignCert(rand.Reader, testSigners["ecdsa"])
338 if err := tryAuth(t, clientConfig); err == nil {
339 t.Errorf("cert login passed with unrecognized critical option")
342 // allowed source address
343 cert.CriticalOptions = map[string]string{"source-address": "127.0.0.42/24,::42/120"}
344 cert.SignCert(rand.Reader, testSigners["ecdsa"])
345 if err := tryAuth(t, clientConfig); err != nil {
346 t.Errorf("cert login with source-address failed: %v", err)
349 // disallowed source address
350 cert.CriticalOptions = map[string]string{"source-address": "127.0.0.42,::42"}
351 cert.SignCert(rand.Reader, testSigners["ecdsa"])
352 if err := tryAuth(t, clientConfig); err == nil {
353 t.Errorf("cert login with source-address succeeded")
357 func testPermissionsPassing(withPermissions bool, t *testing.T) {
358 serverConfig := &ServerConfig{
359 PublicKeyCallback: func(conn ConnMetadata, key PublicKey) (*Permissions, error) {
360 if conn.User() == "nopermissions" {
363 return &Permissions{}, nil
366 serverConfig.AddHostKey(testSigners["rsa"])
368 clientConfig := &ClientConfig{
370 PublicKeys(testSigners["rsa"]),
372 HostKeyCallback: InsecureIgnoreHostKey(),
375 clientConfig.User = "permissions"
377 clientConfig.User = "nopermissions"
380 c1, c2, err := netPipe()
382 t.Fatalf("netPipe: %v", err)
387 go NewClientConn(c2, "", clientConfig)
388 serverConn, err := newServer(c1, serverConfig)
392 if p := serverConn.Permissions; (p != nil) != withPermissions {
393 t.Fatalf("withPermissions is %t, but Permissions object is %#v", withPermissions, p)
397 func TestPermissionsPassing(t *testing.T) {
398 testPermissionsPassing(true, t)
401 func TestNoPermissionsPassing(t *testing.T) {
402 testPermissionsPassing(false, t)
405 func TestRetryableAuth(t *testing.T) {
407 passwords := []string{"WRONG1", "WRONG2"}
409 config := &ClientConfig{
412 RetryableAuthMethod(PasswordCallback(func() (string, error) {
417 PublicKeys(testSigners["rsa"]),
419 HostKeyCallback: InsecureIgnoreHostKey(),
422 if err := tryAuth(t, config); err != nil {
423 t.Fatalf("unable to dial remote side: %s", err)
426 t.Fatalf("Did not try all passwords")
430 func ExampleRetryableAuthMethod(t *testing.T) {
434 // Normally this would be a callback that prompts the user to answer the
435 // provided questions
436 Cb := func(user, instruction string, questions []string, echos []bool) (answers []string, err error) {
437 return []string{"answer1", "answer2"}, nil
440 config := &ClientConfig{
441 HostKeyCallback: InsecureIgnoreHostKey(),
444 RetryableAuthMethod(KeyboardInteractiveChallenge(Cb), NumberOfPrompts),
448 if err := tryAuth(t, config); err != nil {
449 t.Fatalf("unable to dial remote side: %s", err)
453 // Test if username is received on server side when NoClientAuth is used
454 func TestClientAuthNone(t *testing.T) {
456 serverConfig := &ServerConfig{
459 serverConfig.AddHostKey(testSigners["rsa"])
461 clientConfig := &ClientConfig{
463 HostKeyCallback: InsecureIgnoreHostKey(),
466 c1, c2, err := netPipe()
468 t.Fatalf("netPipe: %v", err)
473 go NewClientConn(c2, "", clientConfig)
474 serverConn, err := newServer(c1, serverConfig)
476 t.Fatalf("newServer: %v", err)
478 if serverConn.User() != user {
479 t.Fatalf("server: got %q, want %q", serverConn.User(), user)
483 // Test if authentication attempts are limited on server when MaxAuthTries is set
484 func TestClientAuthMaxAuthTries(t *testing.T) {
487 serverConfig := &ServerConfig{
489 PasswordCallback: func(conn ConnMetadata, pass []byte) (*Permissions, error) {
490 if conn.User() == "testuser" && string(pass) == "right" {
493 return nil, errors.New("password auth failed")
496 serverConfig.AddHostKey(testSigners["rsa"])
498 expectedErr := fmt.Errorf("ssh: handshake failed: %v", &disconnectMsg{
500 Message: "too many authentication failures",
503 for tries := 2; tries < 4; tries++ {
505 clientConfig := &ClientConfig{
508 RetryableAuthMethod(PasswordCallback(func() (string, error) {
516 HostKeyCallback: InsecureIgnoreHostKey(),
519 c1, c2, err := netPipe()
521 t.Fatalf("netPipe: %v", err)
526 go newServer(c1, serverConfig)
527 _, _, _, err = NewClientConn(c2, "", clientConfig)
530 t.Fatalf("client: got no error, want %s", expectedErr)
531 } else if err.Error() != expectedErr.Error() {
532 t.Fatalf("client: got %s, want %s", err, expectedErr)
536 t.Fatalf("client: got %s, want no error", err)
542 // Test if authentication attempts are correctly limited on server
543 // when more public keys are provided then MaxAuthTries
544 func TestClientAuthMaxAuthTriesPublicKey(t *testing.T) {
545 signers := []Signer{}
546 for i := 0; i < 6; i++ {
547 signers = append(signers, testSigners["dsa"])
550 validConfig := &ClientConfig{
553 PublicKeys(append([]Signer{testSigners["rsa"]}, signers...)...),
555 HostKeyCallback: InsecureIgnoreHostKey(),
557 if err := tryAuth(t, validConfig); err != nil {
558 t.Fatalf("unable to dial remote side: %s", err)
561 expectedErr := fmt.Errorf("ssh: handshake failed: %v", &disconnectMsg{
563 Message: "too many authentication failures",
565 invalidConfig := &ClientConfig{
568 PublicKeys(append(signers, testSigners["rsa"])...),
570 HostKeyCallback: InsecureIgnoreHostKey(),
572 if err := tryAuth(t, invalidConfig); err == nil {
573 t.Fatalf("client: got no error, want %s", expectedErr)
574 } else if err.Error() != expectedErr.Error() {
575 t.Fatalf("client: got %s, want %s", err, expectedErr)
579 // Test whether authentication errors are being properly logged if all
580 // authentication methods have been exhausted
581 func TestClientAuthErrorList(t *testing.T) {
582 publicKeyErr := errors.New("This is an error from PublicKeyCallback")
584 clientConfig := &ClientConfig{
586 PublicKeys(testSigners["rsa"]),
588 HostKeyCallback: InsecureIgnoreHostKey(),
590 serverConfig := &ServerConfig{
591 PublicKeyCallback: func(_ ConnMetadata, _ PublicKey) (*Permissions, error) {
592 return nil, publicKeyErr
595 serverConfig.AddHostKey(testSigners["rsa"])
597 c1, c2, err := netPipe()
599 t.Fatalf("netPipe: %v", err)
604 go NewClientConn(c2, "", clientConfig)
605 _, err = newServer(c1, serverConfig)
607 t.Fatal("newServer: got nil, expected errors")
610 authErrs, ok := err.(*ServerAuthError)
612 t.Fatalf("errors: got %T, want *ssh.ServerAuthError", err)
614 for i, e := range authErrs.Errors {
617 if e.Error() != "no auth passed yet" {
618 t.Fatalf("errors: got %v, want no auth passed yet", e.Error())
621 if e != publicKeyErr {
622 t.Fatalf("errors: got %v, want %v", e, publicKeyErr)
625 t.Fatalf("errors: got %v, expected 2 errors", authErrs.Errors)