1
0
Fork 0
mirror of https://github.com/Luzifer/nginx-sso.git synced 2024-12-20 04:41:17 +00:00

Move MFA plugins to own modules

Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
Knut Ahlers 2019-04-21 19:36:28 +02:00
parent 8d968ce29d
commit 282a95c2e9
Signed by: luzifer
GPG key ID: DC2729FDD34BE99E
6 changed files with 48 additions and 39 deletions

11
core.go
View file

@ -1,7 +1,16 @@
package main 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() { func registerModules() {
registerAuthenticator(google.New(cookieStore)) registerAuthenticator(google.New(cookieStore))
registerMFAProvider(duo.New())
registerMFAProvider(totp.New())
registerMFAProvider(mfa_yubikey.New())
} }

4
mfa.go
View file

@ -10,11 +10,9 @@ import (
"github.com/Luzifer/nginx-sso/plugins" "github.com/Luzifer/nginx-sso/plugins"
) )
const mfaLoginFieldName = "mfa-token"
var mfaLoginField = plugins.LoginField{ var mfaLoginField = plugins.LoginField{
Label: "MFA Token", Label: "MFA Token",
Name: mfaLoginFieldName, Name: plugins.MFALoginFieldName,
Placeholder: "(optional)", Placeholder: "(optional)",
Type: "text", Type: "text",
} }

View file

