Merge branch 'update-ssh-package' of github.com:higebu/packer into higebu-update-ssh-package

Conflicts:
	builder/amazon/common/ssh.go
	builder/digitalocean/ssh.go
	builder/googlecompute/ssh.go
	builder/openstack/ssh.go
	communicator/ssh/communicator_test.go
	communicator/ssh/keychain.go
	communicator/ssh/keychain_test.go
This commit is contained in:
Mitchell Hashimoto 2014-04-26 11:12:06 -07:00
commit e84e5e4f2c
20 changed files with 151 additions and 294 deletions

View File

@ -1,12 +1,11 @@
package common
import (
gossh "code.google.com/p/gosshold/ssh"
"code.google.com/p/go.crypto/ssh"
"errors"
"fmt"
"github.com/mitchellh/goamz/ec2"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/communicator/ssh"
"time"
)
@ -51,19 +50,19 @@ func SSHAddress(e *ec2.EC2, port int) func(multistep.StateBag) (string, error) {
// SSHConfig returns a function that can be used for the SSH communicator
// config for connecting to the instance created over SSH using the generated
// private key.
func SSHConfig(username string) func(multistep.StateBag) (*gossh.ClientConfig, error) {
return func(state multistep.StateBag) (*gossh.ClientConfig, error) {
func SSHConfig(username string) func(multistep.StateBag) (*ssh.ClientConfig, error) {
return func(state multistep.StateBag) (*ssh.ClientConfig, error) {
privateKey := state.Get("privateKey").(string)
keyring := new(ssh.SimpleKeychain)
if err := keyring.AddPEMKey(privateKey); err != nil {
signer, err := ssh.ParsePrivateKey([]byte(privateKey))
if err != nil {
return nil, fmt.Errorf("Error setting up SSH config: %s", err)
}
return &gossh.ClientConfig{
return &ssh.ClientConfig{
User: username,
Auth: []gossh.ClientAuth{
gossh.ClientAuthKeyring(keyring),
Auth: []ssh.AuthMethod{
ssh.PublicKeys(signer),
},
}, nil
}

View File

@ -1,10 +1,9 @@
package digitalocean
import (
gossh "code.google.com/p/gosshold/ssh"
"code.google.com/p/go.crypto/ssh"
"fmt"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/communicator/ssh"
)
func sshAddress(state multistep.StateBag) (string, error) {
@ -13,19 +12,19 @@ func sshAddress(state multistep.StateBag) (string, error) {
return fmt.Sprintf("%s:%d", ipAddress, config.SSHPort), nil
}
func sshConfig(state multistep.StateBag) (*gossh.ClientConfig, error) {
func sshConfig(state multistep.StateBag) (*ssh.ClientConfig, error) {
config := state.Get("config").(config)
privateKey := state.Get("privateKey").(string)
keyring := new(ssh.SimpleKeychain)
if err := keyring.AddPEMKey(privateKey); err != nil {
signer, err := ssh.ParsePrivateKey([]byte(privateKey))
if err != nil {
return nil, fmt.Errorf("Error setting up SSH config: %s", err)
}
return &gossh.ClientConfig{
return &ssh.ClientConfig{
User: config.SSHUsername,
Auth: []gossh.ClientAuth{
gossh.ClientAuthKeyring(keyring),
Auth: []ssh.AuthMethod{
ssh.PublicKeys(signer),
},
}, nil
}

View File

@ -1,11 +1,9 @@
package googlecompute
import (
"code.google.com/p/go.crypto/ssh"
"fmt"
gossh "code.google.com/p/gosshold/ssh"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/communicator/ssh"
)
// sshAddress returns the ssh address.
@ -16,19 +14,19 @@ func sshAddress(state multistep.StateBag) (string, error) {
}
// sshConfig returns the ssh configuration.
func sshConfig(state multistep.StateBag) (*gossh.ClientConfig, error) {
func sshConfig(state multistep.StateBag) (*ssh.ClientConfig, error) {
config := state.Get("config").(*Config)
privateKey := state.Get("ssh_private_key").(string)
keyring := new(ssh.SimpleKeychain)
if err := keyring.AddPEMKey(privateKey); err != nil {
signer, err := ssh.ParsePrivateKey([]byte(privateKey))
if err != nil {
return nil, fmt.Errorf("Error setting up SSH config: %s", err)
}
sshConfig := &gossh.ClientConfig{
return &ssh.ClientConfig{
User: config.SSHUsername,
Auth: []gossh.ClientAuth{gossh.ClientAuthKeyring(keyring)},
}
return sshConfig, nil
Auth: []ssh.AuthMethod{
ssh.PublicKeys(signer),
},
}, nil
}

View File

@ -1,11 +1,10 @@
package openstack
import (
gossh "code.google.com/p/gosshold/ssh"
"code.google.com/p/go.crypto/ssh"
"errors"
"fmt"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/communicator/ssh"
"github.com/rackspace/gophercloud"
"time"
)
@ -39,19 +38,19 @@ func SSHAddress(csp gophercloud.CloudServersProvider, port int) func(multistep.S
// SSHConfig returns a function that can be used for the SSH communicator
// config for connecting to the instance created over SSH using the generated
// private key.
func SSHConfig(username string) func(multistep.StateBag) (*gossh.ClientConfig, error) {
return func(state multistep.StateBag) (*gossh.ClientConfig, error) {
func SSHConfig(username string) func(multistep.StateBag) (*ssh.ClientConfig, error) {
return func(state multistep.StateBag) (*ssh.ClientConfig, error) {
privateKey := state.Get("privateKey").(string)
keyring := new(ssh.SimpleKeychain)
if err := keyring.AddPEMKey(privateKey); err != nil {
signer, err := ssh.ParsePrivateKey([]byte(privateKey))
if err != nil {
return nil, fmt.Errorf("Error setting up SSH config: %s", err)
}
return &gossh.ClientConfig{
return &ssh.ClientConfig{
User: username,
Auth: []gossh.ClientAuth{
gossh.ClientAuthKeyring(keyring),
Auth: []ssh.AuthMethod{
ssh.PublicKeys(signer),
},
}, nil
}

View File

@ -338,7 +338,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
if _, err := os.Stat(b.config.SSHKeyPath); err != nil {
errs = packer.MultiErrorAppend(
errs, fmt.Errorf("ssh_key_path is invalid: %s", err))
} else if _, err := sshKeyToKeyring(b.config.SSHKeyPath); err != nil {
} else if _, err := sshKeyToSigner(b.config.SSHKeyPath); err != nil {
errs = packer.MultiErrorAppend(
errs, fmt.Errorf("ssh_key_path is invalid: %s", err))
}

View File

@ -17,19 +17,19 @@ func sshAddress(state multistep.StateBag) (string, error) {
func sshConfig(state multistep.StateBag) (*gossh.ClientConfig, error) {
config := state.Get("config").(*config)
auth := []gossh.ClientAuth{
gossh.ClientAuthPassword(ssh.Password(config.SSHPassword)),
gossh.ClientAuthKeyboardInteractive(
auth := []gossh.AuthMethod{
gossh.Password(config.SSHPassword),
gossh.KeyboardInteractive(
ssh.PasswordKeyboardInteractive(config.SSHPassword)),
}
if config.SSHKeyPath != "" {
keyring, err := sshKeyToKeyring(config.SSHKeyPath)
signer, err := sshKeyToSigner(config.SSHKeyPath)
if err != nil {
return nil, err
}
auth = append(auth, gossh.ClientAuthKeyring(keyring))
auth = append(auth, gossh.PublicKeys(signer))
}
return &gossh.ClientConfig{
@ -38,7 +38,7 @@ func sshConfig(state multistep.StateBag) (*gossh.ClientConfig, error) {
}, nil
}
func sshKeyToKeyring(path string) (gossh.ClientKeyring, error) {
func sshKeyToSigner(path string) (gossh.Signer, error) {
f, err := os.Open(path)
if err != nil {
return nil, err
@ -50,10 +50,10 @@ func sshKeyToKeyring(path string) (gossh.ClientKeyring, error) {
return nil, err
}
keyring := new(ssh.SimpleKeychain)
if err := keyring.AddPEMKey(string(keyBytes)); err != nil {
return nil, err
signer, err := gossh.ParsePrivateKey(keyBytes)
if err != nil {
return nil, fmt.Errorf("Error setting up SSH config: %s", err)
}
return keyring, nil
return signer, nil
}

View File

@ -16,19 +16,19 @@ func SSHAddress(state multistep.StateBag) (string, error) {
func SSHConfigFunc(config SSHConfig) func(multistep.StateBag) (*gossh.ClientConfig, error) {
return func(state multistep.StateBag) (*gossh.ClientConfig, error) {
auth := []gossh.ClientAuth{
gossh.ClientAuthPassword(ssh.Password(config.SSHPassword)),
gossh.ClientAuthKeyboardInteractive(
auth := []gossh.AuthMethod{
gossh.Password(config.SSHPassword),
gossh.KeyboardInteractive(
ssh.PasswordKeyboardInteractive(config.SSHPassword)),
}
if config.SSHKeyPath != "" {
keyring, err := sshKeyToKeyring(config.SSHKeyPath)
signer, err := sshKeyToSigner(config.SSHKeyPath)
if err != nil {
return nil, err
}
auth = append(auth, gossh.ClientAuthKeyring(keyring))
auth = append(auth, gossh.PublicKeys(signer))
}
return &gossh.ClientConfig{
@ -38,7 +38,7 @@ func SSHConfigFunc(config SSHConfig) func(multistep.StateBag) (*gossh.ClientConf
}
}
func sshKeyToKeyring(path string) (gossh.ClientKeyring, error) {
func sshKeyToSigner(path string) (gossh.Signer, error) {
f, err := os.Open(path)
if err != nil {
return nil, err
@ -50,10 +50,10 @@ func sshKeyToKeyring(path string) (gossh.ClientKeyring, error) {
return nil, err
}
keyring := new(ssh.SimpleKeychain)
if err := keyring.AddPEMKey(string(keyBytes)); err != nil {
return nil, err
signer, err := gossh.ParsePrivateKey(keyBytes)
if err != nil {
return nil, fmt.Errorf("Error setting up SSH config: %s", err)
}
return keyring, nil
return signer, nil
}

View File

@ -56,7 +56,7 @@ func (c *SSHConfig) Prepare(t *packer.ConfigTemplate) []error {
if c.SSHKeyPath != "" {
if _, err := os.Stat(c.SSHKeyPath); err != nil {
errs = append(errs, fmt.Errorf("ssh_key_path is invalid: %s", err))
} else if _, err := sshKeyToKeyring(c.SSHKeyPath); err != nil {
} else if _, err := sshKeyToSigner(c.SSHKeyPath); err != nil {
errs = append(errs, fmt.Errorf("ssh_key_path is invalid: %s", err))
}
}

View File

@ -63,19 +63,19 @@ func SSHAddressFunc(config *SSHConfig) func(multistep.StateBag) (string, error)
func SSHConfigFunc(config *SSHConfig) func(multistep.StateBag) (*gossh.ClientConfig, error) {
return func(state multistep.StateBag) (*gossh.ClientConfig, error) {
auth := []gossh.ClientAuth{
gossh.ClientAuthPassword(ssh.Password(config.SSHPassword)),
gossh.ClientAuthKeyboardInteractive(
auth := []gossh.AuthMethod{
gossh.Password(config.SSHPassword),
gossh.KeyboardInteractive(
ssh.PasswordKeyboardInteractive(config.SSHPassword)),
}
if config.SSHKeyPath != "" {
keyring, err := sshKeyToKeyring(config.SSHKeyPath)
signer, err := sshKeyToSigner(config.SSHKeyPath)
if err != nil {
return nil, err
}
auth = append(auth, gossh.ClientAuthKeyring(keyring))
auth = append(auth, gossh.PublicKeys(signer))
}
return &gossh.ClientConfig{
@ -85,7 +85,7 @@ func SSHConfigFunc(config *SSHConfig) func(multistep.StateBag) (*gossh.ClientCon
}
}
func sshKeyToKeyring(path string) (gossh.ClientKeyring, error) {
func sshKeyToSigner(path string) (gossh.Signer, error) {
f, err := os.Open(path)
if err != nil {
return nil, err
@ -97,10 +97,10 @@ func sshKeyToKeyring(path string) (gossh.ClientKeyring, error) {
return nil, err
}
keyring := new(ssh.SimpleKeychain)
if err := keyring.AddPEMKey(string(keyBytes)); err != nil {
return nil, err
signer, err := gossh.ParsePrivateKey(keyBytes)
if err != nil {
return nil, fmt.Errorf("Error setting up SSH config: %s", err)
}
return keyring, nil
return signer, nil
}

View File

@ -48,7 +48,7 @@ func (c *SSHConfig) Prepare(t *packer.ConfigTemplate) []error {
if c.SSHKeyPath != "" {
if _, err := os.Stat(c.SSHKeyPath); err != nil {
errs = append(errs, fmt.Errorf("ssh_key_path is invalid: %s", err))
} else if _, err := sshKeyToKeyring(c.SSHKeyPath); err != nil {
} else if _, err := sshKeyToSigner(c.SSHKeyPath); err != nil {
errs = append(errs, fmt.Errorf("ssh_key_path is invalid: %s", err))
}
}

View File

@ -249,9 +249,9 @@ func (d *ESX5Driver) datastorePath(path string) string {
func (d *ESX5Driver) connect() error {
address := fmt.Sprintf("%s:%d", d.Host, d.Port)
auth := []gossh.ClientAuth{
gossh.ClientAuthPassword(ssh.Password(d.Password)),
gossh.ClientAuthKeyboardInteractive(
auth := []gossh.AuthMethod{
gossh.Password(d.Password),
gossh.KeyboardInteractive(
ssh.PasswordKeyboardInteractive(d.Password)),
}
@ -265,7 +265,7 @@ func (d *ESX5Driver) connect() error {
NoPty: true,
}
comm, err := ssh.New(sshConfig)
comm, err := ssh.New(address, sshConfig)
if err != nil {
return err
}

View File

@ -137,7 +137,7 @@ func (s *StepConnectSSH) waitForSSH(state multistep.StateBag, cancel <-chan stru
}
log.Println("Attempting SSH connection...")
comm, err = ssh.New(config)
comm, err = ssh.New(address, config)
if err != nil {
log.Printf("SSH handshake err: %s", err)

View File

@ -18,9 +18,10 @@ import (
)
type comm struct {
client *ssh.ClientConn
client *ssh.Client
config *Config
conn net.Conn
address string
}
// Config is the structure used to configure the SSH communicator.
@ -39,10 +40,11 @@ type Config struct {
// Creates a new packer.Communicator implementation over SSH. This takes
// an already existing TCP connection and SSH configuration.
func New(config *Config) (result *comm, err error) {
func New(address string, config *Config) (result *comm, err error) {
// Establish an initial connection and connect
result = &comm{
config: config,
address: address,
}
if err = result.reconnect(); err != nil {
@ -253,10 +255,13 @@ func (c *comm) reconnect() (err error) {
}
log.Printf("handshaking with SSH")
c.client, err = ssh.Client(c.conn, c.config.SSHConfig)
sshConn, sshChan, req, err := ssh.NewClientConn(c.conn, c.address, c.config.SSHConfig)
if err != nil {
log.Printf("handshake error: %s", err)
}
if sshConn != nil {
c.client = ssh.NewClient(sshConn, sshChan, req)
}
return
}

View File

@ -4,7 +4,8 @@ package ssh
import (
"bytes"
"code.google.com/p/gosshold/ssh"
"code.google.com/p/go.crypto/ssh"
"fmt"
"github.com/mitchellh/packer/packer"
"net"
"testing"
@ -39,65 +40,57 @@ gqnBycHj6AhEycjda75cs+0zybZvN4x65KZHOGW/O/7OAWEcZP5TPb3zf9ned3Hl
NsZoFj52ponUM6+99A2CmezFCN16c4mbA//luWF+k3VVqR6BpkrhKw==
-----END RSA PRIVATE KEY-----`
// password implements the ClientPassword interface
type password string
func (p password) Password(user string) (string, error) {
return string(p), nil
}
var serverConfig = &ssh.ServerConfig{
PasswordCallback: func(c *ssh.ServerConn, user, pass string) bool {
return user == "user" && pass == "pass"
PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
if c.User() == "user" && string(pass) == "pass" {
return nil, nil
}
return nil, fmt.Errorf("password rejected for %q", c.User())
},
}
func init() {
// Set the private key of the server, required to accept connections
if err := serverConfig.SetRSAPrivateKey([]byte(testServerPrivateKey)); err != nil {
panic("unable to set private key: " + err.Error())
// Parse and set the private key of the server, required to accept connections
signer, err := ssh.ParsePrivateKey([]byte(testServerPrivateKey))
if err != nil {
panic("unable to parse private key: " + err.Error())
}
serverConfig.AddHostKey(signer)
}
func newMockLineServer(t *testing.T) string {
l, err := ssh.Listen("tcp", "127.0.0.1:0", serverConfig)
l, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatalf("unable to newMockAuthServer: %s", err)
t.Fatalf("Unable to listen for connection: %s", err)
}
go func() {
defer l.Close()
c, err := l.Accept()
if err != nil {
t.Errorf("Unable to accept incoming connection: %v", err)
return
t.Errorf("Unable to accept incoming connection: %s", err)
}
if err := c.Handshake(); err != nil {
// not Errorf because this is expected to
// fail for some tests.
t.Logf("Handshaking error: %v", err)
return
}
t.Log("Accepted SSH connection")
defer c.Close()
channel, err := c.Accept()
conn, chans, _, err := ssh.NewServerConn(c, serverConfig)
if err != nil {
t.Errorf("Unable to accept a channel: %s", err)
return
t.Logf("Handshaking error: %v", err)
}
t.Log("Accepted SSH connection")
for newChannel := range chans {
channel, _, err := newChannel.Accept()
if err != nil {
t.Errorf("Unable to accept channel.")
}
// Just go in a loop now accepting things... we need to
// do this to handle packets for SSH.
go func() {
c.Accept()
}()
channel.Accept()
t.Log("Accepted channel")
go func() {
defer channel.Close()
conn.OpenChannel(newChannel.ChannelType(), nil)
}()
}
conn.Close()
}()
return l.Addr().String()
}
@ -112,15 +105,16 @@ func TestCommIsCommunicator(t *testing.T) {
func TestNew_Invalid(t *testing.T) {
clientConfig := &ssh.ClientConfig{
User: "user",
Auth: []ssh.ClientAuth{
ssh.ClientAuthPassword(password("i-am-invalid")),
Auth: []ssh.AuthMethod{
ssh.Password("i-am-invalid"),
},
}
address := newMockLineServer(t)
conn := func() (net.Conn, error) {
conn, err := net.Dial("tcp", newMockLineServer(t))
conn, err := net.Dial("tcp", address)
if err != nil {
t.Fatalf("unable to dial to remote side: %s", err)
t.Errorf("Unable to accept incoming connection: %v", err)
}
return conn, err
}
@ -130,7 +124,7 @@ func TestNew_Invalid(t *testing.T) {
SSHConfig: clientConfig,
}
_, err := New(config)
_, err := New(address, config)
if err == nil {
t.Fatal("should have had an error connecting")
}
@ -139,13 +133,14 @@ func TestNew_Invalid(t *testing.T) {
func TestStart(t *testing.T) {
clientConfig := &ssh.ClientConfig{
User: "user",
Auth: []ssh.ClientAuth{
ssh.ClientAuthPassword(password("pass")),
Auth: []ssh.AuthMethod{
ssh.Password("pass"),
},
}
address := newMockLineServer(t)
conn := func() (net.Conn, error) {
conn, err := net.Dial("tcp", newMockLineServer(t))
conn, err := net.Dial("tcp", address)
if err != nil {
t.Fatalf("unable to dial to remote side: %s", err)
}
@ -157,7 +152,7 @@ func TestStart(t *testing.T) {
SSHConfig: clientConfig,
}
client, err := New(config)
client, err := New(address, config)
if err != nil {
t.Fatalf("error connecting to SSH: %s", err)
}

View File

@ -1,81 +0,0 @@
package ssh
import (
"code.google.com/p/gosshold/ssh"
"crypto"
"crypto/dsa"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"errors"
"io"
)
// SimpleKeychain makes it easy to use private keys in order to connect
// via SSH, since the interface exposed by Go isn't the easiest to use
// right away.
type SimpleKeychain struct {
keys []interface{}
}
// AddPEMKey adds a simple PEM encoded private key to the keychain.
func (k *SimpleKeychain) AddPEMKey(key string) (err error) {
block, _ := pem.Decode([]byte(key))
if block == nil {
return errors.New("no block in key")
}
var rsakey interface{}
rsakey, err = x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
rsakey, err = x509.ParsePKCS8PrivateKey(block.Bytes)
}
if err != nil {
return
}
k.keys = append(k.keys, rsakey)
return
}
// AddPEMKeyPassword adds a PEM encoded private key that is protected by
// a password to the keychain.
func (k *SimpleKeychain) AddPEMKeyPassword(key string, password string) (err error) {
block, _ := pem.Decode([]byte(key))
bytes, _ := x509.DecryptPEMBlock(block, []byte(password))
rsakey, err := x509.ParsePKCS1PrivateKey(bytes)
if err != nil {
return
}
k.keys = append(k.keys, rsakey)
return
}
// Key method for ssh.ClientKeyring interface
func (k *SimpleKeychain) Key(i int) (ssh.PublicKey, error) {
if i < 0 || i >= len(k.keys) {
return nil, nil
}
switch key := k.keys[i].(type) {
case *rsa.PrivateKey:
return ssh.NewPublicKey(&key.PublicKey)
case *dsa.PrivateKey:
return ssh.NewPublicKey(&key.PublicKey)
}
panic("unknown key type")
}
// Sign method for ssh.ClientKeyring interface
func (k *SimpleKeychain) Sign(i int, rand io.Reader, data []byte) (sig []byte, err error) {
hashFunc := crypto.SHA1
h := hashFunc.New()
h.Write(data)
digest := h.Sum(nil)
switch key := k.keys[i].(type) {
case *rsa.PrivateKey:
return rsa.SignPKCS1v15(rand, key, hashFunc, digest)
}
return nil, errors.New("ssh: unknown key type")
}

View File

@ -1,32 +0,0 @@
package ssh
import (
"code.google.com/p/gosshold/ssh"
"testing"
)
const testPrivateKey = `-----BEGIN RSA PRIVATE KEY-----
MIIBOwIBAAJBALdGZxkXDAjsYk10ihwU6Id2KeILz1TAJuoq4tOgDWxEEGeTrcld
r/ZwVaFzjWzxaf6zQIJbfaSEAhqD5yo72+sCAwEAAQJBAK8PEVU23Wj8mV0QjwcJ
tZ4GcTUYQL7cF4+ezTCE9a1NrGnCP2RuQkHEKxuTVrxXt+6OF15/1/fuXnxKjmJC
nxkCIQDaXvPPBi0c7vAxGwNY9726x01/dNbHCE0CBtcotobxpwIhANbbQbh3JHVW
2haQh4fAG5mhesZKAGcxTyv4mQ7uMSQdAiAj+4dzMpJWdSzQ+qGHlHMIBvVHLkqB
y2VdEyF7DPCZewIhAI7GOI/6LDIFOvtPo6Bj2nNmyQ1HU6k/LRtNIXi4c9NJAiAr
rrxx26itVhJmcvoUhOjwuzSlP2bE5VHAvkGB352YBg==
-----END RSA PRIVATE KEY-----`
func TestAddPEMKey(t *testing.T) {
k := &SimpleKeychain{}
err := k.AddPEMKey(testPrivateKey)
if err != nil {
t.Fatalf("error while adding key: %s", err)
}
}
func TestSimpleKeyChain_ImplementsClientkeyring(t *testing.T) {
var raw interface{}
raw = &SimpleKeychain{}
if _, ok := raw.(ssh.ClientKeyring); !ok {
t.Fatal("SimpleKeychain is not a valid ssh.ClientKeyring")
}
}

View File

@ -1,20 +1,14 @@
package ssh
import "log"
import (
"log"
"code.google.com/p/go.crypto/ssh"
)
// An implementation of ssh.ClientPassword so that you can use a static
// string password for the password to ClientAuthPassword.
type Password string
func (p Password) Password(user string) (string, error) {
return string(p), nil
}
// An implementation of ssh.ClientKeyboardInteractive that simply sends
// An implementation of ssh.KeyboardInteractiveChallenge that simply sends
// back the password for all questions. The questions are logged.
type PasswordKeyboardInteractive string
func (p PasswordKeyboardInteractive) Challenge(user, instruction string, questions []string, echos []bool) ([]string, error) {
func PasswordKeyboardInteractive (password string) (ssh.KeyboardInteractiveChallenge) {
return func (user, instruction string, questions []string, echos []bool) ([]string, error) {
log.Printf("Keyboard interactive challenge: ")
log.Printf("-- User: %s", user)
log.Printf("-- Instructions: %s", instruction)
@ -25,8 +19,9 @@ func (p PasswordKeyboardInteractive) Challenge(user, instruction string, questio
// Just send the password back for all questions
answers := make([]string, len(questions))
for i, _ := range answers {
answers[i] = string(p)
answers[i] = string(password)
}
return answers, nil
}
}

View File

@ -6,37 +6,17 @@ import (
"testing"
)
func TestPassword_Impl(t *testing.T) {
var raw interface{}
raw = Password("foo")
if _, ok := raw.(ssh.ClientPassword); !ok {
t.Fatal("Password must implement ClientPassword")
}
}
func TestPasswordPassword(t *testing.T) {
p := Password("foo")
result, err := p.Password("user")
if err != nil {
t.Fatalf("err not nil: %s", err)
}
if result != "foo" {
t.Fatalf("invalid password: %s", result)
}
}
func TestPasswordKeyboardInteractive_Impl(t *testing.T) {
var raw interface{}
raw = PasswordKeyboardInteractive("foo")
if _, ok := raw.(ssh.ClientKeyboardInteractive); !ok {
t.Fatal("PasswordKeyboardInteractive must implement ClientKeyboardInteractive")
if _, ok := raw.(ssh.KeyboardInteractiveChallenge); !ok {
t.Fatal("PasswordKeyboardInteractive must implement KeyboardInteractiveChallenge")
}
}
func TestPasswordKeybardInteractive_Challenge(t *testing.T) {
p := PasswordKeyboardInteractive("foo")
result, err := p.Challenge("foo", "bar", []string{"one", "two"}, nil)
result, err := p("foo", "bar", []string{"one", "two"}, nil)
if err != nil {
t.Fatalf("err not nil: %s", err)
}

View File

@ -6,7 +6,7 @@ import (
)
func testConn(t *testing.T) (net.Conn, net.Conn) {
l, err := net.Listen("tcp", ":0")
l, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatalf("err: %s", err)
}

View File

@ -18,7 +18,7 @@ func readStream(t *testing.T, s io.Reader) string {
}
func testMux(t *testing.T) (client *MuxConn, server *MuxConn) {
l, err := net.Listen("tcp", ":0")
l, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatalf("err: %s", err)
}