mirror of
https://github.com/volatiletech/authboss.git
synced 2025-02-03 13:21:22 +02:00
Fix modules after refactor.
This commit is contained in:
parent
9ff0b65629
commit
c98ef93e06
47
auth/auth.go
47
auth/auth.go
@ -24,24 +24,27 @@ func init() {
|
||||
|
||||
// Auth module
|
||||
type Auth struct {
|
||||
*authboss.Authboss
|
||||
templates response.Templates
|
||||
}
|
||||
|
||||
// Initialize module
|
||||
func (a *Auth) Initialize() (err error) {
|
||||
if authboss.a.Storer == nil {
|
||||
func (a *Auth) Initialize(ab *authboss.Authboss) (err error) {
|
||||
a.Authboss = ab
|
||||
|
||||
if a.Storer == nil {
|
||||
return errors.New("auth: Need a Storer")
|
||||
}
|
||||
|
||||
if len(authboss.a.XSRFName) == 0 {
|
||||
if len(a.XSRFName) == 0 {
|
||||
return errors.New("auth: XSRFName must be set")
|
||||
}
|
||||
|
||||
if authboss.a.XSRFMaker == nil {
|
||||
if a.XSRFMaker == nil {
|
||||
return errors.New("auth: XSRFMaker must be defined")
|
||||
}
|
||||
|
||||
a.templates, err = response.LoadTemplates(authboss.a.Layout, authboss.a.ViewsPath, tplLogin)
|
||||
a.templates, err = response.LoadTemplates(a.Authboss, a.Layout, a.ViewsPath, tplLogin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -60,7 +63,7 @@ func (a *Auth) Routes() authboss.RouteTable {
|
||||
// Storage requirements
|
||||
func (a *Auth) Storage() authboss.StorageOptions {
|
||||
return authboss.StorageOptions{
|
||||
authboss.a.PrimaryID: authboss.String,
|
||||
a.PrimaryID: authboss.String,
|
||||
authboss.StorePassword: authboss.String,
|
||||
}
|
||||
}
|
||||
@ -70,32 +73,32 @@ 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.SessionHalfAuthKey); !ok || halfAuthed == "false" {
|
||||
//http.Redirect(w, r, authboss.a.AuthLoginOKPath, http.StatusFound, true)
|
||||
response.Redirect(ctx, w, r, authboss.a.AuthLoginOKPath, "", "", true)
|
||||
//http.Redirect(w, r, a.AuthLoginOKPath, http.StatusFound, true)
|
||||
response.Redirect(ctx, w, r, a.AuthLoginOKPath, "", "", true)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
data := authboss.NewHTMLData(
|
||||
"showRemember", authboss.IsLoaded("remember"),
|
||||
"showRecover", authboss.IsLoaded("recover"),
|
||||
"primaryID", authboss.a.PrimaryID,
|
||||
"showRemember", a.IsLoaded("remember"),
|
||||
"showRecover", a.IsLoaded("recover"),
|
||||
"primaryID", a.PrimaryID,
|
||||
"primaryIDValue", "",
|
||||
)
|
||||
return a.templates.Render(ctx, w, r, tplLogin, data)
|
||||
case methodPOST:
|
||||
key, _ := ctx.FirstPostFormValue(authboss.a.PrimaryID)
|
||||
key, _ := ctx.FirstPostFormValue(a.PrimaryID)
|
||||
password, _ := ctx.FirstPostFormValue("password")
|
||||
|
||||
errData := authboss.NewHTMLData(
|
||||
"error", fmt.Sprintf("invalid %s and/or password", authboss.a.PrimaryID),
|
||||
"primaryID", authboss.a.PrimaryID,
|
||||
"error", fmt.Sprintf("invalid %s and/or password", a.PrimaryID),
|
||||
"primaryID", a.PrimaryID,
|
||||
"primaryIDValue", key,
|
||||
"showRemember", authboss.IsLoaded("remember"),
|
||||
"showRecover", authboss.IsLoaded("recover"),
|
||||
"showRemember", a.IsLoaded("remember"),
|
||||
"showRecover", a.IsLoaded("recover"),
|
||||
)
|
||||
|
||||
policies := authboss.FilterValidators(authboss.a.Policies, authboss.a.PrimaryID, authboss.StorePassword)
|
||||
policies := authboss.FilterValidators(a.Policies, a.PrimaryID, authboss.StorePassword)
|
||||
if validationErrs := ctx.Validate(policies); len(validationErrs) > 0 {
|
||||
return a.templates.Render(ctx, w, r, tplLogin, errData)
|
||||
}
|
||||
@ -104,7 +107,7 @@ func (a *Auth) loginHandlerFunc(ctx *authboss.Context, w http.ResponseWriter, r
|
||||
return a.templates.Render(ctx, w, r, tplLogin, errData)
|
||||
}
|
||||
|
||||
interrupted, err := authboss.a.Callbacks.FireBefore(authboss.EventAuth, ctx)
|
||||
interrupted, err := a.Callbacks.FireBefore(authboss.EventAuth, ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if interrupted != authboss.InterruptNone {
|
||||
@ -115,17 +118,17 @@ func (a *Auth) loginHandlerFunc(ctx *authboss.Context, w http.ResponseWriter, r
|
||||
case authboss.InterruptAccountNotConfirmed:
|
||||
reason = "Your account has not been confirmed."
|
||||
}
|
||||
response.Redirect(ctx, w, r, authboss.a.AuthLoginFailPath, "", reason, false)
|
||||
response.Redirect(ctx, w, r, a.AuthLoginFailPath, "", reason, false)
|
||||
return nil
|
||||
}
|
||||
|
||||
ctx.SessionStorer.Put(authboss.SessionKey, key)
|
||||
ctx.SessionStorer.Del(authboss.SessionHalfAuthKey)
|
||||
|
||||
if err := authboss.a.Callbacks.FireAfter(authboss.EventAuth, ctx); err != nil {
|
||||
if err := a.Callbacks.FireAfter(authboss.EventAuth, ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
response.Redirect(ctx, w, r, authboss.a.AuthLoginOKPath, "", "", true)
|
||||
response.Redirect(ctx, w, r, a.AuthLoginOKPath, "", "", true)
|
||||
default:
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
}
|
||||
@ -157,7 +160,7 @@ func (a *Auth) logoutHandlerFunc(ctx *authboss.Context, w http.ResponseWriter, r
|
||||
ctx.CookieStorer.Del(authboss.CookieRemember)
|
||||
ctx.SessionStorer.Del(authboss.SessionLastAction)
|
||||
|
||||
response.Redirect(ctx, w, r, authboss.a.AuthLogoutOKPath, "You have logged out", "", true)
|
||||
response.Redirect(ctx, w, r, a.AuthLogoutOKPath, "You have logged out", "", true)
|
||||
default:
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
}
|
||||
|
@ -16,43 +16,45 @@ import (
|
||||
func testSetup() (a *Auth, s *mocks.MockStorer) {
|
||||
s = mocks.NewMockStorer()
|
||||
|
||||
authboss.Cfg = authboss.NewConfig()
|
||||
authboss.a.LogWriter = ioutil.Discard
|
||||
authboss.a.Layout = template.Must(template.New("").Parse(`{{template "authboss" .}}`))
|
||||
authboss.a.Storer = s
|
||||
authboss.a.XSRFName = "xsrf"
|
||||
authboss.a.XSRFMaker = func(_ http.ResponseWriter, _ *http.Request) string {
|
||||
ab := authboss.New()
|
||||
ab.LogWriter = ioutil.Discard
|
||||
ab.Layout = template.Must(template.New("").Parse(`{{template "authboss" .}}`))
|
||||
ab.Storer = s
|
||||
ab.XSRFName = "xsrf"
|
||||
ab.XSRFMaker = func(_ http.ResponseWriter, _ *http.Request) string {
|
||||
return "xsrfvalue"
|
||||
}
|
||||
authboss.a.PrimaryID = authboss.StoreUsername
|
||||
ab.PrimaryID = authboss.StoreUsername
|
||||
|
||||
a = &Auth{}
|
||||
if err := a.Initialize(); err != nil {
|
||||
if err := a.Initialize(ab); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return a, s
|
||||
}
|
||||
|
||||
func testRequest(method string, postFormValues ...string) (*authboss.Context, *httptest.ResponseRecorder, *http.Request, authboss.ClientStorerErr) {
|
||||
func testRequest(ab *authboss.Authboss, method string, postFormValues ...string) (*authboss.Context, *httptest.ResponseRecorder, *http.Request, authboss.ClientStorerErr) {
|
||||
r, err := http.NewRequest(method, "", nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
sessionStorer := mocks.NewMockClientStorer()
|
||||
ctx := mocks.MockRequestContext(postFormValues...)
|
||||
ctx := mocks.MockRequestContext(ab, postFormValues...)
|
||||
ctx.SessionStorer = sessionStorer
|
||||
|
||||
return ctx, httptest.NewRecorder(), r, sessionStorer
|
||||
}
|
||||
|
||||
func TestAuth(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
a, _ := testSetup()
|
||||
|
||||
storage := a.Storage()
|
||||
if storage[authboss.a.PrimaryID] != authboss.String {
|
||||
t.Error("Expected storage KV:", authboss.a.PrimaryID, authboss.String)
|
||||
if storage[a.PrimaryID] != authboss.String {
|
||||
t.Error("Expected storage KV:", a.PrimaryID, authboss.String)
|
||||
}
|
||||
if storage[authboss.StorePassword] != authboss.String {
|
||||
t.Error("Expected storage KV:", authboss.StorePassword, authboss.String)
|
||||
@ -68,13 +70,15 @@ func TestAuth(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAuth_loginHandlerFunc_GET_RedirectsWhenHalfAuthed(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
a, _ := testSetup()
|
||||
ctx, w, r, sessionStore := testRequest("GET")
|
||||
ctx, w, r, sessionStore := testRequest(a.Authboss, "GET")
|
||||
|
||||
sessionStore.Put(authboss.SessionKey, "a")
|
||||
sessionStore.Put(authboss.SessionHalfAuthKey, "false")
|
||||
|
||||
authboss.a.AuthLoginOKPath = "/dashboard"
|
||||
a.AuthLoginOKPath = "/dashboard"
|
||||
|
||||
if err := a.loginHandlerFunc(ctx, w, r); err != nil {
|
||||
t.Error("Unexpeced error:", err)
|
||||
@ -85,14 +89,16 @@ func TestAuth_loginHandlerFunc_GET_RedirectsWhenHalfAuthed(t *testing.T) {
|
||||
}
|
||||
|
||||
loc := w.Header().Get("Location")
|
||||
if loc != authboss.a.AuthLoginOKPath {
|
||||
if loc != a.AuthLoginOKPath {
|
||||
t.Error("Unexpected redirect:", loc)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuth_loginHandlerFunc_GET(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
a, _ := testSetup()
|
||||
ctx, w, r, _ := testRequest("GET")
|
||||
ctx, w, r, _ := testRequest(a.Authboss, "GET")
|
||||
|
||||
if err := a.loginHandlerFunc(ctx, w, r); err != nil {
|
||||
t.Error("Unexpected error:", err)
|
||||
@ -106,7 +112,7 @@ func TestAuth_loginHandlerFunc_GET(t *testing.T) {
|
||||
if !strings.Contains(body, "<form") {
|
||||
t.Error("Should have rendered a form")
|
||||
}
|
||||
if !strings.Contains(body, `name="`+authboss.a.PrimaryID) {
|
||||
if !strings.Contains(body, `name="`+a.PrimaryID) {
|
||||
t.Error("Form should contain the primary ID field:", body)
|
||||
}
|
||||
if !strings.Contains(body, `name="password"`) {
|
||||
@ -115,15 +121,17 @@ func TestAuth_loginHandlerFunc_GET(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAuth_loginHandlerFunc_POST_ReturnsErrorOnCallbackFailure(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
a, storer := testSetup()
|
||||
storer.Users["john"] = authboss.Attributes{"password": "$2a$10$B7aydtqVF9V8RSNx3lCKB.l09jqLV/aMiVqQHajtL7sWGhCS9jlOu"}
|
||||
|
||||
authboss.a.Callbacks = authboss.NewCallbacks()
|
||||
authboss.a.Callbacks.Before(authboss.EventAuth, func(_ *authboss.Context) (authboss.Interrupt, error) {
|
||||
a.Callbacks = authboss.NewCallbacks()
|
||||
a.Callbacks.Before(authboss.EventAuth, func(_ *authboss.Context) (authboss.Interrupt, error) {
|
||||
return authboss.InterruptNone, errors.New("explode")
|
||||
})
|
||||
|
||||
ctx, w, r, _ := testRequest("POST", "username", "john", "password", "1234")
|
||||
ctx, w, r, _ := testRequest(a.Authboss, "POST", "username", "john", "password", "1234")
|
||||
|
||||
if err := a.loginHandlerFunc(ctx, w, r); err.Error() != "explode" {
|
||||
t.Error("Unexpected error:", err)
|
||||
@ -131,15 +139,17 @@ func TestAuth_loginHandlerFunc_POST_ReturnsErrorOnCallbackFailure(t *testing.T)
|
||||
}
|
||||
|
||||
func TestAuth_loginHandlerFunc_POST_RedirectsWhenInterrupted(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
a, storer := testSetup()
|
||||
storer.Users["john"] = authboss.Attributes{"password": "$2a$10$B7aydtqVF9V8RSNx3lCKB.l09jqLV/aMiVqQHajtL7sWGhCS9jlOu"}
|
||||
|
||||
authboss.a.Callbacks = authboss.NewCallbacks()
|
||||
authboss.a.Callbacks.Before(authboss.EventAuth, func(_ *authboss.Context) (authboss.Interrupt, error) {
|
||||
a.Callbacks = authboss.NewCallbacks()
|
||||
a.Callbacks.Before(authboss.EventAuth, func(_ *authboss.Context) (authboss.Interrupt, error) {
|
||||
return authboss.InterruptAccountLocked, nil
|
||||
})
|
||||
|
||||
ctx, w, r, sessionStore := testRequest("POST", "username", "john", "password", "1234")
|
||||
ctx, w, r, sessionStore := testRequest(a.Authboss, "POST", "username", "john", "password", "1234")
|
||||
|
||||
if err := a.loginHandlerFunc(ctx, w, r); err != nil {
|
||||
t.Error("Unexpected error:", err)
|
||||
@ -150,7 +160,7 @@ func TestAuth_loginHandlerFunc_POST_RedirectsWhenInterrupted(t *testing.T) {
|
||||
}
|
||||
|
||||
loc := w.Header().Get("Location")
|
||||
if loc != authboss.a.AuthLoginFailPath {
|
||||
if loc != a.AuthLoginFailPath {
|
||||
t.Error("Unexpeced location:", loc)
|
||||
}
|
||||
|
||||
@ -159,8 +169,8 @@ func TestAuth_loginHandlerFunc_POST_RedirectsWhenInterrupted(t *testing.T) {
|
||||
t.Error("Expected error flash message:", expectedMsg)
|
||||
}
|
||||
|
||||
authboss.a.Callbacks = authboss.NewCallbacks()
|
||||
authboss.a.Callbacks.Before(authboss.EventAuth, func(_ *authboss.Context) (authboss.Interrupt, error) {
|
||||
a.Callbacks = authboss.NewCallbacks()
|
||||
a.Callbacks.Before(authboss.EventAuth, func(_ *authboss.Context) (authboss.Interrupt, error) {
|
||||
return authboss.InterruptAccountNotConfirmed, nil
|
||||
})
|
||||
|
||||
@ -173,7 +183,7 @@ func TestAuth_loginHandlerFunc_POST_RedirectsWhenInterrupted(t *testing.T) {
|
||||
}
|
||||
|
||||
loc = w.Header().Get("Location")
|
||||
if loc != authboss.a.AuthLoginFailPath {
|
||||
if loc != a.AuthLoginFailPath {
|
||||
t.Error("Unexpeced location:", loc)
|
||||
}
|
||||
|
||||
@ -184,9 +194,11 @@ func TestAuth_loginHandlerFunc_POST_RedirectsWhenInterrupted(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAuth_loginHandlerFunc_POST_AuthenticationFailure(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
a, _ := testSetup()
|
||||
|
||||
ctx, w, r, _ := testRequest("POST", "username", "john", "password", "1")
|
||||
ctx, w, r, _ := testRequest(a.Authboss, "POST", "username", "john", "password", "1")
|
||||
|
||||
if err := a.loginHandlerFunc(ctx, w, r); err != nil {
|
||||
t.Error("Unexpected error:", err)
|
||||
@ -201,7 +213,7 @@ func TestAuth_loginHandlerFunc_POST_AuthenticationFailure(t *testing.T) {
|
||||
t.Error("Should have rendered with error")
|
||||
}
|
||||
|
||||
ctx, w, r, _ = testRequest("POST", "username", "john", "password", "1234")
|
||||
ctx, w, r, _ = testRequest(a.Authboss, "POST", "username", "john", "password", "1234")
|
||||
|
||||
if err := a.loginHandlerFunc(ctx, w, r); err != nil {
|
||||
t.Error("Unexpected error:", err)
|
||||
@ -218,15 +230,17 @@ func TestAuth_loginHandlerFunc_POST_AuthenticationFailure(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAuth_loginHandlerFunc_POST(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
a, storer := testSetup()
|
||||
storer.Users["john"] = authboss.Attributes{"password": "$2a$10$B7aydtqVF9V8RSNx3lCKB.l09jqLV/aMiVqQHajtL7sWGhCS9jlOu"}
|
||||
|
||||
ctx, w, r, _ := testRequest("POST", "username", "john", "password", "1234")
|
||||
ctx, w, r, _ := testRequest(a.Authboss, "POST", "username", "john", "password", "1234")
|
||||
cb := mocks.NewMockAfterCallback()
|
||||
|
||||
authboss.a.Callbacks = authboss.NewCallbacks()
|
||||
authboss.a.Callbacks.After(authboss.EventAuth, cb.Fn)
|
||||
authboss.a.AuthLoginOKPath = "/dashboard"
|
||||
a.Callbacks = authboss.NewCallbacks()
|
||||
a.Callbacks.After(authboss.EventAuth, cb.Fn)
|
||||
a.AuthLoginOKPath = "/dashboard"
|
||||
|
||||
sessions := mocks.NewMockClientStorer()
|
||||
ctx.SessionStorer = sessions
|
||||
@ -244,7 +258,7 @@ func TestAuth_loginHandlerFunc_POST(t *testing.T) {
|
||||
}
|
||||
|
||||
loc := w.Header().Get("Location")
|
||||
if loc != authboss.a.AuthLoginOKPath {
|
||||
if loc != a.AuthLoginOKPath {
|
||||
t.Error("Unexpeced location:", loc)
|
||||
}
|
||||
|
||||
@ -257,6 +271,8 @@ func TestAuth_loginHandlerFunc_POST(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAuth_loginHandlerFunc_OtherMethods(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
a, _ := testSetup()
|
||||
methods := []string{"HEAD", "PUT", "DELETE", "TRACE", "CONNECT"}
|
||||
|
||||
@ -279,35 +295,39 @@ func TestAuth_loginHandlerFunc_OtherMethods(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAuth_validateCredentials(t *testing.T) {
|
||||
authboss.Cfg = authboss.NewConfig()
|
||||
t.Parallel()
|
||||
|
||||
ab := authboss.New()
|
||||
|
||||
storer := mocks.NewMockStorer()
|
||||
storer.GetErr = "Failed to load user"
|
||||
authboss.a.Storer = storer
|
||||
ab.Storer = storer
|
||||
|
||||
ctx := authboss.Context{}
|
||||
ctx := ab.NewContext()
|
||||
|
||||
if err := validateCredentials(&ctx, "", ""); err.Error() != "Failed to load user" {
|
||||
if err := validateCredentials(ctx, "", ""); err.Error() != "Failed to load user" {
|
||||
t.Error("Unexpected error:", err)
|
||||
}
|
||||
|
||||
storer.GetErr = ""
|
||||
storer.Users["john"] = authboss.Attributes{"password": "$2a$10$pgFsuQwdhwOdZp/v52dvHeEi53ZaI7dGmtwK4bAzGGN5A4nT6doqm"}
|
||||
if err := validateCredentials(&ctx, "john", "b"); err == nil {
|
||||
if err := validateCredentials(ctx, "john", "b"); err == nil {
|
||||
t.Error("Expected error about passwords mismatch")
|
||||
}
|
||||
|
||||
if err := validateCredentials(&ctx, "john", "a"); err != nil {
|
||||
if err := validateCredentials(ctx, "john", "a"); err != nil {
|
||||
t.Error("Unexpected error:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuth_logoutHandlerFunc_GET(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
a, _ := testSetup()
|
||||
|
||||
authboss.a.AuthLogoutOKPath = "/dashboard"
|
||||
a.AuthLogoutOKPath = "/dashboard"
|
||||
|
||||
ctx, w, r, sessionStorer := testRequest("GET")
|
||||
ctx, w, r, sessionStorer := testRequest(a.Authboss, "GET")
|
||||
sessionStorer.Put(authboss.SessionKey, "asdf")
|
||||
sessionStorer.Put(authboss.SessionLastAction, "1234")
|
||||
|
||||
|
@ -46,30 +46,33 @@ func init() {
|
||||
|
||||
// Confirm module
|
||||
type Confirm struct {
|
||||
*authboss.Authboss
|
||||
emailHTMLTemplates response.Templates
|
||||
emailTextTemplates response.Templates
|
||||
}
|
||||
|
||||
// Initialize the module
|
||||
func (c *Confirm) Initialize() (err error) {
|
||||
func (c *Confirm) Initialize(ab *authboss.Authboss) (err error) {
|
||||
c.Authboss = ab
|
||||
|
||||
var ok bool
|
||||
storer, ok := authboss.a.Storer.(ConfirmStorer)
|
||||
storer, ok := c.Storer.(ConfirmStorer)
|
||||
if storer == nil || !ok {
|
||||
return errors.New("confirm: Need a ConfirmStorer")
|
||||
}
|
||||
|
||||
c.emailHTMLTemplates, err = response.LoadTemplates(authboss.a.LayoutHTMLEmail, authboss.a.ViewsPath, tplConfirmHTML)
|
||||
c.emailHTMLTemplates, err = response.LoadTemplates(ab, c.LayoutHTMLEmail, c.ViewsPath, tplConfirmHTML)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.emailTextTemplates, err = response.LoadTemplates(authboss.a.LayoutTextEmail, authboss.a.ViewsPath, tplConfirmText)
|
||||
c.emailTextTemplates, err = response.LoadTemplates(ab, c.LayoutTextEmail, c.ViewsPath, tplConfirmText)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
authboss.a.Callbacks.Before(authboss.EventGet, c.beforeGet)
|
||||
authboss.a.Callbacks.Before(authboss.EventAuth, c.beforeGet)
|
||||
authboss.a.Callbacks.After(authboss.EventRegister, c.afterRegister)
|
||||
c.Callbacks.Before(authboss.EventGet, c.beforeGet)
|
||||
c.Callbacks.Before(authboss.EventAuth, c.beforeGet)
|
||||
c.Callbacks.After(authboss.EventRegister, c.afterRegister)
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -84,10 +87,10 @@ func (c *Confirm) Routes() authboss.RouteTable {
|
||||
// Storage requirements
|
||||
func (c *Confirm) Storage() authboss.StorageOptions {
|
||||
return authboss.StorageOptions{
|
||||
authboss.a.PrimaryID: authboss.String,
|
||||
authboss.StoreEmail: authboss.String,
|
||||
StoreConfirmToken: authboss.String,
|
||||
StoreConfirmed: authboss.Bool,
|
||||
c.PrimaryID: authboss.String,
|
||||
authboss.StoreEmail: authboss.String,
|
||||
StoreConfirmToken: authboss.String,
|
||||
StoreConfirmed: authboss.Bool,
|
||||
}
|
||||
}
|
||||
|
||||
@ -135,18 +138,18 @@ var goConfirmEmail = func(c *Confirm, to, token string) {
|
||||
|
||||
// confirmEmail sends a confirmation e-mail.
|
||||
func (c *Confirm) confirmEmail(to, token string) {
|
||||
p := path.Join(authboss.a.MountPath, "confirm")
|
||||
url := fmt.Sprintf("%s%s?%s=%s", authboss.a.RootURL, p, url.QueryEscape(FormValueConfirm), url.QueryEscape(token))
|
||||
p := path.Join(c.MountPath, "confirm")
|
||||
url := fmt.Sprintf("%s%s?%s=%s", c.RootURL, p, url.QueryEscape(FormValueConfirm), url.QueryEscape(token))
|
||||
|
||||
email := authboss.Email{
|
||||
To: []string{to},
|
||||
From: authboss.a.EmailFrom,
|
||||
Subject: authboss.a.EmailSubjectPrefix + "Confirm New Account",
|
||||
From: c.EmailFrom,
|
||||
Subject: c.EmailSubjectPrefix + "Confirm New Account",
|
||||
}
|
||||
|
||||
err := response.Email(email, c.emailHTMLTemplates, tplConfirmHTML, c.emailTextTemplates, tplConfirmText, url)
|
||||
err := response.Email(c.Mailer, email, c.emailHTMLTemplates, tplConfirmHTML, c.emailTextTemplates, tplConfirmText, url)
|
||||
if err != nil {
|
||||
fmt.Fprintf(authboss.a.LogWriter, "confirm: Failed to send e-mail: %v", err)
|
||||
fmt.Fprintf(c.LogWriter, "confirm: Failed to send e-mail: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -166,7 +169,7 @@ func (c *Confirm) confirmHandler(ctx *authboss.Context, w http.ResponseWriter, r
|
||||
sum := md5.Sum(toHash)
|
||||
|
||||
dbTok := base64.StdEncoding.EncodeToString(sum[:])
|
||||
user, err := authboss.a.Storer.(ConfirmStorer).ConfirmUser(dbTok)
|
||||
user, err := c.Storer.(ConfirmStorer).ConfirmUser(dbTok)
|
||||
if err == authboss.ErrUserNotFound {
|
||||
return authboss.ErrAndRedirect{Location: "/", Err: errors.New("confirm: token not found")}
|
||||
} else if err != nil {
|
||||
@ -178,7 +181,7 @@ func (c *Confirm) confirmHandler(ctx *authboss.Context, w http.ResponseWriter, r
|
||||
ctx.User[StoreConfirmToken] = ""
|
||||
ctx.User[StoreConfirmed] = true
|
||||
|
||||
key, err := ctx.User.StringErr(authboss.a.PrimaryID)
|
||||
key, err := ctx.User.StringErr(c.PrimaryID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -188,7 +191,7 @@ func (c *Confirm) confirmHandler(ctx *authboss.Context, w http.ResponseWriter, r
|
||||
}
|
||||
|
||||
ctx.SessionStorer.Put(authboss.SessionKey, key)
|
||||
response.Redirect(ctx, w, r, authboss.a.RegisterOKPath, "You have successfully confirmed your account.", "", true)
|
||||
response.Redirect(ctx, w, r, c.RegisterOKPath, "You have successfully confirmed your account.", "", true)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -17,22 +17,24 @@ import (
|
||||
)
|
||||
|
||||
func setup() *Confirm {
|
||||
authboss.NewConfig()
|
||||
authboss.a.Storer = mocks.NewMockStorer()
|
||||
authboss.a.LayoutHTMLEmail = template.Must(template.New("").Parse(`email ^_^`))
|
||||
authboss.a.LayoutTextEmail = template.Must(template.New("").Parse(`email`))
|
||||
ab := authboss.New()
|
||||
ab.Storer = mocks.NewMockStorer()
|
||||
ab.LayoutHTMLEmail = template.Must(template.New("").Parse(`email ^_^`))
|
||||
ab.LayoutTextEmail = template.Must(template.New("").Parse(`email`))
|
||||
|
||||
c := &Confirm{}
|
||||
if err := c.Initialize(); err != nil {
|
||||
if err := c.Initialize(ab); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func TestConfirm_Initialize(t *testing.T) {
|
||||
authboss.NewConfig()
|
||||
t.Parallel()
|
||||
|
||||
ab := authboss.New()
|
||||
c := &Confirm{}
|
||||
if err := c.Initialize(); err == nil {
|
||||
if err := c.Initialize(ab); err == nil {
|
||||
t.Error("Should cry about not having a storer.")
|
||||
}
|
||||
|
||||
@ -58,7 +60,7 @@ func TestConfirm_Routes(t *testing.T) {
|
||||
func TestConfirm_Storage(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
c := &Confirm{}
|
||||
c := &Confirm{Authboss: authboss.New()}
|
||||
storage := c.Storage()
|
||||
|
||||
if authboss.String != storage[StoreConfirmToken] {
|
||||
@ -70,8 +72,10 @@ func TestConfirm_Storage(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestConfirm_BeforeGet(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
c := setup()
|
||||
ctx := authboss.NewContext()
|
||||
ctx := c.NewContext()
|
||||
|
||||
if _, err := c.beforeGet(ctx); err == nil {
|
||||
t.Error("Should stop the get due to attribute missing:", err)
|
||||
@ -97,12 +101,14 @@ func TestConfirm_BeforeGet(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestConfirm_AfterRegister(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
c := setup()
|
||||
ctx := authboss.NewContext()
|
||||
ctx := c.NewContext()
|
||||
log := &bytes.Buffer{}
|
||||
authboss.a.LogWriter = log
|
||||
authboss.a.Mailer = authboss.LogMailer(log)
|
||||
authboss.a.PrimaryID = authboss.StoreUsername
|
||||
c.LogWriter = log
|
||||
c.Mailer = authboss.LogMailer(log)
|
||||
c.PrimaryID = authboss.StoreUsername
|
||||
|
||||
sentEmail := false
|
||||
|
||||
@ -115,7 +121,7 @@ func TestConfirm_AfterRegister(t *testing.T) {
|
||||
t.Error("Expected it to die with user error:", err)
|
||||
}
|
||||
|
||||
ctx.User = authboss.Attributes{authboss.a.PrimaryID: "username"}
|
||||
ctx.User = authboss.Attributes{c.PrimaryID: "username"}
|
||||
if err := c.afterRegister(ctx); err == nil || err.(authboss.AttributeErr).Name != "email" {
|
||||
t.Error("Expected it to die with e-mail address error:", err)
|
||||
}
|
||||
@ -133,10 +139,12 @@ func TestConfirm_AfterRegister(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestConfirm_ConfirmHandlerErrors(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
c := setup()
|
||||
log := &bytes.Buffer{}
|
||||
authboss.a.LogWriter = log
|
||||
authboss.a.Mailer = authboss.LogMailer(log)
|
||||
c.LogWriter = log
|
||||
c.Mailer = authboss.LogMailer(log)
|
||||
|
||||
tests := []struct {
|
||||
URL string
|
||||
@ -155,7 +163,7 @@ func TestConfirm_ConfirmHandlerErrors(t *testing.T) {
|
||||
for i, test := range tests {
|
||||
r, _ := http.NewRequest("GET", test.URL, nil)
|
||||
w := httptest.NewRecorder()
|
||||
ctx, _ := authboss.ContextFromRequest(r)
|
||||
ctx, _ := c.ContextFromRequest(r)
|
||||
|
||||
err := c.confirmHandler(ctx, w, r)
|
||||
if err == nil {
|
||||
@ -174,11 +182,14 @@ func TestConfirm_ConfirmHandlerErrors(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestConfirm_Confirm(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
c := setup()
|
||||
ctx := authboss.NewContext()
|
||||
ctx := c.NewContext()
|
||||
log := &bytes.Buffer{}
|
||||
authboss.a.LogWriter = log
|
||||
authboss.a.Mailer = authboss.LogMailer(log)
|
||||
c.LogWriter = log
|
||||
c.PrimaryID = authboss.StoreUsername
|
||||
c.Mailer = authboss.LogMailer(log)
|
||||
|
||||
// Create a token
|
||||
token := []byte("hi")
|
||||
@ -186,7 +197,7 @@ func TestConfirm_Confirm(t *testing.T) {
|
||||
|
||||
// Create the "database"
|
||||
storer := mocks.NewMockStorer()
|
||||
authboss.a.Storer = storer
|
||||
c.Storer = storer
|
||||
user := authboss.Attributes{
|
||||
authboss.StoreUsername: "usern",
|
||||
StoreConfirmToken: base64.StdEncoding.EncodeToString(sum[:]),
|
||||
@ -196,7 +207,7 @@ func TestConfirm_Confirm(t *testing.T) {
|
||||
// Make a request with session and context support.
|
||||
r, _ := http.NewRequest("GET", "http://localhost?cnf="+base64.URLEncoding.EncodeToString(token), nil)
|
||||
w := httptest.NewRecorder()
|
||||
ctx, _ = authboss.ContextFromRequest(r)
|
||||
ctx, _ = c.ContextFromRequest(r)
|
||||
ctx.CookieStorer = mocks.NewMockClientStorer()
|
||||
session := mocks.NewMockClientStorer()
|
||||
ctx.User = user
|
||||
|
@ -279,7 +279,7 @@ func (m *MockClientStorer) Put(key, val string) { m.Values[key] = val }
|
||||
func (m *MockClientStorer) Del(key string) { delete(m.Values, key) }
|
||||
|
||||
// MockRequestContext returns a new context as if it came from POST request.
|
||||
func MockRequestContext(ab authboss.Authboss, postKeyValues ...string) *authboss.Context {
|
||||
func MockRequestContext(ab *authboss.Authboss, postKeyValues ...string) *authboss.Context {
|
||||
keyValues := &bytes.Buffer{}
|
||||
for i := 0; i < len(postKeyValues); i += 2 {
|
||||
if i != 0 {
|
||||
|
@ -14,8 +14,8 @@ import (
|
||||
)
|
||||
|
||||
var testViewTemplate = template.Must(template.New("").Parse(`{{.external}} {{.fun}} {{.flash_success}} {{.flash_error}} {{.xsrfName}} {{.xsrfToken}}`))
|
||||
var testEmailHTMLTempalte = template.Must(template.New("").Parse(`<h2>{{.}}</h2>`))
|
||||
var testEmailPlainTempalte = template.Must(template.New("").Parse(`i am a {{.}}`))
|
||||
var testEmailHTMLTemplate = template.Must(template.New("").Parse(`<h2>{{.}}</h2>`))
|
||||
var testEmailPlainTemplate = template.Must(template.New("").Parse(`i am a {{.}}`))
|
||||
|
||||
func TestLoadTemplates(t *testing.T) {
|
||||
t.Parallel()
|
||||
@ -35,7 +35,7 @@ func TestLoadTemplates(t *testing.T) {
|
||||
|
||||
filename := filepath.Base(file.Name())
|
||||
|
||||
tpls, err := LoadTemplates(layout, filepath.Dir(file.Name()), filename)
|
||||
tpls, err := LoadTemplates(authboss.New(), layout, filepath.Dir(file.Name()), filename)
|
||||
if err != nil {
|
||||
t.Error("Unexpected error:", err)
|
||||
}
|
||||
@ -50,15 +50,16 @@ func TestLoadTemplates(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestTemplates_Render(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
cookies := mocks.NewMockClientStorer()
|
||||
authboss.Cfg = &authboss.Config{
|
||||
LayoutDataMaker: func(_ http.ResponseWriter, _ *http.Request) authboss.HTMLData {
|
||||
return authboss.HTMLData{"fun": "is"}
|
||||
},
|
||||
XSRFName: "do you think",
|
||||
XSRFMaker: func(_ http.ResponseWriter, _ *http.Request) string {
|
||||
return "that's air you're breathing now?"
|
||||
},
|
||||
ab := authboss.New()
|
||||
ab.LayoutDataMaker = func(_ http.ResponseWriter, _ *http.Request) authboss.HTMLData {
|
||||
return authboss.HTMLData{"fun": "is"}
|
||||
}
|
||||
ab.XSRFName = "do you think"
|
||||
ab.XSRFMaker = func(_ http.ResponseWriter, _ *http.Request) string {
|
||||
return "that's air you're breathing now?"
|
||||
}
|
||||
|
||||
// Set up flashes
|
||||
@ -67,7 +68,7 @@ func TestTemplates_Render(t *testing.T) {
|
||||
|
||||
r, _ := http.NewRequest("GET", "http://localhost", nil)
|
||||
w := httptest.NewRecorder()
|
||||
ctx, _ := authboss.ContextFromRequest(r)
|
||||
ctx, _ := ab.ContextFromRequest(r)
|
||||
ctx.SessionStorer = cookies
|
||||
|
||||
tpls := Templates{
|
||||
@ -85,17 +86,20 @@ func TestTemplates_Render(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Email(t *testing.T) {
|
||||
mockMailer := &mocks.MockMailer{}
|
||||
authboss.a.Mailer = mockMailer
|
||||
t.Parallel()
|
||||
|
||||
htmlTpls := Templates{"html": testEmailHTMLTempalte}
|
||||
textTpls := Templates{"plain": testEmailPlainTempalte}
|
||||
ab := authboss.New()
|
||||
mockMailer := &mocks.MockMailer{}
|
||||
ab.Mailer = mockMailer
|
||||
|
||||
htmlTpls := Templates{"html": testEmailHTMLTemplate}
|
||||
textTpls := Templates{"plain": testEmailPlainTemplate}
|
||||
|
||||
email := authboss.Email{
|
||||
To: []string{"a@b.c"},
|
||||
}
|
||||
|
||||
err := Email(email, htmlTpls, "html", textTpls, "plain", "spoon")
|
||||
err := Email(ab.Mailer, email, htmlTpls, "html", textTpls, "plain", "spoon")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@ -117,11 +121,14 @@ func Test_Email(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRedirect(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ab := authboss.New()
|
||||
cookies := mocks.NewMockClientStorer()
|
||||
|
||||
r, _ := http.NewRequest("GET", "http://localhost", nil)
|
||||
w := httptest.NewRecorder()
|
||||
ctx, _ := authboss.ContextFromRequest(r)
|
||||
ctx, _ := ab.ContextFromRequest(r)
|
||||
ctx.SessionStorer = cookies
|
||||
|
||||
Redirect(ctx, w, r, "/", "success", "failure", false)
|
||||
@ -143,11 +150,14 @@ func TestRedirect(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRedirect_Override(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ab := authboss.New()
|
||||
cookies := mocks.NewMockClientStorer()
|
||||
|
||||
r, _ := http.NewRequest("GET", "http://localhost?redir=foo/bar", nil)
|
||||
w := httptest.NewRecorder()
|
||||
ctx, _ := authboss.ContextFromRequest(r)
|
||||
ctx, _ := ab.ContextFromRequest(r)
|
||||
ctx.SessionStorer = cookies
|
||||
|
||||
Redirect(ctx, w, r, "/shouldNotGo", "success", "failure", true)
|
||||
|
42
lock/lock.go
42
lock/lock.go
@ -25,19 +25,21 @@ func init() {
|
||||
|
||||
// Lock module
|
||||
type Lock struct {
|
||||
*authboss.Authboss
|
||||
}
|
||||
|
||||
// Initialize the module
|
||||
func (l *Lock) Initialize() error {
|
||||
if authboss.a.Storer == nil {
|
||||
func (l *Lock) Initialize(ab *authboss.Authboss) error {
|
||||
l.Authboss = ab
|
||||
if l.Storer == nil {
|
||||
return errors.New("lock: Need a Storer")
|
||||
}
|
||||
|
||||
// Events
|
||||
authboss.a.Callbacks.Before(authboss.EventGet, l.beforeAuth)
|
||||
authboss.a.Callbacks.Before(authboss.EventAuth, l.beforeAuth)
|
||||
authboss.a.Callbacks.After(authboss.EventAuth, l.afterAuth)
|
||||
authboss.a.Callbacks.After(authboss.EventAuthFail, l.afterAuthFail)
|
||||
l.Callbacks.Before(authboss.EventGet, l.beforeAuth)
|
||||
l.Callbacks.Before(authboss.EventAuth, l.beforeAuth)
|
||||
l.Callbacks.After(authboss.EventAuth, l.afterAuth)
|
||||
l.Callbacks.After(authboss.EventAuthFail, l.afterAuthFail)
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -50,10 +52,10 @@ func (l *Lock) Routes() authboss.RouteTable {
|
||||
// Storage requirements
|
||||
func (l *Lock) Storage() authboss.StorageOptions {
|
||||
return authboss.StorageOptions{
|
||||
authboss.a.PrimaryID: authboss.String,
|
||||
StoreAttemptNumber: authboss.Integer,
|
||||
StoreAttemptTime: authboss.DateTime,
|
||||
StoreLocked: authboss.DateTime,
|
||||
l.PrimaryID: authboss.String,
|
||||
StoreAttemptNumber: authboss.Integer,
|
||||
StoreAttemptTime: authboss.DateTime,
|
||||
StoreLocked: authboss.DateTime,
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,9 +106,9 @@ func (l *Lock) afterAuthFail(ctx *authboss.Context) error {
|
||||
|
||||
nAttempts++
|
||||
|
||||
if time.Now().UTC().Sub(lastAttempt) <= authboss.a.LockWindow {
|
||||
if nAttempts >= int64(authboss.a.LockAfter) {
|
||||
ctx.User[StoreLocked] = time.Now().UTC().Add(authboss.a.LockDuration)
|
||||
if time.Now().UTC().Sub(lastAttempt) <= l.LockWindow {
|
||||
if nAttempts >= int64(l.LockAfter) {
|
||||
ctx.User[StoreLocked] = time.Now().UTC().Add(l.LockDuration)
|
||||
}
|
||||
|
||||
ctx.User[StoreAttemptNumber] = nAttempts
|
||||
@ -124,7 +126,7 @@ func (l *Lock) afterAuthFail(ctx *authboss.Context) error {
|
||||
|
||||
// Lock a user manually.
|
||||
func (l *Lock) Lock(key string) error {
|
||||
user, err := authboss.a.Storer.Get(key)
|
||||
user, err := l.Storer.Get(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -134,14 +136,14 @@ func (l *Lock) Lock(key string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
attr[StoreLocked] = time.Now().UTC().Add(authboss.a.LockDuration)
|
||||
attr[StoreLocked] = time.Now().UTC().Add(l.LockDuration)
|
||||
|
||||
return authboss.a.Storer.Put(key, attr)
|
||||
return l.Storer.Put(key, attr)
|
||||
}
|
||||
|
||||
// Unlock a user that was locked by this module.
|
||||
func (l *Lock) Unlock(key string) error {
|
||||
user, err := authboss.a.Storer.Get(key)
|
||||
user, err := l.Storer.Get(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -153,9 +155,9 @@ func (l *Lock) Unlock(key string) error {
|
||||
|
||||
// Set the last attempt to be -window*2 to avoid immediately
|
||||
// giving another login failure.
|
||||
attr[StoreAttemptTime] = time.Now().UTC().Add(-authboss.a.LockWindow * 2)
|
||||
attr[StoreAttemptTime] = time.Now().UTC().Add(-l.LockWindow * 2)
|
||||
attr[StoreAttemptNumber] = int64(0)
|
||||
attr[StoreLocked] = time.Now().UTC().Add(-authboss.a.LockDuration)
|
||||
attr[StoreLocked] = time.Now().UTC().Add(-l.LockDuration)
|
||||
|
||||
return authboss.a.Storer.Put(key, attr)
|
||||
return l.Storer.Put(key, attr)
|
||||
}
|
||||
|
@ -9,8 +9,9 @@ import (
|
||||
)
|
||||
|
||||
func TestStorage(t *testing.T) {
|
||||
l := &Lock{}
|
||||
authboss.NewConfig()
|
||||
t.Parallel()
|
||||
|
||||
l := &Lock{authboss.New()}
|
||||
storage := l.Storage()
|
||||
if _, ok := storage[StoreAttemptNumber]; !ok {
|
||||
t.Error("Expected attempt number storage option.")
|
||||
@ -24,9 +25,11 @@ func TestStorage(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestBeforeAuth(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
l := &Lock{}
|
||||
authboss.NewConfig()
|
||||
ctx := authboss.NewContext()
|
||||
ab := authboss.New()
|
||||
ctx := ab.NewContext()
|
||||
|
||||
if interrupt, err := l.beforeAuth(ctx); err != errUserMissing {
|
||||
t.Error("Expected an error because of missing user:", err)
|
||||
@ -44,17 +47,19 @@ func TestBeforeAuth(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAfterAuth(t *testing.T) {
|
||||
authboss.NewConfig()
|
||||
t.Parallel()
|
||||
|
||||
ab := authboss.New()
|
||||
lock := Lock{}
|
||||
ctx := authboss.NewContext()
|
||||
ctx := ab.NewContext()
|
||||
|
||||
if err := lock.afterAuth(ctx); err != errUserMissing {
|
||||
t.Error("Expected an error because of missing user:", err)
|
||||
}
|
||||
|
||||
storer := mocks.NewMockStorer()
|
||||
authboss.a.Storer = storer
|
||||
ctx.User = authboss.Attributes{authboss.a.PrimaryID: "john@john.com"}
|
||||
ab.Storer = storer
|
||||
ctx.User = authboss.Attributes{ab.PrimaryID: "john@john.com"}
|
||||
|
||||
if err := lock.afterAuth(ctx); err != nil {
|
||||
t.Error(err)
|
||||
@ -68,21 +73,23 @@ func TestAfterAuth(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAfterAuthFail_Lock(t *testing.T) {
|
||||
authboss.NewConfig()
|
||||
t.Parallel()
|
||||
|
||||
ab := authboss.New()
|
||||
var old, current time.Time
|
||||
var ok bool
|
||||
|
||||
ctx := authboss.NewContext()
|
||||
ctx := ab.NewContext()
|
||||
storer := mocks.NewMockStorer()
|
||||
authboss.a.Storer = storer
|
||||
lock := Lock{}
|
||||
authboss.a.LockWindow = 30 * time.Minute
|
||||
authboss.a.LockDuration = 30 * time.Minute
|
||||
authboss.a.LockAfter = 3
|
||||
ab.Storer = storer
|
||||
lock := Lock{ab}
|
||||
ab.LockWindow = 30 * time.Minute
|
||||
ab.LockDuration = 30 * time.Minute
|
||||
ab.LockAfter = 3
|
||||
|
||||
email := "john@john.com"
|
||||
|
||||
ctx.User = map[string]interface{}{authboss.a.PrimaryID: email}
|
||||
ctx.User = map[string]interface{}{ab.PrimaryID: email}
|
||||
|
||||
old = time.Now().UTC().Add(-1 * time.Hour)
|
||||
|
||||
@ -116,24 +123,26 @@ func TestAfterAuthFail_Lock(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAfterAuthFail_Reset(t *testing.T) {
|
||||
authboss.NewConfig()
|
||||
t.Parallel()
|
||||
|
||||
ab := authboss.New()
|
||||
var old, current time.Time
|
||||
var ok bool
|
||||
|
||||
ctx := authboss.NewContext()
|
||||
ctx := ab.NewContext()
|
||||
storer := mocks.NewMockStorer()
|
||||
lock := Lock{}
|
||||
authboss.a.LockWindow = 30 * time.Minute
|
||||
authboss.a.Storer = storer
|
||||
lock := Lock{ab}
|
||||
ab.LockWindow = 30 * time.Minute
|
||||
ab.Storer = storer
|
||||
|
||||
old = time.Now().UTC().Add(-time.Hour)
|
||||
|
||||
email := "john@john.com"
|
||||
ctx.User = map[string]interface{}{
|
||||
authboss.a.PrimaryID: email,
|
||||
StoreAttemptNumber: int64(2),
|
||||
StoreAttemptTime: old,
|
||||
StoreLocked: old,
|
||||
ab.PrimaryID: email,
|
||||
StoreAttemptNumber: int64(2),
|
||||
StoreAttemptTime: old,
|
||||
StoreLocked: old,
|
||||
}
|
||||
|
||||
lock.afterAuthFail(ctx)
|
||||
@ -149,9 +158,11 @@ func TestAfterAuthFail_Reset(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAfterAuthFail_Errors(t *testing.T) {
|
||||
authboss.NewConfig()
|
||||
lock := Lock{}
|
||||
ctx := authboss.NewContext()
|
||||
t.Parallel()
|
||||
|
||||
ab := authboss.New()
|
||||
lock := Lock{ab}
|
||||
ctx := ab.NewContext()
|
||||
|
||||
lock.afterAuthFail(ctx)
|
||||
if _, ok := ctx.User[StoreAttemptNumber]; ok {
|
||||
@ -160,15 +171,17 @@ func TestAfterAuthFail_Errors(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLock(t *testing.T) {
|
||||
authboss.NewConfig()
|
||||
t.Parallel()
|
||||
|
||||
ab := authboss.New()
|
||||
storer := mocks.NewMockStorer()
|
||||
authboss.a.Storer = storer
|
||||
lock := Lock{}
|
||||
ab.Storer = storer
|
||||
lock := Lock{ab}
|
||||
|
||||
email := "john@john.com"
|
||||
storer.Users[email] = map[string]interface{}{
|
||||
authboss.a.PrimaryID: email,
|
||||
"password": "password",
|
||||
ab.PrimaryID: email,
|
||||
"password": "password",
|
||||
}
|
||||
|
||||
err := lock.Lock(email)
|
||||
@ -182,17 +195,19 @@ func TestLock(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestUnlock(t *testing.T) {
|
||||
authboss.NewConfig()
|
||||
t.Parallel()
|
||||
|
||||
ab := authboss.New()
|
||||
storer := mocks.NewMockStorer()
|
||||
authboss.a.Storer = storer
|
||||
lock := Lock{}
|
||||
authboss.a.LockWindow = 1 * time.Hour
|
||||
ab.Storer = storer
|
||||
lock := Lock{ab}
|
||||
ab.LockWindow = 1 * time.Hour
|
||||
|
||||
email := "john@john.com"
|
||||
storer.Users[email] = map[string]interface{}{
|
||||
authboss.a.PrimaryID: email,
|
||||
"password": "password",
|
||||
"locked": true,
|
||||
ab.PrimaryID: email,
|
||||
"password": "password",
|
||||
"locked": true,
|
||||
}
|
||||
|
||||
err := lock.Unlock(email)
|
||||
@ -201,7 +216,7 @@ func TestUnlock(t *testing.T) {
|
||||
}
|
||||
|
||||
attemptTime := storer.Users[email][StoreAttemptTime].(time.Time)
|
||||
if attemptTime.After(time.Now().UTC().Add(-authboss.a.LockWindow)) {
|
||||
if attemptTime.After(time.Now().UTC().Add(-ab.LockWindow)) {
|
||||
t.Error("StoreLocked not set correctly:", attemptTime)
|
||||
}
|
||||
if number := storer.Users[email][StoreAttemptNumber].(int64); number != int64(0) {
|
||||
|
@ -22,15 +22,18 @@ var (
|
||||
)
|
||||
|
||||
// OAuth2 module
|
||||
type OAuth2 struct{}
|
||||
type OAuth2 struct {
|
||||
*authboss.Authboss
|
||||
}
|
||||
|
||||
func init() {
|
||||
authboss.RegisterModule("oauth2", &OAuth2{})
|
||||
}
|
||||
|
||||
// Initialize module
|
||||
func (o *OAuth2) Initialize() error {
|
||||
if authboss.a.OAuth2Storer == nil {
|
||||
func (o *OAuth2) Initialize(ab *authboss.Authboss) error {
|
||||
o.Authboss = ab
|
||||
if o.OAuth2Storer == nil {
|
||||
return errors.New("oauth2: need an OAuth2Storer")
|
||||
}
|
||||
return nil
|
||||
@ -40,23 +43,23 @@ func (o *OAuth2) Initialize() error {
|
||||
func (o *OAuth2) Routes() authboss.RouteTable {
|
||||
routes := make(authboss.RouteTable)
|
||||
|
||||
for prov, cfg := range authboss.a.OAuth2Providers {
|
||||
for prov, cfg := range o.OAuth2Providers {
|
||||
prov = strings.ToLower(prov)
|
||||
|
||||
init := fmt.Sprintf("/oauth2/%s", prov)
|
||||
callback := fmt.Sprintf("/oauth2/callback/%s", prov)
|
||||
|
||||
routes[init] = oauthInit
|
||||
routes[callback] = oauthCallback
|
||||
routes[init] = o.oauthInit
|
||||
routes[callback] = o.oauthCallback
|
||||
|
||||
if len(authboss.a.MountPath) > 0 {
|
||||
callback = path.Join(authboss.a.MountPath, callback)
|
||||
if len(o.MountPath) > 0 {
|
||||
callback = path.Join(o.MountPath, callback)
|
||||
}
|
||||
|
||||
a.OAuth2Config.RedirectURL = authboss.a.RootURL + callback
|
||||
cfg.OAuth2Config.RedirectURL = o.RootURL + callback
|
||||
}
|
||||
|
||||
routes["/oauth2/logout"] = logout
|
||||
routes["/oauth2/logout"] = o.logout
|
||||
|
||||
return routes
|
||||
}
|
||||
@ -73,9 +76,9 @@ func (o *OAuth2) Storage() authboss.StorageOptions {
|
||||
}
|
||||
}
|
||||
|
||||
func oauthInit(ctx *authboss.Context, w http.ResponseWriter, r *http.Request) error {
|
||||
func (o *OAuth2) oauthInit(ctx *authboss.Context, w http.ResponseWriter, r *http.Request) error {
|
||||
provider := strings.ToLower(filepath.Base(r.URL.Path))
|
||||
cfg, ok := authboss.a.OAuth2Providers[provider]
|
||||
cfg, ok := o.OAuth2Providers[provider]
|
||||
if !ok {
|
||||
return fmt.Errorf("OAuth2 provider %q not found", provider)
|
||||
}
|
||||
@ -106,9 +109,9 @@ func oauthInit(ctx *authboss.Context, w http.ResponseWriter, r *http.Request) er
|
||||
ctx.SessionStorer.Del(authboss.SessionOAuth2Params)
|
||||
}
|
||||
|
||||
url := a.OAuth2Config.AuthCodeURL(state)
|
||||
url := cfg.OAuth2Config.AuthCodeURL(state)
|
||||
|
||||
extraParams := a.AdditionalParams.Encode()
|
||||
extraParams := cfg.AdditionalParams.Encode()
|
||||
if len(extraParams) > 0 {
|
||||
url = fmt.Sprintf("%s&%s", url, extraParams)
|
||||
}
|
||||
@ -120,7 +123,7 @@ func oauthInit(ctx *authboss.Context, w http.ResponseWriter, r *http.Request) er
|
||||
// for testing
|
||||
var exchanger = (*oauth2.Config).Exchange
|
||||
|
||||
func oauthCallback(ctx *authboss.Context, w http.ResponseWriter, r *http.Request) error {
|
||||
func (o *OAuth2) oauthCallback(ctx *authboss.Context, w http.ResponseWriter, r *http.Request) error {
|
||||
provider := strings.ToLower(filepath.Base(r.URL.Path))
|
||||
|
||||
sessState, err := ctx.SessionStorer.GetErr(authboss.SessionOAuth2State)
|
||||
@ -140,18 +143,18 @@ func oauthCallback(ctx *authboss.Context, w http.ResponseWriter, r *http.Request
|
||||
|
||||
hasErr := r.FormValue("error")
|
||||
if len(hasErr) > 0 {
|
||||
if err := authboss.a.Callbacks.FireAfter(authboss.EventOAuthFail, ctx); err != nil {
|
||||
if err := o.Callbacks.FireAfter(authboss.EventOAuthFail, ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return authboss.ErrAndRedirect{
|
||||
Err: errors.New(r.FormValue("error_reason")),
|
||||
Location: authboss.a.AuthLoginFailPath,
|
||||
Location: o.AuthLoginFailPath,
|
||||
FlashError: fmt.Sprintf("%s login cancelled or failed.", strings.Title(provider)),
|
||||
}
|
||||
}
|
||||
|
||||
cfg, ok := authboss.a.OAuth2Providers[provider]
|
||||
cfg, ok := o.OAuth2Providers[provider]
|
||||
if !ok {
|
||||
return fmt.Errorf("OAuth2 provider %q not found", provider)
|
||||
}
|
||||
@ -165,12 +168,12 @@ func oauthCallback(ctx *authboss.Context, w http.ResponseWriter, r *http.Request
|
||||
|
||||
// Get the code
|
||||
code := r.FormValue("code")
|
||||
token, err := exchanger(a.OAuth2Config, oauth2.NoContext, code)
|
||||
token, err := exchanger(cfg.OAuth2Config, oauth2.NoContext, code)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Could not validate oauth2 code: %v", err)
|
||||
}
|
||||
|
||||
user, err := a.Callback(*cfg.OAuth2Config, token)
|
||||
user, err := cfg.Callback(*cfg.OAuth2Config, token)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -189,7 +192,7 @@ func oauthCallback(ctx *authboss.Context, w http.ResponseWriter, r *http.Request
|
||||
user[authboss.StoreOAuth2Refresh] = token.RefreshToken
|
||||
}
|
||||
|
||||
if err = authboss.a.OAuth2Storer.PutOAuth(uid, provider, user); err != nil {
|
||||
if err = o.OAuth2Storer.PutOAuth(uid, provider, user); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -197,13 +200,13 @@ func oauthCallback(ctx *authboss.Context, w http.ResponseWriter, r *http.Request
|
||||
ctx.SessionStorer.Put(authboss.SessionKey, fmt.Sprintf("%s;%s", uid, provider))
|
||||
ctx.SessionStorer.Del(authboss.SessionHalfAuthKey)
|
||||
|
||||
if err = authboss.a.Callbacks.FireAfter(authboss.EventOAuth, ctx); err != nil {
|
||||
if err = o.Callbacks.FireAfter(authboss.EventOAuth, ctx); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
ctx.SessionStorer.Del(authboss.SessionOAuth2Params)
|
||||
|
||||
redirect := authboss.a.AuthLoginOKPath
|
||||
redirect := o.AuthLoginOKPath
|
||||
query := make(url.Values)
|
||||
for k, v := range values {
|
||||
switch k {
|
||||
@ -224,14 +227,14 @@ func oauthCallback(ctx *authboss.Context, w http.ResponseWriter, r *http.Request
|
||||
return nil
|
||||
}
|
||||
|
||||
func logout(ctx *authboss.Context, w http.ResponseWriter, r *http.Request) error {
|
||||
func (o *OAuth2) logout(ctx *authboss.Context, w http.ResponseWriter, r *http.Request) error {
|
||||
switch r.Method {
|
||||
case "GET":
|
||||
ctx.SessionStorer.Del(authboss.SessionKey)
|
||||
ctx.CookieStorer.Del(authboss.CookieRemember)
|
||||
ctx.SessionStorer.Del(authboss.SessionLastAction)
|
||||
|
||||
response.Redirect(ctx, w, r, authboss.a.AuthLogoutOKPath, "You have logged out", "", true)
|
||||
response.Redirect(ctx, w, r, o.AuthLogoutOKPath, "You have logged out", "", true)
|
||||
default:
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
}
|
||||
|
@ -30,29 +30,34 @@ var testProviders = map[string]authboss.OAuth2Provider{
|
||||
}
|
||||
|
||||
func TestInitialize(t *testing.T) {
|
||||
authboss.Cfg = authboss.NewConfig()
|
||||
authboss.a.OAuth2Storer = mocks.NewMockStorer()
|
||||
t.Parallel()
|
||||
|
||||
ab := authboss.New()
|
||||
ab.OAuth2Storer = mocks.NewMockStorer()
|
||||
o := OAuth2{}
|
||||
if err := o.Initialize(); err != nil {
|
||||
if err := o.Initialize(ab); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRoutes(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
root := "https://localhost:8080"
|
||||
mount := "/auth"
|
||||
|
||||
authboss.Cfg = authboss.NewConfig()
|
||||
authboss.a.RootURL = root
|
||||
authboss.a.MountPath = mount
|
||||
authboss.a.OAuth2Providers = testProviders
|
||||
ab := authboss.New()
|
||||
o := OAuth2{ab}
|
||||
|
||||
googleCfg := authboss.a.OAuth2Providers["google"].OAuth2Config
|
||||
ab.RootURL = root
|
||||
ab.MountPath = mount
|
||||
ab.OAuth2Providers = testProviders
|
||||
|
||||
googleCfg := ab.OAuth2Providers["google"].OAuth2Config
|
||||
if 0 != len(googleCfg.RedirectURL) {
|
||||
t.Error("RedirectURL should not be set")
|
||||
}
|
||||
|
||||
o := OAuth2{}
|
||||
routes := o.Routes()
|
||||
authURL := path.Join("/oauth2", "google")
|
||||
tokenURL := path.Join("/oauth2", "callback", "google")
|
||||
@ -71,18 +76,20 @@ func TestRoutes(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestOAuth2Init(t *testing.T) {
|
||||
cfg := authboss.NewConfig()
|
||||
t.Parallel()
|
||||
|
||||
ab := authboss.New()
|
||||
oauth := OAuth2{ab}
|
||||
session := mocks.NewMockClientStorer()
|
||||
|
||||
a.OAuth2Providers = testProviders
|
||||
authboss.Cfg = cfg
|
||||
ab.OAuth2Providers = testProviders
|
||||
|
||||
r, _ := http.NewRequest("GET", "/oauth2/google?redir=/my/redirect%23lol&rm=true", nil)
|
||||
w := httptest.NewRecorder()
|
||||
ctx := authboss.NewContext()
|
||||
ctx := ab.NewContext()
|
||||
ctx.SessionStorer = session
|
||||
|
||||
oauthInit(ctx, w, r)
|
||||
oauth.oauthInit(ctx, w, r)
|
||||
|
||||
if w.Code != http.StatusFound {
|
||||
t.Error("Code was wrong:", w.Code)
|
||||
@ -112,7 +119,10 @@ func TestOAuth2Init(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestOAuthSuccess(t *testing.T) {
|
||||
cfg := authboss.NewConfig()
|
||||
t.Parallel()
|
||||
|
||||
ab := authboss.New()
|
||||
oauth := OAuth2{ab}
|
||||
|
||||
expiry := time.Now().UTC().Add(3600 * time.Second)
|
||||
fakeToken := &oauth2.Token{
|
||||
@ -137,7 +147,7 @@ func TestOAuthSuccess(t *testing.T) {
|
||||
return fakeToken, nil
|
||||
}
|
||||
|
||||
a.OAuth2Providers = map[string]authboss.OAuth2Provider{
|
||||
ab.OAuth2Providers = map[string]authboss.OAuth2Provider{
|
||||
"fake": authboss.OAuth2Provider{
|
||||
OAuth2Config: &oauth2.Config{
|
||||
ClientID: `jazz`,
|
||||
@ -152,7 +162,6 @@ func TestOAuthSuccess(t *testing.T) {
|
||||
AdditionalParams: url.Values{"include_requested_scopes": []string{"true"}},
|
||||
},
|
||||
}
|
||||
authboss.Cfg = cfg
|
||||
|
||||
values := make(url.Values)
|
||||
values.Set("code", "code")
|
||||
@ -161,17 +170,17 @@ func TestOAuthSuccess(t *testing.T) {
|
||||
url := fmt.Sprintf("/oauth2/fake?%s", values.Encode())
|
||||
r, _ := http.NewRequest("GET", url, nil)
|
||||
w := httptest.NewRecorder()
|
||||
ctx := authboss.NewContext()
|
||||
ctx := ab.NewContext()
|
||||
session := mocks.NewMockClientStorer()
|
||||
session.Put(authboss.SessionOAuth2State, authboss.FormValueOAuth2State)
|
||||
session.Put(authboss.SessionOAuth2Params, `{"redir":"/myurl?myparam=5","rm":"true"}`)
|
||||
|
||||
storer := mocks.NewMockStorer()
|
||||
ctx.SessionStorer = session
|
||||
a.OAuth2Storer = storer
|
||||
a.AuthLoginOKPath = "/fakeloginok"
|
||||
ab.OAuth2Storer = storer
|
||||
ab.AuthLoginOKPath = "/fakeloginok"
|
||||
|
||||
if err := oauthCallback(ctx, w, r); err != nil {
|
||||
if err := oauth.oauthCallback(ctx, w, r); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@ -209,46 +218,50 @@ func TestOAuthSuccess(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestOAuthXSRFFailure(t *testing.T) {
|
||||
cfg := authboss.NewConfig()
|
||||
t.Parallel()
|
||||
|
||||
ab := authboss.New()
|
||||
oauth := OAuth2{ab}
|
||||
|
||||
session := mocks.NewMockClientStorer()
|
||||
session.Put(authboss.SessionOAuth2State, authboss.FormValueOAuth2State)
|
||||
|
||||
a.OAuth2Providers = testProviders
|
||||
authboss.Cfg = cfg
|
||||
ab.OAuth2Providers = testProviders
|
||||
|
||||
values := url.Values{}
|
||||
values.Set(authboss.FormValueOAuth2State, "notstate")
|
||||
values.Set("code", "code")
|
||||
|
||||
ctx := authboss.NewContext()
|
||||
ctx := ab.NewContext()
|
||||
ctx.SessionStorer = session
|
||||
r, _ := http.NewRequest("GET", "/oauth2/google?"+values.Encode(), nil)
|
||||
|
||||
err := oauthCallback(ctx, nil, r)
|
||||
err := oauth.oauthCallback(ctx, nil, r)
|
||||
if err != errOAuthStateValidation {
|
||||
t.Error("Should have gotten an error about state validation:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOAuthFailure(t *testing.T) {
|
||||
cfg := authboss.NewConfig()
|
||||
t.Parallel()
|
||||
|
||||
a.OAuth2Providers = testProviders
|
||||
authboss.Cfg = cfg
|
||||
ab := authboss.New()
|
||||
oauth := OAuth2{ab}
|
||||
|
||||
ab.OAuth2Providers = testProviders
|
||||
|
||||
values := url.Values{}
|
||||
values.Set("error", "something")
|
||||
values.Set("error_reason", "auth_failure")
|
||||
values.Set("error_description", "Failed to auth.")
|
||||
|
||||
ctx := authboss.NewContext()
|
||||
ctx := ab.NewContext()
|
||||
session := mocks.NewMockClientStorer()
|
||||
session.Put(authboss.SessionOAuth2State, authboss.FormValueOAuth2State)
|
||||
ctx.SessionStorer = session
|
||||
r, _ := http.NewRequest("GET", "/oauth2/google?"+values.Encode(), nil)
|
||||
|
||||
err := oauthCallback(ctx, nil, r)
|
||||
err := oauth.oauthCallback(ctx, nil, r)
|
||||
if red, ok := err.(authboss.ErrAndRedirect); !ok {
|
||||
t.Error("Should be a redirect error")
|
||||
} else if len(red.FlashError) == 0 {
|
||||
@ -259,19 +272,22 @@ func TestOAuthFailure(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLogout(t *testing.T) {
|
||||
authboss.Cfg = authboss.NewConfig()
|
||||
authboss.a.AuthLogoutOKPath = "/dashboard"
|
||||
t.Parallel()
|
||||
|
||||
ab := authboss.New()
|
||||
oauth := OAuth2{ab}
|
||||
ab.AuthLogoutOKPath = "/dashboard"
|
||||
|
||||
r, _ := http.NewRequest("GET", "/oauth2/google?", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
ctx := authboss.NewContext()
|
||||
ctx := ab.NewContext()
|
||||
session := mocks.NewMockClientStorer(authboss.SessionKey, "asdf", authboss.SessionLastAction, "1234")
|
||||
cookies := mocks.NewMockClientStorer(authboss.CookieRemember, "qwert")
|
||||
ctx.SessionStorer = session
|
||||
ctx.CookieStorer = cookies
|
||||
|
||||
if err := logout(ctx, w, r); err != nil {
|
||||
if err := oauth.logout(ctx, w, r); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@ -292,7 +308,7 @@ func TestLogout(t *testing.T) {
|
||||
}
|
||||
|
||||
location := w.Header().Get("Location")
|
||||
if location != authboss.a.AuthLogoutOKPath {
|
||||
if location != ab.AuthLogoutOKPath {
|
||||
t.Error("Redirect wrong:", location)
|
||||
}
|
||||
}
|
||||
|
@ -26,8 +26,8 @@ type googleMeResponse struct {
|
||||
var clientGet = (*http.Client).Get
|
||||
|
||||
// Google is a callback appropriate for use with Google's OAuth2 configuration.
|
||||
func Google(a.oauth2.Config, token *oauth2.Token) (authboss.Attributes, error) {
|
||||
client := a.Client(oauth2.NoContext, token)
|
||||
func Google(cfg oauth2.Config, token *oauth2.Token) (authboss.Attributes, error) {
|
||||
client := cfg.Client(oauth2.NoContext, token)
|
||||
resp, err := clientGet(client, googleInfoEndpoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -56,39 +56,42 @@ func init() {
|
||||
|
||||
// Recover module
|
||||
type Recover struct {
|
||||
*authboss.Authboss
|
||||
templates response.Templates
|
||||
emailHTMLTemplates response.Templates
|
||||
emailTextTemplates response.Templates
|
||||
}
|
||||
|
||||
// Initialize module
|
||||
func (r *Recover) Initialize() (err error) {
|
||||
if authboss.a.Storer == nil {
|
||||
func (r *Recover) Initialize(ab *authboss.Authboss) (err error) {
|
||||
r.Authboss = ab
|
||||
|
||||
if r.Storer == nil {
|
||||
return errors.New("recover: Need a RecoverStorer")
|
||||
}
|
||||
|
||||
if _, ok := authboss.a.Storer.(RecoverStorer); !ok {
|
||||
if _, ok := r.Storer.(RecoverStorer); !ok {
|
||||
return errors.New("recover: RecoverStorer required for recover functionality")
|
||||
}
|
||||
|
||||
if len(authboss.a.XSRFName) == 0 {
|
||||
if len(r.XSRFName) == 0 {
|
||||
return errors.New("auth: XSRFName must be set")
|
||||
}
|
||||
|
||||
if authboss.a.XSRFMaker == nil {
|
||||
if r.XSRFMaker == nil {
|
||||
return errors.New("auth: XSRFMaker must be defined")
|
||||
}
|
||||
|
||||
r.templates, err = response.LoadTemplates(authboss.a.Layout, authboss.a.ViewsPath, tplRecover, tplRecoverComplete)
|
||||
r.templates, err = response.LoadTemplates(r.Authboss, r.Layout, r.ViewsPath, tplRecover, tplRecoverComplete)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r.emailHTMLTemplates, err = response.LoadTemplates(authboss.a.LayoutHTMLEmail, authboss.a.ViewsPath, tplInitHTMLEmail)
|
||||
r.emailHTMLTemplates, err = response.LoadTemplates(r.Authboss, r.LayoutHTMLEmail, r.ViewsPath, tplInitHTMLEmail)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.emailTextTemplates, err = response.LoadTemplates(authboss.a.LayoutTextEmail, authboss.a.ViewsPath, tplInitTextEmail)
|
||||
r.emailTextTemplates, err = response.LoadTemplates(r.Authboss, r.LayoutTextEmail, r.ViewsPath, tplInitTextEmail)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -107,7 +110,7 @@ func (r *Recover) Routes() authboss.RouteTable {
|
||||
// Storage requirements
|
||||
func (r *Recover) Storage() authboss.StorageOptions {
|
||||
return authboss.StorageOptions{
|
||||
authboss.a.PrimaryID: authboss.String,
|
||||
r.PrimaryID: authboss.String,
|
||||
authboss.StoreEmail: authboss.String,
|
||||
authboss.StorePassword: authboss.String,
|
||||
StoreRecoverToken: authboss.String,
|
||||
@ -119,31 +122,31 @@ func (rec *Recover) startHandlerFunc(ctx *authboss.Context, w http.ResponseWrite
|
||||
switch r.Method {
|
||||
case methodGET:
|
||||
data := authboss.NewHTMLData(
|
||||
"primaryID", authboss.a.PrimaryID,
|
||||
"primaryID", rec.PrimaryID,
|
||||
"primaryIDValue", "",
|
||||
"confirmPrimaryIDValue", "",
|
||||
)
|
||||
|
||||
return rec.templates.Render(ctx, w, r, tplRecover, data)
|
||||
case methodPOST:
|
||||
primaryID, _ := ctx.FirstPostFormValue(authboss.a.PrimaryID)
|
||||
confirmPrimaryID, _ := ctx.FirstPostFormValue(fmt.Sprintf("confirm_%s", authboss.a.PrimaryID))
|
||||
primaryID, _ := ctx.FirstPostFormValue(rec.PrimaryID)
|
||||
confirmPrimaryID, _ := ctx.FirstPostFormValue(fmt.Sprintf("confirm_%s", rec.PrimaryID))
|
||||
|
||||
errData := authboss.NewHTMLData(
|
||||
"primaryID", authboss.a.PrimaryID,
|
||||
"primaryID", rec.PrimaryID,
|
||||
"primaryIDValue", primaryID,
|
||||
"confirmPrimaryIDValue", confirmPrimaryID,
|
||||
)
|
||||
|
||||
policies := authboss.FilterValidators(authboss.a.Policies, authboss.a.PrimaryID)
|
||||
if validationErrs := ctx.Validate(policies, authboss.a.PrimaryID, authboss.ConfirmPrefix+authboss.a.PrimaryID).Map(); len(validationErrs) > 0 {
|
||||
policies := authboss.FilterValidators(rec.Policies, rec.PrimaryID)
|
||||
if validationErrs := ctx.Validate(policies, rec.PrimaryID, authboss.ConfirmPrefix+rec.PrimaryID).Map(); len(validationErrs) > 0 {
|
||||
errData.MergeKV("errs", validationErrs)
|
||||
return rec.templates.Render(ctx, w, r, tplRecover, errData)
|
||||
}
|
||||
|
||||
// redirect to login when user not found to prevent username sniffing
|
||||
if err := ctx.LoadUser(primaryID); err == authboss.ErrUserNotFound {
|
||||
return authboss.ErrAndRedirect{err, authboss.a.RecoverOKPath, recoverInitiateSuccessFlash, ""}
|
||||
return authboss.ErrAndRedirect{err, rec.RecoverOKPath, recoverInitiateSuccessFlash, ""}
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -159,7 +162,7 @@ func (rec *Recover) startHandlerFunc(ctx *authboss.Context, w http.ResponseWrite
|
||||
}
|
||||
|
||||
ctx.User[StoreRecoverToken] = encodedChecksum
|
||||
ctx.User[StoreRecoverTokenExpiry] = time.Now().Add(authboss.a.RecoverTokenDuration)
|
||||
ctx.User[StoreRecoverTokenExpiry] = time.Now().Add(rec.RecoverTokenDuration)
|
||||
|
||||
if err := ctx.SaveUser(); err != nil {
|
||||
return err
|
||||
@ -168,7 +171,7 @@ func (rec *Recover) startHandlerFunc(ctx *authboss.Context, w http.ResponseWrite
|
||||
goRecoverEmail(rec, email, encodedToken)
|
||||
|
||||
ctx.SessionStorer.Put(authboss.FlashSuccessKey, recoverInitiateSuccessFlash)
|
||||
response.Redirect(ctx, w, r, authboss.a.RecoverOKPath, "", "", true)
|
||||
response.Redirect(ctx, w, r, rec.RecoverOKPath, "", "", true)
|
||||
default:
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
}
|
||||
@ -191,17 +194,17 @@ var goRecoverEmail = func(r *Recover, to, encodedToken string) {
|
||||
}
|
||||
|
||||
func (r *Recover) sendRecoverEmail(to, encodedToken string) {
|
||||
p := path.Join(authboss.a.MountPath, "recover/complete")
|
||||
url := fmt.Sprintf("%s%s?token=%s", authboss.a.RootURL, p, encodedToken)
|
||||
p := path.Join(r.MountPath, "recover/complete")
|
||||
url := fmt.Sprintf("%s%s?token=%s", r.RootURL, p, encodedToken)
|
||||
|
||||
email := authboss.Email{
|
||||
To: []string{to},
|
||||
From: authboss.a.EmailFrom,
|
||||
Subject: authboss.a.EmailSubjectPrefix + "Password Reset",
|
||||
From: r.EmailFrom,
|
||||
Subject: r.EmailSubjectPrefix + "Password Reset",
|
||||
}
|
||||
|
||||
if err := response.Email(email, r.emailHTMLTemplates, tplInitHTMLEmail, r.emailTextTemplates, tplInitTextEmail, url); err != nil {
|
||||
fmt.Fprintln(authboss.a.LogWriter, "recover: failed to send recover email:", err)
|
||||
if err := response.Email(r.Mailer, email, r.emailHTMLTemplates, tplInitHTMLEmail, r.emailTextTemplates, tplInitTextEmail, url); err != nil {
|
||||
fmt.Fprintln(r.LogWriter, "recover: failed to send recover email:", err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -227,7 +230,7 @@ func (r *Recover) completeHandlerFunc(ctx *authboss.Context, w http.ResponseWrit
|
||||
password, _ := ctx.FirstPostFormValue("password")
|
||||
confirmPassword, _ := ctx.FirstPostFormValue("confirmPassword")
|
||||
|
||||
policies := authboss.FilterValidators(authboss.a.Policies, "password")
|
||||
policies := authboss.FilterValidators(r.Policies, "password")
|
||||
if validationErrs := ctx.Validate(policies, authboss.StorePassword, authboss.ConfirmPrefix+authboss.StorePassword).Map(); len(validationErrs) > 0 {
|
||||
data := authboss.NewHTMLData(
|
||||
"token", token,
|
||||
@ -242,7 +245,7 @@ func (r *Recover) completeHandlerFunc(ctx *authboss.Context, w http.ResponseWrit
|
||||
return err
|
||||
}
|
||||
|
||||
encryptedPassword, err := bcrypt.GenerateFromPassword([]byte(password), authboss.a.BCryptCost)
|
||||
encryptedPassword, err := bcrypt.GenerateFromPassword([]byte(password), r.BCryptCost)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -252,7 +255,7 @@ func (r *Recover) completeHandlerFunc(ctx *authboss.Context, w http.ResponseWrit
|
||||
var nullTime time.Time
|
||||
ctx.User[StoreRecoverTokenExpiry] = nullTime
|
||||
|
||||
primaryID, err := ctx.User.StringErr(authboss.a.PrimaryID)
|
||||
primaryID, err := ctx.User.StringErr(r.PrimaryID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -261,12 +264,12 @@ func (r *Recover) completeHandlerFunc(ctx *authboss.Context, w http.ResponseWrit
|
||||
return err
|
||||
}
|
||||
|
||||
if err := authboss.a.Callbacks.FireAfter(authboss.EventPasswordReset, ctx); err != nil {
|
||||
if err := r.Callbacks.FireAfter(authboss.EventPasswordReset, ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx.SessionStorer.Put(authboss.SessionKey, primaryID)
|
||||
response.Redirect(ctx, w, req, authboss.a.AuthLoginOKPath, "", "", true)
|
||||
response.Redirect(ctx, w, req, r.AuthLoginOKPath, "", "", true)
|
||||
default:
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
}
|
||||
@ -287,7 +290,7 @@ func verifyToken(ctx *authboss.Context) (attrs authboss.Attributes, err error) {
|
||||
}
|
||||
|
||||
sum := md5.Sum(decoded)
|
||||
storer := authboss.a.Storer.(RecoverStorer)
|
||||
storer := ctx.Storer.(RecoverStorer)
|
||||
|
||||
userInter, err := storer.RecoverUser(base64.StdEncoding.EncodeToString(sum[:]))
|
||||
if err != nil {
|
||||
|
@ -25,45 +25,47 @@ func testSetup() (r *Recover, s *mocks.MockStorer, l *bytes.Buffer) {
|
||||
s = mocks.NewMockStorer()
|
||||
l = &bytes.Buffer{}
|
||||
|
||||
authboss.Cfg = authboss.NewConfig()
|
||||
authboss.a.Layout = template.Must(template.New("").Parse(`{{template "authboss" .}}`))
|
||||
authboss.a.LayoutHTMLEmail = template.Must(template.New("").Parse(`<strong>{{template "authboss" .}}</strong>`))
|
||||
authboss.a.LayoutTextEmail = template.Must(template.New("").Parse(`{{template "authboss" .}}`))
|
||||
authboss.a.Storer = s
|
||||
authboss.a.XSRFName = "xsrf"
|
||||
authboss.a.XSRFMaker = func(_ http.ResponseWriter, _ *http.Request) string {
|
||||
ab := authboss.New()
|
||||
ab.Layout = template.Must(template.New("").Parse(`{{template "authboss" .}}`))
|
||||
ab.LayoutHTMLEmail = template.Must(template.New("").Parse(`<strong>{{template "authboss" .}}</strong>`))
|
||||
ab.LayoutTextEmail = template.Must(template.New("").Parse(`{{template "authboss" .}}`))
|
||||
ab.Storer = s
|
||||
ab.XSRFName = "xsrf"
|
||||
ab.XSRFMaker = func(_ http.ResponseWriter, _ *http.Request) string {
|
||||
return "xsrfvalue"
|
||||
}
|
||||
authboss.a.PrimaryID = authboss.StoreUsername
|
||||
authboss.a.LogWriter = l
|
||||
ab.PrimaryID = authboss.StoreUsername
|
||||
ab.LogWriter = l
|
||||
|
||||
r = &Recover{}
|
||||
if err := r.Initialize(); err != nil {
|
||||
if err := r.Initialize(ab); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return r, s, l
|
||||
}
|
||||
|
||||
func testRequest(method string, postFormValues ...string) (*authboss.Context, *httptest.ResponseRecorder, *http.Request, authboss.ClientStorerErr) {
|
||||
func testRequest(ab *authboss.Authboss, method string, postFormValues ...string) (*authboss.Context, *httptest.ResponseRecorder, *http.Request, authboss.ClientStorerErr) {
|
||||
r, err := http.NewRequest(method, "", nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
sessionStorer := mocks.NewMockClientStorer()
|
||||
ctx := mocks.MockRequestContext(postFormValues...)
|
||||
ctx := mocks.MockRequestContext(ab, postFormValues...)
|
||||
ctx.SessionStorer = sessionStorer
|
||||
|
||||
return ctx, httptest.NewRecorder(), r, sessionStorer
|
||||
}
|
||||
|
||||
func TestRecover(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
r, _, _ := testSetup()
|
||||
|
||||
storage := r.Storage()
|
||||
if storage[authboss.a.PrimaryID] != authboss.String {
|
||||
t.Error("Expected storage KV:", authboss.a.PrimaryID, authboss.String)
|
||||
if storage[r.PrimaryID] != authboss.String {
|
||||
t.Error("Expected storage KV:", r.PrimaryID, authboss.String)
|
||||
}
|
||||
if storage[authboss.StoreEmail] != authboss.String {
|
||||
t.Error("Expected storage KV:", authboss.StoreEmail, authboss.String)
|
||||
@ -88,8 +90,10 @@ func TestRecover(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRecover_startHandlerFunc_GET(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
rec, _, _ := testSetup()
|
||||
ctx, w, r, _ := testRequest("GET")
|
||||
ctx, w, r, _ := testRequest(rec.Authboss, "GET")
|
||||
|
||||
if err := rec.startHandlerFunc(ctx, w, r); err != nil {
|
||||
t.Error("Unexpected error:", err)
|
||||
@ -103,17 +107,19 @@ func TestRecover_startHandlerFunc_GET(t *testing.T) {
|
||||
if !strings.Contains(body, `<form action="recover"`) {
|
||||
t.Error("Should have rendered a form")
|
||||
}
|
||||
if !strings.Contains(body, `name="`+authboss.a.PrimaryID) {
|
||||
if !strings.Contains(body, `name="`+rec.PrimaryID) {
|
||||
t.Error("Form should contain the primary ID field")
|
||||
}
|
||||
if !strings.Contains(body, `name="confirm_`+authboss.a.PrimaryID) {
|
||||
if !strings.Contains(body, `name="confirm_`+rec.PrimaryID) {
|
||||
t.Error("Form should contain the confirm primary ID field")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRecover_startHandlerFunc_POST_ValidationFails(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
rec, _, _ := testSetup()
|
||||
ctx, w, r, _ := testRequest("POST")
|
||||
ctx, w, r, _ := testRequest(rec.Authboss, "POST")
|
||||
|
||||
if err := rec.startHandlerFunc(ctx, w, r); err != nil {
|
||||
t.Error("Unexpected error:", err)
|
||||
@ -129,8 +135,10 @@ func TestRecover_startHandlerFunc_POST_ValidationFails(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRecover_startHandlerFunc_POST_UserNotFound(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
rec, _, _ := testSetup()
|
||||
ctx, w, r, _ := testRequest("POST", "username", "john", "confirm_username", "john")
|
||||
ctx, w, r, _ := testRequest(rec.Authboss, "POST", "username", "john", "confirm_username", "john")
|
||||
|
||||
err := rec.startHandlerFunc(ctx, w, r)
|
||||
if err == nil {
|
||||
@ -141,7 +149,7 @@ func TestRecover_startHandlerFunc_POST_UserNotFound(t *testing.T) {
|
||||
t.Error("Expected ErrAndRedirect error")
|
||||
}
|
||||
|
||||
if rerr.Location != authboss.a.RecoverOKPath {
|
||||
if rerr.Location != rec.RecoverOKPath {
|
||||
t.Error("Unexpected location:", rerr.Location)
|
||||
}
|
||||
|
||||
@ -151,6 +159,8 @@ func TestRecover_startHandlerFunc_POST_UserNotFound(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRecover_startHandlerFunc_POST(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
rec, storer, _ := testSetup()
|
||||
|
||||
storer.Users["john"] = authboss.Attributes{authboss.StoreUsername: "john", authboss.StoreEmail: "a@b.c"}
|
||||
@ -160,7 +170,7 @@ func TestRecover_startHandlerFunc_POST(t *testing.T) {
|
||||
sentEmail = true
|
||||
}
|
||||
|
||||
ctx, w, r, sessionStorer := testRequest("POST", "username", "john", "confirm_username", "john")
|
||||
ctx, w, r, sessionStorer := testRequest(rec.Authboss, "POST", "username", "john", "confirm_username", "john")
|
||||
|
||||
if err := rec.startHandlerFunc(ctx, w, r); err != nil {
|
||||
t.Error("Unexpected error:", err)
|
||||
@ -187,7 +197,7 @@ func TestRecover_startHandlerFunc_POST(t *testing.T) {
|
||||
}
|
||||
|
||||
loc := w.Header().Get("Location")
|
||||
if loc != authboss.a.RecoverOKPath {
|
||||
if loc != rec.RecoverOKPath {
|
||||
t.Error("Unexpected location:", loc)
|
||||
}
|
||||
|
||||
@ -199,12 +209,14 @@ func TestRecover_startHandlerFunc_POST(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRecover_startHandlerFunc_OtherMethods(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
rec, _, _ := testSetup()
|
||||
|
||||
methods := []string{"HEAD", "PUT", "DELETE", "TRACE", "CONNECT"}
|
||||
|
||||
for i, method := range methods {
|
||||
_, w, r, _ := testRequest(method)
|
||||
_, w, r, _ := testRequest(rec.Authboss, method)
|
||||
|
||||
if err := rec.startHandlerFunc(nil, w, r); err != nil {
|
||||
t.Errorf("%d> Unexpected error: %s", i, err)
|
||||
@ -218,6 +230,8 @@ func TestRecover_startHandlerFunc_OtherMethods(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRecover_newToken(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
regexURL := regexp.MustCompile(`^(?:[A-Za-z0-9-_]{4})*(?:[A-Za-z0-9-_]{2}==|[A-Za-z0-9-_]{3}=)?$`)
|
||||
regexSTD := regexp.MustCompile(`^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$`)
|
||||
|
||||
@ -233,13 +247,15 @@ func TestRecover_newToken(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRecover_sendRecoverMail_FailToSend(t *testing.T) {
|
||||
a, _, logger := testSetup()
|
||||
t.Parallel()
|
||||
|
||||
r, _, logger := testSetup()
|
||||
|
||||
mailer := mocks.NewMockMailer()
|
||||
mailer.SendErr = "failed to send"
|
||||
authboss.a.Mailer = mailer
|
||||
r.Mailer = mailer
|
||||
|
||||
a.sendRecoverEmail("", "")
|
||||
r.sendRecoverEmail("", "")
|
||||
|
||||
if !strings.Contains(logger.String(), "failed to send") {
|
||||
t.Error("Expected logged to have msg:", "failed to send")
|
||||
@ -247,14 +263,16 @@ func TestRecover_sendRecoverMail_FailToSend(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRecover_sendRecoverEmail(t *testing.T) {
|
||||
a, _, _ := testSetup()
|
||||
t.Parallel()
|
||||
|
||||
r, _, _ := testSetup()
|
||||
|
||||
mailer := mocks.NewMockMailer()
|
||||
authboss.a.EmailSubjectPrefix = "foo "
|
||||
authboss.a.RootURL = "bar"
|
||||
authboss.a.Mailer = mailer
|
||||
r.EmailSubjectPrefix = "foo "
|
||||
r.RootURL = "bar"
|
||||
r.Mailer = mailer
|
||||
|
||||
a.sendRecoverEmail("a@b.c", "abc=")
|
||||
r.sendRecoverEmail("a@b.c", "abc=")
|
||||
if len(mailer.Last.To) != 1 {
|
||||
t.Error("Expected 1 to email")
|
||||
}
|
||||
@ -265,7 +283,7 @@ func TestRecover_sendRecoverEmail(t *testing.T) {
|
||||
t.Error("Unexpected subject:", mailer.Last.Subject)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/recover/complete?token=abc=", authboss.a.RootURL)
|
||||
url := fmt.Sprintf("%s/recover/complete?token=abc=", r.RootURL)
|
||||
if !strings.Contains(mailer.Last.HTMLBody, url) {
|
||||
t.Error("Expected HTMLBody to contain url:", url)
|
||||
}
|
||||
@ -275,9 +293,11 @@ func TestRecover_sendRecoverEmail(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRecover_completeHandlerFunc_GET_VerifyFails(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
rec, storer, _ := testSetup()
|
||||
|
||||
ctx, w, r, _ := testRequest("GET", "token", testURLBase64Token)
|
||||
ctx, w, r, _ := testRequest(rec.Authboss, "GET", "token", testURLBase64Token)
|
||||
|
||||
err := rec.completeHandlerFunc(ctx, w, r)
|
||||
rerr, ok := err.(authboss.ErrAndRedirect)
|
||||
@ -291,7 +311,7 @@ func TestRecover_completeHandlerFunc_GET_VerifyFails(t *testing.T) {
|
||||
var zeroTime time.Time
|
||||
storer.Users["john"] = authboss.Attributes{StoreRecoverToken: testStdBase64Token, StoreRecoverTokenExpiry: zeroTime}
|
||||
|
||||
ctx, w, r, _ = testRequest("GET", "token", testURLBase64Token)
|
||||
ctx, w, r, _ = testRequest(rec.Authboss, "GET", "token", testURLBase64Token)
|
||||
|
||||
err = rec.completeHandlerFunc(ctx, w, r)
|
||||
rerr, ok = err.(authboss.ErrAndRedirect)
|
||||
@ -307,11 +327,13 @@ func TestRecover_completeHandlerFunc_GET_VerifyFails(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRecover_completeHandlerFunc_GET(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
rec, storer, _ := testSetup()
|
||||
|
||||
storer.Users["john"] = authboss.Attributes{StoreRecoverToken: testStdBase64Token, StoreRecoverTokenExpiry: time.Now().Add(1 * time.Hour)}
|
||||
|
||||
ctx, w, r, _ := testRequest("GET", "token", testURLBase64Token)
|
||||
ctx, w, r, _ := testRequest(rec.Authboss, "GET", "token", testURLBase64Token)
|
||||
|
||||
if err := rec.completeHandlerFunc(ctx, w, r); err != nil {
|
||||
t.Error("Unexpected error:", err)
|
||||
@ -337,8 +359,10 @@ func TestRecover_completeHandlerFunc_GET(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRecover_completeHandlerFunc_POST_TokenMissing(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
rec, _, _ := testSetup()
|
||||
ctx, w, r, _ := testRequest("POST")
|
||||
ctx, w, r, _ := testRequest(rec.Authboss, "POST")
|
||||
|
||||
err := rec.completeHandlerFunc(ctx, w, r)
|
||||
if err.Error() != "Failed to retrieve client attribute: token" {
|
||||
@ -348,8 +372,10 @@ func TestRecover_completeHandlerFunc_POST_TokenMissing(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRecover_completeHandlerFunc_POST_ValidationFails(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
rec, _, _ := testSetup()
|
||||
ctx, w, r, _ := testRequest("POST", "token", testURLBase64Token)
|
||||
ctx, w, r, _ := testRequest(rec.Authboss, "POST", "token", testURLBase64Token)
|
||||
|
||||
if err := rec.completeHandlerFunc(ctx, w, r); err != nil {
|
||||
t.Error("Unexpected error:", err)
|
||||
@ -365,8 +391,10 @@ func TestRecover_completeHandlerFunc_POST_ValidationFails(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRecover_completeHandlerFunc_POST_VerificationFails(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
rec, _, _ := testSetup()
|
||||
ctx, w, r, _ := testRequest("POST", "token", testURLBase64Token, authboss.StorePassword, "abcd", "confirm_"+authboss.StorePassword, "abcd")
|
||||
ctx, w, r, _ := testRequest(rec.Authboss, "POST", "token", testURLBase64Token, authboss.StorePassword, "abcd", "confirm_"+authboss.StorePassword, "abcd")
|
||||
|
||||
if err := rec.completeHandlerFunc(ctx, w, r); err == nil {
|
||||
log.Println(w.Body.String())
|
||||
@ -375,19 +403,21 @@ func TestRecover_completeHandlerFunc_POST_VerificationFails(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRecover_completeHandlerFunc_POST(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
rec, storer, _ := testSetup()
|
||||
|
||||
storer.Users["john"] = authboss.Attributes{authboss.a.PrimaryID: "john", StoreRecoverToken: testStdBase64Token, StoreRecoverTokenExpiry: time.Now().Add(1 * time.Hour), authboss.StorePassword: "asdf"}
|
||||
storer.Users["john"] = authboss.Attributes{rec.PrimaryID: "john", StoreRecoverToken: testStdBase64Token, StoreRecoverTokenExpiry: time.Now().Add(1 * time.Hour), authboss.StorePassword: "asdf"}
|
||||
|
||||
cbCalled := false
|
||||
|
||||
authboss.a.Callbacks = authboss.NewCallbacks()
|
||||
authboss.a.Callbacks.After(authboss.EventPasswordReset, func(_ *authboss.Context) error {
|
||||
rec.Callbacks = authboss.NewCallbacks()
|
||||
rec.Callbacks.After(authboss.EventPasswordReset, func(_ *authboss.Context) error {
|
||||
cbCalled = true
|
||||
return nil
|
||||
})
|
||||
|
||||
ctx, w, r, sessionStorer := testRequest("POST", "token", testURLBase64Token, authboss.StorePassword, "abcd", "confirm_"+authboss.StorePassword, "abcd")
|
||||
ctx, w, r, sessionStorer := testRequest(rec.Authboss, "POST", "token", testURLBase64Token, authboss.StorePassword, "abcd", "confirm_"+authboss.StorePassword, "abcd")
|
||||
|
||||
if err := rec.completeHandlerFunc(ctx, w, r); err != nil {
|
||||
t.Error("Unexpected error:", err)
|
||||
@ -421,12 +451,14 @@ func TestRecover_completeHandlerFunc_POST(t *testing.T) {
|
||||
}
|
||||
|
||||
loc := w.Header().Get("Location")
|
||||
if loc != authboss.a.AuthLogoutOKPath {
|
||||
if loc != rec.AuthLogoutOKPath {
|
||||
t.Error("Unexpected location:", loc)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_verifyToken_MissingToken(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testSetup()
|
||||
|
||||
ctx := &authboss.Context{}
|
||||
@ -436,38 +468,44 @@ func Test_verifyToken_MissingToken(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_verifyToken_InvalidToken(t *testing.T) {
|
||||
_, storer, _ := testSetup()
|
||||
t.Parallel()
|
||||
|
||||
rec, storer, _ := testSetup()
|
||||
storer.Users["a"] = authboss.Attributes{
|
||||
StoreRecoverToken: testStdBase64Token,
|
||||
}
|
||||
|
||||
ctx := mocks.MockRequestContext("token", "asdf")
|
||||
ctx := mocks.MockRequestContext(rec.Authboss, "token", "asdf")
|
||||
if _, err := verifyToken(ctx); err != authboss.ErrUserNotFound {
|
||||
t.Error("Unexpected error:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_verifyToken_ExpiredToken(t *testing.T) {
|
||||
_, storer, _ := testSetup()
|
||||
t.Parallel()
|
||||
|
||||
rec, storer, _ := testSetup()
|
||||
storer.Users["a"] = authboss.Attributes{
|
||||
StoreRecoverToken: testStdBase64Token,
|
||||
StoreRecoverTokenExpiry: time.Now().Add(time.Duration(-24) * time.Hour),
|
||||
}
|
||||
|
||||
ctx := mocks.MockRequestContext("token", testURLBase64Token)
|
||||
ctx := mocks.MockRequestContext(rec.Authboss, "token", testURLBase64Token)
|
||||
if _, err := verifyToken(ctx); err != errRecoveryTokenExpired {
|
||||
t.Error("Unexpected error:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_verifyToken(t *testing.T) {
|
||||
_, storer, _ := testSetup()
|
||||
t.Parallel()
|
||||
|
||||
rec, storer, _ := testSetup()
|
||||
storer.Users["a"] = authboss.Attributes{
|
||||
StoreRecoverToken: testStdBase64Token,
|
||||
StoreRecoverTokenExpiry: time.Now().Add(time.Duration(24) * time.Hour),
|
||||
}
|
||||
|
||||
ctx := mocks.MockRequestContext("token", testURLBase64Token)
|
||||
ctx := mocks.MockRequestContext(rec.Authboss, "token", testURLBase64Token)
|
||||
attrs, err := verifyToken(ctx)
|
||||
if err != nil {
|
||||
t.Error("Unexpected error:", err)
|
||||
|
@ -28,20 +28,23 @@ func init() {
|
||||
|
||||
// Register module.
|
||||
type Register struct {
|
||||
*authboss.Authboss
|
||||
templates response.Templates
|
||||
}
|
||||
|
||||
// Initialize the module.
|
||||
func (r *Register) Initialize() (err error) {
|
||||
if authboss.a.Storer == nil {
|
||||
func (r *Register) Initialize(ab *authboss.Authboss) (err error) {
|
||||
r.Authboss = ab
|
||||
|
||||
if r.Storer == nil {
|
||||
return errors.New("register: Need a RegisterStorer")
|
||||
}
|
||||
|
||||
if _, ok := authboss.a.Storer.(RegisterStorer); !ok {
|
||||
if _, ok := r.Storer.(RegisterStorer); !ok {
|
||||
return errors.New("register: RegisterStorer required for register functionality")
|
||||
}
|
||||
|
||||
if r.templates, err = response.LoadTemplates(authboss.a.Layout, authboss.a.ViewsPath, tplRegister); err != nil {
|
||||
if r.templates, err = response.LoadTemplates(r.Authboss, r.Layout, r.ViewsPath, tplRegister); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -58,7 +61,7 @@ func (r *Register) Routes() authboss.RouteTable {
|
||||
// Storage returns storage requirements.
|
||||
func (r *Register) Storage() authboss.StorageOptions {
|
||||
return authboss.StorageOptions{
|
||||
authboss.a.PrimaryID: authboss.String,
|
||||
r.PrimaryID: authboss.String,
|
||||
authboss.StorePassword: authboss.String,
|
||||
}
|
||||
}
|
||||
@ -67,7 +70,7 @@ func (reg *Register) registerHandler(ctx *authboss.Context, w http.ResponseWrite
|
||||
switch r.Method {
|
||||
case "GET":
|
||||
data := authboss.HTMLData{
|
||||
"primaryID": authboss.a.PrimaryID,
|
||||
"primaryID": reg.PrimaryID,
|
||||
"primaryIDValue": "",
|
||||
}
|
||||
return reg.templates.Render(ctx, w, r, tplRegister, data)
|
||||
@ -78,15 +81,15 @@ func (reg *Register) registerHandler(ctx *authboss.Context, w http.ResponseWrite
|
||||
}
|
||||
|
||||
func (reg *Register) registerPostHandler(ctx *authboss.Context, w http.ResponseWriter, r *http.Request) error {
|
||||
key, _ := ctx.FirstPostFormValue(authboss.a.PrimaryID)
|
||||
key, _ := ctx.FirstPostFormValue(reg.PrimaryID)
|
||||
password, _ := ctx.FirstPostFormValue(authboss.StorePassword)
|
||||
|
||||
policies := authboss.FilterValidators(authboss.a.Policies, authboss.a.PrimaryID, authboss.StorePassword)
|
||||
validationErrs := ctx.Validate(policies, authboss.a.ConfirmFields...)
|
||||
policies := authboss.FilterValidators(reg.Policies, reg.PrimaryID, authboss.StorePassword)
|
||||
validationErrs := ctx.Validate(policies, reg.ConfirmFields...)
|
||||
|
||||
if len(validationErrs) != 0 {
|
||||
data := authboss.HTMLData{
|
||||
"primaryID": authboss.a.PrimaryID,
|
||||
"primaryID": reg.PrimaryID,
|
||||
"primaryIDValue": key,
|
||||
"errs": validationErrs.Map(),
|
||||
}
|
||||
@ -99,30 +102,30 @@ func (reg *Register) registerPostHandler(ctx *authboss.Context, w http.ResponseW
|
||||
return err
|
||||
}
|
||||
|
||||
pass, err := bcrypt.GenerateFromPassword([]byte(password), authboss.a.BCryptCost)
|
||||
pass, err := bcrypt.GenerateFromPassword([]byte(password), reg.BCryptCost)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
attr[authboss.a.PrimaryID] = key
|
||||
attr[reg.PrimaryID] = key
|
||||
attr[authboss.StorePassword] = string(pass)
|
||||
ctx.User = attr
|
||||
|
||||
if err := authboss.a.Storer.(RegisterStorer).Create(key, attr); err != nil {
|
||||
if err := reg.Storer.(RegisterStorer).Create(key, attr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := authboss.a.Callbacks.FireAfter(authboss.EventRegister, ctx); err != nil {
|
||||
if err := reg.Callbacks.FireAfter(authboss.EventRegister, ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if authboss.IsLoaded("confirm") {
|
||||
response.Redirect(ctx, w, r, authboss.a.RegisterOKPath, "Account successfully created, please verify your e-mail address.", "", true)
|
||||
if reg.IsLoaded("confirm") {
|
||||
response.Redirect(ctx, w, r, reg.RegisterOKPath, "Account successfully created, please verify your e-mail address.", "", true)
|
||||
return nil
|
||||
}
|
||||
|
||||
ctx.SessionStorer.Put(authboss.SessionKey, key)
|
||||
response.Redirect(ctx, w, r, authboss.a.RegisterOKPath, "Account successfully created, you are now logged in.", "", true)
|
||||
response.Redirect(ctx, w, r, reg.RegisterOKPath, "Account successfully created, you are now logged in.", "", true)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -14,18 +14,18 @@ import (
|
||||
)
|
||||
|
||||
func setup() *Register {
|
||||
authboss.Cfg = authboss.NewConfig()
|
||||
authboss.a.RegisterOKPath = "/regsuccess"
|
||||
authboss.a.Layout = template.Must(template.New("").Parse(`{{template "authboss" .}}`))
|
||||
authboss.a.XSRFName = "xsrf"
|
||||
authboss.a.XSRFMaker = func(_ http.ResponseWriter, _ *http.Request) string {
|
||||
ab := authboss.New()
|
||||
ab.RegisterOKPath = "/regsuccess"
|
||||
ab.Layout = template.Must(template.New("").Parse(`{{template "authboss" .}}`))
|
||||
ab.XSRFName = "xsrf"
|
||||
ab.XSRFMaker = func(_ http.ResponseWriter, _ *http.Request) string {
|
||||
return "xsrfvalue"
|
||||
}
|
||||
authboss.a.ConfirmFields = []string{"password", "confirm_password"}
|
||||
authboss.a.Storer = mocks.NewMockStorer()
|
||||
ab.ConfirmFields = []string{"password", "confirm_password"}
|
||||
ab.Storer = mocks.NewMockStorer()
|
||||
|
||||
reg := Register{}
|
||||
if err := reg.Initialize(); err != nil {
|
||||
if err := reg.Initialize(ab); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@ -33,11 +33,10 @@ func setup() *Register {
|
||||
}
|
||||
|
||||
func TestRegister(t *testing.T) {
|
||||
authboss.Cfg = authboss.NewConfig()
|
||||
authboss.a.Storer = mocks.NewMockStorer()
|
||||
ab := authboss.New()
|
||||
ab.Storer = mocks.NewMockStorer()
|
||||
r := Register{}
|
||||
|
||||
if err := r.Initialize(); err != nil {
|
||||
if err := r.Initialize(ab); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@ -46,7 +45,7 @@ func TestRegister(t *testing.T) {
|
||||
}
|
||||
|
||||
sto := r.Storage()
|
||||
if sto[authboss.a.PrimaryID] != authboss.String {
|
||||
if sto[r.PrimaryID] != authboss.String {
|
||||
t.Error("Wanted primary ID to be a string.")
|
||||
}
|
||||
if sto[authboss.StorePassword] != authboss.String {
|
||||
@ -59,7 +58,7 @@ func TestRegisterGet(t *testing.T) {
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
r, _ := http.NewRequest("GET", "/register", nil)
|
||||
ctx, _ := authboss.ContextFromRequest(r)
|
||||
ctx, _ := reg.ContextFromRequest(r)
|
||||
ctx.SessionStorer = mocks.NewMockClientStorer()
|
||||
|
||||
if err := reg.registerHandler(ctx, w, r); err != nil {
|
||||
@ -76,7 +75,7 @@ func TestRegisterGet(t *testing.T) {
|
||||
|
||||
if str := w.Body.String(); !strings.Contains(str, "<form") {
|
||||
t.Error("It should have rendered a nice form:", str)
|
||||
} else if !strings.Contains(str, `name="`+authboss.a.PrimaryID) {
|
||||
} else if !strings.Contains(str, `name="`+reg.PrimaryID) {
|
||||
t.Error("Form should contain the primary ID:", str)
|
||||
}
|
||||
}
|
||||
@ -88,13 +87,13 @@ func TestRegisterPostValidationErrs(t *testing.T) {
|
||||
vals := url.Values{}
|
||||
|
||||
email := "email@address.com"
|
||||
vals.Set(authboss.a.PrimaryID, email)
|
||||
vals.Set(reg.PrimaryID, email)
|
||||
vals.Set(authboss.StorePassword, "pass")
|
||||
vals.Set(authboss.ConfirmPrefix+authboss.StorePassword, "pass2")
|
||||
|
||||
r, _ := http.NewRequest("POST", "/register", bytes.NewBufferString(vals.Encode()))
|
||||
r.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
ctx, _ := authboss.ContextFromRequest(r)
|
||||
ctx, _ := reg.ContextFromRequest(r)
|
||||
ctx.SessionStorer = mocks.NewMockClientStorer()
|
||||
|
||||
if err := reg.registerHandler(ctx, w, r); err != nil {
|
||||
@ -113,7 +112,7 @@ func TestRegisterPostValidationErrs(t *testing.T) {
|
||||
t.Error("Confirm password should have an error:", str)
|
||||
}
|
||||
|
||||
if _, err := authboss.a.Storer.Get(email); err != authboss.ErrUserNotFound {
|
||||
if _, err := reg.Storer.Get(email); err != authboss.ErrUserNotFound {
|
||||
t.Error("The user should not have been saved.")
|
||||
}
|
||||
}
|
||||
@ -125,13 +124,13 @@ func TestRegisterPostSuccess(t *testing.T) {
|
||||
vals := url.Values{}
|
||||
|
||||
email := "email@address.com"
|
||||
vals.Set(authboss.a.PrimaryID, email)
|
||||
vals.Set(reg.PrimaryID, email)
|
||||
vals.Set(authboss.StorePassword, "pass")
|
||||
vals.Set(authboss.ConfirmPrefix+authboss.StorePassword, "pass")
|
||||
|
||||
r, _ := http.NewRequest("POST", "/register", bytes.NewBufferString(vals.Encode()))
|
||||
r.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
ctx, _ := authboss.ContextFromRequest(r)
|
||||
ctx, _ := reg.ContextFromRequest(r)
|
||||
ctx.SessionStorer = mocks.NewMockClientStorer()
|
||||
|
||||
if err := reg.registerHandler(ctx, w, r); err != nil {
|
||||
@ -142,17 +141,17 @@ func TestRegisterPostSuccess(t *testing.T) {
|
||||
t.Error("It should have written a redirect:", w.Code)
|
||||
}
|
||||
|
||||
if loc := w.Header().Get("Location"); loc != authboss.a.RegisterOKPath {
|
||||
if loc := w.Header().Get("Location"); loc != reg.RegisterOKPath {
|
||||
t.Error("Redirected to the wrong location", loc)
|
||||
}
|
||||
|
||||
user, err := authboss.a.Storer.Get(email)
|
||||
user, err := reg.Storer.Get(email)
|
||||
if err == authboss.ErrUserNotFound {
|
||||
t.Error("The user have been saved.")
|
||||
}
|
||||
|
||||
attrs := authboss.Unbind(user)
|
||||
if e, err := attrs.StringErr(authboss.a.PrimaryID); err != nil {
|
||||
if e, err := attrs.StringErr(reg.PrimaryID); err != nil {
|
||||
t.Error(err)
|
||||
} else if e != email {
|
||||
t.Errorf("Email was not set properly, want: %s, got: %s", email, e)
|
||||
|
@ -43,24 +43,28 @@ func init() {
|
||||
}
|
||||
|
||||
// Remember module
|
||||
type Remember struct{}
|
||||
type Remember struct {
|
||||
*authboss.Authboss
|
||||
}
|
||||
|
||||
// Initialize module
|
||||
func (r *Remember) Initialize() error {
|
||||
if authboss.a.Storer == nil && authboss.a.OAuth2Storer == nil {
|
||||
func (r *Remember) Initialize(ab *authboss.Authboss) error {
|
||||
r.Authboss = ab
|
||||
|
||||
if r.Storer == nil && r.OAuth2Storer == nil {
|
||||
return errors.New("remember: Need a RememberStorer")
|
||||
}
|
||||
|
||||
if _, ok := authboss.a.Storer.(RememberStorer); !ok {
|
||||
if _, ok := authboss.a.OAuth2Storer.(RememberStorer); !ok {
|
||||
if _, ok := r.Storer.(RememberStorer); !ok {
|
||||
if _, ok := r.OAuth2Storer.(RememberStorer); !ok {
|
||||
return errors.New("remember: RememberStorer required for remember functionality")
|
||||
}
|
||||
}
|
||||
|
||||
authboss.a.Callbacks.Before(authboss.EventGetUserSession, r.auth)
|
||||
authboss.a.Callbacks.After(authboss.EventAuth, r.afterAuth)
|
||||
authboss.a.Callbacks.After(authboss.EventOAuth, r.afterOAuth)
|
||||
authboss.a.Callbacks.After(authboss.EventPasswordReset, r.afterPassword)
|
||||
r.Callbacks.Before(authboss.EventGetUserSession, r.auth)
|
||||
r.Callbacks.After(authboss.EventAuth, r.afterAuth)
|
||||
r.Callbacks.After(authboss.EventOAuth, r.afterOAuth)
|
||||
r.Callbacks.After(authboss.EventPasswordReset, r.afterPassword)
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -73,7 +77,7 @@ func (r *Remember) Routes() authboss.RouteTable {
|
||||
// Storage requirements
|
||||
func (r *Remember) Storage() authboss.StorageOptions {
|
||||
return authboss.StorageOptions{
|
||||
authboss.a.PrimaryID: authboss.String,
|
||||
r.PrimaryID: authboss.String,
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,7 +91,7 @@ func (r *Remember) afterAuth(ctx *authboss.Context) error {
|
||||
return errUserMissing
|
||||
}
|
||||
|
||||
key, err := ctx.User.StringErr(authboss.a.PrimaryID)
|
||||
key, err := ctx.User.StringErr(r.PrimaryID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -146,7 +150,7 @@ func (r *Remember) afterPassword(ctx *authboss.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
id, ok := ctx.User.String(authboss.a.PrimaryID)
|
||||
id, ok := ctx.User.String(r.PrimaryID)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
@ -154,8 +158,8 @@ func (r *Remember) afterPassword(ctx *authboss.Context) error {
|
||||
ctx.CookieStorer.Del(authboss.CookieRemember)
|
||||
|
||||
var storer RememberStorer
|
||||
if storer, ok = authboss.a.Storer.(RememberStorer); !ok {
|
||||
if storer, ok = authboss.a.OAuth2Storer.(RememberStorer); !ok {
|
||||
if storer, ok = r.Storer.(RememberStorer); !ok {
|
||||
if storer, ok = r.OAuth2Storer.(RememberStorer); !ok {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@ -181,8 +185,8 @@ func (r *Remember) new(cstorer authboss.ClientStorer, storageKey string) (string
|
||||
|
||||
var storer RememberStorer
|
||||
var ok bool
|
||||
if storer, ok = authboss.a.Storer.(RememberStorer); !ok {
|
||||
storer, ok = authboss.a.OAuth2Storer.(RememberStorer)
|
||||
if storer, ok = r.Storer.(RememberStorer); !ok {
|
||||
storer, ok = r.OAuth2Storer.(RememberStorer)
|
||||
}
|
||||
|
||||
// Save the token in the DB
|
||||
@ -226,8 +230,8 @@ func (r *Remember) auth(ctx *authboss.Context) (authboss.Interrupt, error) {
|
||||
sum := md5.Sum(token)
|
||||
|
||||
var storer RememberStorer
|
||||
if storer, ok = authboss.a.Storer.(RememberStorer); !ok {
|
||||
storer, ok = authboss.a.OAuth2Storer.(RememberStorer)
|
||||
if storer, ok = r.Storer.(RememberStorer); !ok {
|
||||
storer, ok = r.OAuth2Storer.(RememberStorer)
|
||||
}
|
||||
|
||||
err = storer.UseToken(givenKey, base64.StdEncoding.EncodeToString(sum[:]))
|
||||
|
@ -11,32 +11,34 @@ import (
|
||||
)
|
||||
|
||||
func TestInitialize(t *testing.T) {
|
||||
authboss.NewConfig()
|
||||
t.Parallel()
|
||||
|
||||
ab := authboss.New()
|
||||
r := &Remember{}
|
||||
err := r.Initialize()
|
||||
err := r.Initialize(ab)
|
||||
if err == nil {
|
||||
t.Error("Expected error about token storers.")
|
||||
}
|
||||
|
||||
authboss.a.Storer = mocks.MockFailStorer{}
|
||||
err = r.Initialize()
|
||||
ab.Storer = mocks.MockFailStorer{}
|
||||
err = r.Initialize(ab)
|
||||
if err == nil {
|
||||
t.Error("Expected error about token storers.")
|
||||
}
|
||||
|
||||
authboss.a.Storer = mocks.NewMockStorer()
|
||||
err = r.Initialize()
|
||||
ab.Storer = mocks.NewMockStorer()
|
||||
err = r.Initialize(ab)
|
||||
if err != nil {
|
||||
t.Error("Unexpected error:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAfterAuth(t *testing.T) {
|
||||
r := Remember{}
|
||||
authboss.NewConfig()
|
||||
t.Parallel()
|
||||
|
||||
r := Remember{authboss.New()}
|
||||
storer := mocks.NewMockStorer()
|
||||
authboss.a.Storer = storer
|
||||
r.Storer = storer
|
||||
|
||||
cookies := mocks.NewMockClientStorer()
|
||||
session := mocks.NewMockClientStorer()
|
||||
@ -47,14 +49,14 @@ func TestAfterAuth(t *testing.T) {
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
|
||||
ctx, err := authboss.ContextFromRequest(req)
|
||||
ctx, err := r.ContextFromRequest(req)
|
||||
if err != nil {
|
||||
t.Error("Unexpected error:", err)
|
||||
}
|
||||
|
||||
ctx.SessionStorer = session
|
||||
ctx.CookieStorer = cookies
|
||||
ctx.User = authboss.Attributes{authboss.a.PrimaryID: "test@email.com"}
|
||||
ctx.User = authboss.Attributes{r.PrimaryID: "test@email.com"}
|
||||
|
||||
if err := r.afterAuth(ctx); err != nil {
|
||||
t.Error(err)
|
||||
@ -66,10 +68,11 @@ func TestAfterAuth(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAfterOAuth(t *testing.T) {
|
||||
r := Remember{}
|
||||
authboss.NewConfig()
|
||||
t.Parallel()
|
||||
|
||||
r := Remember{authboss.New()}
|
||||
storer := mocks.NewMockStorer()
|
||||
authboss.a.Storer = storer
|
||||
r.Storer = storer
|
||||
|
||||
cookies := mocks.NewMockClientStorer()
|
||||
session := mocks.NewMockClientStorer(authboss.SessionOAuth2Params, `{"rm":"true"}`)
|
||||
@ -80,7 +83,7 @@ func TestAfterOAuth(t *testing.T) {
|
||||
t.Error("Unexpected Error:", err)
|
||||
}
|
||||
|
||||
ctx, err := authboss.ContextFromRequest(req)
|
||||
ctx, err := r.ContextFromRequest(req)
|
||||
if err != nil {
|
||||
t.Error("Unexpected error:", err)
|
||||
}
|
||||
@ -102,20 +105,21 @@ func TestAfterOAuth(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAfterPasswordReset(t *testing.T) {
|
||||
r := Remember{}
|
||||
authboss.NewConfig()
|
||||
t.Parallel()
|
||||
|
||||
r := Remember{authboss.New()}
|
||||
|
||||
id := "test@email.com"
|
||||
|
||||
storer := mocks.NewMockStorer()
|
||||
authboss.a.Storer = storer
|
||||
r.Storer = storer
|
||||
session := mocks.NewMockClientStorer()
|
||||
cookies := mocks.NewMockClientStorer()
|
||||
storer.Tokens[id] = []string{"one", "two"}
|
||||
cookies.Values[authboss.CookieRemember] = "token"
|
||||
|
||||
ctx := authboss.NewContext()
|
||||
ctx.User = authboss.Attributes{authboss.a.PrimaryID: id}
|
||||
ctx := r.NewContext()
|
||||
ctx.User = authboss.Attributes{r.PrimaryID: id}
|
||||
ctx.SessionStorer = session
|
||||
ctx.CookieStorer = cookies
|
||||
|
||||
@ -133,10 +137,11 @@ func TestAfterPasswordReset(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
r := &Remember{}
|
||||
authboss.NewConfig()
|
||||
t.Parallel()
|
||||
|
||||
r := &Remember{authboss.New()}
|
||||
storer := mocks.NewMockStorer()
|
||||
authboss.a.Storer = storer
|
||||
r.Storer = storer
|
||||
cookies := mocks.NewMockClientStorer()
|
||||
|
||||
key := "tester"
|
||||
@ -162,14 +167,15 @@ func TestNew(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAuth(t *testing.T) {
|
||||
r := &Remember{}
|
||||
authboss.NewConfig()
|
||||
t.Parallel()
|
||||
|
||||
r := &Remember{authboss.New()}
|
||||
storer := mocks.NewMockStorer()
|
||||
authboss.a.Storer = storer
|
||||
r.Storer = storer
|
||||
|
||||
cookies := mocks.NewMockClientStorer()
|
||||
session := mocks.NewMockClientStorer()
|
||||
ctx := authboss.NewContext()
|
||||
ctx := r.NewContext()
|
||||
ctx.CookieStorer = cookies
|
||||
ctx.SessionStorer = session
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user