From f312057e851dc995da9a8837c2861d97c33ef0a3 Mon Sep 17 00:00:00 2001 From: Boshi Lian Date: Mon, 19 Feb 2018 18:21:43 +0800 Subject: [PATCH] support challenger as plugin --- sshpiperd/challenger/challenger.go | 51 +++++++++---------- sshpiperd/challenger/loader/load.go | 6 +++ sshpiperd/challenger/pam/doc.go | 1 + .../challenger/{ => pam}/pam_challenger.go | 14 +++-- sshpiperd/challenger/plugin.go | 42 +++++++++++++++ sshpiperd/challenger/welcome_text.go | 17 ------- .../challenger/welcometext/welcometext.go | 32 ++++++++++++ sshpiperd/cmd.go | 45 ++++++++-------- sshpiperd/sshpiperd.go | 19 +++---- sshpiperd/upstream/provider.go | 7 ++- 10 files changed, 154 insertions(+), 80 deletions(-) create mode 100644 sshpiperd/challenger/loader/load.go create mode 100644 sshpiperd/challenger/pam/doc.go rename sshpiperd/challenger/{ => pam}/pam_challenger.go (91%) create mode 100644 sshpiperd/challenger/plugin.go delete mode 100644 sshpiperd/challenger/welcome_text.go create mode 100644 sshpiperd/challenger/welcometext/welcometext.go diff --git a/sshpiperd/challenger/challenger.go b/sshpiperd/challenger/challenger.go index d4d43f8c..e4ad4e3e 100644 --- a/sshpiperd/challenger/challenger.go +++ b/sshpiperd/challenger/challenger.go @@ -1,41 +1,36 @@ package challenger import ( - "fmt" - "sort" - "golang.org/x/crypto/ssh" + + "github.com/tg123/sshpiper/sshpiperd/registry" ) -type Challenger func(conn ssh.ConnMetadata, client ssh.KeyboardInteractiveChallenge) (bool, error) +type ChallengerHandler func(conn ssh.ConnMetadata, client ssh.KeyboardInteractiveChallenge) (bool, error) -var challengers = make(map[string]Challenger) +type Challenger interface { + registry.Plugin -// copied from database/sql - -func Register(name string, challenger Challenger) { - if challenger == nil { - panic("challenger is nil") - } - if _, dup := challengers[name]; dup { - panic("Register twice for challenger" + name) - } - challengers[name] = challenger + GetChallengerHandler() ChallengerHandler } -func Challengers() []string { - var list []string - for name := range challengers { - list = append(list, name) - } - sort.Strings(list) - return list +var ( + drivers = registry.NewRegistry() +) + +func Register(name string, driver Challenger) { + drivers.Register(name, driver) } -func GetChallenger(name string) (Challenger, error) { - challenger, ok := challengers[name] - if !ok { - return nil, fmt.Errorf("no such challenger:" + name) - } - return challenger, nil +func All() []string { + return drivers.Drivers() +} + +func Get(name string) Challenger { + if d, ok := drivers.Get(name).(Challenger); ok { + return d + + } + + return nil } diff --git a/sshpiperd/challenger/loader/load.go b/sshpiperd/challenger/loader/load.go new file mode 100644 index 00000000..debf5516 --- /dev/null +++ b/sshpiperd/challenger/loader/load.go @@ -0,0 +1,6 @@ +package loader + +import ( + _ "github.com/tg123/sshpiper/sshpiperd/challenger/pam" + _ "github.com/tg123/sshpiper/sshpiperd/challenger/welcometext" +) diff --git a/sshpiperd/challenger/pam/doc.go b/sshpiperd/challenger/pam/doc.go new file mode 100644 index 00000000..4cebb8e9 --- /dev/null +++ b/sshpiperd/challenger/pam/doc.go @@ -0,0 +1 @@ +package pam diff --git a/sshpiperd/challenger/pam_challenger.go b/sshpiperd/challenger/pam/pam_challenger.go similarity index 91% rename from sshpiperd/challenger/pam_challenger.go rename to sshpiperd/challenger/pam/pam_challenger.go index 7b5b5ef9..2f59dd28 100644 --- a/sshpiperd/challenger/pam_challenger.go +++ b/sshpiperd/challenger/pam/pam_challenger.go @@ -1,12 +1,16 @@ // +build pam -package challenger +package pam import ( "fmt" - pam "github.com/vvanpo/golang-pam" - "golang.org/x/crypto/ssh" "os" + + "golang.org/x/crypto/ssh" + + pam "github.com/vvanpo/golang-pam" + + "github.com/tg123/sshpiperd/challenger" ) const ( @@ -61,10 +65,10 @@ func pamChallenger(conn ssh.ConnMetadata, client ssh.KeyboardInteractiveChalleng } func init() { - if _, err := os.Stat(SSHPIPER_PAM_SERVICE_FILE); os.IsNotExist(err) { + return } - Register("pam", pamChallenger) + challenger.Registry(challenger.NewFromHandler("pam", pamChallenger, nil, nil)) } diff --git a/sshpiperd/challenger/plugin.go b/sshpiperd/challenger/plugin.go new file mode 100644 index 00000000..2bc75003 --- /dev/null +++ b/sshpiperd/challenger/plugin.go @@ -0,0 +1,42 @@ +package challenger + +import ( + "log" +) + +type plugin struct { + name string + init func(logger *log.Logger) error + opts interface{} + handler ChallengerHandler +} + +func (p *plugin) GetName() string { + return p.name +} + +func (p *plugin) GetOpts() interface{} { + return p.opts +} + +func (p *plugin) GetChallengerHandler() ChallengerHandler { + return p.handler +} + +func (p *plugin) Init(logger *log.Logger) error { + logger.Printf("challenger: %v init", p.name) + + if p.init != nil { + return p.init(logger) + } + return nil +} + +func NewFromHandler(name string, handler ChallengerHandler, opts interface{}, init func(glogger *log.Logger) error) Challenger { + return &plugin{ + name: name, + init: init, + opts: opts, + handler: handler, + } +} diff --git a/sshpiperd/challenger/welcome_text.go b/sshpiperd/challenger/welcome_text.go deleted file mode 100644 index b92c9a9d..00000000 --- a/sshpiperd/challenger/welcome_text.go +++ /dev/null @@ -1,17 +0,0 @@ -package challenger - -import ( - "golang.org/x/crypto/ssh" -) - -// piper.AdditionalChallenge = challenger.MakeWelcomeChallenger("Please Use your phone to do the authentication") - -func MakeWelcomeChallenger(text string) Challenger { - return func(conn ssh.ConnMetadata, client ssh.KeyboardInteractiveChallenge) (bool, error) { - - client(conn.User(), text, nil, nil) - - return true, nil - } - -} diff --git a/sshpiperd/challenger/welcometext/welcometext.go b/sshpiperd/challenger/welcometext/welcometext.go new file mode 100644 index 00000000..18b02d6e --- /dev/null +++ b/sshpiperd/challenger/welcometext/welcometext.go @@ -0,0 +1,32 @@ +package challenger + +import ( + "log" + + "golang.org/x/crypto/ssh" + + "github.com/tg123/sshpiper/sshpiperd/challenger" +) + +func makeWelcomeChallenger(text string) challenger.ChallengerHandler { + return func(conn ssh.ConnMetadata, client ssh.KeyboardInteractiveChallenge) (bool, error) { + + client(conn.User(), text, nil, nil) + + return true, nil + } +} + +func init() { + + var h challenger.ChallengerHandler + + config := &struct { + WelcomeText string `long:"challenger-welcometext" description:"Show a welcome text when connect to sshpiper server" ini-name:"challenger-welcometext"` + }{} + + challenger.Register("welcometext", challenger.NewFromHandler("welcometext", h, config, func(logger *log.Logger) error { + h = makeWelcomeChallenger(config.WelcomeText) + return nil + })) +} diff --git a/sshpiperd/cmd.go b/sshpiperd/cmd.go index 9bd01ba9..f234c63c 100644 --- a/sshpiperd/cmd.go +++ b/sshpiperd/cmd.go @@ -6,6 +6,9 @@ import ( "github.com/jessevdk/go-flags" + "github.com/tg123/sshpiper/sshpiperd/challenger" + _ "github.com/tg123/sshpiper/sshpiperd/challenger/loader" + "github.com/tg123/sshpiper/sshpiperd/registry" "github.com/tg123/sshpiper/sshpiperd/upstream" _ "github.com/tg123/sshpiper/sshpiperd/upstream/loader" ) @@ -32,6 +35,25 @@ func addOpt(parser *flags.Parser, name string, data interface{}) { } } +func addPlugins(parser *flags.Parser, name string, pluginNames []string, getter func(n string) registry.Plugin) { + for _, n := range pluginNames { + + p := getter(n) + + opt := p.GetOpts() + + if opt == nil { + continue + } + + _, err := parser.AddGroup(name+"."+p.GetName(), "", opt) + + if err != nil { + panic(err) + } + } +} + func main() { parser := flags.NewNamedParser("sshpiperd", flags.Default) @@ -60,28 +82,11 @@ func main() { Logfile string `long:"log" description:"Logfile path. Leave empty or any error occurs will fall back to stdout" env:"SSHPIPERD_LOG_PATH" ini-name:"log-path"` ConfigFile flags.Filename `long:"config" description:"Config file path. Higher priority than arg options and environment variables" default:"/etc/sshpiperd.ini" no-ini:"true"` }{} + addOpt(parser, "sshpiperd", config) - // registry upstream - //upstreamOpt := make(map[string]interface{}) - for _, n := range upstream.All() { - - u := upstream.Get(n) - - opt := u.GetOpts() - - if opt == nil { - continue - } - - _, err := parser.AddGroup("upstream."+u.GetName(), "", opt) - - if err != nil { - panic(err) - } - - //upstreamOpt[u.GetName()] = opt - } + addPlugins(parser, "upstream", upstream.All(), func(n string) registry.Plugin { return upstream.Get(n) }) + addPlugins(parser, "challenger", challenger.All(), func(n string) registry.Plugin { return challenger.Get(n) }) if _, err := parser.Parse(); err != nil { return diff --git a/sshpiperd/sshpiperd.go b/sshpiperd/sshpiperd.go index 28d9f8f4..ddb7f639 100644 --- a/sshpiperd/sshpiperd.go +++ b/sshpiperd/sshpiperd.go @@ -16,18 +16,18 @@ type piperdConfig struct { Port uint `short:"p" long:"port" description:"Listening Port" default:"2222" env:"SSHPIPERD_PORT" ini-name:"listen-port"` PiperKeyFile string `short:"i" long:"server-key" description:"Server key file for SSH Piper" default:"/etc/ssh/ssh_host_rsa_key" env:"SSHPIPERD_SERVER_KEY" ini-name:"server-key"` - UpstreamDriver string `short:"d" long:"upstream-driver" description:"Upstream provider driver" default:"workingdir" env:"SSHPIPERD_UPSTREAM_DRIVER"` - ChallengerDriver string `short:"c" long:"challenger-driver" description:"Additional challenger name, e.g. pam, empty for no additional challenge" env:"SSHPIPERD_CHALLENGER"` + UpstreamDriver string `short:"u" long:"upstream-driver" description:"Upstream provider driver" default:"workingdir" env:"SSHPIPERD_UPSTREAM_DRIVER" ini-name:"upstream-driver"` + ChallengerDriver string `short:"c" long:"challenger-driver" description:"Additional challenger name, e.g. pam, empty for no additional challenge" env:"SSHPIPERD_CHALLENGER" ini-name:"challenger-driver"` } func startPiper(config *piperdConfig) { logger.Println("sshpiper is about to start") - // init upstream + // install upstream driver upstream := upstream.Get(config.UpstreamDriver) if upstream == nil { - logger.Fatal("upstream driver %v not found", config.UpstreamDriver) + logger.Fatalf("upstream driver %v not found", config.UpstreamDriver) } upstream.Init(logger) @@ -35,15 +35,16 @@ func startPiper(config *piperdConfig) { FindUpstream: upstream.GetFindUpstreamHandle(), } - // TODO move to plugin + // install challenger if config.ChallengerDriver != "" { - ac, err := challenger.GetChallenger(config.ChallengerDriver) - if err != nil { - logger.Fatalln("failed to load challenger", err) + ac := challenger.Get(config.ChallengerDriver) + if ac == nil { + logger.Fatalf("challenger driver %v not found", config.ChallengerDriver) } logger.Printf("using additional challenger %s", config.ChallengerDriver) - piper.AdditionalChallenge = ac + ac.Init(logger) + piper.AdditionalChallenge = ac.GetChallengerHandler() } privateBytes, err := ioutil.ReadFile(config.PiperKeyFile) diff --git a/sshpiperd/upstream/provider.go b/sshpiperd/upstream/provider.go index 4e0c9ac1..243c206f 100644 --- a/sshpiperd/upstream/provider.go +++ b/sshpiperd/upstream/provider.go @@ -29,5 +29,10 @@ func All() []string { } func Get(name string) UpstreamProvider { - return drivers.Get(name).(UpstreamProvider) + if d, ok := drivers.Get(name).(UpstreamProvider); ok { + return d + + } + + return nil }