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:
parent
681bfdeac0
commit
bab0da8575
@ -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.
|
||||||
|
46
lock/lock.go
46
lock/lock.go
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user