113 lines
3.0 KiB
Go
113 lines
3.0 KiB
Go
package authmethod
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
"sync"
|
|
|
|
"github.com/hashicorp/consul/agent/structs"
|
|
"github.com/mitchellh/mapstructure"
|
|
)
|
|
|
|
type ValidatorFactory func(method *structs.ACLAuthMethod) (Validator, error)
|
|
|
|
type Validator interface {
|
|
// Name returns the name of the auth method backing this validator.
|
|
Name() string
|
|
|
|
// ValidateLogin takes raw user-provided auth method metadata and ensures
|
|
// it is sane, provably correct, and currently valid. Relevant identifying
|
|
// data is extracted and returned for immediate use by the role binding
|
|
// process.
|
|
//
|
|
// Depending upon the method, it may make sense to use these calls to
|
|
// continue to extend the life of the underlying token.
|
|
//
|
|
// Returns auth method specific metadata suitable for the Role Binding
|
|
// process.
|
|
ValidateLogin(loginToken string) (map[string]string, error)
|
|
|
|
// AvailableFields returns a slice of all fields that are returned as a
|
|
// result of ValidateLogin. These are valid fields for use in any
|
|
// BindingRule tied to this auth method.
|
|
AvailableFields() []string
|
|
|
|
// MakeFieldMapSelectable converts a field map as returned by ValidateLogin
|
|
// into a structure suitable for selection with a binding rule.
|
|
MakeFieldMapSelectable(fieldMap map[string]string) interface{}
|
|
}
|
|
|
|
var (
|
|
typesMu sync.RWMutex
|
|
types = make(map[string]ValidatorFactory)
|
|
)
|
|
|
|
// Register makes an auth method with the given type available for use. If
|
|
// Register is called twice with the same name or if validator is nil, it
|
|
// panics.
|
|
func Register(name string, factory ValidatorFactory) {
|
|
typesMu.Lock()
|
|
defer typesMu.Unlock()
|
|
if factory == nil {
|
|
panic("authmethod: Register factory is nil for type " + name)
|
|
}
|
|
if _, dup := types[name]; dup {
|
|
panic("authmethod: Register called twice for type " + name)
|
|
}
|
|
types[name] = factory
|
|
}
|
|
|
|
func IsRegisteredType(typeName string) bool {
|
|
typesMu.RLock()
|
|
_, ok := types[typeName]
|
|
typesMu.RUnlock()
|
|
return ok
|
|
}
|
|
|
|
// NewValidator instantiates a new Validator for the given auth method
|
|
// configuration. If no auth method is registered with the provided type an
|
|
// error is returned.
|
|
func NewValidator(method *structs.ACLAuthMethod) (Validator, error) {
|
|
typesMu.RLock()
|
|
factory, ok := types[method.Type]
|
|
typesMu.RUnlock()
|
|
|
|
if !ok {
|
|
return nil, fmt.Errorf("no auth method registered with type: %s", method.Type)
|
|
}
|
|
|
|
return factory(method)
|
|
}
|
|
|
|
// Types returns a sorted list of the names of the registered types.
|
|
func Types() []string {
|
|
typesMu.RLock()
|
|
defer typesMu.RUnlock()
|
|
var list []string
|
|
for name := range types {
|
|
list = append(list, name)
|
|
}
|
|
sort.Strings(list)
|
|
return list
|
|
}
|
|
|
|
// ParseConfig parses the config block for a auth method.
|
|
func ParseConfig(rawConfig map[string]interface{}, out interface{}) error {
|
|
decodeConf := &mapstructure.DecoderConfig{
|
|
Result: out,
|
|
WeaklyTypedInput: true,
|
|
ErrorUnused: true,
|
|
}
|
|
|
|
decoder, err := mapstructure.NewDecoder(decodeConf)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := decoder.Decode(rawConfig); err != nil {
|
|
return fmt.Errorf("error decoding config: %s", err)
|
|
}
|
|
|
|
return nil
|
|
}
|