@ -2,6 +2,8 @@ package plugins
import "net/http" import "net/http"
const MFALoginFieldName = "mfa-token"
type MFAProvider interface { type MFAProvider interface {
// ProviderID needs to return an unique string to identify // ProviderID needs to return an unique string to identify
// this special MFA provider // this special MFA provider

View file

@ -1,4 +1,4 @@
package main package duo
import ( import (
"net" "net"
@ -21,29 +21,29 @@ const (
var mfaDuoTrustedIPHeaders = []string{"X-Forwarded-For", "X-Real-IP"} var mfaDuoTrustedIPHeaders = []string{"X-Forwarded-For", "X-Real-IP"}
func init() { type MFADuo struct {
registerMFAProvider(&mfaDuo{})
}
type mfaDuo struct {
IKey string `yaml:"ikey"` IKey string `yaml:"ikey"`
SKey string `yaml:"skey"` SKey string `yaml:"skey"`
Host string `yaml:"host"` Host string `yaml:"host"`
UserAgent string `yaml:"user_agent"` UserAgent string `yaml:"user_agent"`
} }
func New() *MFADuo {
return &MFADuo{}
}
// ProviderID needs to return an unique string to identify // ProviderID needs to return an unique string to identify
// this special MFA provider // 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 // Configure loads the configuration for the Authenticator from the
// global config.yaml file which is passed as a byte-slice. // global config.yaml file which is passed as a byte-slice.
// If no configuration for the Authenticator is supplied the function // If no configuration for the Authenticator is supplied the function
// needs to return the plugins.ErrProviderUnconfigured // needs to return the plugins.ErrProviderUnconfigured
func (m *mfaDuo) Configure(yamlSource []byte) (err error) { func (m *MFADuo) Configure(yamlSource []byte) (err error) {
envelope := struct { envelope := struct {
MFA struct { MFA struct {
Duo *mfaDuo `yaml:"duo"` Duo *MFADuo `yaml:"duo"`
} `yaml:"mfa"` } `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 // ValidateMFA takes the user from the login cookie and performs a
// validation against the provided MFA configuration for this user // 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 var keyInput string
// Look for mfaConfigs with own provider name // 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))) duo := authapi.NewAuthApi(*duoapi.NewDuoApi(m.IKey, m.SKey, m.Host, m.UserAgent, duoapi.SetTimeout(mfaDuoRequestTimeout)))
for key, values := range r.Form { 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] keyInput = values[0]
} }
} }
@ -108,7 +108,7 @@ func (m mfaDuo) ValidateMFA(res http.ResponseWriter, r *http.Request, user strin
return plugins.ErrNoValidUserFound 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 { for _, hdr := range mfaDuoTrustedIPHeaders {
if value := r.Header.Get(hdr); value != "" { if value := r.Header.Get(hdr); value != "" {
return m.parseIP(value) return m.parseIP(value)
@ -118,7 +118,7 @@ func (m mfaDuo) findIP(r *http.Request) (string, error) {
return m.parseIP(r.RemoteAddr) 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) ip, _, err := net.SplitHostPort(s)
if err == nil { if err == nil {
return ip, nil return ip, nil

View file

@ -1,4 +1,4 @@
package main package totp
import ( import (
"net/http" "net/http"
@ -12,27 +12,27 @@ import (
"github.com/Luzifer/nginx-sso/plugins" "github.com/Luzifer/nginx-sso/plugins"
) )
func init() { type MFATOTP struct{}
registerMFAProvider(&mfaTOTP{})
}
type mfaTOTP struct{}
// ProviderID needs to return an unique string to identify // ProviderID needs to return an unique string to identify
// this special MFA provider // this special MFA provider
func (m mfaTOTP) ProviderID() (id string) { func (m MFATOTP) ProviderID() (id string) {
return "totp" return "totp"
} }
func New() *MFATOTP {
return &MFATOTP{}
}
// Configure loads the configuration for the Authenticator from the // Configure loads the configuration for the Authenticator from the
// global config.yaml file which is passed as a byte-slice. // global config.yaml file which is passed as a byte-slice.
// If no configuration for the Authenticator is supplied the function // If no configuration for the Authenticator is supplied the function
// needs to return the plugins.ErrProviderUnconfigured // 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 // ValidateMFA takes the user from the login cookie and performs a
// validation against the provided MFA configuration for this user // 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 // Look for mfaConfigs with own provider name
for _, c := range mfaCfgs { for _, c := range mfaCfgs {
// Provider has been renamed, keep "google" for backwards compatibility // 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 { 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 return nil
} }
} }
@ -56,7 +56,7 @@ func (m mfaTOTP) ValidateMFA(res http.ResponseWriter, r *http.Request, user stri
return plugins.ErrNoValidUserFound 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") secret := c.AttributeString("secret")
// By default use Google Authenticator compatible settings // By default use Google Authenticator compatible settings

View file

@ -1,4 +1,4 @@
package main package yubikey
import ( import (
"net/http" "net/http"
@ -11,27 +11,27 @@ import (
"github.com/Luzifer/nginx-sso/plugins" "github.com/Luzifer/nginx-sso/plugins"
) )
func init() { type MFAYubikey struct {
registerMFAProvider(&mfaYubikey{})
}
type mfaYubikey struct {
ClientID string `yaml:"client_id"` ClientID string `yaml:"client_id"`
SecretKey string `yaml:"secret_key"` SecretKey string `yaml:"secret_key"`
} }
func New() *MFAYubikey {
return &MFAYubikey{}
}
// ProviderID needs to return an unique string to identify // ProviderID needs to return an unique string to identify
// this special MFA provider // 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 // Configure loads the configuration for the Authenticator from the
// global config.yaml file which is passed as a byte-slice. // global config.yaml file which is passed as a byte-slice.
// If no configuration for the Authenticator is supplied the function // If no configuration for the Authenticator is supplied the function
// needs to return the plugins.ErrProviderUnconfigured // needs to return the plugins.ErrProviderUnconfigured
func (m *mfaYubikey) Configure(yamlSource []byte) (err error) { func (m *MFAYubikey) Configure(yamlSource []byte) (err error) {
envelope := struct { envelope := struct {
MFA struct { MFA struct {
Yubikey *mfaYubikey `yaml:"yubikey"` Yubikey *MFAYubikey `yaml:"yubikey"`
} `yaml:"mfa"` } `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 // ValidateMFA takes the user from the login cookie and performs a
// validation against the provided MFA configuration for this user // 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 var keyInput string
yubiAuth, err := yubigo.NewYubiAuth(m.ClientID, m.SecretKey) 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 { 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] keyInput = values[0]
} }
} }