2019-04-21 17:55:52 +00:00
|
|
|
package token
|
2018-01-28 14:16:52 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"net/http"
|
|
|
|
"strings"
|
|
|
|
|
2018-02-04 10:34:04 +00:00
|
|
|
"github.com/Luzifer/go_helpers/str"
|
2019-02-21 23:10:43 +00:00
|
|
|
"github.com/Luzifer/nginx-sso/plugins"
|
2018-02-04 10:34:04 +00:00
|
|
|
|
2018-01-28 14:16:52 +00:00
|
|
|
yaml "gopkg.in/yaml.v2"
|
|
|
|
)
|
|
|
|
|
2019-04-21 17:55:52 +00:00
|
|
|
type AuthToken struct {
|
2018-02-04 10:34:04 +00:00
|
|
|
Tokens map[string]string `yaml:"tokens"`
|
|
|
|
Groups map[string][]string `yaml:"groups"`
|
2018-01-28 14:16:52 +00:00
|
|
|
}
|
|
|
|
|
2019-04-21 17:55:52 +00:00
|
|
|
func New() *AuthToken {
|
|
|
|
return &AuthToken{}
|
|
|
|
}
|
|
|
|
|
2018-01-28 14:16:52 +00:00
|
|
|
// AuthenticatorID needs to return an unique string to identify
|
|
|
|
// this special authenticator
|
2019-04-21 17:55:52 +00:00
|
|
|
func (a AuthToken) AuthenticatorID() string { return "token" }
|
2018-01-28 14:16:52 +00:00
|
|
|
|
|
|
|
// 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
|
2019-02-21 23:27:02 +00:00
|
|
|
// needs to return the plugins.ErrProviderUnconfigured
|
2019-04-21 17:55:52 +00:00
|
|
|
func (a *AuthToken) Configure(yamlSource []byte) error {
|
2018-01-28 14:16:52 +00:00
|
|
|
envelope := struct {
|
|
|
|
Providers struct {
|
2019-04-21 17:55:52 +00:00
|
|
|
Token *AuthToken `yaml:"token"`
|
2018-01-28 14:16:52 +00:00
|
|
|
} `yaml:"providers"`
|
|
|
|
}{}
|
|
|
|
|
|
|
|
if err := yaml.Unmarshal(yamlSource, &envelope); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if envelope.Providers.Token == nil {
|
2019-02-21 23:27:02 +00:00
|
|
|
return plugins.ErrProviderUnconfigured
|
2018-01-28 14:16:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
a.Tokens = envelope.Providers.Token.Tokens
|
2018-02-04 12:11:00 +00:00
|
|
|
a.Groups = envelope.Providers.Token.Groups
|
2018-01-28 14:16:52 +00:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// DetectUser is used to detect a user without a login form from
|
|
|
|
// a cookie, header or other methods
|
2019-02-21 23:27:02 +00:00
|
|
|
// If no user was detected the plugins.ErrNoValidUserFound needs to be
|
2018-01-28 14:16:52 +00:00
|
|
|
// returned
|
2019-04-21 17:55:52 +00:00
|
|
|
func (a AuthToken) DetectUser(res http.ResponseWriter, r *http.Request) (string, []string, error) {
|
2018-01-28 14:16:52 +00:00
|
|
|
authHeader := r.Header.Get("Authorization")
|
|
|
|
|
|
|
|
if !strings.HasPrefix(authHeader, "Token ") {
|
2019-02-21 23:27:02 +00:00
|
|
|
return "", nil, plugins.ErrNoValidUserFound
|
2018-01-28 14:16:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
tmp := strings.SplitN(authHeader, " ", 2)
|
|
|
|
suppliedToken := tmp[1]
|
|
|
|
|
2018-02-04 12:00:33 +00:00
|
|
|
var (
|
|
|
|
user, token string
|
|
|
|
userFound bool
|
|
|
|
)
|
2018-02-04 10:34:04 +00:00
|
|
|
for user, token = range a.Tokens {
|
2018-01-28 14:16:52 +00:00
|
|
|
if token == suppliedToken {
|
2018-02-04 12:00:33 +00:00
|
|
|
userFound = true
|
2018-02-04 10:34:04 +00:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-04 12:00:33 +00:00
|
|
|
if !userFound {
|
2019-02-21 23:27:02 +00:00
|
|
|
return "", nil, plugins.ErrNoValidUserFound
|
2018-02-04 10:34:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
groups := []string{}
|
|
|
|
for group, users := range a.Groups {
|
|
|
|
if str.StringInSlice(user, users) {
|
|
|
|
groups = append(groups, group)
|
2018-01-28 14:16:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-04 10:34:04 +00:00
|
|
|
return user, groups, nil
|
2018-01-28 14:16:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Login is called when the user submits the login form and needs
|
|
|
|
// 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.
|
2019-02-21 23:27:02 +00:00
|
|
|
// If the user did not login correctly the plugins.ErrNoValidUserFound
|
2018-01-28 14:16:52 +00:00
|
|
|
// needs to be returned
|
2019-04-21 17:55:52 +00:00
|
|
|
func (a AuthToken) Login(res http.ResponseWriter, r *http.Request) (string, []plugins.MFAConfig, error) {
|
2019-02-21 23:27:02 +00:00
|
|
|
return "", nil, plugins.ErrNoValidUserFound
|
2018-12-24 09:07:49 +00:00
|
|
|
}
|
2018-01-28 14:16:52 +00:00
|
|
|
|
|
|
|
// 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.
|
2019-04-21 17:55:52 +00:00
|
|
|
func (a AuthToken) LoginFields() []plugins.LoginField { return nil }
|
2018-01-28 14:16:52 +00:00
|
|
|
|
|
|
|
// Logout is called when the user visits the logout endpoint and
|
|
|
|
// needs to destroy any persistent stored cookies
|
2019-04-21 17:55:52 +00:00
|
|
|
func (a AuthToken) Logout(res http.ResponseWriter, r *http.Request) error { return nil }
|
2018-12-24 09:07:49 +00:00
|
|
|
|
|
|
|
// 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.
|
2019-04-21 17:55:52 +00:00
|
|
|
func (a AuthToken) SupportsMFA() bool { return false }
|