From 282a95c2e9717d5b2e73c6856537b70f5c9316c1 Mon Sep 17 00:00:00 2001 From: Knut Ahlers Date: Sun, 21 Apr 2019 19:36:28 +0200 Subject: [PATCH] Move MFA plugins to own modules Signed-off-by: Knut Ahlers --- core.go | 11 ++++++++- mfa.go | 4 +-- plugins/mfa.go | 2 ++ mfa_duo.go => plugins/mfa/duo/mfa.go | 26 ++++++++++---------- mfa_totp.go => plugins/mfa/totp/mfa.go | 22 ++++++++--------- mfa_yubikey.go => plugins/mfa/yubikey/mfa.go | 22 ++++++++--------- 6 files changed, 48 insertions(+), 39 deletions(-) rename mfa_duo.go => plugins/mfa/duo/mfa.go (86%) rename mfa_totp.go => plugins/mfa/totp/mfa.go (85%) rename mfa_yubikey.go => plugins/mfa/yubikey/mfa.go (79%) diff --git a/core.go b/core.go index 4cae8c9..dcfadfb 100644 --- a/core.go +++ b/core.go @@ -1,7 +1,16 @@ package main -import "github.com/Luzifer/nginx-sso/plugins/auth/google" +import ( + "github.com/Luzifer/nginx-sso/plugins/auth/google" + "github.com/Luzifer/nginx-sso/plugins/mfa/duo" + "github.com/Luzifer/nginx-sso/plugins/mfa/totp" + mfa_yubikey "github.com/Luzifer/nginx-sso/plugins/mfa/yubikey" +) func registerModules() { registerAuthenticator(google.New(cookieStore)) + + registerMFAProvider(duo.New()) + registerMFAProvider(totp.New()) + registerMFAProvider(mfa_yubikey.New()) } diff --git a/mfa.go b/mfa.go index 73e4065..7aa43ac 100644 --- a/mfa.go +++ b/mfa.go @@ -10,11 +10,9 @@ import ( "github.com/Luzifer/nginx-sso/plugins" ) -const mfaLoginFieldName = "mfa-token" - var mfaLoginField = plugins.LoginField{ Label: "MFA Token", - Name: mfaLoginFieldName, + Name: plugins.MFALoginFieldName, Placeholder: "(optional)", Type: "text", } diff --git a/plugins/mfa.go b/plugins/mfa.go index e3301ca..f21c28b 100644 --- a/plugins/mfa.go +++ b/plugins/mfa.go @@ -2,6 +2,8 @@ package plugins import "net/http" +const MFALoginFieldName = "mfa-token" + type MFAProvider interface { // ProviderID needs to return an unique string to identify // this special MFA provider diff --git a/mfa_duo.go b/plugins/mfa/duo/mfa.go similarity index 86% rename from mfa_duo.go rename to plugins/mfa/duo/mfa.go index 4a49810..3f234f8 100644 --- a/mfa_duo.go +++ b/plugins/mfa/duo/mfa.go @@ -1,4 +1,4 @@ -package main +package duo import ( "net" @@ -21,29 +21,29 @@ const ( var mfaDuoTrustedIPHeaders = []string{"X-Forwarded-For", "X-Real-IP"} -func init() { - registerMFAProvider(&mfaDuo{}) -} - -type mfaDuo struct { +type MFADuo struct { IKey string `yaml:"ikey"` SKey string `yaml:"skey"` Host string `yaml:"host"` UserAgent string `yaml:"user_agent"` } +func New() *MFADuo { + return &MFADuo{} +} + // ProviderID needs to return an unique string to identify // this special MFA provider -func (m mfaDuo) ProviderID() (id string) { return "duo" } +func (m MFADuo) ProviderID() (id string) { return "duo" } // Configure loads the configuration for the Authenticator from the // global config.yaml file which is passed as a byte-slice. // If no configuration for the Authenticator is supplied the function // needs to return the plugins.ErrProviderUnconfigured -func (m *mfaDuo) Configure(yamlSource []byte) (err error) { +func (m *MFADuo) Configure(yamlSource []byte) (err error) { envelope := struct { MFA struct { - Duo *mfaDuo `yaml:"duo"` + Duo *MFADuo `yaml:"duo"` } `yaml:"mfa"` }{} @@ -64,7 +64,7 @@ func (m *mfaDuo) Configure(yamlSource []byte) (err error) { // ValidateMFA takes the user from the login cookie and performs a // validation against the provided MFA configuration for this user -func (m mfaDuo) ValidateMFA(res http.ResponseWriter, r *http.Request, user string, mfaCfgs []plugins.MFAConfig) error { +func (m MFADuo) ValidateMFA(res http.ResponseWriter, r *http.Request, user string, mfaCfgs []plugins.MFAConfig) error { var keyInput string // Look for mfaConfigs with own provider name @@ -81,7 +81,7 @@ func (m mfaDuo) ValidateMFA(res http.ResponseWriter, r *http.Request, user strin duo := authapi.NewAuthApi(*duoapi.NewDuoApi(m.IKey, m.SKey, m.Host, m.UserAgent, duoapi.SetTimeout(mfaDuoRequestTimeout))) for key, values := range r.Form { - if strings.HasSuffix(key, mfaLoginFieldName) && len(values[0]) > 0 { + if strings.HasSuffix(key, plugins.MFALoginFieldName) && len(values[0]) > 0 { keyInput = values[0] } } @@ -108,7 +108,7 @@ func (m mfaDuo) ValidateMFA(res http.ResponseWriter, r *http.Request, user strin return plugins.ErrNoValidUserFound } -func (m mfaDuo) findIP(r *http.Request) (string, error) { +func (m MFADuo) findIP(r *http.Request) (string, error) { for _, hdr := range mfaDuoTrustedIPHeaders { if value := r.Header.Get(hdr); value != "" { return m.parseIP(value) @@ -118,7 +118,7 @@ func (m mfaDuo) findIP(r *http.Request) (string, error) { return m.parseIP(r.RemoteAddr) } -func (m mfaDuo) parseIP(s string) (string, error) { +func (m MFADuo) parseIP(s string) (string, error) { ip, _, err := net.SplitHostPort(s) if err == nil { return ip, nil diff --git a/mfa_totp.go b/plugins/mfa/totp/mfa.go similarity index 85% rename from mfa_totp.go rename to plugins/mfa/totp/mfa.go index 39101a1..b572160 100644 --- a/mfa_totp.go +++ b/plugins/mfa/totp/mfa.go @@ -1,4 +1,4 @@ -package main +package totp import ( "net/http" @@ -12,27 +12,27 @@ import ( "github.com/Luzifer/nginx-sso/plugins" ) -func init() { - registerMFAProvider(&mfaTOTP{}) -} - -type mfaTOTP struct{} +type MFATOTP struct{} // ProviderID needs to return an unique string to identify // this special MFA provider -func (m mfaTOTP) ProviderID() (id string) { +func (m MFATOTP) ProviderID() (id string) { return "totp" } +func New() *MFATOTP { + return &MFATOTP{} +} + // Configure loads the configuration for the Authenticator from the // global config.yaml file which is passed as a byte-slice. // If no configuration for the Authenticator is supplied the function // needs to return the plugins.ErrProviderUnconfigured -func (m mfaTOTP) Configure(yamlSource []byte) (err error) { return nil } +func (m MFATOTP) Configure(yamlSource []byte) (err error) { return nil } // ValidateMFA takes the user from the login cookie and performs a // validation against the provided MFA configuration for this user -func (m mfaTOTP) ValidateMFA(res http.ResponseWriter, r *http.Request, user string, mfaCfgs []plugins.MFAConfig) error { +func (m MFATOTP) ValidateMFA(res http.ResponseWriter, r *http.Request, user string, mfaCfgs []plugins.MFAConfig) error { // Look for mfaConfigs with own provider name for _, c := range mfaCfgs { // Provider has been renamed, keep "google" for backwards compatibility @@ -46,7 +46,7 @@ func (m mfaTOTP) ValidateMFA(res http.ResponseWriter, r *http.Request, user stri } for key, values := range r.Form { - if strings.HasSuffix(key, mfaLoginFieldName) && values[0] == token { + if strings.HasSuffix(key, plugins.MFALoginFieldName) && values[0] == token { return nil } } @@ -56,7 +56,7 @@ func (m mfaTOTP) ValidateMFA(res http.ResponseWriter, r *http.Request, user stri return plugins.ErrNoValidUserFound } -func (m mfaTOTP) exec(c plugins.MFAConfig) (string, error) { +func (m MFATOTP) exec(c plugins.MFAConfig) (string, error) { secret := c.AttributeString("secret") // By default use Google Authenticator compatible settings diff --git a/mfa_yubikey.go b/plugins/mfa/yubikey/mfa.go similarity index 79% rename from mfa_yubikey.go rename to plugins/mfa/yubikey/mfa.go index 996e01c..8fa430b 100644 --- a/mfa_yubikey.go +++ b/plugins/mfa/yubikey/mfa.go @@ -1,4 +1,4 @@ -package main +package yubikey import ( "net/http" @@ -11,27 +11,27 @@ import ( "github.com/Luzifer/nginx-sso/plugins" ) -func init() { - registerMFAProvider(&mfaYubikey{}) -} - -type mfaYubikey struct { +type MFAYubikey struct { ClientID string `yaml:"client_id"` SecretKey string `yaml:"secret_key"` } +func New() *MFAYubikey { + return &MFAYubikey{} +} + // ProviderID needs to return an unique string to identify // this special MFA provider -func (m mfaYubikey) ProviderID() (id string) { return "yubikey" } +func (m MFAYubikey) ProviderID() (id string) { return "yubikey" } // Configure loads the configuration for the Authenticator from the // global config.yaml file which is passed as a byte-slice. // If no configuration for the Authenticator is supplied the function // needs to return the plugins.ErrProviderUnconfigured -func (m *mfaYubikey) Configure(yamlSource []byte) (err error) { +func (m *MFAYubikey) Configure(yamlSource []byte) (err error) { envelope := struct { MFA struct { - Yubikey *mfaYubikey `yaml:"yubikey"` + Yubikey *MFAYubikey `yaml:"yubikey"` } `yaml:"mfa"` }{} @@ -51,7 +51,7 @@ func (m *mfaYubikey) Configure(yamlSource []byte) (err error) { // ValidateMFA takes the user from the login cookie and performs a // validation against the provided MFA configuration for this user -func (m mfaYubikey) ValidateMFA(res http.ResponseWriter, r *http.Request, user string, mfaCfgs []plugins.MFAConfig) error { +func (m MFAYubikey) ValidateMFA(res http.ResponseWriter, r *http.Request, user string, mfaCfgs []plugins.MFAConfig) error { var keyInput string yubiAuth, err := yubigo.NewYubiAuth(m.ClientID, m.SecretKey) @@ -65,7 +65,7 @@ func (m mfaYubikey) ValidateMFA(res http.ResponseWriter, r *http.Request, user s } for key, values := range r.Form { - if strings.HasSuffix(key, mfaLoginFieldName) && strings.HasPrefix(values[0], c.AttributeString("device")) { + if strings.HasSuffix(key, plugins.MFALoginFieldName) && strings.HasPrefix(values[0], c.AttributeString("device")) { keyInput = values[0] } }