add testcases for start piper
This commit is contained in:
parent
fa2352a43d
commit
28b0937029
4 changed files with 352 additions and 44 deletions
|
|
@ -196,9 +196,7 @@ func main() {
|
|||
showVersion()
|
||||
dumpConfig()
|
||||
|
||||
startPiper(&config.piperdConfig)
|
||||
|
||||
return nil
|
||||
return startPiper(&config.piperdConfig)
|
||||
}
|
||||
|
||||
return command.Execute(args)
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ import (
|
|||
|
||||
"github.com/tg123/sshpiper/sshpiperd/auditor"
|
||||
"github.com/tg123/sshpiper/sshpiperd/challenger"
|
||||
"github.com/tg123/sshpiper/sshpiperd/upstream"
|
||||
"github.com/tg123/sshpiper/sshpiperd/registry"
|
||||
"github.com/tg123/sshpiper/sshpiperd/upstream"
|
||||
)
|
||||
|
||||
type piperdConfig struct {
|
||||
|
|
@ -23,72 +23,120 @@ type piperdConfig struct {
|
|||
AuditorDriver string `long:"auditor-driver" description:"Auditor for ssh connections piped by SSH Piper " env:"SSHPIPERD_AUDITOR" ini-name:"auditor-driver"`
|
||||
}
|
||||
|
||||
func getAndInstall(name string, get func(n string) registry.Plugin, install func(plugin registry.Plugin)) {
|
||||
func getAndInstall(name string, get func(n string) registry.Plugin, install func(plugin registry.Plugin) error) error {
|
||||
if name == "" {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
p := get(name)
|
||||
|
||||
if p == nil {
|
||||
logger.Fatalf("driver %v not found", name)
|
||||
return fmt.Errorf("driver %v not found", name)
|
||||
}
|
||||
|
||||
p.Init(logger)
|
||||
install(p)
|
||||
err := p.Init(logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return install(p)
|
||||
}
|
||||
|
||||
func startPiper(config *piperdConfig) {
|
||||
func installDrivers(piper *ssh.SSHPiperConfig, config *piperdConfig) (auditor.Provider, error) {
|
||||
|
||||
// install upstreamProvider driver
|
||||
if config.UpstreamDriver == "" {
|
||||
return nil, fmt.Errorf("must provider upstream driver")
|
||||
}
|
||||
|
||||
var bigbro auditor.Provider
|
||||
|
||||
for _, d := range []struct {
|
||||
name string
|
||||
get func(n string) registry.Plugin
|
||||
install func(plugin registry.Plugin) error
|
||||
}{
|
||||
// upstream driver
|
||||
{
|
||||
config.UpstreamDriver,
|
||||
func(n string) registry.Plugin {
|
||||
return upstream.Get(n)
|
||||
},
|
||||
func(plugin registry.Plugin) error {
|
||||
handler := plugin.(upstream.Provider).GetHandler()
|
||||
|
||||
if handler == nil {
|
||||
return fmt.Errorf("driver return nil handler")
|
||||
}
|
||||
|
||||
piper.FindUpstream = handler
|
||||
return nil
|
||||
},
|
||||
},
|
||||
// challenger driver
|
||||
{
|
||||
config.ChallengerDriver,
|
||||
func(n string) registry.Plugin {
|
||||
return challenger.Get(n)
|
||||
},
|
||||
func(plugin registry.Plugin) error {
|
||||
handler := plugin.(challenger.Provider).GetHandler()
|
||||
|
||||
if handler == nil {
|
||||
return fmt.Errorf("driver return nil handler")
|
||||
}
|
||||
|
||||
piper.AdditionalChallenge = handler
|
||||
return nil
|
||||
},
|
||||
},
|
||||
// auditor driver
|
||||
{
|
||||
config.AuditorDriver,
|
||||
func(n string) registry.Plugin {
|
||||
return auditor.Get(n)
|
||||
},
|
||||
func(plugin registry.Plugin) error {
|
||||
bigbro = plugin.(auditor.Provider)
|
||||
return nil
|
||||
},
|
||||
},
|
||||
} {
|
||||
err := getAndInstall(d.name, d.get, d.install)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return bigbro, nil
|
||||
}
|
||||
|
||||
func startPiper(config *piperdConfig) error {
|
||||
|
||||
logger.Println("sshpiper is about to start")
|
||||
|
||||
piper := &ssh.SSHPiperConfig{}
|
||||
|
||||
// install upstreamProvider driver
|
||||
if config.UpstreamDriver == "" {
|
||||
logger.Fatalf("must provider upstream driver")
|
||||
}
|
||||
|
||||
getAndInstall(config.UpstreamDriver, func(n string) registry.Plugin {
|
||||
return upstream.Get(n)
|
||||
}, func(plugin registry.Plugin) {
|
||||
piper.FindUpstream = plugin.(upstream.Provider).GetHandler()
|
||||
})
|
||||
|
||||
// install challenger
|
||||
getAndInstall(config.UpstreamDriver, func(n string) registry.Plugin {
|
||||
return challenger.Get(n)
|
||||
}, func(plugin registry.Plugin) {
|
||||
piper.AdditionalChallenge = plugin.(challenger.Provider).GetHandler()
|
||||
})
|
||||
|
||||
// install auditor
|
||||
var bigbro auditor.Provider
|
||||
getAndInstall(config.UpstreamDriver, func(n string) registry.Plugin {
|
||||
return auditor.Get(n)
|
||||
}, func(plugin registry.Plugin) {
|
||||
bigbro = plugin.(auditor.Provider)
|
||||
})
|
||||
bigbro, err := installDrivers(piper, config)
|
||||
|
||||
privateBytes, err := ioutil.ReadFile(config.PiperKeyFile)
|
||||
if err != nil {
|
||||
logger.Fatalln(err)
|
||||
return err
|
||||
}
|
||||
|
||||
private, err := ssh.ParsePrivateKey(privateBytes)
|
||||
if err != nil {
|
||||
logger.Fatalln(err)
|
||||
return err
|
||||
}
|
||||
|
||||
piper.AddHostKey(private)
|
||||
|
||||
listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", config.ListenAddr, config.Port))
|
||||
if err != nil {
|
||||
logger.Fatalf("failed to listen for connection: %v", err)
|
||||
return fmt.Errorf("failed to listen for connection: %v", err)
|
||||
}
|
||||
defer listener.Close()
|
||||
|
||||
logger.Printf("SSHPiperd started")
|
||||
logger.Printf("sshpiperd started")
|
||||
|
||||
for {
|
||||
c, err := listener.Accept()
|
||||
|
|
@ -122,4 +170,6 @@ func startPiper(config *piperdConfig) {
|
|||
logger.Printf("connection from %v closed reason: %v", c.RemoteAddr(), err)
|
||||
}()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,20 +1,280 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"testing"
|
||||
|
||||
"fmt"
|
||||
"github.com/tg123/sshpiper/sshpiperd/auditor"
|
||||
"github.com/tg123/sshpiper/sshpiperd/challenger"
|
||||
"github.com/tg123/sshpiper/sshpiperd/registry"
|
||||
"github.com/tg123/sshpiper/sshpiperd/upstream"
|
||||
"golang.org/x/crypto/ssh"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
type testplugin struct {
|
||||
name string
|
||||
init func(logger *log.Logger) error
|
||||
}
|
||||
|
||||
func (p *testplugin) GetName() string {
|
||||
return p.name
|
||||
}
|
||||
|
||||
func (p *testplugin) GetOpts() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *testplugin) Init(logger *log.Logger) error {
|
||||
if p.init == nil {
|
||||
return nil
|
||||
}
|
||||
return p.init(logger)
|
||||
}
|
||||
|
||||
func Test_getAndInstall(t *testing.T) {
|
||||
|
||||
// ignore empty
|
||||
getAndInstall("", func(n string) registry.Plugin {
|
||||
t.Errorf("should not call get")
|
||||
return nil
|
||||
}, func(plugin registry.Plugin) {
|
||||
}, func(plugin registry.Plugin) error {
|
||||
t.Errorf("should not call install")
|
||||
return nil
|
||||
})
|
||||
|
||||
// fail when not found
|
||||
err := getAndInstall("test", func(n string) registry.Plugin {
|
||||
if n != "test" {
|
||||
t.Errorf("plugin name changed")
|
||||
}
|
||||
return nil
|
||||
}, func(plugin registry.Plugin) error {
|
||||
t.Errorf("should not call install")
|
||||
return nil
|
||||
})
|
||||
|
||||
if err == nil {
|
||||
t.Errorf("should err when not found")
|
||||
}
|
||||
|
||||
// init err
|
||||
err = getAndInstall("test", func(n string) registry.Plugin {
|
||||
return &testplugin{
|
||||
init: func(logger *log.Logger) error {
|
||||
return fmt.Errorf("init failed")
|
||||
},
|
||||
}
|
||||
}, func(plugin registry.Plugin) error {
|
||||
return fmt.Errorf("test")
|
||||
})
|
||||
|
||||
if err == nil {
|
||||
t.Errorf("should err when not found")
|
||||
}
|
||||
|
||||
// call init
|
||||
inited := false
|
||||
installed := false
|
||||
err = getAndInstall("test", func(n string) registry.Plugin {
|
||||
if n != "test" {
|
||||
t.Errorf("plugin name changed")
|
||||
}
|
||||
return &testplugin{
|
||||
init: func(logger *log.Logger) error {
|
||||
inited = true
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}, func(plugin registry.Plugin) error {
|
||||
if !inited {
|
||||
t.Errorf("not inited")
|
||||
}
|
||||
|
||||
installed = true
|
||||
return nil
|
||||
})
|
||||
|
||||
if !installed {
|
||||
t.Errorf("not installed")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("should err when not found")
|
||||
}
|
||||
}
|
||||
|
||||
type testupstream struct {
|
||||
testplugin
|
||||
|
||||
h upstream.Handler
|
||||
}
|
||||
|
||||
func (t *testupstream) GetHandler() upstream.Handler {
|
||||
return t.h
|
||||
}
|
||||
|
||||
type testchallenger struct {
|
||||
testplugin
|
||||
|
||||
h challenger.Handler
|
||||
}
|
||||
|
||||
func (t *testchallenger) GetHandler() challenger.Handler {
|
||||
return t.h
|
||||
}
|
||||
|
||||
type testauditorprovider struct {
|
||||
testplugin
|
||||
|
||||
a auditor.Auditor
|
||||
}
|
||||
|
||||
func (t *testauditorprovider) Create(ssh.ConnMetadata) (auditor.Auditor, error) {
|
||||
return t.a, nil
|
||||
}
|
||||
|
||||
type testauditor struct {
|
||||
up auditor.Hook
|
||||
down auditor.Hook
|
||||
}
|
||||
|
||||
func (t *testauditor) GetUpstreamHook() auditor.Hook {
|
||||
return t.up
|
||||
}
|
||||
|
||||
func (t *testauditor) GetDownstreamHook() auditor.Hook {
|
||||
return t.down
|
||||
}
|
||||
|
||||
func (t *testauditor) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func Test_installDriver(t *testing.T) {
|
||||
var (
|
||||
upstreamName = fmt.Sprintf("u_%v", time.Now().UTC().UnixNano())
|
||||
challengerName = fmt.Sprintf("c_%v", time.Now().UTC().UnixNano())
|
||||
auditorName = fmt.Sprintf("a_%v", time.Now().UTC().UnixNano())
|
||||
)
|
||||
|
||||
findUpstream := func(conn ssh.ConnMetadata) (net.Conn, *ssh.SSHPiperAuthPipe, error) {
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
upstream.Register(upstreamName, &testupstream{
|
||||
testplugin: testplugin{
|
||||
name: upstreamName,
|
||||
},
|
||||
h: findUpstream,
|
||||
})
|
||||
|
||||
challenger.Register(challengerName, &testchallenger{
|
||||
testplugin: testplugin{
|
||||
name: upstreamName,
|
||||
},
|
||||
h: func(conn ssh.ConnMetadata, client ssh.KeyboardInteractiveChallenge) (bool, error) {
|
||||
return true, nil
|
||||
},
|
||||
})
|
||||
|
||||
auditor.Register(auditorName, &testauditorprovider{})
|
||||
|
||||
// empty driver name
|
||||
{
|
||||
piper := &ssh.SSHPiperConfig{}
|
||||
_, err := installDrivers(piper, &piperdConfig{
|
||||
UpstreamDriver: "",
|
||||
})
|
||||
|
||||
if err == nil {
|
||||
t.Errorf("should fail when empty driver")
|
||||
}
|
||||
}
|
||||
|
||||
// install upstream
|
||||
{
|
||||
piper := &ssh.SSHPiperConfig{}
|
||||
_, err := installDrivers(piper, &piperdConfig{
|
||||
UpstreamDriver: upstreamName,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("install failed %v", err)
|
||||
}
|
||||
|
||||
if _, _, err := piper.FindUpstream(nil); err != nil {
|
||||
t.Errorf("install wrong func")
|
||||
}
|
||||
|
||||
if piper.AdditionalChallenge != nil {
|
||||
t.Errorf("should not install challenger")
|
||||
}
|
||||
}
|
||||
|
||||
// install challenger
|
||||
{
|
||||
piper := &ssh.SSHPiperConfig{}
|
||||
_, err := installDrivers(piper, &piperdConfig{
|
||||
UpstreamDriver: upstreamName,
|
||||
ChallengerDriver: challengerName,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("install failed %v", err)
|
||||
}
|
||||
|
||||
if ok, err := piper.AdditionalChallenge(nil, nil); err != nil || !ok {
|
||||
t.Errorf("should install challenger")
|
||||
}
|
||||
}
|
||||
|
||||
// install auditor
|
||||
{
|
||||
piper := &ssh.SSHPiperConfig{}
|
||||
ap, err := installDrivers(piper, &piperdConfig{
|
||||
UpstreamDriver: upstreamName,
|
||||
AuditorDriver: auditorName,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("install failed %v", err)
|
||||
}
|
||||
|
||||
if ap == nil {
|
||||
t.Errorf("nil auditor provider")
|
||||
}
|
||||
|
||||
ap0 := ap.(*testauditorprovider)
|
||||
|
||||
ap0.a = &testauditor{
|
||||
up: func(conn ssh.ConnMetadata, msg []byte) ([]byte, error) {
|
||||
msg[0] = 42
|
||||
return msg, nil
|
||||
},
|
||||
down: func(conn ssh.ConnMetadata, msg []byte) ([]byte, error) {
|
||||
msg[0] = 100
|
||||
return msg, nil
|
||||
},
|
||||
}
|
||||
|
||||
a, err := ap.Create(nil)
|
||||
if err != nil {
|
||||
t.Errorf("install failed %v", err)
|
||||
}
|
||||
|
||||
m := []byte{0}
|
||||
|
||||
a.GetUpstreamHook()(nil, m)
|
||||
if m[0] != 42 {
|
||||
t.Errorf("upstream not handled")
|
||||
}
|
||||
|
||||
a.GetDownstreamHook()(nil, m)
|
||||
if m[0] != 100 {
|
||||
t.Errorf("downstream not handled")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,12 +11,12 @@ var githash = "0000000000"
|
|||
|
||||
func showVersion() {
|
||||
versionTemplate := template.Must(template.New("ver").Parse(`
|
||||
SSHPiper ver: {{.VER}} by Boshi Lian<farmer1992@gmail.com>
|
||||
sshpiperd by Boshi Lian<farmer1992@gmail.com>
|
||||
https://github.com/tg123/sshpiper
|
||||
|
||||
go runtime : {{.GOVER}}
|
||||
git hash : {{.GITHASH}}
|
||||
|
||||
Version : {{.VER}}
|
||||
Go Runtime : {{.GOVER}}
|
||||
Git Commit : {{.GITHASH}}
|
||||
`[1:]))
|
||||
|
||||
versionTemplate.Execute(os.Stdout, struct {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue