mirror of
https://github.com/Luzifer/nginx-sso.git
synced 2024-12-20 12:51:17 +00:00
Move auth plugins to own modules
Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
parent
282a95c2e9
commit
29beaa6fa3
6 changed files with 131 additions and 92 deletions
10
core.go
10
core.go
|
@ -1,14 +1,24 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/Luzifer/nginx-sso/plugins/auth/crowd"
|
||||
"github.com/Luzifer/nginx-sso/plugins/auth/google"
|
||||
"github.com/Luzifer/nginx-sso/plugins/auth/ldap"
|
||||
"github.com/Luzifer/nginx-sso/plugins/auth/simple"
|
||||
"github.com/Luzifer/nginx-sso/plugins/auth/token"
|
||||
auth_yubikey "github.com/Luzifer/nginx-sso/plugins/auth/yubikey"
|
||||
"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(crowd.New())
|
||||
registerAuthenticator(ldap.New(cookieStore))
|
||||
registerAuthenticator(google.New(cookieStore))
|
||||
registerAuthenticator(simple.New(cookieStore))
|
||||
registerAuthenticator(token.New())
|
||||
registerAuthenticator(auth_yubikey.New(cookieStore))
|
||||
|
||||
registerMFAProvider(duo.New())
|
||||
registerMFAProvider(totp.New())
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package main
|
||||
package crowd
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
@ -11,11 +11,7 @@ import (
|
|||
"github.com/Luzifer/nginx-sso/plugins"
|
||||
)
|
||||
|
||||
func init() {
|
||||
registerAuthenticator(&authCrowd{})
|
||||
}
|
||||
|
||||
type authCrowd struct {
|
||||
type AuthCrowd struct {
|
||||
URL string `yaml:"url"`
|
||||
AppName string `yaml:"app_name"`
|
||||
AppPassword string `yaml:"app_pass"`
|
||||
|
@ -23,18 +19,22 @@ type authCrowd struct {
|
|||
crowd crowd.Crowd
|
||||
}
|
||||
|
||||
func New() *AuthCrowd {
|
||||
return &AuthCrowd{}
|
||||
}
|
||||
|
||||
// AuthenticatorID needs to return an unique string to identify
|
||||
// this special authenticator
|
||||
func (a authCrowd) AuthenticatorID() string { return "crowd" }
|
||||
func (a AuthCrowd) AuthenticatorID() string { return "crowd" }
|
||||
|
||||
// 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 (a *authCrowd) Configure(yamlSource []byte) error {
|
||||
func (a *AuthCrowd) Configure(yamlSource []byte) error {
|
||||
envelope := struct {
|
||||
Providers struct {
|
||||
Crowd *authCrowd `yaml:"crowd"`
|
||||
Crowd *AuthCrowd `yaml:"crowd"`
|
||||
} `yaml:"providers"`
|
||||
}{}
|
||||
|
||||
|
@ -64,7 +64,7 @@ func (a *authCrowd) Configure(yamlSource []byte) error {
|
|||
// a cookie, header or other methods
|
||||
// If no user was detected the plugins.ErrNoValidUserFound needs to be
|
||||
// returned
|
||||
func (a authCrowd) DetectUser(res http.ResponseWriter, r *http.Request) (string, []string, error) {
|
||||
func (a AuthCrowd) DetectUser(res http.ResponseWriter, r *http.Request) (string, []string, error) {
|
||||
cc, err := a.crowd.GetCookieConfig()
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
|
@ -108,7 +108,7 @@ func (a authCrowd) DetectUser(res http.ResponseWriter, r *http.Request) (string,
|
|||
// in order to use DetectUser for the next login.
|
||||
// If the user did not login correctly the plugins.ErrNoValidUserFound
|
||||
// needs to be returned
|
||||
func (a authCrowd) Login(res http.ResponseWriter, r *http.Request) (string, []plugins.MFAConfig, error) {
|
||||
func (a AuthCrowd) Login(res http.ResponseWriter, r *http.Request) (string, []plugins.MFAConfig, error) {
|
||||
username := r.FormValue(strings.Join([]string{a.AuthenticatorID(), "username"}, "-"))
|
||||
password := r.FormValue(strings.Join([]string{a.AuthenticatorID(), "password"}, "-"))
|
||||
|
||||
|
@ -141,7 +141,7 @@ func (a authCrowd) Login(res http.ResponseWriter, r *http.Request) (string, []pl
|
|||
// LoginFields needs to return the fields required for this login
|
||||
// method. If no login using this method is possible the function
|
||||
// needs to return nil.
|
||||
func (a authCrowd) LoginFields() (fields []plugins.LoginField) {
|
||||
func (a AuthCrowd) LoginFields() (fields []plugins.LoginField) {
|
||||
return []plugins.LoginField{
|
||||
{
|
||||
Label: "Username",
|
||||
|
@ -160,7 +160,7 @@ func (a authCrowd) LoginFields() (fields []plugins.LoginField) {
|
|||
|
||||
// Logout is called when the user visits the logout endpoint and
|
||||
// needs to destroy any persistent stored cookies
|
||||
func (a authCrowd) Logout(res http.ResponseWriter, r *http.Request) (err error) {
|
||||
func (a AuthCrowd) Logout(res http.ResponseWriter, r *http.Request) (err error) {
|
||||
cc, err := a.crowd.GetCookieConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -184,4 +184,4 @@ func (a authCrowd) Logout(res http.ResponseWriter, r *http.Request) (err error)
|
|||
// configuration return true. If this is true the login interface
|
||||
// will display an additional field for this provider for the user
|
||||
// to fill in their MFA token.
|
||||
func (a authCrowd) SupportsMFA() bool { return false }
|
||||
func (a AuthCrowd) SupportsMFA() bool { return false }
|
|
@ -1,4 +1,4 @@
|
|||
package main
|
||||
package ldap
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
|
@ -10,6 +10,8 @@ import (
|
|||
ldap "gopkg.in/ldap.v2"
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/gorilla/sessions"
|
||||
|
||||
"github.com/Luzifer/nginx-sso/plugins"
|
||||
)
|
||||
|
||||
|
@ -18,11 +20,7 @@ const (
|
|||
authLDAPProtoLDAPs = "ldaps"
|
||||
)
|
||||
|
||||
func init() {
|
||||
registerAuthenticator(&authLDAP{})
|
||||
}
|
||||
|
||||
type authLDAP struct {
|
||||
type AuthLDAP struct {
|
||||
EnableBasicAuth bool `yaml:"enable_basic_auth"`
|
||||
GroupMembershipFilter string `yaml:"group_membership_filter"`
|
||||
GroupSearchBase string `yaml:"group_search_base"`
|
||||
|
@ -37,20 +35,30 @@ type authLDAP struct {
|
|||
ValidateHostname string `yaml:"validate_hostname"`
|
||||
AllowInsecure bool `yaml:"allow_insecure"`
|
||||
} `yaml:"tls_config"`
|
||||
|
||||
cookie plugins.CookieConfig
|
||||
cookieStore *sessions.CookieStore
|
||||
}
|
||||
|
||||
func New(cs *sessions.CookieStore) *AuthLDAP {
|
||||
return &AuthLDAP{
|
||||
cookieStore: cs,
|
||||
}
|
||||
}
|
||||
|
||||
// AuthenticatorID needs to return an unique string to identify
|
||||
// this special authenticator
|
||||
func (a authLDAP) AuthenticatorID() string { return "ldap" }
|
||||
func (a AuthLDAP) AuthenticatorID() string { return "ldap" }
|
||||
|
||||
// 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 (a *authLDAP) Configure(yamlSource []byte) error {
|
||||
func (a *AuthLDAP) Configure(yamlSource []byte) error {
|
||||
envelope := struct {
|
||||
Cookie plugins.CookieConfig `yaml:"cookie"`
|
||||
Providers struct {
|
||||
LDAP *authLDAP `yaml:"ldap"`
|
||||
LDAP *AuthLDAP `yaml:"ldap"`
|
||||
} `yaml:"providers"`
|
||||
}{}
|
||||
|
||||
|
@ -74,6 +82,8 @@ func (a *authLDAP) Configure(yamlSource []byte) error {
|
|||
a.UsernameAttribute = envelope.Providers.LDAP.UsernameAttribute
|
||||
a.TLSConfig = envelope.Providers.LDAP.TLSConfig
|
||||
|
||||
a.cookie = envelope.Cookie
|
||||
|
||||
// Set defaults
|
||||
if a.UserSearchFilter == "" {
|
||||
a.UserSearchFilter = `(uid={0})`
|
||||
|
@ -100,7 +110,7 @@ func (a *authLDAP) Configure(yamlSource []byte) error {
|
|||
// a cookie, header or other methods
|
||||
// If no user was detected the plugins.ErrNoValidUserFound needs to be
|
||||
// returned
|
||||
func (a authLDAP) DetectUser(res http.ResponseWriter, r *http.Request) (string, []string, error) {
|
||||
func (a AuthLDAP) DetectUser(res http.ResponseWriter, r *http.Request) (string, []string, error) {
|
||||
var alias, user string
|
||||
|
||||
if a.EnableBasicAuth {
|
||||
|
@ -116,7 +126,7 @@ func (a authLDAP) DetectUser(res http.ResponseWriter, r *http.Request) (string,
|
|||
}
|
||||
|
||||
if user == "" {
|
||||
sess, err := cookieStore.Get(r, strings.Join([]string{mainCfg.Cookie.Prefix, a.AuthenticatorID()}, "-"))
|
||||
sess, err := a.cookieStore.Get(r, strings.Join([]string{a.cookie.Prefix, a.AuthenticatorID()}, "-"))
|
||||
if err != nil {
|
||||
return "", nil, plugins.ErrNoValidUserFound
|
||||
}
|
||||
|
@ -132,7 +142,7 @@ func (a authLDAP) DetectUser(res http.ResponseWriter, r *http.Request) (string,
|
|||
}
|
||||
|
||||
// We had a cookie, lets renew it
|
||||
sess.Options = mainCfg.Cookie.GetSessionOpts()
|
||||
sess.Options = a.cookie.GetSessionOpts()
|
||||
if err := sess.Save(r, res); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
@ -149,7 +159,7 @@ func (a authLDAP) DetectUser(res http.ResponseWriter, r *http.Request) (string,
|
|||
// in order to use DetectUser for the next login.
|
||||
// If the user did not login correctly the plugins.ErrNoValidUserFound
|
||||
// needs to be returned
|
||||
func (a authLDAP) Login(res http.ResponseWriter, r *http.Request) (string, []plugins.MFAConfig, error) {
|
||||
func (a AuthLDAP) Login(res http.ResponseWriter, r *http.Request) (string, []plugins.MFAConfig, error) {
|
||||
username := r.FormValue(strings.Join([]string{a.AuthenticatorID(), "username"}, "-"))
|
||||
password := r.FormValue(strings.Join([]string{a.AuthenticatorID(), "password"}, "-"))
|
||||
|
||||
|
@ -163,8 +173,8 @@ func (a authLDAP) Login(res http.ResponseWriter, r *http.Request) (string, []plu
|
|||
return "", nil, err
|
||||
}
|
||||
|
||||
sess, _ := cookieStore.Get(r, strings.Join([]string{mainCfg.Cookie.Prefix, a.AuthenticatorID()}, "-")) // #nosec G104 - On error empty session is returned
|
||||
sess.Options = mainCfg.Cookie.GetSessionOpts()
|
||||
sess, _ := a.cookieStore.Get(r, strings.Join([]string{a.cookie.Prefix, a.AuthenticatorID()}, "-")) // #nosec G104 - On error empty session is returned
|
||||
sess.Options = a.cookie.GetSessionOpts()
|
||||
sess.Values["user"] = userDN
|
||||
sess.Values["alias"] = alias
|
||||
return userDN, nil, sess.Save(r, res)
|
||||
|
@ -173,7 +183,7 @@ func (a authLDAP) Login(res http.ResponseWriter, r *http.Request) (string, []plu
|
|||
// LoginFields needs to return the fields required for this login
|
||||
// method. If no login using this method is possible the function
|
||||
// needs to return nil.
|
||||
func (a authLDAP) LoginFields() (fields []plugins.LoginField) {
|
||||
func (a AuthLDAP) LoginFields() (fields []plugins.LoginField) {
|
||||
return []plugins.LoginField{
|
||||
{
|
||||
Label: "Username",
|
||||
|
@ -192,16 +202,16 @@ func (a authLDAP) LoginFields() (fields []plugins.LoginField) {
|
|||
|
||||
// Logout is called when the user visits the logout endpoint and
|
||||
// needs to destroy any persistent stored cookies
|
||||
func (a authLDAP) Logout(res http.ResponseWriter, r *http.Request) (err error) {
|
||||
sess, _ := cookieStore.Get(r, strings.Join([]string{mainCfg.Cookie.Prefix, a.AuthenticatorID()}, "-")) // #nosec G104 - On error empty session is returned
|
||||
sess.Options = mainCfg.Cookie.GetSessionOpts()
|
||||
func (a AuthLDAP) Logout(res http.ResponseWriter, r *http.Request) (err error) {
|
||||
sess, _ := a.cookieStore.Get(r, strings.Join([]string{a.cookie.Prefix, a.AuthenticatorID()}, "-")) // #nosec G104 - On error empty session is returned
|
||||
sess.Options = a.cookie.GetSessionOpts()
|
||||
sess.Options.MaxAge = -1 // Instant delete
|
||||
return sess.Save(r, res)
|
||||
}
|
||||
|
||||
// checkLogin searches for the username using the specified UserSearchFilter
|
||||
// and returns the UserDN and an error (plugins.ErrNoValidUserFound / processing error)
|
||||
func (a authLDAP) checkLogin(username, password, aliasAttribute string) (string, string, error) {
|
||||
func (a AuthLDAP) checkLogin(username, password, aliasAttribute string) (string, string, error) {
|
||||
l, err := a.dial()
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
|
@ -242,7 +252,7 @@ func (a authLDAP) checkLogin(username, password, aliasAttribute string) (string,
|
|||
return userDN, alias, nil
|
||||
}
|
||||
|
||||
func (a authLDAP) portFromScheme(scheme, override string) string {
|
||||
func (a AuthLDAP) portFromScheme(scheme, override string) string {
|
||||
if override != "" {
|
||||
return override
|
||||
}
|
||||
|
@ -258,7 +268,7 @@ func (a authLDAP) portFromScheme(scheme, override string) string {
|
|||
}
|
||||
|
||||
// dial connects to the LDAP server and authenticates using manager_dn
|
||||
func (a authLDAP) dial() (*ldap.Conn, error) {
|
||||
func (a AuthLDAP) dial() (*ldap.Conn, error) {
|
||||
u, err := url.Parse(a.Server)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -305,7 +315,7 @@ func (a authLDAP) dial() (*ldap.Conn, error) {
|
|||
}
|
||||
|
||||
// getUserGroups searches for groups containing the user
|
||||
func (a authLDAP) getUserGroups(userDN, alias string) ([]string, error) {
|
||||
func (a AuthLDAP) getUserGroups(userDN, alias string) ([]string, error) {
|
||||
l, err := a.dial()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -343,4 +353,4 @@ func (a authLDAP) getUserGroups(userDN, alias string) ([]string, error) {
|
|||
// configuration return true. If this is true the login interface
|
||||
// will display an additional field for this provider for the user
|
||||
// to fill in their MFA token.
|
||||
func (a authLDAP) SupportsMFA() bool { return false } // TODO: Implement
|
||||
func (a AuthLDAP) SupportsMFA() bool { return false } // TODO: Implement
|
|
@ -1,4 +1,4 @@
|
|||
package main
|
||||
package simple
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
@ -7,33 +7,41 @@ import (
|
|||
"golang.org/x/crypto/bcrypt"
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/gorilla/sessions"
|
||||
|
||||
"github.com/Luzifer/go_helpers/str"
|
||||
"github.com/Luzifer/nginx-sso/plugins"
|
||||
)
|
||||
|
||||
func init() {
|
||||
registerAuthenticator(&authSimple{})
|
||||
}
|
||||
|
||||
type authSimple struct {
|
||||
type AuthSimple struct {
|
||||
EnableBasicAuth bool `yaml:"enable_basic_auth"`
|
||||
Users map[string]string `yaml:"users"`
|
||||
Groups map[string][]string `yaml:"groups"`
|
||||
MFA map[string][]plugins.MFAConfig `yaml:"mfa"`
|
||||
|
||||
cookie plugins.CookieConfig
|
||||
cookieStore *sessions.CookieStore
|
||||
}
|
||||
|
||||
func New(cs *sessions.CookieStore) *AuthSimple {
|
||||
return &AuthSimple{
|
||||
cookieStore: cs,
|
||||
}
|
||||
}
|
||||
|
||||
// AuthenticatorID needs to return an unique string to identify
|
||||
// this special authenticator
|
||||
func (a authSimple) AuthenticatorID() string { return "simple" }
|
||||
func (a AuthSimple) AuthenticatorID() string { return "simple" }
|
||||
|
||||
// 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 (a *authSimple) Configure(yamlSource []byte) error {
|
||||
func (a *AuthSimple) Configure(yamlSource []byte) error {
|
||||
envelope := struct {
|
||||
Cookie plugins.CookieConfig `yaml:"cookie"`
|
||||
Providers struct {
|
||||
Simple *authSimple `yaml:"simple"`
|
||||
Simple *AuthSimple `yaml:"simple"`
|
||||
} `yaml:"providers"`
|
||||
}{}
|
||||
|
||||
|
@ -50,6 +58,8 @@ func (a *authSimple) Configure(yamlSource []byte) error {
|
|||
a.Groups = envelope.Providers.Simple.Groups
|
||||
a.MFA = envelope.Providers.Simple.MFA
|
||||
|
||||
a.cookie = envelope.Cookie
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -57,7 +67,7 @@ func (a *authSimple) Configure(yamlSource []byte) error {
|
|||
// a cookie, header or other methods
|
||||
// If no user was detected the plugins.ErrNoValidUserFound needs to be
|
||||
// returned
|
||||
func (a authSimple) DetectUser(res http.ResponseWriter, r *http.Request) (string, []string, error) {
|
||||
func (a AuthSimple) DetectUser(res http.ResponseWriter, r *http.Request) (string, []string, error) {
|
||||
var user string
|
||||
|
||||
if a.EnableBasicAuth {
|
||||
|
@ -76,7 +86,7 @@ func (a authSimple) DetectUser(res http.ResponseWriter, r *http.Request) (string
|
|||
}
|
||||
|
||||
if user == "" {
|
||||
sess, err := cookieStore.Get(r, strings.Join([]string{mainCfg.Cookie.Prefix, a.AuthenticatorID()}, "-"))
|
||||
sess, err := a.cookieStore.Get(r, strings.Join([]string{a.cookie.Prefix, a.AuthenticatorID()}, "-"))
|
||||
if err != nil {
|
||||
return "", nil, plugins.ErrNoValidUserFound
|
||||
}
|
||||
|
@ -88,7 +98,7 @@ func (a authSimple) DetectUser(res http.ResponseWriter, r *http.Request) (string
|
|||
}
|
||||
|
||||
// We had a cookie, lets renew it
|
||||
sess.Options = mainCfg.Cookie.GetSessionOpts()
|
||||
sess.Options = a.cookie.GetSessionOpts()
|
||||
if err := sess.Save(r, res); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
@ -110,7 +120,7 @@ func (a authSimple) DetectUser(res http.ResponseWriter, r *http.Request) (string
|
|||
// in order to use DetectUser for the next login.
|
||||
// If the user did not login correctly the plugins.ErrNoValidUserFound
|
||||
// needs to be returned
|
||||
func (a authSimple) Login(res http.ResponseWriter, r *http.Request) (string, []plugins.MFAConfig, error) {
|
||||
func (a AuthSimple) Login(res http.ResponseWriter, r *http.Request) (string, []plugins.MFAConfig, error) {
|
||||
username := r.FormValue(strings.Join([]string{a.AuthenticatorID(), "username"}, "-"))
|
||||
password := r.FormValue(strings.Join([]string{a.AuthenticatorID(), "password"}, "-"))
|
||||
|
||||
|
@ -122,8 +132,8 @@ func (a authSimple) Login(res http.ResponseWriter, r *http.Request) (string, []p
|
|||
continue
|
||||
}
|
||||
|
||||
sess, _ := cookieStore.Get(r, strings.Join([]string{mainCfg.Cookie.Prefix, a.AuthenticatorID()}, "-")) // #nosec G104 - On error empty session is returned
|
||||
sess.Options = mainCfg.Cookie.GetSessionOpts()
|
||||
sess, _ := a.cookieStore.Get(r, strings.Join([]string{a.cookie.Prefix, a.AuthenticatorID()}, "-")) // #nosec G104 - On error empty session is returned
|
||||
sess.Options = a.cookie.GetSessionOpts()
|
||||
sess.Values["user"] = u
|
||||
return u, a.MFA[u], sess.Save(r, res)
|
||||
}
|
||||
|
@ -134,7 +144,7 @@ func (a authSimple) Login(res http.ResponseWriter, r *http.Request) (string, []p
|
|||
// LoginFields needs to return the fields required for this login
|
||||
// method. If no login using this method is possible the function
|
||||
// needs to return nil.
|
||||
func (a authSimple) LoginFields() (fields []plugins.LoginField) {
|
||||
func (a AuthSimple) LoginFields() (fields []plugins.LoginField) {
|
||||
return []plugins.LoginField{
|
||||
{
|
||||
Label: "Username",
|
||||
|
@ -153,9 +163,9 @@ func (a authSimple) LoginFields() (fields []plugins.LoginField) {
|
|||
|
||||
// Logout is called when the user visits the logout endpoint and
|
||||
// needs to destroy any persistent stored cookies
|
||||
func (a authSimple) Logout(res http.ResponseWriter, r *http.Request) (err error) {
|
||||
sess, _ := cookieStore.Get(r, strings.Join([]string{mainCfg.Cookie.Prefix, a.AuthenticatorID()}, "-")) // #nosec G104 - On error empty session is returned
|
||||
sess.Options = mainCfg.Cookie.GetSessionOpts()
|
||||
func (a AuthSimple) Logout(res http.ResponseWriter, r *http.Request) (err error) {
|
||||
sess, _ := a.cookieStore.Get(r, strings.Join([]string{a.cookie.Prefix, a.AuthenticatorID()}, "-")) // #nosec G104 - On error empty session is returned
|
||||
sess.Options = a.cookie.GetSessionOpts()
|
||||
sess.Options.MaxAge = -1 // Instant delete
|
||||
return sess.Save(r, res)
|
||||
}
|
||||
|
@ -165,4 +175,4 @@ func (a authSimple) Logout(res http.ResponseWriter, r *http.Request) (err error)
|
|||
// configuration return true. If this is true the login interface
|
||||
// will display an additional field for this provider for the user
|
||||
// to fill in their MFA token.
|
||||
func (a authSimple) SupportsMFA() bool { return true }
|
||||
func (a AuthSimple) SupportsMFA() bool { return true }
|
|
@ -1,4 +1,4 @@
|
|||
package main
|
||||
package token
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
@ -10,27 +10,27 @@ import (
|
|||
yaml "gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
func init() {
|
||||
registerAuthenticator(&authToken{})
|
||||
}
|
||||
|
||||
type authToken struct {
|
||||
type AuthToken struct {
|
||||
Tokens map[string]string `yaml:"tokens"`
|
||||
Groups map[string][]string `yaml:"groups"`
|
||||
}
|
||||
|
||||
func New() *AuthToken {
|
||||
return &AuthToken{}
|
||||
}
|
||||
|
||||
// AuthenticatorID needs to return an unique string to identify
|
||||
// this special authenticator
|
||||
func (a authToken) AuthenticatorID() string { return "token" }
|
||||
func (a AuthToken) AuthenticatorID() string { return "token" }
|
||||
|
||||
// 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 (a *authToken) Configure(yamlSource []byte) error {
|
||||
func (a *AuthToken) Configure(yamlSource []byte) error {
|
||||
envelope := struct {
|
||||
Providers struct {
|
||||
Token *authToken `yaml:"token"`
|
||||
Token *AuthToken `yaml:"token"`
|
||||
} `yaml:"providers"`
|
||||
}{}
|
||||
|
||||
|
@ -52,7 +52,7 @@ func (a *authToken) Configure(yamlSource []byte) error {
|
|||
// a cookie, header or other methods
|
||||
// If no user was detected the plugins.ErrNoValidUserFound needs to be
|
||||
// returned
|
||||
func (a authToken) DetectUser(res http.ResponseWriter, r *http.Request) (string, []string, error) {
|
||||
func (a AuthToken) DetectUser(res http.ResponseWriter, r *http.Request) (string, []string, error) {
|
||||
authHeader := r.Header.Get("Authorization")
|
||||
|
||||
if !strings.HasPrefix(authHeader, "Token ") {
|
||||
|
@ -93,22 +93,22 @@ func (a authToken) DetectUser(res http.ResponseWriter, r *http.Request) (string,
|
|||
// in order to use DetectUser for the next login.
|
||||
// If the user did not login correctly the plugins.ErrNoValidUserFound
|
||||
// needs to be returned
|
||||
func (a authToken) Login(res http.ResponseWriter, r *http.Request) (string, []plugins.MFAConfig, error) {
|
||||
func (a AuthToken) Login(res http.ResponseWriter, r *http.Request) (string, []plugins.MFAConfig, error) {
|
||||
return "", nil, plugins.ErrNoValidUserFound
|
||||
}
|
||||
|
||||
// LoginFields needs to return the fields required for this login
|
||||
// method. If no login using this method is possible the function
|
||||
// needs to return nil.
|
||||
func (a authToken) LoginFields() []plugins.LoginField { return nil }
|
||||
func (a AuthToken) LoginFields() []plugins.LoginField { return nil }
|
||||
|
||||
// Logout is called when the user visits the logout endpoint and
|
||||
// needs to destroy any persistent stored cookies
|
||||
func (a authToken) Logout(res http.ResponseWriter, r *http.Request) error { return nil }
|
||||
func (a AuthToken) Logout(res http.ResponseWriter, r *http.Request) error { return nil }
|
||||
|
||||
// SupportsMFA returns the MFA detection capabilities of the login
|
||||
// provider. If the provider can provide mfaConfig objects from its
|
||||
// configuration return true. If this is true the login interface
|
||||
// will display an additional field for this provider for the user
|
||||
// to fill in their MFA token.
|
||||
func (a authToken) SupportsMFA() bool { return false }
|
||||
func (a AuthToken) SupportsMFA() bool { return false }
|
|
@ -1,39 +1,46 @@
|
|||
package main
|
||||
package yubikey
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/GeertJohan/yubigo"
|
||||
"github.com/gorilla/sessions"
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/Luzifer/go_helpers/str"
|
||||
"github.com/Luzifer/nginx-sso/plugins"
|
||||
)
|
||||
|
||||
func init() {
|
||||
registerAuthenticator(&authYubikey{})
|
||||
}
|
||||
|
||||
type authYubikey struct {
|
||||
type AuthYubikey struct {
|
||||
ClientID string `yaml:"client_id"`
|
||||
SecretKey string `yaml:"secret_key"`
|
||||
Devices map[string]string `yaml:"devices"`
|
||||
Groups map[string][]string `yaml:"groups"`
|
||||
|
||||
cookie plugins.CookieConfig
|
||||
cookieStore *sessions.CookieStore
|
||||
}
|
||||
|
||||
func New(cs *sessions.CookieStore) *AuthYubikey {
|
||||
return &AuthYubikey{
|
||||
cookieStore: cs,
|
||||
}
|
||||
}
|
||||
|
||||
// AuthenticatorID needs to return an unique string to identify
|
||||
// this special authenticator
|
||||
func (a authYubikey) AuthenticatorID() string { return "yubikey" }
|
||||
func (a AuthYubikey) AuthenticatorID() 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 (a *authYubikey) Configure(yamlSource []byte) error {
|
||||
func (a *AuthYubikey) Configure(yamlSource []byte) error {
|
||||
envelope := struct {
|
||||
Cookie plugins.CookieConfig `yaml:"cookie"`
|
||||
Providers struct {
|
||||
Yubikey *authYubikey `yaml:"yubikey"`
|
||||
Yubikey *AuthYubikey `yaml:"yubikey"`
|
||||
} `yaml:"providers"`
|
||||
}{}
|
||||
|
||||
|
@ -50,6 +57,8 @@ func (a *authYubikey) Configure(yamlSource []byte) error {
|
|||
a.Devices = envelope.Providers.Yubikey.Devices
|
||||
a.Groups = envelope.Providers.Yubikey.Groups
|
||||
|
||||
a.cookie = envelope.Cookie
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -57,8 +66,8 @@ func (a *authYubikey) Configure(yamlSource []byte) error {
|
|||
// a cookie, header or other methods
|
||||
// If no user was detected the plugins.ErrNoValidUserFound needs to be
|
||||
// returned
|
||||
func (a authYubikey) DetectUser(res http.ResponseWriter, r *http.Request) (string, []string, error) {
|
||||
sess, err := cookieStore.Get(r, strings.Join([]string{mainCfg.Cookie.Prefix, a.AuthenticatorID()}, "-"))
|
||||
func (a AuthYubikey) DetectUser(res http.ResponseWriter, r *http.Request) (string, []string, error) {
|
||||
sess, err := a.cookieStore.Get(r, strings.Join([]string{a.cookie.Prefix, a.AuthenticatorID()}, "-"))
|
||||
if err != nil {
|
||||
return "", nil, plugins.ErrNoValidUserFound
|
||||
}
|
||||
|
@ -69,7 +78,7 @@ func (a authYubikey) DetectUser(res http.ResponseWriter, r *http.Request) (strin
|
|||
}
|
||||
|
||||
// We had a cookie, lets renew it
|
||||
sess.Options = mainCfg.Cookie.GetSessionOpts()
|
||||
sess.Options = a.cookie.GetSessionOpts()
|
||||
if err := sess.Save(r, res); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
@ -90,7 +99,7 @@ func (a authYubikey) DetectUser(res http.ResponseWriter, r *http.Request) (strin
|
|||
// in order to use DetectUser for the next login.
|
||||
// If the user did not login correctly the plugins.ErrNoValidUserFound
|
||||
// needs to be returned
|
||||
func (a authYubikey) Login(res http.ResponseWriter, r *http.Request) (string, []plugins.MFAConfig, error) {
|
||||
func (a AuthYubikey) Login(res http.ResponseWriter, r *http.Request) (string, []plugins.MFAConfig, error) {
|
||||
keyInput := r.FormValue(strings.Join([]string{a.AuthenticatorID(), "key-input"}, "-"))
|
||||
|
||||
yubiAuth, err := yubigo.NewYubiAuth(a.ClientID, a.SecretKey)
|
||||
|
@ -114,8 +123,8 @@ func (a authYubikey) Login(res http.ResponseWriter, r *http.Request) (string, []
|
|||
return "", nil, plugins.ErrNoValidUserFound
|
||||
}
|
||||
|
||||
sess, _ := cookieStore.Get(r, strings.Join([]string{mainCfg.Cookie.Prefix, a.AuthenticatorID()}, "-")) // #nosec G104 - On error empty session is returned
|
||||
sess.Options = mainCfg.Cookie.GetSessionOpts()
|
||||
sess, _ := a.cookieStore.Get(r, strings.Join([]string{a.cookie.Prefix, a.AuthenticatorID()}, "-")) // #nosec G104 - On error empty session is returned
|
||||
sess.Options = a.cookie.GetSessionOpts()
|
||||
sess.Values["user"] = user
|
||||
return user, nil, sess.Save(r, res)
|
||||
}
|
||||
|
@ -123,7 +132,7 @@ func (a authYubikey) Login(res http.ResponseWriter, r *http.Request) (string, []
|
|||
// LoginFields needs to return the fields required for this login
|
||||
// method. If no login using this method is possible the function
|
||||
// needs to return nil.
|
||||
func (a authYubikey) LoginFields() (fields []plugins.LoginField) {
|
||||
func (a AuthYubikey) LoginFields() (fields []plugins.LoginField) {
|
||||
return []plugins.LoginField{
|
||||
{
|
||||
Label: "Yubikey One-Time-Password",
|
||||
|
@ -136,9 +145,9 @@ func (a authYubikey) LoginFields() (fields []plugins.LoginField) {
|
|||
|
||||
// Logout is called when the user visits the logout endpoint and
|
||||
// needs to destroy any persistent stored cookies
|
||||
func (a authYubikey) Logout(res http.ResponseWriter, r *http.Request) (err error) {
|
||||
sess, _ := cookieStore.Get(r, strings.Join([]string{mainCfg.Cookie.Prefix, a.AuthenticatorID()}, "-")) // #nosec G104 - On error empty session is returned
|
||||
sess.Options = mainCfg.Cookie.GetSessionOpts()
|
||||
func (a AuthYubikey) Logout(res http.ResponseWriter, r *http.Request) (err error) {
|
||||
sess, _ := a.cookieStore.Get(r, strings.Join([]string{a.cookie.Prefix, a.AuthenticatorID()}, "-")) // #nosec G104 - On error empty session is returned
|
||||
sess.Options = a.cookie.GetSessionOpts()
|
||||
sess.Options.MaxAge = -1 // Instant delete
|
||||
return sess.Save(r, res)
|
||||
}
|
||||
|
@ -148,4 +157,4 @@ func (a authYubikey) Logout(res http.ResponseWriter, r *http.Request) (err error
|
|||
// configuration return true. If this is true the login interface
|
||||
// will display an additional field for this provider for the user
|
||||
// to fill in their MFA token.
|
||||
func (a authYubikey) SupportsMFA() bool { return false }
|
||||
func (a AuthYubikey) SupportsMFA() bool { return false }
|
Loading…
Reference in a new issue