README update and missing dependencies.
This commit is contained in:
144
vendor/golang.org/x/crypto/ssh/test/multi_auth_test.go
generated
vendored
Normal file
144
vendor/golang.org/x/crypto/ssh/test/multi_auth_test.go
generated
vendored
Normal file
@@ -0,0 +1,144 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Tests for ssh client multi-auth
|
||||
//
|
||||
// These tests run a simple go ssh client against OpenSSH server
|
||||
// over unix domain sockets. The tests use multiple combinations
|
||||
// of password, keyboard-interactive and publickey authentication
|
||||
// methods.
|
||||
//
|
||||
// A wrapper library for making sshd PAM authentication use test
|
||||
// passwords is required in ./sshd_test_pw.so. If the library does
|
||||
// not exist these tests will be skipped. See compile instructions
|
||||
// (for linux) in file ./sshd_test_pw.c.
|
||||
|
||||
// +build linux
|
||||
|
||||
package test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
// test cases
|
||||
type multiAuthTestCase struct {
|
||||
authMethods []string
|
||||
expectedPasswordCbs int
|
||||
expectedKbdIntCbs int
|
||||
}
|
||||
|
||||
// test context
|
||||
type multiAuthTestCtx struct {
|
||||
password string
|
||||
numPasswordCbs int
|
||||
numKbdIntCbs int
|
||||
}
|
||||
|
||||
// create test context
|
||||
func newMultiAuthTestCtx(t *testing.T) *multiAuthTestCtx {
|
||||
password, err := randomPassword()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to generate random test password: %s", err.Error())
|
||||
}
|
||||
|
||||
return &multiAuthTestCtx{
|
||||
password: password,
|
||||
}
|
||||
}
|
||||
|
||||
// password callback
|
||||
func (ctx *multiAuthTestCtx) passwordCb() (secret string, err error) {
|
||||
ctx.numPasswordCbs++
|
||||
return ctx.password, nil
|
||||
}
|
||||
|
||||
// keyboard-interactive callback
|
||||
func (ctx *multiAuthTestCtx) kbdIntCb(user, instruction string, questions []string, echos []bool) (answers []string, err error) {
|
||||
if len(questions) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
ctx.numKbdIntCbs++
|
||||
if len(questions) == 1 {
|
||||
return []string{ctx.password}, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("unsupported keyboard-interactive flow")
|
||||
}
|
||||
|
||||
// TestMultiAuth runs several subtests for different combinations of password, keyboard-interactive and publickey authentication methods
|
||||
func TestMultiAuth(t *testing.T) {
|
||||
testCases := []multiAuthTestCase{
|
||||
// Test password,publickey authentication, assert that password callback is called 1 time
|
||||
multiAuthTestCase{
|
||||
authMethods: []string{"password", "publickey"},
|
||||
expectedPasswordCbs: 1,
|
||||
},
|
||||
// Test keyboard-interactive,publickey authentication, assert that keyboard-interactive callback is called 1 time
|
||||
multiAuthTestCase{
|
||||
authMethods: []string{"keyboard-interactive", "publickey"},
|
||||
expectedKbdIntCbs: 1,
|
||||
},
|
||||
// Test publickey,password authentication, assert that password callback is called 1 time
|
||||
multiAuthTestCase{
|
||||
authMethods: []string{"publickey", "password"},
|
||||
expectedPasswordCbs: 1,
|
||||
},
|
||||
// Test publickey,keyboard-interactive authentication, assert that keyboard-interactive callback is called 1 time
|
||||
multiAuthTestCase{
|
||||
authMethods: []string{"publickey", "keyboard-interactive"},
|
||||
expectedKbdIntCbs: 1,
|
||||
},
|
||||
// Test password,password authentication, assert that password callback is called 2 times
|
||||
multiAuthTestCase{
|
||||
authMethods: []string{"password", "password"},
|
||||
expectedPasswordCbs: 2,
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(strings.Join(testCase.authMethods, ","), func(t *testing.T) {
|
||||
ctx := newMultiAuthTestCtx(t)
|
||||
|
||||
server := newServerForConfig(t, "MultiAuth", map[string]string{"AuthMethods": strings.Join(testCase.authMethods, ",")})
|
||||
defer server.Shutdown()
|
||||
|
||||
clientConfig := clientConfig()
|
||||
server.setTestPassword(clientConfig.User, ctx.password)
|
||||
|
||||
publicKeyAuthMethod := clientConfig.Auth[0]
|
||||
clientConfig.Auth = nil
|
||||
for _, authMethod := range testCase.authMethods {
|
||||
switch authMethod {
|
||||
case "publickey":
|
||||
clientConfig.Auth = append(clientConfig.Auth, publicKeyAuthMethod)
|
||||
case "password":
|
||||
clientConfig.Auth = append(clientConfig.Auth,
|
||||
ssh.RetryableAuthMethod(ssh.PasswordCallback(ctx.passwordCb), 5))
|
||||
case "keyboard-interactive":
|
||||
clientConfig.Auth = append(clientConfig.Auth,
|
||||
ssh.RetryableAuthMethod(ssh.KeyboardInteractive(ctx.kbdIntCb), 5))
|
||||
default:
|
||||
t.Fatalf("Unknown authentication method %s", authMethod)
|
||||
}
|
||||
}
|
||||
|
||||
conn := server.Dial(clientConfig)
|
||||
defer conn.Close()
|
||||
|
||||
if ctx.numPasswordCbs != testCase.expectedPasswordCbs {
|
||||
t.Fatalf("passwordCallback was called %d times, expected %d times", ctx.numPasswordCbs, testCase.expectedPasswordCbs)
|
||||
}
|
||||
|
||||
if ctx.numKbdIntCbs != testCase.expectedKbdIntCbs {
|
||||
t.Fatalf("keyboardInteractiveCallback was called %d times, expected %d times", ctx.numKbdIntCbs, testCase.expectedKbdIntCbs)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
173
vendor/golang.org/x/crypto/ssh/test/sshd_test_pw.c
generated
vendored
Normal file
173
vendor/golang.org/x/crypto/ssh/test/sshd_test_pw.c
generated
vendored
Normal file
@@ -0,0 +1,173 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// sshd_test_pw.c
|
||||
// Wrapper to inject test password data for sshd PAM authentication
|
||||
//
|
||||
// This wrapper implements custom versions of getpwnam, getpwnam_r,
|
||||
// getspnam and getspnam_r. These functions first call their real
|
||||
// libc versions, then check if the requested user matches test user
|
||||
// specified in env variable TEST_USER and if so replace the password
|
||||
// with crypted() value of TEST_PASSWD env variable.
|
||||
//
|
||||
// Compile:
|
||||
// gcc -Wall -shared -o sshd_test_pw.so -fPIC sshd_test_pw.c
|
||||
//
|
||||
// Compile with debug:
|
||||
// gcc -DVERBOSE -Wall -shared -o sshd_test_pw.so -fPIC sshd_test_pw.c
|
||||
//
|
||||
// Run sshd:
|
||||
// LD_PRELOAD="sshd_test_pw.so" TEST_USER="..." TEST_PASSWD="..." sshd ...
|
||||
|
||||
// +build ignore
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <string.h>
|
||||
#include <pwd.h>
|
||||
#include <shadow.h>
|
||||
#include <dlfcn.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef VERBOSE
|
||||
#define DEBUG(X...) fprintf(stderr, X)
|
||||
#else
|
||||
#define DEBUG(X...) while (0) { }
|
||||
#endif
|
||||
|
||||
/* crypt() password */
|
||||
static char *
|
||||
pwhash(char *passwd) {
|
||||
return strdup(crypt(passwd, "$6$"));
|
||||
}
|
||||
|
||||
/* Pointers to real functions in libc */
|
||||
static struct passwd * (*real_getpwnam)(const char *) = NULL;
|
||||
static int (*real_getpwnam_r)(const char *, struct passwd *, char *, size_t, struct passwd **) = NULL;
|
||||
static struct spwd * (*real_getspnam)(const char *) = NULL;
|
||||
static int (*real_getspnam_r)(const char *, struct spwd *, char *, size_t, struct spwd **) = NULL;
|
||||
|
||||
/* Cached test user and test password */
|
||||
static char *test_user = NULL;
|
||||
static char *test_passwd_hash = NULL;
|
||||
|
||||
static void
|
||||
init(void) {
|
||||
/* Fetch real libc function pointers */
|
||||
real_getpwnam = dlsym(RTLD_NEXT, "getpwnam");
|
||||
real_getpwnam_r = dlsym(RTLD_NEXT, "getpwnam_r");
|
||||
real_getspnam = dlsym(RTLD_NEXT, "getspnam");
|
||||
real_getspnam_r = dlsym(RTLD_NEXT, "getspnam_r");
|
||||
|
||||
/* abort if env variables are not defined */
|
||||
if (getenv("TEST_USER") == NULL || getenv("TEST_PASSWD") == NULL) {
|
||||
fprintf(stderr, "env variables TEST_USER and TEST_PASSWD are missing\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
/* Fetch test user and test password from env */
|
||||
test_user = strdup(getenv("TEST_USER"));
|
||||
test_passwd_hash = pwhash(getenv("TEST_PASSWD"));
|
||||
|
||||
DEBUG("sshd_test_pw init():\n");
|
||||
DEBUG("\treal_getpwnam: %p\n", real_getpwnam);
|
||||
DEBUG("\treal_getpwnam_r: %p\n", real_getpwnam_r);
|
||||
DEBUG("\treal_getspnam: %p\n", real_getspnam);
|
||||
DEBUG("\treal_getspnam_r: %p\n", real_getspnam_r);
|
||||
DEBUG("\tTEST_USER: '%s'\n", test_user);
|
||||
DEBUG("\tTEST_PASSWD: '%s'\n", getenv("TEST_PASSWD"));
|
||||
DEBUG("\tTEST_PASSWD_HASH: '%s'\n", test_passwd_hash);
|
||||
}
|
||||
|
||||
static int
|
||||
is_test_user(const char *name) {
|
||||
if (test_user != NULL && strcmp(test_user, name) == 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* getpwnam */
|
||||
|
||||
struct passwd *
|
||||
getpwnam(const char *name) {
|
||||
struct passwd *pw;
|
||||
|
||||
DEBUG("sshd_test_pw getpwnam(%s)\n", name);
|
||||
|
||||
if (real_getpwnam == NULL)
|
||||
init();
|
||||
if ((pw = real_getpwnam(name)) == NULL)
|
||||
return NULL;
|
||||
|
||||
if (is_test_user(name))
|
||||
pw->pw_passwd = strdup(test_passwd_hash);
|
||||
|
||||
return pw;
|
||||
}
|
||||
|
||||
/* getpwnam_r */
|
||||
|
||||
int
|
||||
getpwnam_r(const char *name,
|
||||
struct passwd *pwd,
|
||||
char *buf,
|
||||
size_t buflen,
|
||||
struct passwd **result) {
|
||||
int r;
|
||||
|
||||
DEBUG("sshd_test_pw getpwnam_r(%s)\n", name);
|
||||
|
||||
if (real_getpwnam_r == NULL)
|
||||
init();
|
||||
if ((r = real_getpwnam_r(name, pwd, buf, buflen, result)) != 0 || *result == NULL)
|
||||
return r;
|
||||
|
||||
if (is_test_user(name))
|
||||
pwd->pw_passwd = strdup(test_passwd_hash);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* getspnam */
|
||||
|
||||
struct spwd *
|
||||
getspnam(const char *name) {
|
||||
struct spwd *sp;
|
||||
|
||||
DEBUG("sshd_test_pw getspnam(%s)\n", name);
|
||||
|
||||
if (real_getspnam == NULL)
|
||||
init();
|
||||
if ((sp = real_getspnam(name)) == NULL)
|
||||
return NULL;
|
||||
|
||||
if (is_test_user(name))
|
||||
sp->sp_pwdp = strdup(test_passwd_hash);
|
||||
|
||||
return sp;
|
||||
}
|
||||
|
||||
/* getspnam_r */
|
||||
|
||||
int
|
||||
getspnam_r(const char *name,
|
||||
struct spwd *spbuf,
|
||||
char *buf,
|
||||
size_t buflen,
|
||||
struct spwd **spbufp) {
|
||||
int r;
|
||||
|
||||
DEBUG("sshd_test_pw getspnam_r(%s)\n", name);
|
||||
|
||||
if (real_getspnam_r == NULL)
|
||||
init();
|
||||
if ((r = real_getspnam_r(name, spbuf, buf, buflen, spbufp)) != 0)
|
||||
return r;
|
||||
|
||||
if (is_test_user(name))
|
||||
spbuf->sp_pwdp = strdup(test_passwd_hash);
|
||||
|
||||
return r;
|
||||
}
|
Reference in New Issue
Block a user