github.com/deis/deis@v1.13.5-0.20170519182049-1d9e59fbdbfc/Godeps/_workspace/src/golang.org/x/crypto/ssh/client_auth_test.go (about)

     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.
     4  
     5  package ssh
     6  
     7  import (
     8  	"bytes"
     9  	"crypto/rand"
    10  	"errors"
    11  	"fmt"
    12  	"strings"
    13  	"testing"
    14  )
    15  
    16  type keyboardInteractive map[string]string
    17  
    18  func (cr keyboardInteractive) Challenge(user string, instruction string, questions []string, echos []bool) ([]string, error) {
    19  	var answers []string
    20  	for _, q := range questions {
    21  		answers = append(answers, cr[q])
    22  	}
    23  	return answers, nil
    24  }
    25  
    26  // reused internally by tests
    27  var clientPassword = "tiger"
    28  
    29  // tryAuth runs a handshake with a given config against an SSH server
    30  // with config serverConfig
    31  func tryAuth(t *testing.T, config *ClientConfig) error {
    32  	c1, c2, err := netPipe()
    33  	if err != nil {
    34  		t.Fatalf("netPipe: %v", err)
    35  	}
    36  	defer c1.Close()
    37  	defer c2.Close()
    38  
    39  	certChecker := CertChecker{
    40  		IsAuthority: func(k PublicKey) bool {
    41  			return bytes.Equal(k.Marshal(), testPublicKeys["ecdsa"].Marshal())
    42  		},
    43  		UserKeyFallback: func(conn ConnMetadata, key PublicKey) (*Permissions, error) {
    44  			if conn.User() == "testuser" && bytes.Equal(key.Marshal(), testPublicKeys["rsa"].Marshal()) {
    45  				return nil, nil
    46  			}
    47  
    48  			return nil, fmt.Errorf("pubkey for %q not acceptable", conn.User())
    49  		},
    50  		IsRevoked: func(c *Certificate) bool {
    51  			return c.Serial == 666
    52  		},
    53  	}
    54  
    55  	serverConfig := &ServerConfig{
    56  		PasswordCallback: func(conn ConnMetadata, pass []byte) (*Permissions, error) {
    57  			if conn.User() == "testuser" && string(pass) == clientPassword {
    58  				return nil, nil
    59  			}
    60  			return nil, errors.New("password auth failed")
    61  		},
    62  		PublicKeyCallback: certChecker.Authenticate,
    63  		KeyboardInteractiveCallback: func(conn ConnMetadata, challenge KeyboardInteractiveChallenge) (*Permissions, error) {
    64  			ans, err := challenge("user",
    65  				"instruction",
    66  				[]string{"question1", "question2"},
    67  				[]bool{true, true})
    68  			if err != nil {
    69  				return nil, err
    70  			}
    71  			ok := conn.User() == "testuser" && ans[0] == "answer1" && ans[1] == "answer2"
    72  			if ok {
    73  				challenge("user", "motd", nil, nil)
    74  				return nil, nil
    75  			}
    76  			return nil, errors.New("keyboard-interactive failed")
    77  		},
    78  		AuthLogCallback: func(conn ConnMetadata, method string, err error) {
    79  			t.Logf("user %q, method %q: %v", conn.User(), method, err)
    80  		},
    81  	}
    82  	serverConfig.AddHostKey(testSigners["rsa"])
    83  
    84  	go newServer(c1, serverConfig)
    85  	_, _, _, err = NewClientConn(c2, "", config)
    86  	return err
    87  }
    88  
    89  func TestClientAuthPublicKey(t *testing.T) {
    90  	config := &ClientConfig{
    91  		User: "testuser",
    92  		Auth: []AuthMethod{
    93  			PublicKeys(testSigners["rsa"]),
    94  		},
    95  	}
    96  	if err := tryAuth(t, config); err != nil {
    97  		t.Fatalf("unable to dial remote side: %s", err)
    98  	}
    99  }
   100  
   101  func TestAuthMethodPassword(t *testing.T) {
   102  	config := &ClientConfig{
   103  		User: "testuser",
   104  		Auth: []AuthMethod{
   105  			Password(clientPassword),
   106  		},
   107  	}
   108  
   109  	if err := tryAuth(t, config); err != nil {
   110  		t.Fatalf("unable to dial remote side: %s", err)
   111  	}
   112  }
   113  
   114  func TestAuthMethodFallback(t *testing.T) {
   115  	var passwordCalled bool
   116  	config := &ClientConfig{
   117  		User: "testuser",
   118  		Auth: []AuthMethod{
   119  			PublicKeys(testSigners["rsa"]),
   120  			PasswordCallback(
   121  				func() (string, error) {
   122  					passwordCalled = true
   123  					return "WRONG", nil
   124  				}),
   125  		},
   126  	}
   127  
   128  	if err := tryAuth(t, config); err != nil {
   129  		t.Fatalf("unable to dial remote side: %s", err)
   130  	}
   131  
   132  	if passwordCalled {
   133  		t.Errorf("password auth tried before public-key auth.")
   134  	}
   135  }
   136  
   137  func TestAuthMethodWrongPassword(t *testing.T) {
   138  	config := &ClientConfig{
   139  		User: "testuser",
   140  		Auth: []AuthMethod{
   141  			Password("wrong"),
   142  			PublicKeys(testSigners["rsa"]),
   143  		},
   144  	}
   145  
   146  	if err := tryAuth(t, config); err != nil {
   147  		t.Fatalf("unable to dial remote side: %s", err)
   148  	}
   149  }
   150  
   151  func TestAuthMethodKeyboardInteractive(t *testing.T) {
   152  	answers := keyboardInteractive(map[string]string{
   153  		"question1": "answer1",
   154  		"question2": "answer2",
   155  	})
   156  	config := &ClientConfig{
   157  		User: "testuser",
   158  		Auth: []AuthMethod{
   159  			KeyboardInteractive(answers.Challenge),
   160  		},
   161  	}
   162  
   163  	if err := tryAuth(t, config); err != nil {
   164  		t.Fatalf("unable to dial remote side: %s", err)
   165  	}
   166  }
   167  
   168  func TestAuthMethodWrongKeyboardInteractive(t *testing.T) {
   169  	answers := keyboardInteractive(map[string]string{
   170  		"question1": "answer1",
   171  		"question2": "WRONG",
   172  	})
   173  	config := &ClientConfig{
   174  		User: "testuser",
   175  		Auth: []AuthMethod{
   176  			KeyboardInteractive(answers.Challenge),
   177  		},
   178  	}
   179  
   180  	if err := tryAuth(t, config); err == nil {
   181  		t.Fatalf("wrong answers should not have authenticated with KeyboardInteractive")
   182  	}
   183  }
   184  
   185  // the mock server will only authenticate ssh-rsa keys
   186  func TestAuthMethodInvalidPublicKey(t *testing.T) {
   187  	config := &ClientConfig{
   188  		User: "testuser",
   189  		Auth: []AuthMethod{
   190  			PublicKeys(testSigners["dsa"]),
   191  		},
   192  	}
   193  
   194  	if err := tryAuth(t, config); err == nil {
   195  		t.Fatalf("dsa private key should not have authenticated with rsa public key")
   196  	}
   197  }
   198  
   199  // the client should authenticate with the second key
   200  func TestAuthMethodRSAandDSA(t *testing.T) {
   201  	config := &ClientConfig{
   202  		User: "testuser",
   203  		Auth: []AuthMethod{
   204  			PublicKeys(testSigners["dsa"], testSigners["rsa"]),
   205  		},
   206  	}
   207  	if err := tryAuth(t, config); err != nil {
   208  		t.Fatalf("client could not authenticate with rsa key: %v", err)
   209  	}
   210  }
   211  
   212  func TestClientHMAC(t *testing.T) {
   213  	for _, mac := range supportedMACs {
   214  		config := &ClientConfig{
   215  			User: "testuser",
   216  			Auth: []AuthMethod{
   217  				PublicKeys(testSigners["rsa"]),
   218  			},
   219  			Config: Config{
   220  				MACs: []string{mac},
   221  			},
   222  		}
   223  		if err := tryAuth(t, config); err != nil {
   224  			t.Fatalf("client could not authenticate with mac algo %s: %v", mac, err)
   225  		}
   226  	}
   227  }
   228  
   229  // issue 4285.
   230  func TestClientUnsupportedCipher(t *testing.T) {
   231  	config := &ClientConfig{
   232  		User: "testuser",
   233  		Auth: []AuthMethod{
   234  			PublicKeys(),
   235  		},
   236  		Config: Config{
   237  			Ciphers: []string{"aes128-cbc"}, // not currently supported
   238  		},
   239  	}
   240  	if err := tryAuth(t, config); err == nil {
   241  		t.Errorf("expected no ciphers in common")
   242  	}
   243  }
   244  
   245  func TestClientUnsupportedKex(t *testing.T) {
   246  	config := &ClientConfig{
   247  		User: "testuser",
   248  		Auth: []AuthMethod{
   249  			PublicKeys(),
   250  		},
   251  		Config: Config{
   252  			KeyExchanges: []string{"diffie-hellman-group-exchange-sha256"}, // not currently supported
   253  		},
   254  	}
   255  	if err := tryAuth(t, config); err == nil || !strings.Contains(err.Error(), "no common algorithms") {
   256  		t.Errorf("got %v, expected 'no common algorithms'", err)
   257  	}
   258  }
   259  
   260  func TestClientLoginCert(t *testing.T) {
   261  	cert := &Certificate{
   262  		Key:         testPublicKeys["rsa"],
   263  		ValidBefore: CertTimeInfinity,
   264  		CertType:    UserCert,
   265  	}
   266  	cert.SignCert(rand.Reader, testSigners["ecdsa"])
   267  	certSigner, err := NewCertSigner(cert, testSigners["rsa"])
   268  	if err != nil {
   269  		t.Fatalf("NewCertSigner: %v", err)
   270  	}
   271  
   272  	clientConfig := &ClientConfig{
   273  		User: "user",
   274  	}
   275  	clientConfig.Auth = append(clientConfig.Auth, PublicKeys(certSigner))
   276  
   277  	t.Log("should succeed")
   278  	if err := tryAuth(t, clientConfig); err != nil {
   279  		t.Errorf("cert login failed: %v", err)
   280  	}
   281  
   282  	t.Log("corrupted signature")
   283  	cert.Signature.Blob[0]++
   284  	if err := tryAuth(t, clientConfig); err == nil {
   285  		t.Errorf("cert login passed with corrupted sig")
   286  	}
   287  
   288  	t.Log("revoked")
   289  	cert.Serial = 666
   290  	cert.SignCert(rand.Reader, testSigners["ecdsa"])
   291  	if err := tryAuth(t, clientConfig); err == nil {
   292  		t.Errorf("revoked cert login succeeded")
   293  	}
   294  	cert.Serial = 1
   295  
   296  	t.Log("sign with wrong key")
   297  	cert.SignCert(rand.Reader, testSigners["dsa"])
   298  	if err := tryAuth(t, clientConfig); err == nil {
   299  		t.Errorf("cert login passed with non-authoritive key")
   300  	}
   301  
   302  	t.Log("host cert")
   303  	cert.CertType = HostCert
   304  	cert.SignCert(rand.Reader, testSigners["ecdsa"])
   305  	if err := tryAuth(t, clientConfig); err == nil {
   306  		t.Errorf("cert login passed with wrong type")
   307  	}
   308  	cert.CertType = UserCert
   309  
   310  	t.Log("principal specified")
   311  	cert.ValidPrincipals = []string{"user"}
   312  	cert.SignCert(rand.Reader, testSigners["ecdsa"])
   313  	if err := tryAuth(t, clientConfig); err != nil {
   314  		t.Errorf("cert login failed: %v", err)
   315  	}
   316  
   317  	t.Log("wrong principal specified")
   318  	cert.ValidPrincipals = []string{"fred"}
   319  	cert.SignCert(rand.Reader, testSigners["ecdsa"])
   320  	if err := tryAuth(t, clientConfig); err == nil {
   321  		t.Errorf("cert login passed with wrong principal")
   322  	}
   323  	cert.ValidPrincipals = nil
   324  
   325  	t.Log("added critical option")
   326  	cert.CriticalOptions = map[string]string{"root-access": "yes"}
   327  	cert.SignCert(rand.Reader, testSigners["ecdsa"])
   328  	if err := tryAuth(t, clientConfig); err == nil {
   329  		t.Errorf("cert login passed with unrecognized critical option")
   330  	}
   331  
   332  	t.Log("allowed source address")
   333  	cert.CriticalOptions = map[string]string{"source-address": "127.0.0.42/24"}
   334  	cert.SignCert(rand.Reader, testSigners["ecdsa"])
   335  	if err := tryAuth(t, clientConfig); err != nil {
   336  		t.Errorf("cert login with source-address failed: %v", err)
   337  	}
   338  
   339  	t.Log("disallowed source address")
   340  	cert.CriticalOptions = map[string]string{"source-address": "127.0.0.42"}
   341  	cert.SignCert(rand.Reader, testSigners["ecdsa"])
   342  	if err := tryAuth(t, clientConfig); err == nil {
   343  		t.Errorf("cert login with source-address succeeded")
   344  	}
   345  }
   346  
   347  func testPermissionsPassing(withPermissions bool, t *testing.T) {
   348  	serverConfig := &ServerConfig{
   349  		PublicKeyCallback: func(conn ConnMetadata, key PublicKey) (*Permissions, error) {
   350  			if conn.User() == "nopermissions" {
   351  				return nil, nil
   352  			} else {
   353  				return &Permissions{}, nil
   354  			}
   355  		},
   356  	}
   357  	serverConfig.AddHostKey(testSigners["rsa"])
   358  
   359  	clientConfig := &ClientConfig{
   360  		Auth: []AuthMethod{
   361  			PublicKeys(testSigners["rsa"]),
   362  		},
   363  	}
   364  	if withPermissions {
   365  		clientConfig.User = "permissions"
   366  	} else {
   367  		clientConfig.User = "nopermissions"
   368  	}
   369  
   370  	c1, c2, err := netPipe()
   371  	if err != nil {
   372  		t.Fatalf("netPipe: %v", err)
   373  	}
   374  	defer c1.Close()
   375  	defer c2.Close()
   376  
   377  	go NewClientConn(c2, "", clientConfig)
   378  	serverConn, err := newServer(c1, serverConfig)
   379  	if err != nil {
   380  		t.Fatal(err)
   381  	}
   382  	if p := serverConn.Permissions; (p != nil) != withPermissions {
   383  		t.Fatalf("withPermissions is %t, but Permissions object is %#v", withPermissions, p)
   384  	}
   385  }
   386  
   387  func TestPermissionsPassing(t *testing.T) {
   388  	testPermissionsPassing(true, t)
   389  }
   390  
   391  func TestNoPermissionsPassing(t *testing.T) {
   392  	testPermissionsPassing(false, t)
   393  }