support challenger as plugin
This commit is contained in:
parent
c2d67f63fa
commit
f312057e85
10 changed files with 154 additions and 80 deletions
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
6
sshpiperd/challenger/loader/load.go
Normal file
6
sshpiperd/challenger/loader/load.go
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
package loader
|
||||
|
||||
import (
|
||||
_ "github.com/tg123/sshpiper/sshpiperd/challenger/pam"
|
||||
_ "github.com/tg123/sshpiper/sshpiperd/challenger/welcometext"
|
||||
)
|
||||
1
sshpiperd/challenger/pam/doc.go
Normal file
1
sshpiperd/challenger/pam/doc.go
Normal file
|
|
@ -0,0 +1 @@
|
|||
package pam
|
||||
|
|
@ -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))
|
||||
}
|
||||
42
sshpiperd/challenger/plugin.go
Normal file
42
sshpiperd/challenger/plugin.go
Normal file
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
32
sshpiperd/challenger/welcometext/welcometext.go
Normal file
32
sshpiperd/challenger/welcometext/welcometext.go
Normal file
|
|
@ -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
|
||||
}))
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue