update sshpiper lib

This commit is contained in:
Boshi Lian 2018-02-25 04:06:38 +08:00
parent a4a8847e99
commit dd5a38bd8a
9 changed files with 244 additions and 119 deletions

2
Gopkg.lock generated
View file

@ -40,7 +40,7 @@
"ssh",
"ssh/testdata"
]
revision = "c832b236b4049eae471365acd18bc0b462a64a2b"
revision = "a3947c90260b2290d5db1b779520e75f21ad8baf"
source = "https://github.com/tg123/sshpiper.crypto"
[solve-meta]

View file

@ -42,7 +42,7 @@ func getAndInstall(name string, get func(n string) registry.Plugin, install func
return install(p)
}
func installDrivers(piper *ssh.SSHPiperConfig, config *piperdConfig, logger *log.Logger) (auditor.Provider, error) {
func installDrivers(piper *ssh.PiperConfig, config *piperdConfig, logger *log.Logger) (auditor.Provider, error) {
// install upstreamProvider driver
if config.UpstreamDriver == "" {
@ -115,7 +115,7 @@ func startPiper(config *piperdConfig, logger *log.Logger) error {
logger.Println("sshpiper is about to start")
piper := &ssh.SSHPiperConfig{}
piper := &ssh.PiperConfig{}
bigbro, err := installDrivers(piper, config, logger)

View file

@ -39,7 +39,7 @@ func connectServer(db *sql.DB, sid int64) (net.Conn, error) {
return net.Dial("tcp", addr)
}
func (w *mysqlWorkingDir) connectUpstream(db *sql.DB, uid int64, defuser string) (net.Conn, *ssh.SSHPiperAuthPipe, error) {
func (w *mysqlWorkingDir) connectUpstream(db *sql.DB, uid int64, defuser string) (net.Conn, *ssh.AuthPipe, error) {
o := crud.NewUpstream(db)
@ -64,7 +64,7 @@ func (w *mysqlWorkingDir) connectUpstream(db *sql.DB, uid int64, defuser string)
}
logger.Printf("connecting upstream id [%v] addr [%v]@[%v] ", uid, user, c.RemoteAddr())
return c, &ssh.SSHPiperAuthPipe{
return c, &ssh.AuthPipe{
User: user,
PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (ssh.AuthPipeType, ssh.AuthMethod, error) {
@ -134,7 +134,7 @@ func findByUsername(db *sql.DB, username string) (int64, error) {
}
//func (w *mysqlWorkingDir) FindUpstream(conn ssh.ConnMetadata, downkey ssh.PublicKey) (net.Conn, *ssh.SSHPiperAuthPipe, error) {
func (w *mysqlWorkingDir) FindUpstream(conn ssh.ConnMetadata) (net.Conn, *ssh.SSHPiperAuthPipe, error) {
func (w *mysqlWorkingDir) FindUpstream(conn ssh.ConnMetadata) (net.Conn, *ssh.AuthPipe, error) {
db, err := w.ConnectDB()
defer db.Close()

View file

@ -12,7 +12,7 @@ import (
// the returned auth pipe is to map/convert downstream auth method to another auth for
// connecting to upstream.
// e.g. map downstream public key to another upstream private key
type Handler func(conn ssh.ConnMetadata) (net.Conn, *ssh.SSHPiperAuthPipe, error)
type Handler func(conn ssh.ConnMetadata) (net.Conn, *ssh.AuthPipe, error)
// Provider is a factory for Upstream Provider
type Provider interface {

View file

@ -122,7 +122,7 @@ func parseUpstreamFile(data string) (string, string) {
return line, user
}
func findUpstreamFromUserfile(conn ssh.ConnMetadata) (net.Conn, *ssh.SSHPiperAuthPipe, error) {
func findUpstreamFromUserfile(conn ssh.ConnMetadata) (net.Conn, *ssh.AuthPipe, error) {
user := conn.User()
if !checkUsername(user) {
@ -152,7 +152,7 @@ func findUpstreamFromUserfile(conn ssh.ConnMetadata) (net.Conn, *ssh.SSHPiperAut
return nil, nil, err
}
return c, &ssh.SSHPiperAuthPipe{
return c, &ssh.AuthPipe{
User: mappedUser,
PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (ssh.AuthPipeType, ssh.AuthMethod, error) {

View file

@ -614,8 +614,8 @@ func TestClientAuthErrorList(t *testing.T) {
for i, e := range authErrs.Errors {
switch i {
case 0:
if _, ok := e.(*NoAuthError); !ok {
t.Fatalf("errors: got error type %T, want NoAuthError", e)
if e != NoAuthError {
t.Fatalf("errors: got error %v, want NoAuthError", e)
}
case 1:
if e != publicKeyErr {

View file

@ -297,7 +297,7 @@ func checkSourceAddress(addr net.Addr, sourceAddrs string) error {
// provided by the user failed to authenticate.
type ServerAuthError struct {
// Errors contains authentication errors returned by the authentication
// callback methods.
// callback methods. The first entry typically is NoAuthError.
Errors []error
}
@ -309,13 +309,11 @@ func (l ServerAuthError) Error() string {
return "[" + strings.Join(errs, ", ") + "]"
}
// NoAuthError is the unique error that is returned if no authentication method
// has been passed yet
type NoAuthError struct{}
func (e *NoAuthError) Error() string {
return "no auth passed yet"
}
// NoAuthError is the unique error that is returned if no
// authentication method has been passed yet. This happens as a normal
// part of the authentication loop, since the client first tries
// 'none' authentication to discover available methods.
var NoAuthError = errors.New("ssh: no auth passed yet")
func (s *connection) serverAuthenticate(config *ServerConfig) (*Permissions, error) {
sessionID := s.transport.getSessionID()
@ -371,7 +369,7 @@ userAuthLoop:
}
perms = nil
authErr := error(&NoAuthError{})
authErr := NoAuthError
switch userAuthReq.Method {
case "none":

View file

@ -11,54 +11,52 @@ import (
"net"
)
// AuthPipeType declares how sshpiper handle piped auth message
type AuthPipeType int
const (
// Do nothing but pass auth message to upstream
// AuthPipeTypePassThrough does nothing but pass auth message to upstream
AuthPipeTypePassThrough AuthPipeType = iota
// Convert auth message to AuthMetod return by callback and pass it to upstream
// AuthPipeTypeMap converts auth message to AuthMetod return by callback and pass it to upstream
AuthPipeTypeMap
// Discard auth message, do not pass it to uptream
// AuthPipeTypeDiscard discards auth message, do not pass it to uptream
AuthPipeTypeDiscard
// Convert auth message to NoneAuth and pass it to upstream
// AuthPipeTypeNone converts auth message to NoneAuth and pass it to upstream
AuthPipeTypeNone
)
// SSHPiperAuthPipe:
// Convert Auth
// Any Auth to Password
// AuthPipe contains the callbacks of auth msg mapping from downstream to upstream
//
// Any Auth to Public Key
// when AuthPipeType == AuthPipeTypeMap && AuthMethod == PublicKey
// SSHPiper will sign the auth packet message using the returned Signer.
// This func might be called twice, one is for query message, the other
// is real auth packet message.
// If any error occurs during this period, a NoneAuth packet will be sent to
// upstream ssh server instead.
//
// More info: https://github.com/tg123/sshpiper#publickey-sign-again
type SSHPiperAuthPipe struct {
type AuthPipe struct {
// Username to upstream
User string
// PublicKeyCallback, if non-nil, is called when downstream requests a password auth.
PasswordCallback func(conn ConnMetadata, password []byte) (AuthPipeType, AuthMethod, error)
// PublicKeyCallback, if non-nil, is called when downstream requests a publickey auth.
PublicKeyCallback func(conn ConnMetadata, key PublicKey) (AuthPipeType, AuthMethod, error)
// HostKeyCallback is called during the cryptographic
// UpstreamHostKeyCallback is called during the cryptographic
// handshake to validate the uptream server's host key. The piper
// configuration must supply this callback for the connection
// to succeed. The functions InsecureIgnoreHostKey or
// FixedHostKey can be used for simplistic host key checks.
// UpstreamHostKeyCallback HostKeyCallback
UpstreamHostKeyCallback HostKeyCallback
}
// SSHPiperConfig holds SSHPiper specific configuration data.
type SSHPiperConfig struct {
// PiperConfig holds SSHPiper specific configuration data.
type PiperConfig struct {
Config
hostKeys []Signer
@ -74,7 +72,7 @@ type SSHPiperConfig struct {
// and upstream username should be returned.
// SSHPiper will use the username from downstream if empty username is returned.
// If any error occurs, the piped connection will be closed.
FindUpstream func(conn ConnMetadata) (net.Conn, *SSHPiperAuthPipe, error)
FindUpstream func(conn ConnMetadata) (net.Conn, *AuthPipe, error)
// ServerVersion is the version identification string to announce in
// the public handshake.
@ -97,11 +95,11 @@ type pipedConn struct {
hookDownstreamMsg func(msg []byte) ([]byte, error)
}
// SSHPiperConn is a piped SSH connection, linking upstream ssh server and
// PiperConn is a piped SSH connection, linking upstream ssh server and
// downstream ssh client together. After the piped connection was created,
// The downstream ssh client is authenticated by upstream ssh server and
// AdditionalChallenge from SSHPiper.
type SSHPiperConn struct {
type PiperConn struct {
*pipedConn
HookUpstreamMsg func(conn ConnMetadata, msg []byte) ([]byte, error)
@ -110,7 +108,7 @@ type SSHPiperConn struct {
// Wait blocks until the piped connection has shut down, and returns the
// error causing the shutdown.
func (p *SSHPiperConn) Wait() error {
func (p *PiperConn) Wait() error {
p.pipedConn.hookUpstreamMsg = func(msg []byte) ([]byte, error) {
if p.HookUpstreamMsg != nil {
@ -133,22 +131,24 @@ func (p *SSHPiperConn) Wait() error {
}
// Close the piped connection create by SSHPiper
func (p *SSHPiperConn) Close() {
func (p *PiperConn) Close() {
p.pipedConn.Close()
}
func (p *SSHPiperConn) UpstreamConnMeta() ConnMetadata {
// UpstreamConnMeta returns the ConnMetadata of the piper and upstream
func (p *PiperConn) UpstreamConnMeta() ConnMetadata {
return p.pipedConn.upstream
}
func (p *SSHPiperConn) DownstreamConnMeta() ConnMetadata {
// DownstreamConnMeta returns the ConnMetadata of the piper and downstream
func (p *PiperConn) DownstreamConnMeta() ConnMetadata {
return p.pipedConn.downstream
}
// AddHostKey adds a private key as a SSHPiper host key. If an existing host
// key exists with the same algorithm, it is overwritten. Each SSHPiper
// config must have at least one host key.
func (s *SSHPiperConfig) AddHostKey(key Signer) {
func (s *PiperConfig) AddHostKey(key Signer) {
for i, k := range s.hostKeys {
if k.PublicKey().Type() == key.PublicKey().Type() {
s.hostKeys[i] = key
@ -162,7 +162,7 @@ func (s *SSHPiperConfig) AddHostKey(key Signer) {
// NewSSHPiperConn starts a piped ssh connection witch conn as its downstream transport.
// It handshake with downstream ssh client and upstream ssh server provicde by FindUpstream.
// If either handshake is unsuccessful, the whole piped connection will be closed.
func NewSSHPiperConn(conn net.Conn, piper *SSHPiperConfig) (pipe *SSHPiperConn, err error) {
func NewSSHPiperConn(conn net.Conn, piper *PiperConfig) (pipe *PiperConn, err error) {
if piper.FindUpstream == nil {
return nil, errors.New("sshpiper: must specify FindUpstream")
@ -251,6 +251,7 @@ func NewSSHPiperConn(conn net.Conn, piper *SSHPiperConfig) (pipe *SSHPiperConn,
u.Close()
}
}()
u.user = mappedUser
p := &pipedConn{
upstream: u,
@ -259,7 +260,7 @@ func NewSSHPiperConn(conn net.Conn, piper *SSHPiperConfig) (pipe *SSHPiperConn,
p.processAuthMsg = func(msg *userAuthRequestMsg) (*userAuthRequestMsg, error) {
var authType AuthPipeType = AuthPipeTypePassThrough
var authType = AuthPipeTypePassThrough
var authMethod AuthMethod
switch msg.Method {
@ -290,18 +291,16 @@ func NewSSHPiperConn(conn net.Conn, piper *SSHPiperConfig) (pipe *SSHPiperConn,
// discard msg
return nil, nil
} else {
}
ok, err := p.checkPublicKey(msg, downKey, sig)
ok, err := p.checkPublicKey(msg, downKey, sig)
if err != nil {
return nil, err
}
if !ok {
return noneAuthMsg(mappedUser), nil
}
if err != nil {
return nil, err
}
if !ok {
return noneAuthMsg(mappedUser), nil
}
case "password":
@ -406,7 +405,7 @@ func NewSSHPiperConn(conn net.Conn, piper *SSHPiperConfig) (pipe *SSHPiperConn,
return nil, err
}
return &SSHPiperConn{pipedConn: p}, nil
return &PiperConn{pipedConn: p}, nil
}
func (pipe *pipedConn) ack(key PublicKey) error {
@ -415,11 +414,7 @@ func (pipe *pipedConn) ack(key PublicKey) error {
PubKey: key.Marshal(),
}
if err := pipe.downstream.transport.writePacket(Marshal(&okMsg)); err != nil {
return err
}
return nil
return pipe.downstream.transport.writePacket(Marshal(&okMsg))
}
// not used after method to method map enable
@ -638,7 +633,6 @@ func (pipe *pipedConn) pipeAuth(initUserAuthMsg *userAuthRequestMsg) error {
if succ {
return nil
}
}
var packet []byte
@ -688,11 +682,7 @@ func (u *upstream) sendAuthReq() error {
return err
}
var serviceAccept serviceAcceptMsg
if err := Unmarshal(packet, &serviceAccept); err != nil {
return err
}
return nil
return Unmarshal(packet, &serviceAccept)
}
func newDownstream(c net.Conn, config *ServerConfig) (*downstream, error) {
@ -770,41 +760,39 @@ func (c *connection) clientHandshakeNoAuth(dialAddress string, config *ClientCon
if err := c.transport.waitSession(); err != nil {
return err
}
c.sessionID = c.transport.getSessionID()
return nil
}
func (s *connection) serverHandshakeNoAuth(config *ServerConfig) (*Permissions, error) {
func (c *connection) serverHandshakeNoAuth(config *ServerConfig) (*Permissions, error) {
if len(config.hostKeys) == 0 {
return nil, errors.New("ssh: server has no host keys")
}
var err error
if config.ServerVersion != "" {
s.serverVersion = []byte(config.ServerVersion)
c.serverVersion = []byte(config.ServerVersion)
} else {
s.serverVersion = []byte("SSH-2.0-SSHPiper")
c.serverVersion = []byte("SSH-2.0-SSHPiper")
}
s.clientVersion, err = exchangeVersions(s.sshConn.conn, s.serverVersion)
c.clientVersion, err = exchangeVersions(c.sshConn.conn, c.serverVersion)
if err != nil {
return nil, err
}
tr := newTransport(s.sshConn.conn, config.Rand, false /* not client */)
s.transport = newServerTransport(tr, s.clientVersion, s.serverVersion, config)
tr := newTransport(c.sshConn.conn, config.Rand, false /* not client */)
c.transport = newServerTransport(tr, c.clientVersion, c.serverVersion, config)
if err := s.transport.waitSession(); err != nil {
if err := c.transport.waitSession(); err != nil {
return nil, err
}
s.sessionID = s.transport.getSessionID()
c.sessionID = c.transport.getSessionID()
var packet []byte
if packet, err = s.transport.readPacket(); err != nil {
if packet, err = c.transport.readPacket(); err != nil {
return nil, err
}
@ -818,7 +806,7 @@ func (s *connection) serverHandshakeNoAuth(config *ServerConfig) (*Permissions,
serviceAccept := serviceAcceptMsg{
Service: serviceUserAuth,
}
if err := s.transport.writePacket(Marshal(&serviceAccept)); err != nil {
if err := c.transport.writePacket(Marshal(&serviceAccept)); err != nil {
return nil, err
}

View file

@ -20,16 +20,16 @@ func ExampleNewSSHPiperConn() {
// upstream addr
const serverAddr = "127.0.0.1:22"
piper := &SSHPiperConfig{
piper := &PiperConfig{
// return conn dial to serverAddr
FindUpstream: func(conn ConnMetadata) (net.Conn, *SSHPiperAuthPipe, error) {
FindUpstream: func(conn ConnMetadata) (net.Conn, *AuthPipe, error) {
c, err := net.Dial("tcp", serverAddr)
if err != nil {
return nil, nil, err
}
// change upstream username to root
return c, &SSHPiperAuthPipe{
return c, &AuthPipe{
User: "root",
UpstreamHostKeyCallback: InsecureIgnoreHostKey(),
}, nil
@ -71,7 +71,7 @@ func ExampleNewSSHPiperConn() {
// }}}
func dialPiper(piper *SSHPiperConfig) (net.Conn, error) {
func dialPiper(piper *PiperConfig, afterConn func(*PiperConn), t *testing.T) (net.Conn, error) {
c, s, err := netPipe()
if err != nil {
return nil, err
@ -86,10 +86,14 @@ func dialPiper(piper *SSHPiperConfig) (net.Conn, error) {
p, err := NewSSHPiperConn(s, piper)
if err != nil {
fmt.Println(err)
t.Errorf("failed to create piper conn %v", err)
return
}
if afterConn != nil {
afterConn(p)
}
p.Wait()
}()
@ -102,8 +106,8 @@ func TestPiperFindUpstreamCallback(t *testing.T) {
var called bool
c, err := dialPiper(&SSHPiperConfig{
FindUpstream: func(conn ConnMetadata) (net.Conn, *SSHPiperAuthPipe, error) {
c, err := dialPiper(&PiperConfig{
FindUpstream: func(conn ConnMetadata) (net.Conn, *AuthPipe, error) {
if username != conn.User() {
t.Errorf("different username")
}
@ -124,11 +128,11 @@ func TestPiperFindUpstreamCallback(t *testing.T) {
},
}, t)
return s, &SSHPiperAuthPipe{
return s, &AuthPipe{
UpstreamHostKeyCallback: InsecureIgnoreHostKey(),
}, err
},
})
}, nil, t)
if err != nil {
t.Fatalf("connect dial to piper: %v", err)
@ -153,8 +157,8 @@ func TestPiperFindUpstreamWithUserCallback(t *testing.T) {
var called bool
c, err := dialPiper(&SSHPiperConfig{
FindUpstream: func(conn ConnMetadata) (net.Conn, *SSHPiperAuthPipe, error) {
c, err := dialPiper(&PiperConfig{
FindUpstream: func(conn ConnMetadata) (net.Conn, *AuthPipe, error) {
s, err := dialUpstream(simpleEchoHandler, &ServerConfig{
PasswordCallback: func(conn ConnMetadata, password []byte) (*Permissions, error) {
@ -168,12 +172,12 @@ func TestPiperFindUpstreamWithUserCallback(t *testing.T) {
},
}, t)
return s, &SSHPiperAuthPipe{
return s, &AuthPipe{
User: mappedname,
UpstreamHostKeyCallback: InsecureIgnoreHostKey(),
}, err
},
})
}, nil, t)
if err != nil {
t.Fatalf("connect dial to piper: %v", err)
@ -208,12 +212,12 @@ func TestPiperMapPublicKey(t *testing.T) {
},
}
c, err := dialPiper(&SSHPiperConfig{
FindUpstream: func(conn ConnMetadata) (net.Conn, *SSHPiperAuthPipe, error) {
c, err := dialPiper(&PiperConfig{
FindUpstream: func(conn ConnMetadata) (net.Conn, *AuthPipe, error) {
s, err := dialUpstream(simpleEchoHandler, &ServerConfig{
PublicKeyCallback: certChecker.Authenticate,
}, t)
return s, &SSHPiperAuthPipe{
return s, &AuthPipe{
PublicKeyCallback: func(conn ConnMetadata, key PublicKey) (AuthPipeType, AuthMethod, error) {
return AuthPipeTypeMap, PublicKeys(testSigners["rsa"]), nil
@ -222,7 +226,7 @@ func TestPiperMapPublicKey(t *testing.T) {
UpstreamHostKeyCallback: InsecureIgnoreHostKey(),
}, err
},
})
}, nil, t)
if err != nil {
t.Fatalf("connect dial to piper: %v", err)
@ -260,8 +264,8 @@ func TestPiperMapPublicKeyToPassword(t *testing.T) {
var called bool
c, err := dialPiper(&SSHPiperConfig{
FindUpstream: func(conn ConnMetadata) (net.Conn, *SSHPiperAuthPipe, error) {
c, err := dialPiper(&PiperConfig{
FindUpstream: func(conn ConnMetadata) (net.Conn, *AuthPipe, error) {
s, err := dialUpstream(simpleEchoHandler, &ServerConfig{
PasswordCallback: func(conn ConnMetadata, password []byte) (*Permissions, error) {
t.Errorf("PasswordCallback should not be called")
@ -273,7 +277,7 @@ func TestPiperMapPublicKeyToPassword(t *testing.T) {
return certChecker.Authenticate(conn, key)
},
}, t)
return s, &SSHPiperAuthPipe{
return s, &AuthPipe{
PasswordCallback: func(conn ConnMetadata, password []byte) (AuthPipeType, AuthMethod, error) {
if string(password) != "mypassword" {
t.Errorf("password not equal")
@ -285,7 +289,7 @@ func TestPiperMapPublicKeyToPassword(t *testing.T) {
UpstreamHostKeyCallback: InsecureIgnoreHostKey(),
}, err
},
})
}, nil, t)
if err != nil {
t.Fatalf("connect dial to piper: %v", err)
@ -311,8 +315,8 @@ func TestPiperMapPublicKeyToPassword(t *testing.T) {
func TestPiperPasswordToMapPublicKey(t *testing.T) {
var called bool
c, err := dialPiper(&SSHPiperConfig{
FindUpstream: func(conn ConnMetadata) (net.Conn, *SSHPiperAuthPipe, error) {
c, err := dialPiper(&PiperConfig{
FindUpstream: func(conn ConnMetadata) (net.Conn, *AuthPipe, error) {
s, err := dialUpstream(simpleEchoHandler, &ServerConfig{
PasswordCallback: func(conn ConnMetadata, password []byte) (*Permissions, error) {
called = true
@ -329,7 +333,7 @@ func TestPiperPasswordToMapPublicKey(t *testing.T) {
return nil, nil
},
}, t)
return s, &SSHPiperAuthPipe{
return s, &AuthPipe{
PublicKeyCallback: func(conn ConnMetadata, key PublicKey) (AuthPipeType, AuthMethod, error) {
return AuthPipeTypeMap, Password("mypassword"), nil
@ -338,7 +342,7 @@ func TestPiperPasswordToMapPublicKey(t *testing.T) {
UpstreamHostKeyCallback: InsecureIgnoreHostKey(),
}, err
},
})
}, nil, t)
if err != nil {
t.Fatalf("connect dial to piper: %v", err)
@ -368,8 +372,8 @@ func TestPiperServerWithBanner(t *testing.T) {
var called bool
c, err := dialPiper(&SSHPiperConfig{
FindUpstream: func(conn ConnMetadata) (net.Conn, *SSHPiperAuthPipe, error) {
c, err := dialPiper(&PiperConfig{
FindUpstream: func(conn ConnMetadata) (net.Conn, *AuthPipe, error) {
if username != conn.User() {
t.Errorf("different username")
}
@ -387,12 +391,12 @@ func TestPiperServerWithBanner(t *testing.T) {
},
}, t)
return s, &SSHPiperAuthPipe{
return s, &AuthPipe{
User: mappedname,
UpstreamHostKeyCallback: InsecureIgnoreHostKey(),
}, err
},
})
}, nil, t)
if err != nil {
t.Fatalf("connect dial to piper: %v", err)
@ -437,8 +441,8 @@ func TestPiperUsernameNotChangedWithinSession(t *testing.T) {
},
}
c, err := dialPiper(&SSHPiperConfig{
FindUpstream: func(conn ConnMetadata) (net.Conn, *SSHPiperAuthPipe, error) {
c, err := dialPiper(&PiperConfig{
FindUpstream: func(conn ConnMetadata) (net.Conn, *AuthPipe, error) {
s, err := dialUpstream(simpleEchoHandler, &ServerConfig{
PasswordCallback: func(conn ConnMetadata, password []byte) (*Permissions, error) {
if conn.User() != mappedname {
@ -459,10 +463,10 @@ func TestPiperUsernameNotChangedWithinSession(t *testing.T) {
t.Errorf("bad mapped username")
}
callcount += 1
callcount++
},
}, t)
return s, &SSHPiperAuthPipe{
return s, &AuthPipe{
User: mappedname,
PublicKeyCallback: func(conn ConnMetadata, key PublicKey) (AuthPipeType, AuthMethod, error) {
@ -472,7 +476,7 @@ func TestPiperUsernameNotChangedWithinSession(t *testing.T) {
UpstreamHostKeyCallback: InsecureIgnoreHostKey(),
}, err
},
})
}, nil, t)
if err != nil {
t.Fatalf("connect dial to piper: %v", err)
@ -498,7 +502,7 @@ func TestPiperUsernameNotChangedWithinSession(t *testing.T) {
}
func TestPiperAdditionalChallenge(t *testing.T) {
c, err := dialPiper(&SSHPiperConfig{
c, err := dialPiper(&PiperConfig{
AdditionalChallenge: func(conn ConnMetadata, challenge KeyboardInteractiveChallenge) (bool, error) {
ans, err := challenge("user",
"instruction",
@ -516,13 +520,13 @@ func TestPiperAdditionalChallenge(t *testing.T) {
}
return false, fmt.Errorf("keyboard-interactive failed")
},
FindUpstream: func(conn ConnMetadata) (net.Conn, *SSHPiperAuthPipe, error) {
FindUpstream: func(conn ConnMetadata) (net.Conn, *AuthPipe, error) {
s, err := dialUpstream(simpleEchoHandler, &ServerConfig{NoClientAuth: true}, t)
return s, &SSHPiperAuthPipe{
return s, &AuthPipe{
UpstreamHostKeyCallback: InsecureIgnoreHostKey(),
}, err
},
})
}, nil, t)
if err != nil {
t.Fatalf("connect dial to piper: %v", err)
@ -588,17 +592,152 @@ func dialUpstream(handler serverType, upstream *ServerConfig, t *testing.T) (net
return c, nil
}
func TestPiperPipeData(t *testing.T) {
func TestPiperConnMeta(t *testing.T) {
c, err := dialPiper(&SSHPiperConfig{
FindUpstream: func(conn ConnMetadata) (net.Conn, *SSHPiperAuthPipe, error) {
wait := make(chan int)
c, err := dialPiper(&PiperConfig{
FindUpstream: func(conn ConnMetadata) (net.Conn, *AuthPipe, error) {
s, err := dialUpstream(simpleEchoHandler, &ServerConfig{NoClientAuth: true}, t)
return s, &SSHPiperAuthPipe{
return s, &AuthPipe{
User: "up",
UpstreamHostKeyCallback: InsecureIgnoreHostKey(),
}, err
},
}, func(p *PiperConn) {
if p.DownstreamConnMeta().User() != "down" {
t.Errorf("different downstream user")
}
if p.UpstreamConnMeta().User() != "up" {
t.Errorf("different upstream user")
}
wait <- 0
}, t)
_, _, _, err = NewClientConn(c, "", &ClientConfig{
User: "down",
Auth: []AuthMethod{new(noneAuth)},
HostKeyCallback: InsecureIgnoreHostKey(),
})
if err != nil {
t.Fatalf("can connect to piper %v", err)
}
<-wait
}
func TestPiperConnMsgHook(t *testing.T) {
wait := make(chan int)
c, err := dialPiper(&PiperConfig{
FindUpstream: func(conn ConnMetadata) (net.Conn, *AuthPipe, error) {
s, err := dialUpstream(simpleEchoHandler, &ServerConfig{NoClientAuth: true}, t)
return s, &AuthPipe{
UpstreamHostKeyCallback: InsecureIgnoreHostKey(),
}, err
},
}, func(p *PiperConn) {
p.HookDownstreamMsg = func(conn ConnMetadata, msg []byte) ([]byte, error) {
if msg[0] == msgChannelData {
m := channelDataMsg{}
Unmarshal(msg, &m)
if string(m.Rest) != "123456" {
t.Errorf("msg not equal")
}
m.Length = 3
m.Rest = []byte("654")
return Marshal(m), nil
}
return msg, nil
}
p.HookUpstreamMsg = func(conn ConnMetadata, msg []byte) ([]byte, error) {
if msg[0] == msgChannelData {
m := channelDataMsg{}
Unmarshal(msg, &m)
if string(m.Rest) != "654" {
t.Errorf("msg not equal")
}
m.Length = 7
m.Rest = []byte("abcdefg")
return Marshal(m), nil
}
return msg, nil
}
wait <- 0
}, t)
sshc, chans, reqs, err := NewClientConn(c, "", &ClientConfig{
User: "test",
Auth: []AuthMethod{new(noneAuth)},
HostKeyCallback: InsecureIgnoreHostKey(),
})
if err != nil {
t.Fatalf("can connect to piper %v", err)
}
<-wait
conn := NewClient(sshc, chans, reqs)
defer conn.Close()
session, err := conn.NewSession()
if err != nil {
t.Fatal(err)
}
defer session.Close()
stdin, err := session.StdinPipe()
if err != nil {
t.Fatalf("StdinPipe failed: %v", err)
}
stdout, err := session.StdoutPipe()
if err != nil {
t.Fatalf("StdoutPipe failed: %v", err)
}
data := []byte(`123456`)
_, err = stdin.Write(data)
if err != nil {
t.Fatalf("Write failed: %v", err)
}
stdin.Close()
res, err := ioutil.ReadAll(stdout)
if err != nil {
t.Fatalf("Read failed: %v", err)
}
if !bytes.Equal([]byte(`abcdefg`), res) {
t.Fatalf("Read differed from write, wrote: %v, read: %v", data, res)
}
}
func TestPiperPipeData(t *testing.T) {
c, err := dialPiper(&PiperConfig{
FindUpstream: func(conn ConnMetadata) (net.Conn, *AuthPipe, error) {
s, err := dialUpstream(simpleEchoHandler, &ServerConfig{NoClientAuth: true}, t)
return s, &AuthPipe{
UpstreamHostKeyCallback: InsecureIgnoreHostKey(),
}, err
},
}, nil, t)
if err != nil {
t.Fatalf("connect dial to piper: %v", err)
}