1
0
mirror of https://github.com/volatiletech/authboss.git synced 2025-02-09 13:47:09 +02:00

Fix lock module.

This commit is contained in:
Aaron 2015-02-22 12:43:28 -08:00
parent 681bfdeac0
commit bab0da8575
3 changed files with 42 additions and 35 deletions

View File

@ -21,6 +21,8 @@ type MockUser struct {
ConfirmToken string ConfirmToken string
Confirmed bool Confirmed bool
Locked bool Locked bool
AttemptNumber int
AttemptTime time.Time
} }
// MockStorer should be valid for any module storer defined in authboss. // MockStorer should be valid for any module storer defined in authboss.

View File

@ -3,7 +3,6 @@ package lock
import ( import (
"errors" "errors"
"fmt"
"time" "time"
"gopkg.in/authboss.v0" "gopkg.in/authboss.v0"
@ -15,10 +14,6 @@ const (
StoreLocked = "locked" StoreLocked = "locked"
) )
var (
ErrLocked = errors.New("Account is locked.")
)
// L is the singleton instance of the lock module which will have been // L is the singleton instance of the lock module which will have been
// configured and ready to use after authboss.Init() // configured and ready to use after authboss.Init()
var L *Lock var L *Lock
@ -58,39 +53,38 @@ func (l *Lock) Storage() authboss.StorageOptions {
} }
// BeforeAuth ensures the account is not locked. // BeforeAuth ensures the account is not locked.
func (l *Lock) BeforeAuth(ctx *authboss.Context) error { func (l *Lock) BeforeAuth(ctx *authboss.Context) (authboss.Interrupt, error) {
if ctx.User == nil { if ctx.User == nil {
return errors.New("lock: user not loaded in before auth callback") return authboss.InterruptNone, errors.New("lock: user not loaded in BeforeAuth callback")
} }
if intf, ok := ctx.User[StoreLocked]; ok { if locked, ok := ctx.User.Bool(StoreLocked); ok && locked {
if locked, ok := intf.(bool); ok && locked { return authboss.InterruptAccountLocked, nil
return ErrLocked
}
} }
return nil return authboss.InterruptNone, nil
} }
// AfterAuth resets the attempt number field. // AfterAuth resets the attempt number field.
func (l *Lock) AfterAuth(ctx *authboss.Context) { func (l *Lock) AfterAuth(ctx *authboss.Context) error {
if ctx.User == nil { if ctx.User == nil {
fmt.Fprintln(authboss.Cfg.LogWriter, "lock: user not loaded in after auth callback") return errors.New("lock: user not loaded in AfterAuth callback")
return
} }
ctx.User[StoreAttemptNumber] = 0 ctx.User[StoreAttemptNumber] = 0
ctx.User[StoreAttemptTime] = time.Now().UTC() ctx.User[StoreAttemptTime] = time.Now().UTC()
if err := ctx.SaveUser(); err != nil { if err := ctx.SaveUser(); err != nil {
fmt.Fprintf(authboss.Cfg.LogWriter, "lock: saving user failed %v", err) return err
} }
return nil
} }
// AfterAuthFail adjusts the attempt number and time. // AfterAuthFail adjusts the attempt number and time.
func (l *Lock) AfterAuthFail(ctx *authboss.Context) { func (l *Lock) AfterAuthFail(ctx *authboss.Context) error {
if ctx.User == nil { if ctx.User == nil {
return return errors.New("lock: user not loaded in AfterAuth callback")
} }
lastAttempt := time.Now().UTC() lastAttempt := time.Now().UTC()
@ -117,13 +111,15 @@ func (l *Lock) AfterAuthFail(ctx *authboss.Context) {
ctx.User[StoreAttemptTime] = time.Now().UTC() ctx.User[StoreAttemptTime] = time.Now().UTC()
if err := ctx.SaveUser(); err != nil { if err := ctx.SaveUser(); err != nil {
fmt.Fprintf(authboss.Cfg.LogWriter, "lock: saving user failed %v", err) return err
} }
return nil
} }
// Lock a user manually. // Lock a user manually.
func (l *Lock) Lock(key string, storer authboss.Storer) error { func (l *Lock) Lock(key string) error {
user, err := storer.Get(key, authboss.ModuleAttrMeta) user, err := authboss.Cfg.Storer.Get(key, authboss.ModuleAttrMeta)
if err != nil { if err != nil {
return err return err
} }
@ -135,12 +131,12 @@ func (l *Lock) Lock(key string, storer authboss.Storer) error {
attr[StoreLocked] = true attr[StoreLocked] = true
return storer.Put(key, attr) return authboss.Cfg.Storer.Put(key, attr)
} }
// Unlock a user that was locked by this module. // Unlock a user that was locked by this module.
func (l *Lock) Unlock(key string, storer authboss.Storer) error { func (l *Lock) Unlock(key string) error {
user, err := storer.Get(key, authboss.ModuleAttrMeta) user, err := authboss.Cfg.Storer.Get(key, authboss.ModuleAttrMeta)
if err != nil { if err != nil {
return err return err
} }
@ -156,5 +152,5 @@ func (l *Lock) Unlock(key string, storer authboss.Storer) error {
attr[StoreAttemptNumber] = 0 attr[StoreAttemptNumber] = 0
attr[StoreLocked] = false attr[StoreLocked] = false
return storer.Put(key, attr) return authboss.Cfg.Storer.Put(key, attr)
} }

View File

@ -23,14 +23,18 @@ func TestBeforeAuth(t *testing.T) {
authboss.NewConfig() authboss.NewConfig()
ctx := authboss.NewContext() ctx := authboss.NewContext()
if err := L.BeforeAuth(ctx); err == nil { if interrupt, err := L.BeforeAuth(ctx); err == nil {
t.Error("Want death because user not loaded:", err) t.Error("Want death because user not loaded:", err)
} else if interrupt != authboss.InterruptNone {
t.Error("Interrupt should not be set:", interrupt)
} }
ctx.User = authboss.Attributes{"locked": true} ctx.User = authboss.Attributes{"locked": true}
if err := L.BeforeAuth(ctx); err != ErrLocked { if interrupt, err := L.BeforeAuth(ctx); err != nil {
t.Error("Expected an ErrLocked:", err) t.Error(err)
} else if interrupt != authboss.InterruptAccountLocked {
t.Error("Expected a locked interrupt:", interrupt)
} }
} }
@ -39,16 +43,17 @@ func TestAfterAuth(t *testing.T) {
lock := Lock{} lock := Lock{}
ctx := authboss.NewContext() ctx := authboss.NewContext()
lock.AfterAuth(ctx) if err := lock.AfterAuth(ctx); err == nil {
if _, ok := ctx.User[StoreAttemptNumber]; ok { t.Error("Expected an error because of missing user.")
t.Error("Expected nothing to be set, missing user.")
} }
storer := mocks.NewMockStorer() storer := mocks.NewMockStorer()
authboss.Cfg.Storer = storer authboss.Cfg.Storer = storer
ctx.User = authboss.Attributes{"username": "username"} ctx.User = authboss.Attributes{"username": "username"}
lock.AfterAuth(ctx) if err := lock.AfterAuth(ctx); err != nil {
t.Error(err)
}
if storer.Users["username"][StoreAttemptNumber].(int) != 0 { if storer.Users["username"][StoreAttemptNumber].(int) != 0 {
t.Error("StoreAttemptNumber set incorrectly.") t.Error("StoreAttemptNumber set incorrectly.")
} }
@ -78,7 +83,9 @@ func TestAfterAuthFail_Lock(t *testing.T) {
t.Errorf("%d: User should not be locked.", i) t.Errorf("%d: User should not be locked.", i)
} }
lock.AfterAuthFail(ctx) if err := lock.AfterAuthFail(ctx); err != nil {
t.Error(err)
}
if val := storer.Users["username"][StoreAttemptNumber].(int); val != i+1 { if val := storer.Users["username"][StoreAttemptNumber].(int); val != i+1 {
t.Errorf("%d: StoreAttemptNumber set incorrectly: %v", i, val) t.Errorf("%d: StoreAttemptNumber set incorrectly: %v", i, val)
} }
@ -146,6 +153,7 @@ func TestAfterAuthFail_Errors(t *testing.T) {
func TestLock(t *testing.T) { func TestLock(t *testing.T) {
authboss.NewConfig() authboss.NewConfig()
storer := mocks.NewMockStorer() storer := mocks.NewMockStorer()
authboss.Cfg.Storer = storer
lock := Lock{} lock := Lock{}
storer.Users["username"] = map[string]interface{}{ storer.Users["username"] = map[string]interface{}{
@ -153,7 +161,7 @@ func TestLock(t *testing.T) {
"password": "password", "password": "password",
} }
err := lock.Lock("username", storer) err := lock.Lock("username")
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
@ -166,6 +174,7 @@ func TestLock(t *testing.T) {
func TestUnlock(t *testing.T) { func TestUnlock(t *testing.T) {
authboss.NewConfig() authboss.NewConfig()
storer := mocks.NewMockStorer() storer := mocks.NewMockStorer()
authboss.Cfg.Storer = storer
lock := Lock{} lock := Lock{}
authboss.Cfg.LockWindow = 1 * time.Hour authboss.Cfg.LockWindow = 1 * time.Hour
@ -175,7 +184,7 @@ func TestUnlock(t *testing.T) {
"locked": true, "locked": true,
} }
err := lock.Unlock("username", storer) err := lock.Unlock("username")
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }