Fix the build problem by updating ssh package

This commit is contained in:
higebu 2014-04-10 17:48:55 +09:00 committed by Yuya Kusakabe
parent dc21bf011a
commit f087ce16dc
20 changed files with 150 additions and 293 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -338,7 +338,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
if _, err := os.Stat(b.config.SSHKeyPath); err != nil { if _, err := os.Stat(b.config.SSHKeyPath); err != nil {
errs = packer.MultiErrorAppend( errs = packer.MultiErrorAppend(
errs, fmt.Errorf("ssh_key_path is invalid: %s", err)) 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 = packer.MultiErrorAppend(
errs, fmt.Errorf("ssh_key_path is invalid: %s", err)) 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) { func sshConfig(state multistep.StateBag) (*gossh.ClientConfig, error) {
config := state.Get("config").(*config) config := state.Get("config").(*config)
auth := []gossh.ClientAuth{ auth := []gossh.AuthMethod{
gossh.ClientAuthPassword(ssh.Password(config.SSHPassword)), gossh.Password(config.SSHPassword),
gossh.ClientAuthKeyboardInteractive( gossh.KeyboardInteractive(
ssh.PasswordKeyboardInteractive(config.SSHPassword)), ssh.PasswordKeyboardInteractive(config.SSHPassword)),
} }
if config.SSHKeyPath != "" { if config.SSHKeyPath != "" {
keyring, err := sshKeyToKeyring(config.SSHKeyPath) signer, err := sshKeyToSigner(config.SSHKeyPath)
if err != nil { if err != nil {
return nil, err return nil, err
} }
auth = append(auth, gossh.ClientAuthKeyring(keyring)) auth = append(auth, gossh.PublicKeys(signer))
} }
return &gossh.ClientConfig{ return &gossh.ClientConfig{
@ -38,7 +38,7 @@ func sshConfig(state multistep.StateBag) (*gossh.ClientConfig, error) {
}, nil }, nil
} }
func sshKeyToKeyring(path string) (gossh.ClientKeyring, error) { func sshKeyToSigner(path string) (gossh.Signer, error) {
f, err := os.Open(path) f, err := os.Open(path)
if err != nil { if err != nil {
return nil, err return nil, err
@ -50,10 +50,10 @@ func sshKeyToKeyring(path string) (gossh.ClientKeyring, error) {
return nil, err return nil, err
} }
keyring := new(ssh.SimpleKeychain) signer, err := gossh.ParsePrivateKey(keyBytes)
if err := keyring.AddPEMKey(string(keyBytes)); err != nil { if err != nil {
return nil, err 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) { func SSHConfigFunc(config SSHConfig) func(multistep.StateBag) (*gossh.ClientConfig, error) {
return func(state multistep.StateBag) (*gossh.ClientConfig, error) { return func(state multistep.StateBag) (*gossh.ClientConfig, error) {
auth := []gossh.ClientAuth{ auth := []gossh.AuthMethod{
gossh.ClientAuthPassword(ssh.Password(config.SSHPassword)), gossh.Password(config.SSHPassword),
gossh.ClientAuthKeyboardInteractive( gossh.KeyboardInteractive(
ssh.PasswordKeyboardInteractive(config.SSHPassword)), ssh.PasswordKeyboardInteractive(config.SSHPassword)),
} }
if config.SSHKeyPath != "" { if config.SSHKeyPath != "" {
keyring, err := sshKeyToKeyring(config.SSHKeyPath) signer, err := sshKeyToSigner(config.SSHKeyPath)
if err != nil { if err != nil {
return nil, err return nil, err
} }
auth = append(auth, gossh.ClientAuthKeyring(keyring)) auth = append(auth, gossh.PublicKeys(signer))
} }
return &gossh.ClientConfig{ 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) f, err := os.Open(path)
if err != nil { if err != nil {
return nil, err return nil, err
@ -50,10 +50,10 @@ func sshKeyToKeyring(path string) (gossh.ClientKeyring, error) {
return nil, err return nil, err
} }
keyring := new(ssh.SimpleKeychain) signer, err := gossh.ParsePrivateKey(keyBytes)
if err := keyring.AddPEMKey(string(keyBytes)); err != nil { if err != nil {
return nil, err 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 c.SSHKeyPath != "" {
if _, err := os.Stat(c.SSHKeyPath); err != nil { if _, err := os.Stat(c.SSHKeyPath); err != nil {
errs = append(errs, fmt.Errorf("ssh_key_path is invalid: %s", err)) 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)) 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) { func SSHConfigFunc(config *SSHConfig) func(multistep.StateBag) (*gossh.ClientConfig, error) {
return func(state multistep.StateBag) (*gossh.ClientConfig, error) { return func(state multistep.StateBag) (*gossh.ClientConfig, error) {
auth := []gossh.ClientAuth{ auth := []gossh.AuthMethod{
gossh.ClientAuthPassword(ssh.Password(config.SSHPassword)), gossh.Password(config.SSHPassword),
gossh.ClientAuthKeyboardInteractive( gossh.KeyboardInteractive(
ssh.PasswordKeyboardInteractive(config.SSHPassword)), ssh.PasswordKeyboardInteractive(config.SSHPassword)),
} }
if config.SSHKeyPath != "" { if config.SSHKeyPath != "" {
keyring, err := sshKeyToKeyring(config.SSHKeyPath) signer, err := sshKeyToSigner(config.SSHKeyPath)
if err != nil { if err != nil {
return nil, err return nil, err
} }
auth = append(auth, gossh.ClientAuthKeyring(keyring)) auth = append(auth, gossh.PublicKeys(signer))
} }
return &gossh.ClientConfig{ 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) f, err := os.Open(path)
if err != nil { if err != nil {
return nil, err return nil, err
@ -97,10 +97,10 @@ func sshKeyToKeyring(path string) (gossh.ClientKeyring, error) {
return nil, err return nil, err
} }
keyring := new(ssh.SimpleKeychain) signer, err := gossh.ParsePrivateKey(keyBytes)
if err := keyring.AddPEMKey(string(keyBytes)); err != nil { if err != nil {
return nil, err 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 c.SSHKeyPath != "" {
if _, err := os.Stat(c.SSHKeyPath); err != nil { if _, err := os.Stat(c.SSHKeyPath); err != nil {
errs = append(errs, fmt.Errorf("ssh_key_path is invalid: %s", err)) 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)) errs = append(errs, fmt.Errorf("ssh_key_path is invalid: %s", err))
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

@ -1,81 +0,0 @@
package ssh
import (
"code.google.com/p/go.crypto/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/go.crypto/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 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 // An implementation of ssh.KeyboardInteractiveChallenge that simply sends
// 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
// back the password for all questions. The questions are logged. // back the password for all questions. The questions are logged.
type PasswordKeyboardInteractive string func PasswordKeyboardInteractive (password string) (ssh.KeyboardInteractiveChallenge) {
return func (user, instruction string, questions []string, echos []bool) ([]string, error) {
func (p PasswordKeyboardInteractive) Challenge(user, instruction string, questions []string, echos []bool) ([]string, error) {
log.Printf("Keyboard interactive challenge: ") log.Printf("Keyboard interactive challenge: ")
log.Printf("-- User: %s", user) log.Printf("-- User: %s", user)
log.Printf("-- Instructions: %s", instruction) 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 // Just send the password back for all questions
answers := make([]string, len(questions)) answers := make([]string, len(questions))
for i, _ := range answers { for i, _ := range answers {
answers[i] = string(p) answers[i] = string(password)
} }
return answers, nil return answers, nil
} }
}

View File

@ -6,37 +6,17 @@ import (
"testing" "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) { func TestPasswordKeyboardInteractive_Impl(t *testing.T) {
var raw interface{} var raw interface{}
raw = PasswordKeyboardInteractive("foo") raw = PasswordKeyboardInteractive("foo")
if _, ok := raw.(ssh.ClientKeyboardInteractive); !ok { if _, ok := raw.(ssh.KeyboardInteractiveChallenge); !ok {
t.Fatal("PasswordKeyboardInteractive must implement ClientKeyboardInteractive") t.Fatal("PasswordKeyboardInteractive must implement KeyboardInteractiveChallenge")
} }
} }
func TestPasswordKeybardInteractive_Challenge(t *testing.T) { func TestPasswordKeybardInteractive_Challenge(t *testing.T) {
p := PasswordKeyboardInteractive("foo") 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 { if err != nil {
t.Fatalf("err not nil: %s", err) t.Fatalf("err not nil: %s", err)
} }

View File

@ -6,7 +6,7 @@ import (
) )
func testConn(t *testing.T) (net.Conn, net.Conn) { 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 { if err != nil {
t.Fatalf("err: %s", err) 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) { 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 { if err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
} }