1
0
mirror of https://github.com/volatiletech/authboss.git synced 2024-11-24 08:42:17 +02:00

Change config to be global. Updated most modules and tests.

This commit is contained in:
Kris Runzer 2015-02-15 20:07:36 -08:00
parent 1aa0da808c
commit bab1475b72
25 changed files with 284 additions and 421 deletions

View File

@ -3,16 +3,13 @@ package auth
import (
"errors"
"fmt"
"html/template"
"net/http"
"golang.org/x/crypto/bcrypt"
"gopkg.in/authboss.v0"
"gopkg.in/authboss.v0/internal/views"
"html/template"
"io"
)
const (
@ -44,19 +41,14 @@ type AuthPage struct {
type Auth struct {
routes authboss.RouteTable
storageOptions authboss.StorageOptions
storer authboss.Storer
logoutRedirect string
loginRedirect string
logger io.Writer
templates map[string]*template.Template
callbacks *authboss.Callbacks
isRememberLoaded bool
isRecoverLoaded bool
}
func (a *Auth) Initialize(config *authboss.Config) (err error) {
if a.templates, err = views.Get(config.Layout, config.ViewsPath, pageLogin); err != nil {
func (a *Auth) Initialize() (err error) {
if a.templates, err = views.Get(authboss.Cfg.Layout, authboss.Cfg.ViewsPath, pageLogin); err != nil {
return err
}
@ -68,11 +60,6 @@ func (a *Auth) Initialize(config *authboss.Config) (err error) {
attrUsername: authboss.String,
attrPassword: authboss.String,
}
a.storer = config.Storer
a.logoutRedirect = config.AuthLogoutRoute
a.loginRedirect = config.AuthLoginSuccessRoute
a.logger = config.LogWriter
a.callbacks = config.Callbacks
a.isRememberLoaded = authboss.IsLoaded("remember")
a.isRecoverLoaded = authboss.IsLoaded("recover")
@ -93,7 +80,7 @@ func (a *Auth) loginHandlerFunc(ctx *authboss.Context, w http.ResponseWriter, r
case methodGET:
if _, ok := ctx.SessionStorer.Get(authboss.SessionKey); ok {
if halfAuthed, ok := ctx.SessionStorer.Get(authboss.HalfAuthKey); !ok || halfAuthed == "false" {
http.Redirect(w, r, a.loginRedirect, http.StatusFound)
http.Redirect(w, r, authboss.Cfg.AuthLoginSuccessRoute, http.StatusFound)
}
}
@ -106,14 +93,13 @@ func (a *Auth) loginHandlerFunc(ctx *authboss.Context, w http.ResponseWriter, r
tpl := a.templates[pageLogin]
tpl.Execute(w, page)
// tpl.ExecuteTemplate(w, tpl.Name(), page)
case methodPOST:
u, ok := ctx.FirstPostFormValue("username")
if !ok {
fmt.Fprintln(a.logger, errors.New("auth: Expected postFormValue 'username' to be in the context"))
fmt.Fprintln(authboss.Cfg.LogWriter, errors.New("auth: Expected postFormValue 'username' to be in the context"))
}
if err := a.callbacks.FireBefore(authboss.EventAuth, ctx); err != nil {
if err := authboss.Cfg.Callbacks.FireBefore(authboss.EventAuth, ctx); err != nil {
w.WriteHeader(http.StatusForbidden)
tpl := a.templates[pageLogin]
@ -122,11 +108,11 @@ func (a *Auth) loginHandlerFunc(ctx *authboss.Context, w http.ResponseWriter, r
p, ok := ctx.FirstPostFormValue("password")
if !ok {
fmt.Fprintln(a.logger, errors.New("auth: Expected postFormValue 'password' to be in the context"))
fmt.Fprintln(authboss.Cfg.LogWriter, errors.New("auth: Expected postFormValue 'password' to be in the context"))
}
if err := a.authenticate(ctx, u, p); err != nil {
fmt.Fprintln(a.logger, err)
fmt.Fprintln(authboss.Cfg.LogWriter, err)
w.WriteHeader(http.StatusForbidden)
tpl := a.templates[pageLogin]
tpl.ExecuteTemplate(w, tpl.Name(), AuthPage{"invalid username and/or password", u, a.isRememberLoaded, a.isRecoverLoaded, "", ""})
@ -134,9 +120,9 @@ func (a *Auth) loginHandlerFunc(ctx *authboss.Context, w http.ResponseWriter, r
}
ctx.SessionStorer.Put(authboss.SessionKey, u)
a.callbacks.FireAfter(authboss.EventAuth, ctx)
authboss.Cfg.Callbacks.FireAfter(authboss.EventAuth, ctx)
http.Redirect(w, r, a.loginRedirect, http.StatusFound)
http.Redirect(w, r, authboss.Cfg.AuthLoginSuccessRoute, http.StatusFound)
default:
w.WriteHeader(http.StatusMethodNotAllowed)
}
@ -145,7 +131,7 @@ func (a *Auth) loginHandlerFunc(ctx *authboss.Context, w http.ResponseWriter, r
func (a *Auth) authenticate(ctx *authboss.Context, username, password string) error {
var userInter interface{}
var err error
if userInter, err = a.storer.Get(username, nil); err != nil {
if userInter, err = authboss.Cfg.Storer.Get(username, nil); err != nil {
return err
}
@ -172,7 +158,7 @@ func (a *Auth) logoutHandlerFunc(ctx *authboss.Context, w http.ResponseWriter, r
switch r.Method {
case methodGET:
ctx.SessionStorer.Del(authboss.SessionKey)
http.Redirect(w, r, a.logoutRedirect, http.StatusFound)
http.Redirect(w, r, authboss.Cfg.AuthLogoutRoute, http.StatusFound)
default:
w.WriteHeader(http.StatusMethodNotAllowed)
}

View File

@ -1,6 +1,6 @@
package auth
import (
/*import (
"bytes"
"html/template"
"io/ioutil"
@ -33,10 +33,8 @@ func getCompiledTemplate(path string, data interface{}) (b *bytes.Buffer, err er
}
func TestAuth_Storage(t *testing.T) {
t.Parallel()
a := &Auth{}
if err := a.Initialize(authboss.NewConfig()); err != nil {
if err := a.Initialize(); err != nil {
t.Errorf("Unexpected config error: %v", err)
}
options := a.Storage()
@ -61,10 +59,8 @@ func TestAuth_Storage(t *testing.T) {
}
func TestAuth_Routes(t *testing.T) {
t.Parallel()
a := &Auth{}
if err := a.Initialize(authboss.NewConfig()); err != nil {
if err := a.Initialize(); err != nil {
t.Errorf("Unexpected config error: %v", err)
}
routes := a.Routes()
@ -86,53 +82,35 @@ func TestAuth_Routes(t *testing.T) {
}
func TestAuth_loginHandlerFunc_GET(t *testing.T) {
t.Parallel()
tests := []struct {
Config *authboss.Config
}{
{authboss.NewConfig()},
{&authboss.Config{}},
{&authboss.Config{ViewsPath: "views"}},
a := &Auth{}
if err := a.Initialize(); err != nil {
t.Errorf("Unexpected config error: %v", err)
}
for i, test := range tests {
a := &Auth{}
if err := a.Initialize(test.Config); err != nil {
t.Errorf("%d> Unexpected config error: %v", i, err)
continue
}
r, err := http.NewRequest("GET", "/login", nil)
if err != nil {
t.Errorf("Unexpected error '%s'", err)
}
w := httptest.NewRecorder()
r, err := http.NewRequest("GET", "/login", nil)
if err != nil {
t.Errorf("Unexpected error '%s'", err)
}
w := httptest.NewRecorder()
ctx, err := authboss.ContextFromRequest(r)
if err != nil {
t.Errorf("Unexpected error '%s'", err)
}
ctx.SessionStorer = testClientStorer{}
ctx, err := authboss.ContextFromRequest(r)
if err != nil {
t.Errorf("%d> Unexpected error '%s'", i, err)
continue
}
ctx.SessionStorer = testClientStorer{}
a.loginHandlerFunc(ctx, w, r)
a.loginHandlerFunc(ctx, w, r)
if tpl, err := getCompiledTemplate("views/login.tpl", nil); err != nil {
t.Errorf("%d> Unexpected error '%s'", i, err)
continue
} else {
if !bytes.Equal(tpl.Bytes(), w.Body.Bytes()) {
t.Errorf("%d> Expected '%s', got '%s'", i, tpl.Bytes(), w.Body.Bytes())
continue
}
if tpl, err := getCompiledTemplate("views/login.tpl", nil); err != nil {
t.Errorf("Unexpected error '%s'", err)
} else {
if !bytes.Equal(tpl.Bytes(), w.Body.Bytes()) {
t.Errorf("Expected '%s', got '%s'", tpl.Bytes(), w.Body.Bytes())
}
}
}
func TestAuth_loginHandlerFunc_POST(t *testing.T) {
t.Parallel()
tests := []struct {
Username, Password string
StatusCode int
@ -141,17 +119,16 @@ func TestAuth_loginHandlerFunc_POST(t *testing.T) {
BodyData *AuthPage
}{
{"john", "1234", http.StatusFound, true, "/dashboard", nil},
{"jane", "1234", http.StatusForbidden, false, "", &AuthPage{"invalid username and/or password", "jane", false, false}},
{"mike", "", http.StatusForbidden, false, "", &AuthPage{"invalid username and/or password", "jane", false, false}},
{"jane", "1234", http.StatusForbidden, false, "", &AuthPage{"invalid username and/or password", "jane", false, false, "", ""}},
{"mike", "", http.StatusForbidden, false, "", &AuthPage{"invalid username and/or password", "jane", false, false, "", ""}},
}
c := authboss.NewConfig()
c.Storer = NewMockUserStorer()
c.AuthLoginSuccessRoute = "/dashboard"
authboss.Cfg.Storer = NewMockUserStorer()
authboss.Cfg.AuthLoginSuccessRoute = "/dashboard"
for i, test := range tests {
a := &Auth{}
if err := a.Initialize(c); err != nil {
if err := a.Initialize(); err != nil {
t.Errorf("%d> Unexpected config error: %v", i, err)
continue
}
@ -211,8 +188,6 @@ func TestAuth_loginHandlerFunc_POST(t *testing.T) {
}
func TestAuth_loginHandlerFunc_OtherMethods(t *testing.T) {
t.Parallel()
a := Auth{}
methods := []string{"HEAD", "PUT", "DELETE", "TRACE", "CONNECT"}
@ -233,10 +208,9 @@ func TestAuth_loginHandlerFunc_OtherMethods(t *testing.T) {
}
func TestAuth_logoutHandlerFunc_GET(t *testing.T) {
t.Parallel()
authboss.Cfg.AuthLogoutRoute = "/dashboard"
a := Auth{}
if err := a.Initialize(&authboss.Config{AuthLogoutRoute: "/dashboard"}); err != nil {
if err := a.Initialize(); err != nil {
t.Errorf("Unexpeced config error '%s'", err)
}
r, err := http.NewRequest("GET", "/logout", nil)
@ -267,8 +241,6 @@ func TestAuth_logoutHandlerFunc_GET(t *testing.T) {
}
func TestAuth_logoutHandlerFunc_OtherMethods(t *testing.T) {
t.Parallel()
a := Auth{}
methods := []string{"HEAD", "POST", "PUT", "DELETE", "TRACE", "CONNECT"}
@ -287,3 +259,4 @@ func TestAuth_logoutHandlerFunc_OtherMethods(t *testing.T) {
}
}
}
*/

View File

@ -8,26 +8,15 @@ Remember Me tokens, or passwords.
package authboss // import "gopkg.in/authboss.v0"
import (
"errors"
"fmt"
"net/http"
)
var (
cfg *Config
)
// Init authboss and it's loaded modules with a configuration.
func Init(config *Config) error {
if config.Storer == nil {
return errors.New("configuration must provide a storer.")
}
cfg = config
// Init authboss and it's loaded modules.
func Init() error {
for name, mod := range modules {
fmt.Fprintf(cfg.LogWriter, "%-10s Initializing\n", "["+name+"]")
if err := mod.Initialize(config); err != nil {
fmt.Fprintf(Cfg.LogWriter, "%-10s Initializing\n", "["+name+"]")
if err := mod.Initialize(); err != nil {
return fmt.Errorf("[%s] Error Initializing: %v", name, err)
}
}
@ -37,7 +26,7 @@ func Init(config *Config) error {
// CurrentUser retrieves the current user from the session and the database.
func CurrentUser(w http.ResponseWriter, r *http.Request) (interface{}, error) {
sessions := cfg.SessionStoreMaker(w, r)
sessions := Cfg.SessionStoreMaker(w, r)
key, ok := sessions.Get(SessionKey)
if !ok {
return nil, nil
@ -48,17 +37,17 @@ func CurrentUser(w http.ResponseWriter, r *http.Request) (interface{}, error) {
return nil, err
}
err = ctx.LoadUser(key, cfg.Storer)
err = ctx.LoadUser(key, Cfg.Storer)
if err != nil {
return nil, err
}
err = cfg.Callbacks.FireBefore(EventGet, ctx)
err = Cfg.Callbacks.FireBefore(EventGet, ctx)
if err != nil {
return nil, err
}
return cfg.Storer.Get(key, ModuleAttrMeta)
return Cfg.Storer.Get(key, ModuleAttrMeta)
}
// CurrentUserP retrieves the current user but panics if it's not available for

View File

@ -4,45 +4,34 @@ import (
"net/http"
"net/http/httptest"
"os"
"strings"
"testing"
)
func TestMain(main *testing.M) {
RegisterModule("testmodule", testMod)
Init(NewConfig())
Init()
code := main.Run()
os.Exit(code)
}
func TestAuthBossInit(t *testing.T) {
c := NewConfig()
err := Init(c)
if err == nil || !strings.Contains(err.Error(), "storer") {
t.Error("Expected error about a storer, got:", err)
}
c.Storer = mockStorer{}
err = Init(c)
NewConfig()
err := Init()
if err != nil {
t.Error("Unexpected error:", err)
}
if testMod.c == nil {
t.Error("Expected the modules to be passed the config.")
}
}
func TestAuthBossRouter(t *testing.T) {
c := NewConfig()
c.Storer = mockStorer{}
c.CookieStoreMaker = func(_ http.ResponseWriter, _ *http.Request) ClientStorer {
NewConfig()
Cfg.Storer = mockStorer{}
Cfg.CookieStoreMaker = func(_ http.ResponseWriter, _ *http.Request) ClientStorer {
return mockClientStore{}
}
c.SessionStoreMaker = SessionStoreMaker(c.CookieStoreMaker)
c.MountPath = "/candycanes"
Cfg.SessionStoreMaker = SessionStoreMaker(Cfg.CookieStoreMaker)
Cfg.MountPath = "/candycanes"
if err := Init(c); err != nil {
if err := Init(); err != nil {
t.Error("Unexpected error:", err)
}
router := NewRouter()
@ -58,13 +47,13 @@ func TestAuthBossRouter(t *testing.T) {
}
func TestAuthBossCurrentUser(t *testing.T) {
c := NewConfig()
c.Storer = mockStorer{"joe": Attributes{"email": "john@john.com", "password": "lies"}}
c.SessionStoreMaker = func(_ http.ResponseWriter, _ *http.Request) ClientStorer {
NewConfig()
Cfg.Storer = mockStorer{"joe": Attributes{"email": "john@john.com", "password": "lies"}}
Cfg.SessionStoreMaker = func(_ http.ResponseWriter, _ *http.Request) ClientStorer {
return mockClientStore{SessionKey: "joe"}
}
if err := Init(c); err != nil {
if err := Init(); err != nil {
t.Error("Unexpected error:", err)
}

View File

@ -16,6 +16,9 @@ const (
layoutEmailTpl = "layoutEmail.tpl"
)
// Cfg is the singleton instance of Config
var Cfg *Config = NewConfig()
// Config holds all the configuration for both authboss and it's modules.
type Config struct {
// MountPath is the path to mount the router at.
@ -64,7 +67,6 @@ type Config struct {
Mailer Mailer
}
// NewConfig creates a new config full of default values ready to override.
func NewConfig() *Config {
layout, err := views.AssetToTemplate(layoutTpl)
if err != nil {

View File

@ -29,14 +29,10 @@ func init() {
authboss.RegisterModule("expire", E)
}
type Expire struct {
window time.Duration
}
type Expire struct{}
func (e *Expire) Initialize(config *authboss.Config) error {
e.window = config.ExpireAfter
config.Callbacks.Before(authboss.EventGet, e.BeforeAuth)
func (e *Expire) Initialize() error {
authboss.Cfg.Callbacks.Before(authboss.EventGet, e.BeforeAuth)
return nil
}
@ -54,7 +50,7 @@ func (e *Expire) BeforeAuth(ctx *authboss.Context) error {
if ok {
if date, err := time.Parse(time.RFC3339, dateStr); err != nil {
Touch(ctx.SessionStorer)
} else if time.Now().UTC().After(date.Add(e.window)) {
} else if time.Now().UTC().After(date.Add(authboss.Cfg.ExpireAfter)) {
ctx.SessionStorer.Del(authboss.SessionKey)
return ErrExpired
}

View File

@ -9,21 +9,8 @@ import (
"gopkg.in/authboss.v0/internal/mocks"
)
func TestExpire(t *testing.T) {
t.Parallel()
config := authboss.NewConfig()
config.ExpireAfter = time.Hour
E.Initialize(config)
if E.window != time.Hour {
t.Error("Config not loaded properly:", E.window)
}
}
func TestExpire_Touch(t *testing.T) {
t.Parallel()
authboss.NewConfig()
session := mocks.NewMockClientStorer()
if _, ok := session.Get(UserLastAction); ok {
@ -40,9 +27,9 @@ func TestExpire_Touch(t *testing.T) {
}
func TestExpire_BeforeAuth(t *testing.T) {
t.Parallel()
expire := &Expire{window: time.Hour}
authboss.NewConfig()
authboss.Cfg.ExpireAfter = time.Hour
expire := &Expire{}
session := mocks.NewMockClientStorer()
ctx := mocks.MockRequestContext()
@ -82,6 +69,7 @@ func (t *testHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
func TestExpire_Middleware(t *testing.T) {
authboss.NewConfig()
session := mocks.NewMockClientStorer()
session.Values = map[string]string{
authboss.SessionKey: "username",

View File

@ -4,7 +4,6 @@ package lock
import (
"errors"
"fmt"
"io"
"time"
"gopkg.in/authboss.v0"
@ -30,30 +29,18 @@ func init() {
}
type Lock struct {
storer authboss.Storer
logger io.Writer
attempts int
window time.Duration
duration time.Duration
}
func (l *Lock) Initialize(config *authboss.Config) error {
if config.Storer == nil {
func (l *Lock) Initialize() error {
if authboss.Cfg.Storer == nil {
return errors.New("lock: Need a Storer.")
}
l.logger = config.LogWriter
l.attempts = config.LockAfter
l.window = config.LockWindow
l.duration = config.LockDuration
// Events
config.Callbacks.Before(authboss.EventGet, l.BeforeAuth)
config.Callbacks.Before(authboss.EventAuth, l.BeforeAuth)
config.Callbacks.After(authboss.EventAuth, l.AfterAuth)
config.Callbacks.After(authboss.EventAuthFail, l.AfterAuthFail)
authboss.Cfg.Callbacks.Before(authboss.EventGet, l.BeforeAuth)
authboss.Cfg.Callbacks.Before(authboss.EventAuth, l.BeforeAuth)
authboss.Cfg.Callbacks.After(authboss.EventAuth, l.AfterAuth)
authboss.Cfg.Callbacks.After(authboss.EventAuthFail, l.AfterAuthFail)
return nil
}
@ -88,23 +75,23 @@ func (l *Lock) BeforeAuth(ctx *authboss.Context) error {
// AfterAuth resets the attempt number field.
func (l *Lock) AfterAuth(ctx *authboss.Context) {
if ctx.User == nil {
fmt.Fprintln(l.logger, "lock: user not loaded in after auth callback")
fmt.Fprintln(authboss.Cfg.LogWriter, "lock: user not loaded in after auth callback")
}
var username string
if intf, ok := ctx.User["username"]; !ok {
fmt.Fprintf(l.logger, "lock: username not present")
fmt.Fprintf(authboss.Cfg.LogWriter, "lock: username not present")
return
} else if username, ok = intf.(string); !ok {
fmt.Fprintf(l.logger, "lock: username wrong type")
fmt.Fprintf(authboss.Cfg.LogWriter, "lock: username wrong type")
return
}
ctx.User[UserAttemptNumber] = 0
ctx.User[UserAttemptTime] = time.Now().UTC()
if err := ctx.SaveUser(username, l.storer); err != nil {
fmt.Fprintf(l.logger, "lock: saving user failed %v", err)
if err := ctx.SaveUser(username, authboss.Cfg.Storer); err != nil {
fmt.Fprintf(authboss.Cfg.LogWriter, "lock: saving user failed %v", err)
}
}
@ -116,10 +103,10 @@ func (l *Lock) AfterAuthFail(ctx *authboss.Context) {
var username string
if intf, ok := ctx.User["username"]; !ok {
fmt.Fprintf(l.logger, "lock: username not present")
fmt.Fprintf(authboss.Cfg.LogWriter, "lock: username not present")
return
} else if username, ok = intf.(string); !ok {
fmt.Fprintf(l.logger, "lock: username wrong type")
fmt.Fprintf(authboss.Cfg.LogWriter, "lock: username wrong type")
return
}
@ -139,8 +126,8 @@ func (l *Lock) AfterAuthFail(ctx *authboss.Context) {
nAttempts++
if time.Now().UTC().Sub(lastAttempt) <= l.window {
if nAttempts >= l.attempts {
if time.Now().UTC().Sub(lastAttempt) <= authboss.Cfg.LockWindow {
if nAttempts >= authboss.Cfg.LockAfter {
ctx.User[UserLocked] = true
}
@ -150,8 +137,8 @@ func (l *Lock) AfterAuthFail(ctx *authboss.Context) {
}
ctx.User[UserAttemptTime] = time.Now().UTC()
if err := ctx.SaveUser(username, l.storer); err != nil {
fmt.Fprintf(l.logger, "lock: saving user failed %v", err)
if err := ctx.SaveUser(username, authboss.Cfg.Storer); err != nil {
fmt.Fprintf(authboss.Cfg.LogWriter, "lock: saving user failed %v", err)
}
}
@ -186,7 +173,7 @@ func (l *Lock) Unlock(key string, storer authboss.Storer) error {
// Set the last attempt to be -window*2 to avoid immediately
// giving another login failure.
attr[UserAttemptTime] = time.Now().UTC().Add(-l.window * 2)
attr[UserAttemptTime] = time.Now().UTC().Add(-authboss.Cfg.LockWindow * 2)
attr[UserAttemptNumber] = 0
attr[UserLocked] = false

View File

@ -1,7 +1,6 @@
package lock
import (
"io/ioutil"
"testing"
"time"
@ -10,6 +9,7 @@ import (
)
func TestStorage(t *testing.T) {
authboss.NewConfig()
storage := L.Storage()
if _, ok := storage[UserAttemptNumber]; !ok {
t.Error("Expected attempt number storage option.")
@ -20,8 +20,8 @@ func TestStorage(t *testing.T) {
}
func TestBeforeAuth(t *testing.T) {
authboss.NewConfig()
ctx := authboss.NewContext()
L.logger = ioutil.Discard
if nil != L.BeforeAuth(ctx) {
t.Error("Expected it to break early.")
@ -39,8 +39,8 @@ func TestBeforeAuth(t *testing.T) {
}
func TestAfterAuth(t *testing.T) {
authboss.NewConfig()
lock := Lock{}
lock.logger = ioutil.Discard
ctx := authboss.NewContext()
lock.AfterAuth(ctx)
@ -61,7 +61,7 @@ func TestAfterAuth(t *testing.T) {
}
storer := mocks.NewMockStorer()
lock.storer = storer
authboss.Cfg.Storer = storer
ctx.User["username"] = "username"
lock.AfterAuth(ctx)
@ -74,16 +74,16 @@ func TestAfterAuth(t *testing.T) {
}
func TestAfterAuthFail_Lock(t *testing.T) {
authboss.NewConfig()
var old, current time.Time
var ok bool
ctx := authboss.NewContext()
storer := mocks.NewMockStorer()
authboss.Cfg.Storer = storer
lock := Lock{}
lock.logger = ioutil.Discard
lock.storer = storer
lock.window = 30 * time.Minute
lock.attempts = 3
authboss.Cfg.LockWindow = 30 * time.Minute
authboss.Cfg.LockAfter = 3
ctx.User = map[string]interface{}{"username": "username"}
@ -117,15 +117,15 @@ func TestAfterAuthFail_Lock(t *testing.T) {
}
func TestAfterAuthFail_Reset(t *testing.T) {
authboss.NewConfig()
var old, current time.Time
var ok bool
ctx := authboss.NewContext()
storer := mocks.NewMockStorer()
lock := Lock{}
lock.window = 30 * time.Minute
lock.logger = ioutil.Discard
lock.storer = storer
authboss.Cfg.LockWindow = 30 * time.Minute
authboss.Cfg.Storer = storer
old = time.Now().UTC().Add(-time.Hour)
@ -149,8 +149,8 @@ func TestAfterAuthFail_Reset(t *testing.T) {
}
func TestAfterAuthFail_Errors(t *testing.T) {
authboss.NewConfig()
lock := Lock{}
lock.logger = ioutil.Discard
ctx := authboss.NewContext()
lock.AfterAuthFail(ctx)
@ -172,6 +172,7 @@ func TestAfterAuthFail_Errors(t *testing.T) {
}
func TestLock(t *testing.T) {
authboss.NewConfig()
storer := mocks.NewMockStorer()
lock := Lock{}
@ -191,9 +192,10 @@ func TestLock(t *testing.T) {
}
func TestUnlock(t *testing.T) {
authboss.NewConfig()
storer := mocks.NewMockStorer()
lock := Lock{}
lock.window = 1 * time.Hour
authboss.Cfg.LockWindow = 1 * time.Hour
storer.Users["username"] = map[string]interface{}{
"username": "username",
@ -207,7 +209,7 @@ func TestUnlock(t *testing.T) {
}
attemptTime := storer.Users["username"][UserAttemptTime].(time.Time)
if attemptTime.After(time.Now().UTC().Add(-lock.window)) {
if attemptTime.After(time.Now().UTC().Add(-authboss.Cfg.LockWindow)) {
t.Error("UserLocked not set correctly:", attemptTime)
}
if number := storer.Users["username"][UserAttemptNumber].(int); number != 0 {

View File

@ -11,7 +11,7 @@ import (
// SendMail uses the currently configured mailer to deliver e-mails.
func SendMail(data Email) error {
return cfg.Mailer.Send(data)
return Cfg.Mailer.Send(data)
}
// Mailer is a type that is capable of sending an e-mail.

View File

@ -7,12 +7,12 @@ import (
)
func TestMailer(t *testing.T) {
NewConfig()
mailServer := &bytes.Buffer{}
config := NewConfig()
config.Mailer = LogMailer(mailServer)
config.Storer = mockStorer{}
Init(config)
Cfg.Mailer = LogMailer(mailServer)
Cfg.Storer = mockStorer{}
Init()
err := SendMail(Email{
To: []string{"some@email.com", "a@a.com"},

View File

@ -6,7 +6,7 @@ var ModuleAttrMeta = make(AttributeMeta)
// Modularizer should be implemented by all the authboss modules.
type Modularizer interface {
Initialize(*Config) error
Initialize() error
Routes() RouteTable
Storage() StorageOptions
}

View File

@ -8,7 +8,6 @@ import (
const testModName = "testmodule"
type testModule struct {
c *Config
s StorageOptions
r RouteTable
}
@ -23,8 +22,7 @@ func testHandler(ctx *Context, w http.ResponseWriter, r *http.Request) {
w.Header().Set("testhandler", "test")
}
func (t *testModule) Initialize(c *Config) error {
t.c = c
func (t *testModule) Initialize() error {
return nil
}

View File

@ -24,15 +24,15 @@ type pageRecoverComplete struct {
func (m *RecoverModule) recoverCompleteHandlerFunc(ctx *authboss.Context, w http.ResponseWriter, r *http.Request) {
switch r.Method {
case methodGET:
_, err := verifyToken(ctx, m.config.Storer.(authboss.RecoverStorer))
_, err := verifyToken(ctx, authboss.Cfg.Storer.(authboss.RecoverStorer))
if err != nil {
if err.Error() == errRecoveryTokenExpired.Error() {
fmt.Fprintln(m.config.LogWriter, "recover [token expired]:", err)
ctx.SessionStorer.Put(authboss.FlashErrorKey, m.config.RecoverTokenExpiredFlash)
fmt.Fprintln(authboss.Cfg.LogWriter, "recover [token expired]:", err)
ctx.SessionStorer.Put(authboss.FlashErrorKey, authboss.Cfg.RecoverTokenExpiredFlash)
http.Redirect(w, r, "/recover", http.StatusFound)
return
} else {
fmt.Fprintln(m.config.LogWriter, "recover:", err)
fmt.Fprintln(authboss.Cfg.LogWriter, "recover:", err)
http.Redirect(w, r, "/", http.StatusFound)
return
}
@ -52,7 +52,7 @@ func (m *RecoverModule) recoverCompleteHandlerFunc(ctx *authboss.Context, w http
return
}
http.Redirect(w, r, m.config.AuthLoginSuccessRoute, http.StatusFound)
http.Redirect(w, r, authboss.Cfg.AuthLoginSuccessRoute, http.StatusFound)
default:
w.WriteHeader(http.StatusMethodNotAllowed)
}
@ -90,24 +90,24 @@ func (m *RecoverModule) recoverComplete(ctx *authboss.Context) (errPage *pageRec
token, _ := ctx.FirstFormValue("token")
password, _ := ctx.FirstPostFormValue("password")
confirmPassword, _ := ctx.FirstPostFormValue("confirmPassword")
defaultErrPage := &pageRecoverComplete{token, password, confirmPassword, nil, "", m.config.RecoverFailedErrorFlash}
defaultErrPage := &pageRecoverComplete{token, password, confirmPassword, nil, "", authboss.Cfg.RecoverFailedErrorFlash}
var err error
ctx.User, err = verifyToken(ctx, m.config.Storer.(authboss.RecoverStorer))
ctx.User, err = verifyToken(ctx, authboss.Cfg.Storer.(authboss.RecoverStorer))
if err != nil {
fmt.Fprintf(m.config.LogWriter, errFormat, "failed to verify token", err)
fmt.Fprintf(authboss.Cfg.LogWriter, errFormat, "failed to verify token", err)
return defaultErrPage
}
policies := authboss.FilterValidators(m.config.Policies, "password")
if validationErrs := ctx.Validate(policies, m.config.ConfirmFields...); len(validationErrs) > 0 {
fmt.Fprintf(m.config.LogWriter, errFormat, "validation failed", validationErrs)
policies := authboss.FilterValidators(authboss.Cfg.Policies, "password")
if validationErrs := ctx.Validate(policies, authboss.Cfg.ConfirmFields...); len(validationErrs) > 0 {
fmt.Fprintf(authboss.Cfg.LogWriter, errFormat, "validation failed", validationErrs)
return &pageRecoverComplete{token, password, confirmPassword, validationErrs.Map(), "", ""}
}
encryptedPassword, err := bcrypt.GenerateFromPassword([]byte(password), m.config.BCryptCost)
encryptedPassword, err := bcrypt.GenerateFromPassword([]byte(password), authboss.Cfg.BCryptCost)
if err != nil {
fmt.Fprintf(m.config.LogWriter, errFormat, "failed to encrypt password", err)
fmt.Fprintf(authboss.Cfg.LogWriter, errFormat, "failed to encrypt password", err)
return defaultErrPage
}
ctx.User[attrPassword] = string(encryptedPassword)
@ -116,8 +116,8 @@ func (m *RecoverModule) recoverComplete(ctx *authboss.Context) (errPage *pageRec
ctx.User[attrRecoverTokenExpiry] = nullTime
username, _ := ctx.User.String(attrUsername)
if err := ctx.SaveUser(username, m.config.Storer); err != nil {
fmt.Fprintf(m.config.LogWriter, errFormat, "failed to save user", err)
if err := ctx.SaveUser(username, authboss.Cfg.Storer); err != nil {
fmt.Fprintf(authboss.Cfg.LogWriter, errFormat, "failed to save user", err)
return defaultErrPage
}

View File

@ -4,7 +4,6 @@ import (
"bytes"
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
"reflect"
@ -22,11 +21,9 @@ const (
)
func Test_recoverCompleteHandlerFunc_GET_TokenExpired(t *testing.T) {
t.Parallel()
m, logger := testValidRecoverModule()
storer, ok := m.config.Storer.(*mocks.MockStorer)
storer, ok := authboss.Cfg.Storer.(*mocks.MockStorer)
if !ok {
panic("Failed to get storer")
}
@ -50,7 +47,7 @@ func Test_recoverCompleteHandlerFunc_GET_TokenExpired(t *testing.T) {
t.Error("Expected logs to start with:", "recover [token expired]:")
}
if flash := clientStorer.Values[authboss.FlashErrorKey]; flash != m.config.RecoverTokenExpiredFlash {
if flash := clientStorer.Values[authboss.FlashErrorKey]; flash != authboss.Cfg.RecoverTokenExpiredFlash {
t.Error("Unexpected error flash:", flash)
}
@ -60,8 +57,6 @@ func Test_recoverCompleteHandlerFunc_GET_TokenExpired(t *testing.T) {
}
func Test_recoverCompleteHandlerFunc_GET_OtherErrors(t *testing.T) {
t.Parallel()
m, logger := testValidRecoverModule()
w, r, ctx := testHttpRequest("GET", "/recover/complete?token=asdf", nil)
@ -81,11 +76,9 @@ func Test_recoverCompleteHandlerFunc_GET_OtherErrors(t *testing.T) {
}
func Test_recoverCompleteHandlerFunc_GET(t *testing.T) {
t.Parallel()
m, _ := testValidRecoverModule()
storer, ok := m.config.Storer.(*mocks.MockStorer)
storer, ok := authboss.Cfg.Storer.(*mocks.MockStorer)
if !ok {
panic("Failed to get storer")
}
@ -117,8 +110,6 @@ func Test_recoverCompleteHandlerFunc_GET(t *testing.T) {
}
func Test_recoverCompleteHandlerFunc_POST_RecoveryCompleteFailed(t *testing.T) {
t.Parallel()
m, _ := testValidRecoverModule()
w, r, ctx := testHttpRequest(
"POST",
@ -132,7 +123,7 @@ func Test_recoverCompleteHandlerFunc_POST_RecoveryCompleteFailed(t *testing.T) {
Token: testUrlBase64Token,
Password: "a",
ConfirmPassword: "a",
FlashError: m.config.RecoverFailedErrorFlash,
FlashError: authboss.Cfg.RecoverFailedErrorFlash,
}); err != nil {
panic(err)
}
@ -140,9 +131,6 @@ func Test_recoverCompleteHandlerFunc_POST_RecoveryCompleteFailed(t *testing.T) {
// missing storer will cause this to fail
m.recoverCompleteHandlerFunc(ctx, w, r)
// spew.Dump(expectedBody.Bytes())
// spew.Dump(w.Body.Bytes())
if w.Code != http.StatusOK {
t.Error("Unexpected code:", w.Code)
}
@ -153,16 +141,14 @@ func Test_recoverCompleteHandlerFunc_POST_RecoveryCompleteFailed(t *testing.T) {
}
func Test_recoverCompleteHandlerFunc_POST(t *testing.T) {
t.Parallel()
m, logger := testValidRecoverModule()
m, _ := testValidRecoverModule()
w, r, ctx := testHttpRequest(
"POST",
fmt.Sprintf("/recover/complete?token=%s", testUrlBase64Token),
url.Values{"password": []string{"a"}, "confirmPassword": []string{"a"}},
)
storer, ok := m.config.Storer.(*mocks.MockStorer)
storer, ok := authboss.Cfg.Storer.(*mocks.MockStorer)
if !ok {
panic("Failed to get storer")
}
@ -174,8 +160,6 @@ func Test_recoverCompleteHandlerFunc_POST(t *testing.T) {
m.recoverCompleteHandlerFunc(ctx, w, r)
log.Println(logger)
if w.Code != http.StatusFound {
t.Error("Unexpected code:", w.Code)
}
@ -187,8 +171,7 @@ func Test_recoverCompleteHandlerFunc_POST(t *testing.T) {
}
func Test_verifyToken_MissingToken(t *testing.T) {
t.Parallel()
authboss.NewConfig()
ctx := mocks.MockRequestContext()
_, err := verifyToken(ctx, nil)
@ -198,10 +181,9 @@ func Test_verifyToken_MissingToken(t *testing.T) {
}
func Test_verifyToken_InvalidToken(t *testing.T) {
t.Parallel()
config := testValidTestConfig()
storer, ok := config.Storer.(*mocks.MockStorer)
authboss.NewConfig()
testValidTestConfig()
storer, ok := authboss.Cfg.Storer.(*mocks.MockStorer)
if !ok {
panic("Failed to get storer")
}
@ -218,10 +200,8 @@ func Test_verifyToken_InvalidToken(t *testing.T) {
}
func Test_verifyToken_ExpiredToken(t *testing.T) {
t.Parallel()
config := testValidTestConfig()
storer, ok := config.Storer.(*mocks.MockStorer)
testValidTestConfig()
storer, ok := authboss.Cfg.Storer.(*mocks.MockStorer)
if !ok {
panic("Failed to get storer")
}
@ -239,10 +219,9 @@ func Test_verifyToken_ExpiredToken(t *testing.T) {
}
func Test_verifyToken(t *testing.T) {
t.Parallel()
config := testValidTestConfig()
testValidTestConfig()
storer, ok := config.Storer.(*mocks.MockStorer)
storer, ok := authboss.Cfg.Storer.(*mocks.MockStorer)
if !ok {
panic("Failed to get storer")
}
@ -263,8 +242,6 @@ func Test_verifyToken(t *testing.T) {
}
func Test_recoverComplete_TokenVerificationFails(t *testing.T) {
t.Parallel()
m, logger := testValidRecoverModule()
ctx := mocks.MockRequestContext()
@ -272,7 +249,7 @@ func Test_recoverComplete_TokenVerificationFails(t *testing.T) {
if errPage == nil {
t.Error("Expected err page")
}
if !reflect.DeepEqual(*errPage, pageRecoverComplete{FlashError: m.config.RecoverFailedErrorFlash}) {
if !reflect.DeepEqual(*errPage, pageRecoverComplete{FlashError: authboss.Cfg.RecoverFailedErrorFlash}) {
t.Error("Unexpected err page:", errPage)
}
@ -286,12 +263,10 @@ func Test_recoverComplete_TokenVerificationFails(t *testing.T) {
}
func Test_recoverComplete_ValidationFails(t *testing.T) {
t.Parallel()
m, logger := testValidRecoverModule()
ctx := mocks.MockRequestContext("token", testUrlBase64Token, "password", "a", "confirmPassword", "b")
storer, ok := m.config.Storer.(*mocks.MockStorer)
storer, ok := authboss.Cfg.Storer.(*mocks.MockStorer)
if !ok {
panic("Failed to get storer")
}
@ -326,15 +301,13 @@ func Test_recoverComplete_ValidationFails(t *testing.T) {
}
func Test_recoverComplete(t *testing.T) {
t.Parallel()
m, _ := testValidRecoverModule()
ctx := mocks.MockRequestContext("token", testUrlBase64Token, "password", "a", "confirmPassword", "a")
clientStorer := mocks.NewMockClientStorer()
ctx.SessionStorer = clientStorer
storer, ok := m.config.Storer.(*mocks.MockStorer)
storer, ok := authboss.Cfg.Storer.(*mocks.MockStorer)
if !ok {
panic("Failed to get storer")
}
@ -375,8 +348,6 @@ func Test_recoverComplete(t *testing.T) {
}
func Test_recoverCompleteHandlerFunc_OtherMethods(t *testing.T) {
t.Parallel()
m, _ := testValidRecoverModule()
for i, method := range []string{"HEAD", "PUT", "DELETE", "TRACE", "CONNECT"} {

View File

@ -35,8 +35,8 @@ func (m *RecoverModule) recoverHandlerFunc(ctx *authboss.Context, w http.Respons
return
}
ctx.SessionStorer.Put(authboss.FlashSuccessKey, m.config.RecoverInitiateSuccessFlash)
http.Redirect(w, r, m.config.RecoverRedirect, http.StatusFound)
ctx.SessionStorer.Put(authboss.FlashSuccessKey, authboss.Cfg.RecoverInitiateSuccessFlash)
http.Redirect(w, r, authboss.Cfg.RecoverRedirect, http.StatusFound)
default:
w.WriteHeader(http.StatusMethodNotAllowed)
}
@ -46,23 +46,23 @@ func (m *RecoverModule) recover(ctx *authboss.Context) (errPage *pageRecover, em
username, _ := ctx.FirstPostFormValue("username")
confirmUsername, _ := ctx.FirstPostFormValue("confirmUsername")
policies := authboss.FilterValidators(m.config.Policies, "username")
if validationErrs := ctx.Validate(policies, m.config.ConfirmFields...); len(validationErrs) > 0 {
fmt.Fprintf(m.config.LogWriter, errFormat, "validation failed", validationErrs)
policies := authboss.FilterValidators(authboss.Cfg.Policies, "username")
if validationErrs := ctx.Validate(policies, authboss.Cfg.ConfirmFields...); len(validationErrs) > 0 {
fmt.Fprintf(authboss.Cfg.LogWriter, errFormat, "validation failed", validationErrs)
return &pageRecover{username, confirmUsername, validationErrs.Map(), "", ""}, nil
}
err, emailSent := m.makeAndSendToken(ctx, username)
if err != nil {
fmt.Fprintf(m.config.LogWriter, errFormat, "failed to recover", err)
return &pageRecover{username, confirmUsername, nil, "", m.config.RecoverFailedErrorFlash}, nil
fmt.Fprintf(authboss.Cfg.LogWriter, errFormat, "failed to recover", err)
return &pageRecover{username, confirmUsername, nil, "", authboss.Cfg.RecoverFailedErrorFlash}, nil
}
return nil, emailSent
}
func (m *RecoverModule) makeAndSendToken(ctx *authboss.Context, username string) (err error, emailSent <-chan struct{}) {
if err = ctx.LoadUser(username, m.config.Storer); err != nil {
if err = ctx.LoadUser(username, authboss.Cfg.Storer); err != nil {
return err, nil
}
@ -78,9 +78,9 @@ func (m *RecoverModule) makeAndSendToken(ctx *authboss.Context, username string)
sum := md5.Sum(token)
ctx.User[attrRecoverToken] = base64.StdEncoding.EncodeToString(sum[:])
ctx.User[attrRecoverTokenExpiry] = time.Now().Add(m.config.RecoverTokenDuration)
ctx.User[attrRecoverTokenExpiry] = time.Now().Add(authboss.Cfg.RecoverTokenDuration)
if err = ctx.SaveUser(username, m.config.Storer); err != nil {
if err = ctx.SaveUser(username, authboss.Cfg.Storer); err != nil {
return err, nil
}
@ -91,31 +91,31 @@ func (m *RecoverModule) sendRecoverEmail(to string, token []byte) <-chan struct{
emailSent := make(chan struct{}, 1)
go func() {
data := struct{ Link string }{fmt.Sprintf("%s/recover/complete?token=%s", m.config.HostName, base64.URLEncoding.EncodeToString(token))}
data := struct{ Link string }{fmt.Sprintf("%s/recover/complete?token=%s", authboss.Cfg.HostName, base64.URLEncoding.EncodeToString(token))}
htmlEmailBody, err := m.emailTemplates.ExecuteTemplate(tplInitHTMLEmail, data)
if err != nil {
fmt.Fprintf(m.config.LogWriter, errFormat, "failed to build html email", err)
fmt.Fprintf(authboss.Cfg.LogWriter, errFormat, "failed to build html email", err)
close(emailSent)
return
}
textEmaiLBody, err := m.emailTemplates.ExecuteTemplate(tplInitTextEmail, data)
if err != nil {
fmt.Fprintf(m.config.LogWriter, errFormat, "failed to build plaintext email", err)
fmt.Fprintf(authboss.Cfg.LogWriter, errFormat, "failed to build plaintext email", err)
close(emailSent)
return
}
if err := m.config.Mailer.Send(authboss.Email{
if err := authboss.Cfg.Mailer.Send(authboss.Email{
To: []string{to},
ToNames: []string{""},
From: m.config.EmailFrom,
Subject: m.config.EmailSubjectPrefix + "Password Reset",
From: authboss.Cfg.EmailFrom,
Subject: authboss.Cfg.EmailSubjectPrefix + "Password Reset",
TextBody: textEmaiLBody.String(),
HTMLBody: htmlEmailBody.String(),
}); err != nil {
fmt.Fprintf(m.config.LogWriter, errFormat, "failed to send email", err)
fmt.Fprintf(authboss.Cfg.LogWriter, errFormat, "failed to send email", err)
close(emailSent)
return
}

View File

@ -15,8 +15,6 @@ import (
)
func Test_recoverHandlerFunc_GET(t *testing.T) {
t.Parallel()
m, _ := testValidRecoverModule()
w, r, ctx := testHttpRequest("GET", "/recover", nil)
@ -36,8 +34,6 @@ func Test_recoverHandlerFunc_GET(t *testing.T) {
}
func Test_recoverHandlerFunc_POST_RecoveryFailed(t *testing.T) {
t.Parallel()
m, _ := testValidRecoverModule()
w, r, ctx := testHttpRequest("POST", "/login", url.Values{"username": []string{"a"}, "confirmUsername": []string{"a"}})
@ -46,7 +42,7 @@ func Test_recoverHandlerFunc_POST_RecoveryFailed(t *testing.T) {
if err := tpl.Execute(expectedBody, pageRecover{
Username: "a",
ConfirmUsername: "a",
FlashError: m.config.RecoverFailedErrorFlash,
FlashError: authboss.Cfg.RecoverFailedErrorFlash,
}); err != nil {
panic(err)
}
@ -64,12 +60,10 @@ func Test_recoverHandlerFunc_POST_RecoveryFailed(t *testing.T) {
}
func Test_recoverHandlerFunc_POST(t *testing.T) {
t.Parallel()
m, _ := testValidRecoverModule()
w, r, ctx := testHttpRequest("POST", "/login", url.Values{"username": []string{"a"}, "confirmUsername": []string{"a"}})
storer, ok := m.config.Storer.(*mocks.MockStorer)
storer, ok := authboss.Cfg.Storer.(*mocks.MockStorer)
if !ok {
panic("Failed to get storer")
}
@ -87,14 +81,12 @@ func Test_recoverHandlerFunc_POST(t *testing.T) {
}
successFlash := ctx.SessionStorer.(*mocks.MockClientStorer).Values[authboss.FlashSuccessKey]
if successFlash != m.config.RecoverInitiateSuccessFlash {
if successFlash != authboss.Cfg.RecoverInitiateSuccessFlash {
t.Error("Unexpected success flash message:", successFlash)
}
}
func Test_recover_UsernameValidationFail(t *testing.T) {
t.Parallel()
m, logger := testValidRecoverModule()
ctx := mocks.MockRequestContext()
@ -119,8 +111,6 @@ func Test_recover_UsernameValidationFail(t *testing.T) {
}
func Test_recover_ConfirmUsernameCheckFail(t *testing.T) {
t.Parallel()
m, logger := testValidRecoverModule()
ctx := mocks.MockRequestContext("username", "a", "confirmUsername", "b")
@ -148,8 +138,6 @@ func Test_recover_ConfirmUsernameCheckFail(t *testing.T) {
}
func Test_recover_InvalidUser(t *testing.T) {
t.Parallel()
m, logger := testValidRecoverModule()
ctx := mocks.MockRequestContext("username", "a", "confirmUsername", "a")
@ -157,8 +145,8 @@ func Test_recover_InvalidUser(t *testing.T) {
if page.ErrMap != nil {
t.Error("Exepted no validation errors")
}
if page.FlashError != m.config.RecoverFailedErrorFlash {
t.Error("Expected flash error:", m.config.RecoverFailedErrorFlash)
if page.FlashError != authboss.Cfg.RecoverFailedErrorFlash {
t.Error("Expected flash error:", authboss.Cfg.RecoverFailedErrorFlash)
}
actualLog, err := ioutil.ReadAll(logger)
@ -174,11 +162,9 @@ func Test_recover_InvalidUser(t *testing.T) {
}
func Test_recover(t *testing.T) {
t.Parallel()
m, _ := testValidRecoverModule()
storer, ok := m.config.Storer.(*mocks.MockStorer)
storer, ok := authboss.Cfg.Storer.(*mocks.MockStorer)
if !ok {
panic("Failed to get storer")
}
@ -196,8 +182,6 @@ func Test_recover(t *testing.T) {
}
func Test_makeAndSendToken_MissingStorer(t *testing.T) {
t.Parallel()
m, _ := testValidRecoverModule()
ctx := mocks.MockRequestContext()
@ -211,12 +195,10 @@ func Test_makeAndSendToken_MissingStorer(t *testing.T) {
}
func Test_makeAndSendToken_CheckEmail(t *testing.T) {
t.Parallel()
m, _ := testValidRecoverModule()
ctx := mocks.MockRequestContext()
storer, ok := m.config.Storer.(*mocks.MockStorer)
storer, ok := authboss.Cfg.Storer.(*mocks.MockStorer)
if !ok {
panic("Failed to get storer")
}
@ -244,12 +226,10 @@ func Test_makeAndSendToken_CheckEmail(t *testing.T) {
}
func Test_makeAndSendToken(t *testing.T) {
t.Parallel()
m, _ := testValidRecoverModule()
ctx := mocks.MockRequestContext()
storer, ok := m.config.Storer.(*mocks.MockStorer)
storer, ok := authboss.Cfg.Storer.(*mocks.MockStorer)
if !ok {
panic("Failed to get storer")
}
@ -276,7 +256,6 @@ func Test_makeAndSendToken(t *testing.T) {
}
func Test_sendRecoverEmail_InvalidTemplates(t *testing.T) {
t.Parallel()
m, logger := testValidRecoverModule()
failTpl, err := template.New("").Parse("{{.Fail}}")
@ -316,12 +295,11 @@ func Test_sendRecoverEmail_InvalidTemplates(t *testing.T) {
}
func Test_sendRecoverEmail_FailToSend(t *testing.T) {
t.Parallel()
m, logger := testValidRecoverModule()
mailer := mocks.NewMockMailer()
mailer.SendErr = "explode"
m.config.Mailer = mailer
authboss.Cfg.Mailer = mailer
<-m.sendRecoverEmail("a@b.c", []byte("abc123"))
actualLog, err := ioutil.ReadAll(logger)
@ -335,12 +313,11 @@ func Test_sendRecoverEmail_FailToSend(t *testing.T) {
}
func Test_sendRecoverEmail(t *testing.T) {
t.Parallel()
m, _ := testValidRecoverModule()
<-m.sendRecoverEmail("a@b.c", []byte("abc123"))
mailer, ok := m.config.Mailer.(*mocks.MockMailer)
mailer, ok := authboss.Cfg.Mailer.(*mocks.MockMailer)
if !ok {
panic("Failed to assert mock mailer")
}
@ -353,7 +330,7 @@ func Test_sendRecoverEmail(t *testing.T) {
t.Error("Unexpected to email:", sent.To[0])
}
if sent.From != m.config.EmailFrom {
if sent.From != authboss.Cfg.EmailFrom {
t.Error("Unexpected from email:", sent.From)
}
@ -365,7 +342,7 @@ func Test_sendRecoverEmail(t *testing.T) {
Link string
}{
fmt.Sprintf("%s/recover/complete?token=%s",
m.config.HostName,
authboss.Cfg.HostName,
base64.URLEncoding.EncodeToString([]byte("abc123")),
),
}
@ -387,8 +364,6 @@ func Test_sendRecoverEmail(t *testing.T) {
}
func Test_recoverHandlerFunc_OtherMethods(t *testing.T) {
t.Parallel()
m, _ := testValidRecoverModule()
for i, method := range []string{"HEAD", "PUT", "DELETE", "TRACE", "CONNECT"} {

View File

@ -37,34 +37,31 @@ func init() {
type RecoverModule struct {
templates views.Templates
emailTemplates views.Templates
config *authboss.Config
}
func (m *RecoverModule) Initialize(config *authboss.Config) (err error) {
if config.Storer == nil {
func (m *RecoverModule) Initialize() (err error) {
if authboss.Cfg.Storer == nil {
return errors.New("recover: Need a RecoverStorer.")
}
if _, ok := config.Storer.(authboss.RecoverStorer); !ok {
if _, ok := authboss.Cfg.Storer.(authboss.RecoverStorer); !ok {
return errors.New("recover: RecoverStorer required for recover functionality.")
}
if config.Layout == nil {
if authboss.Cfg.Layout == nil {
return errors.New("recover: Layout required for Recover functionallity.")
}
if m.templates, err = views.Get(config.Layout, config.ViewsPath, tplRecover, tplRecoverComplete); err != nil {
if m.templates, err = views.Get(authboss.Cfg.Layout, authboss.Cfg.ViewsPath, tplRecover, tplRecoverComplete); err != nil {
return err
}
if config.LayoutEmail == nil {
if authboss.Cfg.LayoutEmail == nil {
return errors.New("recover: LayoutEmail required for Recover functionallity.")
}
if m.emailTemplates, err = views.Get(config.LayoutEmail, config.ViewsPath, tplInitHTMLEmail, tplInitTextEmail); err != nil {
if m.emailTemplates, err = views.Get(authboss.Cfg.LayoutEmail, authboss.Cfg.ViewsPath, tplInitHTMLEmail, tplInitTextEmail); err != nil {
return err
}
m.config = config
return nil
}
@ -87,7 +84,7 @@ func (m *RecoverModule) Storage() authboss.StorageOptions {
func (m *RecoverModule) execTpl(tpl string, w http.ResponseWriter, data interface{}) {
buffer, err := m.templates.ExecuteTemplate(tpl, data)
if err != nil {
fmt.Fprintf(m.config.LogWriter, errFormat, "unable to execute template", err)
fmt.Fprintf(authboss.Cfg.LogWriter, errFormat, "unable to execute template", err)
w.WriteHeader(http.StatusInternalServerError)
return
}

View File

@ -9,7 +9,6 @@ import (
"net/http"
"net/http/httptest"
"net/url"
"os"
"strings"
"testing"
"time"
@ -20,73 +19,73 @@ import (
)
func Test_Initialize(t *testing.T) {
t.Parallel()
config := &authboss.Config{ViewsPath: os.TempDir()}
authboss.NewConfig()
m := &RecoverModule{}
authboss.Cfg.Storer = nil
if err := m.Initialize(config); err == nil {
if err := m.Initialize(); err == nil {
t.Error("Expected error")
} else if err.Error() != "recover: Need a RecoverStorer." {
t.Error("Got error but wrong reason:", err)
}
config.Storer = mocks.MockFailStorer{}
authboss.Cfg.Storer = mocks.MockFailStorer{}
if err := m.Initialize(config); err == nil {
if err := m.Initialize(); err == nil {
t.Error("Expected error")
} else if err.Error() != "recover: RecoverStorer required for recover functionality." {
t.Error("Got error but wrong reason:", err)
}
config.Storer = mocks.NewMockStorer()
authboss.Cfg.Storer = mocks.NewMockStorer()
authboss.Cfg.Layout = nil
if err := m.Initialize(config); err == nil {
if err := m.Initialize(); err == nil {
t.Error("Expected error")
} else if err.Error() != "recover: Layout required for Recover functionallity." {
t.Error("Got error but wrong reason:", err)
}
var err error
config.Layout, err = template.New("").Parse(`{{template "authboss" .}}`)
authboss.Cfg.Layout, err = template.New("").Parse(`{{template "authboss" .}}`)
if err != nil {
t.Fatal("Unexpected error:", err)
}
authboss.Cfg.LayoutEmail = nil
if err := m.Initialize(config); err == nil {
if err := m.Initialize(); err == nil {
t.Error("Expected error:", err)
} else if err.Error() != "recover: LayoutEmail required for Recover functionallity." {
t.Error("Got error but wrong reason:", err)
}
config.LayoutEmail, err = template.New("").Parse(`{{template "authboss" .}}`)
authboss.Cfg.LayoutEmail, err = template.New("").Parse(`{{template "authboss" .}}`)
if err != nil {
t.Fatal("Unexpected error:", err)
}
if err := m.Initialize(config); err != nil {
if err := m.Initialize(); err != nil {
t.Error("Unexpected error:", err)
}
}
func testValidTestConfig() *authboss.Config {
config := &authboss.Config{}
config.Storer = mocks.NewMockStorer()
config.EmailFrom = "auth@boss.com"
func testValidTestConfig() {
authboss.NewConfig()
authboss.Cfg.Storer = mocks.NewMockStorer()
authboss.Cfg.EmailFrom = "auth@boss.com"
var err error
if config.Layout, err = views.AssetToTemplate("layout.tpl"); err != nil {
if authboss.Cfg.Layout, err = views.AssetToTemplate("layout.tpl"); err != nil {
panic(err)
}
if config.LayoutEmail, err = views.AssetToTemplate("layoutEmail.tpl"); err != nil {
if authboss.Cfg.LayoutEmail, err = views.AssetToTemplate("layoutEmail.tpl"); err != nil {
panic(err)
}
config.RecoverRedirect = "/login"
config.RecoverInitiateSuccessFlash = "sf"
config.RecoverTokenExpiredFlash = "exf"
config.RecoverFailedErrorFlash = "errf"
authboss.Cfg.RecoverRedirect = "/login"
authboss.Cfg.RecoverInitiateSuccessFlash = "sf"
authboss.Cfg.RecoverTokenExpiredFlash = "exf"
authboss.Cfg.RecoverFailedErrorFlash = "errf"
config.Policies = []authboss.Validator{
authboss.Cfg.Policies = []authboss.Validator{
authboss.Rules{
FieldName: "username",
Required: true,
@ -96,31 +95,29 @@ func testValidTestConfig() *authboss.Config {
Required: true,
},
}
config.ConfirmFields = []string{"username", "confirmUsername", "password", "confirmPassword"}
config.LogWriter = &bytes.Buffer{}
config.Mailer = &mocks.MockMailer{}
config.EmailFrom = "auth@boss.com"
config.HostName = "localhost"
config.RecoverTokenDuration = time.Duration(24) * time.Hour
config.BCryptCost = 4
config.AuthLoginSuccessRoute = "/login"
return config
authboss.Cfg.ConfirmFields = []string{"username", "confirmUsername", "password", "confirmPassword"}
authboss.Cfg.LogWriter = &bytes.Buffer{}
authboss.Cfg.Mailer = &mocks.MockMailer{}
authboss.Cfg.EmailFrom = "auth@boss.com"
authboss.Cfg.HostName = "localhost"
authboss.Cfg.RecoverTokenDuration = time.Duration(24) * time.Hour
authboss.Cfg.BCryptCost = 4
authboss.Cfg.AuthLoginSuccessRoute = "/login"
}
func testValidRecoverModule() (*RecoverModule, *bytes.Buffer) {
c := testValidTestConfig()
testValidTestConfig()
m := &RecoverModule{}
if err := m.Initialize(c); err != nil {
if err := m.Initialize(); err != nil {
panic(err)
}
return m, c.LogWriter.(*bytes.Buffer)
return m, authboss.Cfg.LogWriter.(*bytes.Buffer)
}
func Test_Routes(t *testing.T) {
t.Parallel()
testValidTestConfig()
m, _ := testValidRecoverModule()
@ -136,7 +133,7 @@ func Test_Routes(t *testing.T) {
}
func Test_Storage(t *testing.T) {
t.Parallel()
testValidTestConfig()
m, _ := testValidRecoverModule()
@ -186,7 +183,7 @@ func testHttpRequest(method, url string, data url.Values) (*httptest.ResponseRec
}
func Test_execTpl_TemplateExectionFail(t *testing.T) {
t.Parallel()
testValidTestConfig()
m, logger := testValidRecoverModule()
w := httptest.NewRecorder()
@ -213,12 +210,12 @@ func Test_execTpl_TemplateExectionFail(t *testing.T) {
}
func Test_execTpl(t *testing.T) {
t.Parallel()
testValidTestConfig()
m, _ := testValidRecoverModule()
w := httptest.NewRecorder()
page := pageRecover{"bobby", "bob", nil, "", m.config.RecoverFailedErrorFlash}
page := pageRecover{"bobby", "bob", nil, "", authboss.Cfg.RecoverFailedErrorFlash}
m.execTpl(tplRecover, w, page)
tpl := m.templates[tplRecover]

View File

@ -10,7 +10,6 @@ import (
"encoding/base64"
"errors"
"fmt"
"io"
"gopkg.in/authboss.v0"
)
@ -31,26 +30,18 @@ func init() {
authboss.RegisterModule("remember", R)
}
type Remember struct {
storer authboss.TokenStorer
cookieStorer authboss.ClientStorer
sessionStorer authboss.ClientStorer
logger io.Writer
}
type Remember struct{}
func (r *Remember) Initialize(config *authboss.Config) error {
if config.Storer == nil {
func (r *Remember) Initialize() error {
if authboss.Cfg.Storer == nil {
return errors.New("remember: Need a TokenStorer.")
}
if storer, ok := config.Storer.(authboss.TokenStorer); !ok {
if _, ok := authboss.Cfg.Storer.(authboss.TokenStorer); !ok {
return errors.New("remember: TokenStorer required for remember me functionality.")
} else {
r.storer = storer
}
r.logger = config.LogWriter
config.Callbacks.After(authboss.EventAuth, r.AfterAuth)
authboss.Cfg.Callbacks.After(authboss.EventAuth, r.AfterAuth)
return nil
}
@ -70,24 +61,24 @@ func (r *Remember) AfterAuth(ctx *authboss.Context) {
}
if ctx.User == nil {
fmt.Fprintf(r.logger, "remember: AfterAuth no user loaded")
fmt.Fprintf(authboss.Cfg.LogWriter, "remember: AfterAuth no user loaded")
return
}
keyIntf, ok := ctx.User["username"]
if !ok {
fmt.Fprintf(r.logger, "remember: username not present")
fmt.Fprintf(authboss.Cfg.LogWriter, "remember: username not present")
return
}
key, ok := keyIntf.(string)
if !ok {
fmt.Fprintf(r.logger, "remember: username not a string")
fmt.Fprintf(authboss.Cfg.LogWriter, "remember: username not a string")
return
}
if _, err := r.New(ctx.CookieStorer, key); err != nil {
fmt.Fprintf(r.logger, "remember: Failed to create remember token: %v", err)
fmt.Fprintf(authboss.Cfg.LogWriter, "remember: Failed to create remember token: %v", err)
}
}
@ -108,7 +99,7 @@ func (r *Remember) New(cstorer authboss.ClientStorer, storageKey string) (string
storageToken := base64.StdEncoding.EncodeToString(sum[:])
// Save the token in the DB
if err := r.storer.AddToken(storageKey, storageToken); err != nil {
if err := authboss.Cfg.Storer.(authboss.TokenStorer).AddToken(storageKey, storageToken); err != nil {
return "", err
}
@ -143,7 +134,7 @@ func (r *Remember) Auth(
// Verify the tokens match.
sum := md5.Sum(token)
key, err := r.storer.UseToken(string(givenKey), base64.StdEncoding.EncodeToString(sum[:]))
key, err := authboss.Cfg.Storer.(authboss.TokenStorer).UseToken(string(givenKey), base64.StdEncoding.EncodeToString(sum[:]))
if err == authboss.ErrTokenNotFound {
return "", nil
} else if err != nil {

View File

@ -10,30 +10,32 @@ import (
)
func TestInitialize(t *testing.T) {
testConfig := authboss.NewConfig()
authboss.NewConfig()
r := &Remember{}
err := r.Initialize(testConfig)
err := r.Initialize()
if err == nil {
t.Error("Expected error about token storers.")
}
testConfig.Storer = mocks.MockFailStorer{}
err = r.Initialize(testConfig)
authboss.Cfg.Storer = mocks.MockFailStorer{}
err = r.Initialize()
if err == nil {
t.Error("Expected error about token storers.")
}
testConfig.Storer = mocks.NewMockStorer()
err = r.Initialize(testConfig)
authboss.Cfg.Storer = mocks.NewMockStorer()
err = r.Initialize()
if err != nil {
t.Error("Unexpected error:", err)
}
}
func TestAfterAuth(t *testing.T) {
authboss.NewConfig()
storer := mocks.NewMockStorer()
R.storer = storer
authboss.Cfg.Storer = storer
cookies := mocks.NewMockClientStorer()
session := mocks.NewMockClientStorer()
@ -60,8 +62,9 @@ func TestAfterAuth(t *testing.T) {
}
func TestNew(t *testing.T) {
authboss.NewConfig()
storer := mocks.NewMockStorer()
R.storer = storer
authboss.Cfg.Storer = storer
cookies := mocks.NewMockClientStorer()
key := "tester"
@ -87,8 +90,9 @@ func TestNew(t *testing.T) {
}
func TestAuth(t *testing.T) {
authboss.NewConfig()
storer := mocks.NewMockStorer()
R.storer = storer
authboss.Cfg.Storer = storer
cookies := mocks.NewMockClientStorer()
session := mocks.NewMockClientStorer()

View File

@ -18,8 +18,8 @@ func NewRouter() http.Handler {
for name, mod := range modules {
for route, handler := range mod.Routes() {
fmt.Fprintf(cfg.LogWriter, "%-10s Register Route: %s\n", "["+name+"]", route)
mux.Handle(path.Join(cfg.MountPath, route), contextRoute{handler})
fmt.Fprintf(Cfg.LogWriter, "%-10s Register Route: %s\n", "["+name+"]", route)
mux.Handle(path.Join(Cfg.MountPath, route), contextRoute{handler})
}
}
@ -33,12 +33,12 @@ type contextRoute struct {
func (c contextRoute) ServeHTTP(w http.ResponseWriter, r *http.Request) {
ctx, err := ContextFromRequest(r)
if err != nil {
fmt.Fprintf(cfg.LogWriter, "route: Malformed request, could not create context: %v", err)
fmt.Fprintf(Cfg.LogWriter, "route: Malformed request, could not create context: %v", err)
return
}
ctx.CookieStorer = cfg.CookieStoreMaker(w, r)
ctx.SessionStorer = cfg.SessionStoreMaker(w, r)
ctx.CookieStorer = Cfg.CookieStoreMaker(w, r)
ctx.SessionStorer = Cfg.SessionStoreMaker(w, r)
c.fn(ctx, w, r)
}

View File

@ -7,6 +7,8 @@ import (
)
func TestAttributes_Names(t *testing.T) {
t.Parallel()
attr := Attributes{
"integer": 5,
"string": "string",
@ -28,6 +30,8 @@ func TestAttributes_Names(t *testing.T) {
}
func TestAttributeMeta_Names(t *testing.T) {
t.Parallel()
meta := AttributeMeta{
"integer": Integer,
"string": String,
@ -49,6 +53,8 @@ func TestAttributeMeta_Names(t *testing.T) {
}
func TestDataType_String(t *testing.T) {
t.Parallel()
if Integer.String() != "Integer" {
t.Error("Expected Integer:", Integer)
}
@ -64,6 +70,8 @@ func TestDataType_String(t *testing.T) {
}
func TestAttributes_Bind(t *testing.T) {
t.Parallel()
anInteger := 5
aString := "string"
aBool := true
@ -102,6 +110,8 @@ func TestAttributes_Bind(t *testing.T) {
}
func TestAttributes_BindNoPtr(t *testing.T) {
t.Parallel()
data := Attributes{}
s := struct{}{}
@ -113,6 +123,8 @@ func TestAttributes_BindNoPtr(t *testing.T) {
}
func TestAttributes_BindMissingField(t *testing.T) {
t.Parallel()
data := Attributes{"Integer": 5}
s := struct{}{}
@ -124,6 +136,8 @@ func TestAttributes_BindMissingField(t *testing.T) {
}
func TestAttributes_BindTypeFail(t *testing.T) {
t.Parallel()
tests := []struct {
Attr Attributes
Err string
@ -170,6 +184,8 @@ func TestAttributes_BindTypeFail(t *testing.T) {
}
func TestAttributes_Unbind(t *testing.T) {
t.Parallel()
s1 := struct {
Integer int
String string
@ -221,6 +237,8 @@ func TestAttributes_Unbind(t *testing.T) {
}
func TestCasingStyleConversions(t *testing.T) {
t.Parallel()
camel := "SomethingInCamel"
got := camelToUnder(camel)

View File

@ -26,11 +26,11 @@ type Validate struct {
Password authboss.Validator
}
func (v *Validate) Initialize(config *authboss.Config) error {
policies := authboss.FilterValidators(config.Policies, policyEmail, policyUsername, policyPassword)
func (v *Validate) Initialize() error {
policies := authboss.FilterValidators(authboss.Cfg.Policies, policyEmail, policyUsername, policyPassword)
if v.Email = policies[0]; v.Email.Field() != policyEmail {
return fmt.Errorf("validate: missing policy: %s", policyEmail)
return fmt.Errorf("validate: missin g policy: %s", policyEmail)
}
if v.Username = policies[1]; v.Username.Field() != policyUsername {
@ -41,9 +41,9 @@ func (v *Validate) Initialize(config *authboss.Config) error {
return fmt.Errorf("validate: missing policy: %s", policyPassword)
}
config.Callbacks.Before(authboss.EventRegister, v.BeforeRegister)
config.Callbacks.Before(authboss.EventRecoverStart, v.BeforeRegister)
config.Callbacks.Before(authboss.EventRecoverEnd, v.BeforeRegister)
authboss.Cfg.Callbacks.Before(authboss.EventRegister, v.BeforeRegister)
authboss.Cfg.Callbacks.Before(authboss.EventRecoverStart, v.BeforeRegister)
authboss.Cfg.Callbacks.Before(authboss.EventRecoverEnd, v.BeforeRegister)
return nil
}

View File

@ -9,14 +9,14 @@ import (
)
func TestValidate_Initialiaze(t *testing.T) {
cfg := authboss.NewConfig()
cfg.Policies = []authboss.Validator{
authboss.NewConfig()
authboss.Cfg.Policies = []authboss.Validator{
authboss.Rules{FieldName: policyEmail},
authboss.Rules{FieldName: policyUsername},
authboss.Rules{FieldName: policyPassword},
}
err := V.Initialize(cfg)
err := V.Initialize()
if err != nil {
t.Error("Unexpected error:", err)
}
@ -33,14 +33,14 @@ func TestValidate_Initialiaze(t *testing.T) {
}
func TestValidate_BeforeRegister(t *testing.T) {
cfg := authboss.NewConfig()
cfg.Policies = []authboss.Validator{
authboss.NewConfig()
authboss.Cfg.Policies = []authboss.Validator{
authboss.Rules{FieldName: policyEmail, MinLength: 15},
authboss.Rules{FieldName: policyUsername, MaxLength: 1},
authboss.Rules{FieldName: policyPassword, MinLength: 8},
}
err := V.Initialize(cfg)
err := V.Initialize()
if err != nil {
t.Error("Unexpected error:", err)
}