1
0
Fork 0
mirror of https://github.com/Luzifer/nginx-sso.git synced 2024-12-19 20:31:18 +00:00

Export errors for usage in plugins

Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
Knut Ahlers 2019-02-22 00:27:02 +01:00
parent 83fcc4d0fe
commit e9bff08810
Signed by: luzifer
GPG key ID: DC2729FDD34BE99E
14 changed files with 72 additions and 67 deletions

View file

@ -30,7 +30,7 @@ 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 errProviderUnconfigured
// needs to return the plugins.ErrProviderUnconfigured
func (a *authCrowd) Configure(yamlSource []byte) error {
envelope := struct {
Providers struct {
@ -43,7 +43,7 @@ func (a *authCrowd) Configure(yamlSource []byte) error {
}
if envelope.Providers.Crowd == nil {
return errProviderUnconfigured
return plugins.ErrProviderUnconfigured
}
a.URL = envelope.Providers.Crowd.URL
@ -51,7 +51,7 @@ func (a *authCrowd) Configure(yamlSource []byte) error {
a.AppPassword = envelope.Providers.Crowd.AppPassword
if a.AppName == "" || a.AppPassword == "" {
return errProviderUnconfigured
return plugins.ErrProviderUnconfigured
}
var err error
@ -62,7 +62,7 @@ func (a *authCrowd) Configure(yamlSource []byte) error {
// DetectUser is used to detect a user without a login form from
// a cookie, header or other methods
// If no user was detected the errNoValidUserFound needs to be
// 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) {
cc, err := a.crowd.GetCookieConfig()
@ -76,7 +76,7 @@ func (a authCrowd) DetectUser(res http.ResponseWriter, r *http.Request) (string,
// Fine, we do have a cookie
case http.ErrNoCookie:
// Also fine, there is no cookie
return "", nil, errNoValidUserFound
return "", nil, plugins.ErrNoValidUserFound
default:
return "", nil, err
}
@ -85,7 +85,7 @@ func (a authCrowd) DetectUser(res http.ResponseWriter, r *http.Request) (string,
sess, err := a.crowd.GetSession(ssoToken)
if err != nil {
log.WithError(err).Debug("Getting crowd session failed")
return "", nil, errNoValidUserFound
return "", nil, plugins.ErrNoValidUserFound
}
user := sess.User.UserName
@ -106,7 +106,7 @@ func (a authCrowd) DetectUser(res http.ResponseWriter, r *http.Request) (string,
// to authenticate the user or throw an error. If the user has
// successfully logged in the persistent cookie should be written
// in order to use DetectUser for the next login.
// If the user did not login correctly the errNoValidUserFound
// 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) {
username := r.FormValue(strings.Join([]string{a.AuthenticatorID(), "username"}, "-"))
@ -122,7 +122,7 @@ func (a authCrowd) Login(res http.ResponseWriter, r *http.Request) (string, []pl
log.WithFields(log.Fields{
"username": username,
}).WithError(err).Debug("Crowd authentication failed")
return "", nil, errNoValidUserFound
return "", nil, plugins.ErrNoValidUserFound
}
http.SetCookie(res, &http.Cookie{

View file

@ -46,7 +46,7 @@ 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 errProviderUnconfigured
// needs to return the plugins.ErrProviderUnconfigured
func (a *authLDAP) Configure(yamlSource []byte) error {
envelope := struct {
Providers struct {
@ -59,7 +59,7 @@ func (a *authLDAP) Configure(yamlSource []byte) error {
}
if envelope.Providers.LDAP == nil {
return errProviderUnconfigured
return plugins.ErrProviderUnconfigured
}
a.EnableBasicAuth = envelope.Providers.LDAP.EnableBasicAuth
@ -98,7 +98,7 @@ func (a *authLDAP) Configure(yamlSource []byte) error {
// DetectUser is used to detect a user without a login form from
// a cookie, header or other methods
// If no user was detected the errNoValidUserFound needs to be
// 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) {
var alias, user string
@ -118,17 +118,17 @@ 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()}, "-"))
if err != nil {
return "", nil, errNoValidUserFound
return "", nil, plugins.ErrNoValidUserFound
}
var ok bool
if user, ok = sess.Values["user"].(string); !ok {
return "", nil, errNoValidUserFound
return "", nil, plugins.ErrNoValidUserFound
}
if alias, ok = sess.Values["alias"].(string); !ok {
// Most likely an old cookie, force re-login
return "", nil, errNoValidUserFound
return "", nil, plugins.ErrNoValidUserFound
}
// We had a cookie, lets renew it
@ -147,7 +147,7 @@ func (a authLDAP) DetectUser(res http.ResponseWriter, r *http.Request) (string,
// to authenticate the user or throw an error. If the user has
// successfully logged in the persistent cookie should be written
// in order to use DetectUser for the next login.
// If the user did not login correctly the errNoValidUserFound
// 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) {
username := r.FormValue(strings.Join([]string{a.AuthenticatorID(), "username"}, "-"))
@ -200,7 +200,7 @@ func (a authLDAP) Logout(res http.ResponseWriter, r *http.Request) (err error) {
}
// checkLogin searches for the username using the specified UserSearchFilter
// and returns the UserDN and an error (errNoValidUserFound / processing error)
// and returns the UserDN and an error (plugins.ErrNoValidUserFound / processing error)
func (a authLDAP) checkLogin(username, password, aliasAttribute string) (string, string, error) {
l, err := a.dial()
if err != nil {
@ -224,13 +224,13 @@ func (a authLDAP) checkLogin(username, password, aliasAttribute string) (string,
}
if len(sres.Entries) != 1 {
return "", "", errNoValidUserFound
return "", "", plugins.ErrNoValidUserFound
}
userDN := sres.Entries[0].DN
if err := l.Bind(userDN, password); err != nil {
return "", "", errNoValidUserFound
return "", "", plugins.ErrNoValidUserFound
}
alias := sres.Entries[0].GetAttributeValue(aliasAttribute)

View file

@ -29,7 +29,7 @@ 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 errProviderUnconfigured
// needs to return the plugins.ErrProviderUnconfigured
func (a *authSimple) Configure(yamlSource []byte) error {
envelope := struct {
Providers struct {
@ -42,7 +42,7 @@ func (a *authSimple) Configure(yamlSource []byte) error {
}
if envelope.Providers.Simple == nil {
return errProviderUnconfigured
return plugins.ErrProviderUnconfigured
}
a.EnableBasicAuth = envelope.Providers.Simple.EnableBasicAuth
@ -55,7 +55,7 @@ func (a *authSimple) Configure(yamlSource []byte) error {
// DetectUser is used to detect a user without a login form from
// a cookie, header or other methods
// If no user was detected the errNoValidUserFound needs to be
// 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) {
var user string
@ -78,13 +78,13 @@ 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()}, "-"))
if err != nil {
return "", nil, errNoValidUserFound
return "", nil, plugins.ErrNoValidUserFound
}
var ok bool
user, ok = sess.Values["user"].(string)
if !ok {
return "", nil, errNoValidUserFound
return "", nil, plugins.ErrNoValidUserFound
}
// We had a cookie, lets renew it
@ -108,7 +108,7 @@ func (a authSimple) DetectUser(res http.ResponseWriter, r *http.Request) (string
// to authenticate the user or throw an error. If the user has
// successfully logged in the persistent cookie should be written
// in order to use DetectUser for the next login.
// If the user did not login correctly the errNoValidUserFound
// 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) {
username := r.FormValue(strings.Join([]string{a.AuthenticatorID(), "username"}, "-"))
@ -128,7 +128,7 @@ func (a authSimple) Login(res http.ResponseWriter, r *http.Request) (string, []p
return u, a.MFA[u], sess.Save(r, res)
}
return "", nil, errNoValidUserFound
return "", nil, plugins.ErrNoValidUserFound
}
// LoginFields needs to return the fields required for this login

View file

@ -26,7 +26,7 @@ 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 errProviderUnconfigured
// needs to return the plugins.ErrProviderUnconfigured
func (a *authToken) Configure(yamlSource []byte) error {
envelope := struct {
Providers struct {
@ -39,7 +39,7 @@ func (a *authToken) Configure(yamlSource []byte) error {
}
if envelope.Providers.Token == nil {
return errProviderUnconfigured
return plugins.ErrProviderUnconfigured
}
a.Tokens = envelope.Providers.Token.Tokens
@ -50,13 +50,13 @@ func (a *authToken) Configure(yamlSource []byte) error {
// DetectUser is used to detect a user without a login form from
// a cookie, header or other methods
// If no user was detected the errNoValidUserFound needs to be
// 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) {
authHeader := r.Header.Get("Authorization")
if !strings.HasPrefix(authHeader, "Token ") {
return "", nil, errNoValidUserFound
return "", nil, plugins.ErrNoValidUserFound
}
tmp := strings.SplitN(authHeader, " ", 2)
@ -74,7 +74,7 @@ func (a authToken) DetectUser(res http.ResponseWriter, r *http.Request) (string,
}
if !userFound {
return "", nil, errNoValidUserFound
return "", nil, plugins.ErrNoValidUserFound
}
groups := []string{}
@ -91,10 +91,10 @@ func (a authToken) DetectUser(res http.ResponseWriter, r *http.Request) (string,
// to authenticate the user or throw an error. If the user has
// successfully logged in the persistent cookie should be written
// in order to use DetectUser for the next login.
// If the user did not login correctly the errNoValidUserFound
// 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) {
return "", nil, errNoValidUserFound
return "", nil, plugins.ErrNoValidUserFound
}
// LoginFields needs to return the fields required for this login

View file

@ -29,7 +29,7 @@ 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 errProviderUnconfigured
// needs to return the plugins.ErrProviderUnconfigured
func (a *authYubikey) Configure(yamlSource []byte) error {
envelope := struct {
Providers struct {
@ -42,7 +42,7 @@ func (a *authYubikey) Configure(yamlSource []byte) error {
}
if envelope.Providers.Yubikey == nil {
return errProviderUnconfigured
return plugins.ErrProviderUnconfigured
}
a.ClientID = envelope.Providers.Yubikey.ClientID
@ -55,17 +55,17 @@ func (a *authYubikey) Configure(yamlSource []byte) error {
// DetectUser is used to detect a user without a login form from
// a cookie, header or other methods
// If no user was detected the errNoValidUserFound needs to be
// 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()}, "-"))
if err != nil {
return "", nil, errNoValidUserFound
return "", nil, plugins.ErrNoValidUserFound
}
user, ok := sess.Values["user"].(string)
if !ok {
return "", nil, errNoValidUserFound
return "", nil, plugins.ErrNoValidUserFound
}
// We had a cookie, lets renew it
@ -88,7 +88,7 @@ func (a authYubikey) DetectUser(res http.ResponseWriter, r *http.Request) (strin
// to authenticate the user or throw an error. If the user has
// successfully logged in the persistent cookie should be written
// in order to use DetectUser for the next login.
// If the user did not login correctly the errNoValidUserFound
// 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) {
keyInput := r.FormValue(strings.Join([]string{a.AuthenticatorID(), "key-input"}, "-"))
@ -105,13 +105,13 @@ func (a authYubikey) Login(res http.ResponseWriter, r *http.Request) (string, []
if !ok {
// Not a valid authentication
return "", nil, errNoValidUserFound
return "", nil, plugins.ErrNoValidUserFound
}
user, ok := a.Devices[keyInput[:12]]
if !ok {
// We do not have a definition for that key
return "", nil, errNoValidUserFound
return "", nil, plugins.ErrNoValidUserFound
}
sess, _ := cookieStore.Get(r, strings.Join([]string{mainCfg.Cookie.Prefix, a.AuthenticatorID()}, "-")) // #nosec G104 - On error empty session is returned

View file

@ -17,6 +17,7 @@ import (
log "github.com/sirupsen/logrus"
yaml "gopkg.in/yaml.v2"
"github.com/Luzifer/nginx-sso/plugins"
"github.com/Luzifer/rconfig"
)
@ -157,7 +158,7 @@ func handleAuthRequest(res http.ResponseWriter, r *http.Request) {
user, groups, err := detectUser(res, r)
switch err {
case errNoValidUserFound:
case plugins.ErrNoValidUserFound:
mainCfg.AuditLog.Log(auditEventValidate, r, map[string]string{"result": "no valid user found"}) // #nosec G104 - This is only logging
http.Error(res, "No valid user found", http.StatusUnauthorized)
@ -194,7 +195,7 @@ func handleLoginRequest(res http.ResponseWriter, r *http.Request) {
// Simple authentication
user, mfaCfgs, err := loginUser(res, r)
switch err {
case errNoValidUserFound:
case plugins.ErrNoValidUserFound:
auditFields["reason"] = "invalid credentials"
mainCfg.AuditLog.Log(auditEventLoginFailure, r, auditFields) // #nosec G104 - This is only logging
http.Redirect(res, r, "/login?go="+url.QueryEscape(r.FormValue("go")), http.StatusFound)
@ -213,7 +214,7 @@ func handleLoginRequest(res http.ResponseWriter, r *http.Request) {
// MFA validation against configs from login
err = validateMFA(res, r, user, mfaCfgs)
switch err {
case errNoValidUserFound:
case plugins.ErrNoValidUserFound:
auditFields["reason"] = "invalid credentials"
mainCfg.AuditLog.Log(auditEventLoginFailure, r, auditFields) // #nosec G104 - This is only logging
res.Header().Del("Set-Cookie") // Remove login cookie

6
mfa.go
View file

@ -44,7 +44,7 @@ func initializeMFAProviders(yamlSource []byte) error {
case nil:
activeMFAProviders = append(activeMFAProviders, m)
log.WithFields(log.Fields{"mfa_provider": m.ProviderID()}).Debug("Activated MFA provider")
case errProviderUnconfigured:
case plugins.ErrProviderUnconfigured:
log.WithFields(log.Fields{"mfa_provider": m.ProviderID()}).Debug("MFA provider unconfigured")
// This is okay.
default:
@ -70,7 +70,7 @@ func validateMFA(res http.ResponseWriter, r *http.Request, user string, mfaCfgs
case nil:
// Validated successfully
return nil
case errNoValidUserFound:
case plugins.ErrNoValidUserFound:
// This is fine for now
default:
return err
@ -78,5 +78,5 @@ func validateMFA(res http.ResponseWriter, r *http.Request, user string, mfaCfgs
}
// No method could verify the user
return errNoValidUserFound
return plugins.ErrNoValidUserFound
}

View file

@ -39,7 +39,7 @@ 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 errProviderUnconfigured
// needs to return the plugins.ErrProviderUnconfigured
func (m *mfaDuo) Configure(yamlSource []byte) (err error) {
envelope := struct {
MFA struct {
@ -52,7 +52,7 @@ func (m *mfaDuo) Configure(yamlSource []byte) (err error) {
}
if envelope.MFA.Duo == nil {
return errProviderUnconfigured
return plugins.ErrProviderUnconfigured
}
m.IKey = envelope.MFA.Duo.IKey
@ -105,7 +105,7 @@ func (m mfaDuo) ValidateMFA(res http.ResponseWriter, r *http.Request, user strin
}
// Report this provider was not able to verify the MFA request
return errNoValidUserFound
return plugins.ErrNoValidUserFound
}
func (m mfaDuo) findIP(r *http.Request) (string, error) {

View file

@ -27,7 +27,7 @@ func (m mfaTOTP) ProviderID() (id string) {
// 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 errProviderUnconfigured
// needs to return the plugins.ErrProviderUnconfigured
func (m mfaTOTP) Configure(yamlSource []byte) (err error) { return nil }
// ValidateMFA takes the user from the login cookie and performs a
@ -53,7 +53,7 @@ func (m mfaTOTP) ValidateMFA(res http.ResponseWriter, r *http.Request, user stri
}
// Report this provider was not able to verify the MFA request
return errNoValidUserFound
return plugins.ErrNoValidUserFound
}
func (m mfaTOTP) exec(c plugins.MFAConfig) (string, error) {

View file

@ -27,7 +27,7 @@ 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 errProviderUnconfigured
// needs to return the plugins.ErrProviderUnconfigured
func (m *mfaYubikey) Configure(yamlSource []byte) (err error) {
envelope := struct {
MFA struct {
@ -40,7 +40,7 @@ func (m *mfaYubikey) Configure(yamlSource []byte) (err error) {
}
if envelope.MFA.Yubikey == nil {
return errProviderUnconfigured
return plugins.ErrProviderUnconfigured
}
m.ClientID = envelope.MFA.Yubikey.ClientID
@ -85,5 +85,5 @@ func (m mfaYubikey) ValidateMFA(res http.ResponseWriter, r *http.Request, user s
}
// Not a valid authentication
return errNoValidUserFound
return plugins.ErrNoValidUserFound
}

View file

@ -10,12 +10,12 @@ type Authenticator interface {
// 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 errProviderUnconfigured
// needs to return the ErrProviderUnconfigured
Configure(yamlSource []byte) (err error)
// DetectUser is used to detect a user without a login form from
// a cookie, header or other methods
// If no user was detected the errNoValidUserFound needs to be
// If no user was detected the ErrNoValidUserFound needs to be
// returned
DetectUser(res http.ResponseWriter, r *http.Request) (user string, groups []string, err error)
@ -26,7 +26,7 @@ type Authenticator interface {
// With the login result an array of mfaConfig must be returned. In
// case there is no MFA config or the provider does not support MFA
// return nil.
// If the user did not login correctly the errNoValidUserFound
// If the user did not login correctly the ErrNoValidUserFound
// needs to be returned
Login(res http.ResponseWriter, r *http.Request) (user string, mfaConfigs []MFAConfig, err error)

8
plugins/errors.go Normal file
View file

@ -0,0 +1,8 @@
package plugins
import "errors"
var (
ErrProviderUnconfigured = errors.New("No valid configuration found for this provider")
ErrNoValidUserFound = errors.New("No valid users found")
)

View file

@ -10,7 +10,7 @@ type MFAProvider interface {
// 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 errProviderUnconfigured
// needs to return the ErrProviderUnconfigured
Configure(yamlSource []byte) (err error)
// ValidateMFA takes the user from the login cookie and performs a

View file

@ -1,7 +1,6 @@
package main
import (
"errors"
"fmt"
"net/http"
"sync"
@ -12,9 +11,6 @@ import (
)
var (
errProviderUnconfigured = errors.New("No valid configuration found for this provider")
errNoValidUserFound = errors.New("No valid users found")
authenticatorRegistry = []plugins.Authenticator{}
authenticatorRegistryMutex sync.RWMutex
@ -40,7 +36,7 @@ func initializeAuthenticators(yamlSource []byte) error {
case nil:
tmp = append(tmp, a)
log.WithFields(log.Fields{"authenticator": a.AuthenticatorID()}).Debug("Activated authenticator")
case errProviderUnconfigured:
case plugins.ErrProviderUnconfigured:
log.WithFields(log.Fields{"authenticator": a.AuthenticatorID()}).Debug("Authenticator unconfigured")
// This is okay.
default:
@ -66,14 +62,14 @@ func detectUser(res http.ResponseWriter, r *http.Request) (string, []string, err
switch err {
case nil:
return user, groups, err
case errNoValidUserFound:
case plugins.ErrNoValidUserFound:
// This is okay.
default:
return "", nil, err
}
}
return "", nil, errNoValidUserFound
return "", nil, plugins.ErrNoValidUserFound
}
func loginUser(res http.ResponseWriter, r *http.Request) (string, []plugins.MFAConfig, error) {
@ -85,14 +81,14 @@ func loginUser(res http.ResponseWriter, r *http.Request) (string, []plugins.MFAC
switch err {
case nil:
return user, mfaCfgs, nil
case errNoValidUserFound:
case plugins.ErrNoValidUserFound:
// This is okay.
default:
return "", nil, err
}
}
return "", nil, errNoValidUserFound
return "", nil, plugins.ErrNoValidUserFound
}
func logoutUser(res http.ResponseWriter, r *http.Request) error {