Newer
Older
package main
import (
"context"
"crypto/sha256"
"errors"
"fmt"
"log"
func hashPassword(ctx context.Context, db *bolt.DB, user, pass string) (string, error) {
// Look up password salt from DB and hash password with it
var salt []byte
err := db.View(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte("meta"))
if bucket == nil {
return errors.New("no meta bucket")
}
salt = bucket.Get([]byte("pwsalt"))
return nil
})
h := sha256.New()
_, err = h.Write(salt)
if err != nil {
return "", err
}
fmt.Fprint(h, ":", user, ":", pass)
return fmt.Sprintf("%02x", h.Sum(nil)), nil
}
var (
errAuthFailed = errors.New("authentication failed")
errNoUsers = errors.New("no users")
)
}
func (a authProvider) Valid(ctx context.Context, userName, pass string) (*auth.User, error) {
err := a.db.View(func(tx *bolt.Tx) error {
bucket := tx.Bucket([]byte("users"))
if bucket == nil {
return errNoUsers
}
if bucket.Stats().KeyN == 0 {
return errNoUsers
}
dbHash = bucket.Get([]byte(userName))
return nil
})
user := &auth.User{
Name: userName,
}
if err == errNoUsers {
// No users yet in DB, allow everyone
if err != nil {
return nil, err
}
if len(dbHash) == 0 {
return nil, errAuthFailed
}
hashedPw, err := hashPassword(ctx, a.db, userName, pass)
log.Printf("hashed pw for %s: %s", userName, hashedPw)
if string(dbHash) != hashedPw {
return nil, errAuthFailed
}
return user, nil
}
func (a authProvider) updatePassword(ctx context.Context, userName, passOld, passNew string) error {
hashedOld, err := hashPassword(ctx, a.db, userName, passOld)
if err != nil {
return err
}
hashedNew, err := hashPassword(ctx, a.db, userName, passNew)
if err != nil {
return err
}
return a.db.Update(func(tx *bolt.Tx) error {
bucket, err := tx.CreateBucketIfNotExists([]byte("users"))
if err != nil {
return err
}
pwHash := bucket.Get([]byte(userName))
if len(pwHash) != 0 && string(pwHash) != hashedOld {
// A password exists already and it's not the one the user gave as their 'old' password.
return errAuthFailed
}
// Either user doesn't exist yet (no entry) or the password they gave as their old matched. We
// can update.
err = bucket.Put([]byte(userName), []byte(hashedNew))
if err != nil {
return err
}
return nil
})
func (a authProvider) createUser(ctx context.Context, userName string) (string, error) {
// generate random password
const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
var genPw string
for idx := 0; idx < 16; idx++ {
r := chars[rand.Intn(len(chars))]
genPw += string(r)
}
err := a.updatePassword(ctx, userName, "", genPw)
if err != nil {
return "", err
}
return genPw, nil
}