Commit e29f41a8 authored by ale's avatar ale

Show warnings when there are errors in the users file

Currently the only part that can fail is the U2F registration
decoding. As a side effect of validating user objects early, it also
gets rid of runtime allocations by just storing a map of backend.User
objects.
parent d00c9490
Pipeline #2800 passed with stages
in 2 minutes and 7 seconds
......@@ -4,6 +4,7 @@ import (
"context"
"encoding/base64"
"encoding/hex"
"log"
ct "git.autistici.org/ai3/go-common/ldap/compositetypes"
"github.com/tstranex/u2f"
......@@ -35,15 +36,17 @@ type fileUser struct {
} `yaml:"u2f_registrations"`
}
func (f *fileUser) getU2FRegistrations() []u2f.Registration {
func (f *fileUser) getU2FRegistrations(filename string) []u2f.Registration {
var out []u2f.Registration
for _, r := range f.U2FRegistrations {
kh, err := base64.RawURLEncoding.DecodeString(r.KeyHandle)
if err != nil {
log.Printf("warning: %s: user %s: could not decode U2F key handle: %v", filename, f.Name, err)
continue
}
pk, err := hex.DecodeString(r.PublicKey)
if err != nil {
log.Printf("warning: %s: user %s: could not decode U2F public key: %v", filename, f.Name, err)
continue
}
ctr := ct.U2FRegistration{
......@@ -52,6 +55,7 @@ func (f *fileUser) getU2FRegistrations() []u2f.Registration {
}
reg, err := ctr.Decode()
if err != nil {
log.Printf("warning: %s: user %s: could not decode U2F registration: %v", filename, f.Name, err)
continue
}
out = append(out, *reg)
......@@ -59,7 +63,7 @@ func (f *fileUser) getU2FRegistrations() []u2f.Registration {
return out
}
func (f *fileUser) ToUser() *backend.User {
func (f *fileUser) toUser(filename string) *backend.User {
return &backend.User{
Name: f.Name,
Email: f.Email,
......@@ -67,25 +71,25 @@ func (f *fileUser) ToUser() *backend.User {
EncryptedPassword: []byte(f.EncryptedPassword),
TOTPSecret: f.TOTPSecret,
Groups: f.Groups,
U2FRegistrations: f.getU2FRegistrations(),
U2FRegistrations: f.getU2FRegistrations(filename),
}
}
// Simple file-based authentication backend, list users and their
// credentials in a YAML-encoded file.
type fileBackend struct {
files map[string]map[string]*fileUser
files map[string]map[string]*backend.User
configDir string
}
func loadUsersFile(path string) (map[string]*fileUser, error) {
func loadUsersFile(path string) (map[string]*backend.User, error) {
var userList []*fileUser
if err := backend.LoadYAML(path, &userList); err != nil {
return nil, err
}
users := make(map[string]*fileUser)
users := make(map[string]*backend.User)
for _, u := range userList {
users[u.Name] = u
users[u.Name] = u.toUser(path)
}
return users, nil
}
......@@ -93,12 +97,12 @@ func loadUsersFile(path string) (map[string]*fileUser, error) {
// New creates a new file-based UserBackend.
func New(_ yaml.MapSlice, configDir string) (backend.UserBackend, error) {
return &fileBackend{
files: make(map[string]map[string]*fileUser),
files: make(map[string]map[string]*backend.User),
configDir: configDir,
}, nil
}
func (b *fileBackend) getUserMap(path string) (map[string]*fileUser, error) {
func (b *fileBackend) getUserMap(path string) (map[string]*backend.User, error) {
m, ok := b.files[path]
if !ok {
var err error
......@@ -125,12 +129,9 @@ func (b *fileBackend) NewServiceBackend(spec *backend.Spec) (backend.ServiceBack
return fileServiceBackend(m), nil
}
type fileServiceBackend map[string]*fileUser
type fileServiceBackend map[string]*backend.User
func (b fileServiceBackend) GetUser(_ context.Context, name string) (*backend.User, bool) {
u, ok := b[name]
if !ok {
return nil, false
}
return u.ToUser(), true
return u, ok
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment