func TestUnlock(t *testing.T) { t.Parallel() ab := authboss.New() storer := mocks.NewMockStorer() ab.Storer = storer lock := Lock{ab} ab.LockWindow = 1 * time.Hour email := "*****@*****.**" storer.Users[email] = map[string]interface{}{ ab.PrimaryID: email, "password": "******", "locked": true, } err := lock.Unlock(email) if err != nil { t.Error(err) } attemptTime := storer.Users[email][StoreAttemptTime].(time.Time) 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) { t.Error("StoreLocked not set correctly:", number) } if locked := storer.Users[email][StoreLocked].(time.Time); locked.After(time.Now()) { t.Error("User should not be locked.") } }
func TestAfterAuthFail_Reset(t *testing.T) { t.Parallel() ab := authboss.New() var old, current time.Time var ok bool ctx := ab.NewContext() storer := mocks.NewMockStorer() lock := Lock{ab} ab.LockWindow = 30 * time.Minute ab.Storer = storer old = time.Now().UTC().Add(-time.Hour) email := "*****@*****.**" ctx.User = map[string]interface{}{ ab.PrimaryID: email, StoreAttemptNumber: int64(2), StoreAttemptTime: old, StoreLocked: old, } lock.afterAuthFail(ctx) if val := storer.Users[email][StoreAttemptNumber].(int64); val != int64(0) { t.Error("StoreAttemptNumber set incorrectly:", val) } if current, ok = storer.Users[email][StoreAttemptTime].(time.Time); !ok || current.Before(old) { t.Error("StoreAttemptTime not set correctly.") } if locked := storer.Users[email][StoreLocked].(time.Time); locked.After(time.Now()) { t.Error("StoreLocked not set correctly:", locked) } }
func TestAfterOAuth(t *testing.T) { t.Parallel() r := Remember{authboss.New()} storer := mocks.NewMockStorer() r.Storer = storer cookies := mocks.NewMockClientStorer() session := mocks.NewMockClientStorer(authboss.SessionOAuth2Params, `{"rm":"true"}`) ctx := r.NewContext() ctx.SessionStorer = session ctx.CookieStorer = cookies ctx.User = authboss.Attributes{ authboss.StoreOAuth2UID: "uid", authboss.StoreOAuth2Provider: "google", } if err := r.afterOAuth(ctx); err != nil { t.Error(err) } if _, ok := cookies.Values[authboss.CookieRemember]; !ok { t.Error("Expected a cookie to have been set.") } }
func TestAfterPasswordReset(t *testing.T) { t.Parallel() r := Remember{authboss.New()} id := "*****@*****.**" storer := mocks.NewMockStorer() r.Storer = storer session := mocks.NewMockClientStorer() cookies := mocks.NewMockClientStorer() storer.Tokens[id] = []string{"one", "two"} cookies.Values[authboss.CookieRemember] = "token" ctx := r.NewContext() ctx.User = authboss.Attributes{r.PrimaryID: id} ctx.SessionStorer = session ctx.CookieStorer = cookies if err := r.afterPassword(ctx); err != nil { t.Error(err) } if _, ok := cookies.Values[authboss.CookieRemember]; ok { t.Error("Expected the remember cookie to be deleted.") } if len(storer.Tokens) != 0 { t.Error("Should have wiped out all tokens.") } }
func TestAuth_validateCredentials(t *testing.T) { t.Parallel() ab := authboss.New() storer := mocks.NewMockStorer() ab.Storer = storer ctx := ab.NewContext() storer.Users["john"] = authboss.Attributes{"password": "******"} if _, err := validateCredentials(ctx, "john", "a"); err != nil { t.Error("Unexpected error:", err) } ctx = ab.NewContext() if valid, err := validateCredentials(ctx, "jake", "a"); err != nil { t.Error("Expect no error when user not found:", err) } else if valid { t.Error("Expect invalid when not user found") } ctx = ab.NewContext() storer.GetErr = "Failed to load user" if _, err := validateCredentials(ctx, "", ""); err.Error() != "Failed to load user" { t.Error("Unexpected error:", err) } }
func TestNew(t *testing.T) { t.Parallel() r := &Remember{authboss.New()} storer := mocks.NewMockStorer() r.Storer = storer cookies := mocks.NewMockClientStorer() key := "tester" token, err := r.new(cookies, key) if err != nil { t.Error("Unexpected error:", err) } if len(token) == 0 { t.Error("Expected a token.") } if tok, ok := storer.Tokens[key]; !ok { t.Error("Expected it to store against the key:", key) } else if len(tok) != 1 || len(tok[0]) == 0 { t.Error("Expected a token to be saved.") } if token != cookies.Values[authboss.CookieRemember] { t.Error("Expected a cookie set with the token.") } }
func TestAfterAuth(t *testing.T) { t.Parallel() ab := authboss.New() lock := Lock{} ctx := ab.NewContext() if err := lock.afterAuth(ctx); err != errUserMissing { t.Error("Expected an error because of missing user:"******"*****@*****.**"} if err := lock.afterAuth(ctx); err != nil { t.Error(err) } if storer.Users["*****@*****.**"][StoreAttemptNumber].(int64) != int64(0) { t.Error("StoreAttemptNumber set incorrectly.") } if _, ok := storer.Users["*****@*****.**"][StoreAttemptTime].(time.Time); !ok { t.Error("StoreAttemptTime not set.") } }
func TestAfterAuth(t *testing.T) { t.Parallel() r := Remember{authboss.New()} storer := mocks.NewMockStorer() r.Storer = storer cookies := mocks.NewMockClientStorer() session := mocks.NewMockClientStorer() req, err := http.NewRequest("POST", "http://localhost", bytes.NewBufferString("rm=true")) if err != nil { t.Error("Unexpected Error:", err) } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") ctx := r.NewContext() ctx.SessionStorer = session ctx.CookieStorer = cookies ctx.User = authboss.Attributes{r.PrimaryID: "*****@*****.**"} ctx.Values = map[string]string{authboss.CookieRemember: "true"} if err := r.afterAuth(ctx); err != nil { t.Error(err) } if _, ok := cookies.Values[authboss.CookieRemember]; !ok { t.Error("Expected a cookie to have been set.") } }
func TestConfirm_Confirm(t *testing.T) { t.Parallel() c := setup() ctx := c.NewContext() log := &bytes.Buffer{} c.LogWriter = log c.PrimaryID = authboss.StoreUsername c.Mailer = authboss.LogMailer(log) // Create a token token := []byte("hi") sum := md5.Sum(token) // Create the "database" storer := mocks.NewMockStorer() c.Storer = storer user := authboss.Attributes{ authboss.StoreUsername: "******", StoreConfirmToken: base64.StdEncoding.EncodeToString(sum[:]), } storer.Users["usern"] = user // Make a request with session and context support. r, _ := http.NewRequest("GET", "http://localhost?cnf="+base64.URLEncoding.EncodeToString(token), nil) w := httptest.NewRecorder() ctx = c.NewContext() ctx.CookieStorer = mocks.NewMockClientStorer() session := mocks.NewMockClientStorer() ctx.User = user ctx.SessionStorer = session c.confirmHandler(ctx, w, r) if w.Code != http.StatusFound { t.Error("Expected a redirect after success:", w.Code) } if log.Len() != 0 { t.Error("Expected a clean log on success:", log.String()) } is, ok := ctx.User.Bool(StoreConfirmed) if !ok || !is { t.Error("The user should be confirmed.") } tok, ok := ctx.User.String(StoreConfirmToken) if ok && len(tok) != 0 { t.Error("Confirm token should have been wiped out.") } if key, ok := ctx.SessionStorer.Get(authboss.SessionKey); !ok || len(key) == 0 { t.Error("Should have logged the user in.") } if success, ok := ctx.SessionStorer.Get(authboss.FlashSuccessKey); !ok || len(success) == 0 { t.Error("Should have left a nice message.") } }
func TestInitialize(t *testing.T) { t.Parallel() ab := authboss.New() ab.OAuth2Storer = mocks.NewMockStorer() o := OAuth2{} if err := o.Initialize(ab); err != nil { t.Error(err) } }
func setup() *Confirm { 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(ab); err != nil { panic(err) } return c }
func TestAfterAuthFail_Lock(t *testing.T) { t.Parallel() ab := authboss.New() var old, current time.Time var ok bool ctx := ab.NewContext() storer := mocks.NewMockStorer() ab.Storer = storer lock := Lock{ab} ab.LockWindow = 30 * time.Minute ab.LockDuration = 30 * time.Minute ab.LockAfter = 3 email := "*****@*****.**" ctx.User = map[string]interface{}{ab.PrimaryID: email} old = time.Now().UTC().Add(-1 * time.Hour) for i := 0; i < 3; i++ { if lockedIntf, ok := storer.Users["*****@*****.**"][StoreLocked]; ok && lockedIntf.(bool) { t.Errorf("%d: User should not be locked.", i) } if err := lock.afterAuthFail(ctx); err != nil { t.Error(err) } if val := storer.Users[email][StoreAttemptNumber].(int64); val != int64(i+1) { t.Errorf("%d: StoreAttemptNumber set incorrectly: %v", i, val) } if current, ok = storer.Users[email][StoreAttemptTime].(time.Time); !ok || old.After(current) { t.Errorf("%d: StoreAttemptTime not set correctly: %v", i, current) } current = old } if locked := storer.Users[email][StoreLocked].(time.Time); !locked.After(time.Now()) { t.Error("User should be locked for some duration:", locked) } if val := storer.Users[email][StoreAttemptNumber].(int64); val != int64(3) { t.Error("StoreAttemptNumber set incorrectly:", val) } if _, ok = storer.Users[email][StoreAttemptTime].(time.Time); !ok { t.Error("StoreAttemptTime not set correctly.") } }
func setup() *Register { 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" } ab.ConfirmFields = []string{"password", "confirm_password"} ab.Storer = mocks.NewMockStorer() reg := Register{} if err := reg.Initialize(ab); err != nil { panic(err) } return ® }
func TestAuth(t *testing.T) { t.Parallel() r := &Remember{authboss.New()} storer := mocks.NewMockStorer() r.Storer = storer cookies := mocks.NewMockClientStorer() session := mocks.NewMockClientStorer() ctx := r.NewContext() ctx.CookieStorer = cookies ctx.SessionStorer = session key := "tester" _, err := r.new(cookies, key) if err != nil { t.Error("Unexpected error:", err) } cookie, _ := cookies.Get(authboss.CookieRemember) interrupt, err := r.auth(ctx) if err != nil { t.Error("Unexpected error:", err) } if session.Values[authboss.SessionHalfAuthKey] != "true" { t.Error("The user should have been half-authed.") } if session.Values[authboss.SessionKey] != key { t.Error("The user should have been logged in.") } if chocolateChip, _ := cookies.Get(authboss.CookieRemember); chocolateChip == cookie { t.Error("Expected cookie to be different") } if authboss.InterruptNone != interrupt { t.Error("Keys should have matched:", interrupt) } }
func testSetup() (a *Auth, s *mocks.MockStorer) { s = mocks.NewMockStorer() 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" } ab.PrimaryID = authboss.StoreUsername a = &Auth{} if err := a.Initialize(ab); err != nil { panic(err) } return a, s }
func TestRegister(t *testing.T) { ab := authboss.New() ab.Storer = mocks.NewMockStorer() r := Register{} if err := r.Initialize(ab); err != nil { t.Error(err) } if r.Routes()["/register"] == nil { t.Error("Expected a register handler at /register.") } sto := r.Storage() if sto[r.PrimaryID] != authboss.String { t.Error("Wanted primary ID to be a string.") } if sto[authboss.StorePassword] != authboss.String { t.Error("Wanted password to be a string.") } }
func testSetup() (r *Recover, s *mocks.MockStorer, l *bytes.Buffer) { s = mocks.NewMockStorer() l = &bytes.Buffer{} 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" } ab.PrimaryID = authboss.StoreUsername ab.LogWriter = l ab.Policies = []authboss.Validator{ authboss.Rules{ FieldName: "username", Required: true, MinLength: 2, MaxLength: 4, AllowWhitespace: false, }, authboss.Rules{ FieldName: "password", Required: true, MinLength: 4, MaxLength: 8, AllowWhitespace: false, }, } r = &Recover{} if err := r.Initialize(ab); err != nil { panic(err) } return r, s, l }
func TestInitialize(t *testing.T) { t.Parallel() ab := authboss.New() r := &Remember{} err := r.Initialize(ab) if err == nil { t.Error("Expected error about token storers.") } ab.Storer = mocks.MockFailStorer{} err = r.Initialize(ab) if err == nil { t.Error("Expected error about token storers.") } ab.Storer = mocks.NewMockStorer() err = r.Initialize(ab) if err != nil { t.Error("Unexpected error:", err) } }
func TestLock(t *testing.T) { t.Parallel() ab := authboss.New() storer := mocks.NewMockStorer() ab.Storer = storer lock := Lock{ab} email := "*****@*****.**" storer.Users[email] = map[string]interface{}{ ab.PrimaryID: email, "password": "******", } err := lock.Lock(email) if err != nil { t.Error(err) } if locked := storer.Users[email][StoreLocked].(time.Time); !locked.After(time.Now()) { t.Error("User should be locked.") } }
func TestAfterOAuth(t *testing.T) { t.Parallel() r := Remember{authboss.New()} storer := mocks.NewMockStorer() r.Storer = storer cookies := mocks.NewMockClientStorer() session := mocks.NewMockClientStorer(authboss.SessionOAuth2Params, `{"rm":"true"}`) uri := fmt.Sprintf("%s?state=%s", "localhost/oauthed", "xsrf") req, err := http.NewRequest("GET", uri, nil) if err != nil { t.Error("Unexpected Error:", err) } ctx, err := r.ContextFromRequest(req) if err != nil { t.Error("Unexpected error:", err) } ctx.SessionStorer = session ctx.CookieStorer = cookies ctx.User = authboss.Attributes{ authboss.StoreOAuth2UID: "uid", authboss.StoreOAuth2Provider: "google", } if err := r.afterOAuth(ctx); err != nil { t.Error(err) } if _, ok := cookies.Values[authboss.CookieRemember]; !ok { t.Error("Expected a cookie to have been set.") } }
func TestOAuthSuccess(t *testing.T) { t.Parallel() ab := authboss.New() oauth := OAuth2{ab} expiry := time.Now().UTC().Add(3600 * time.Second) fakeToken := &oauth2.Token{ AccessToken: "token", TokenType: "Bearer", RefreshToken: "refresh", Expiry: expiry, } fakeCallback := func(_ oauth2.Config, _ *oauth2.Token) (authboss.Attributes, error) { return authboss.Attributes{ authboss.StoreOAuth2UID: "uid", authboss.StoreEmail: "email", }, nil } saveExchange := exchanger defer func() { exchanger = saveExchange }() exchanger = func(_ *oauth2.Config, _ context.Context, _ string) (*oauth2.Token, error) { return fakeToken, nil } ab.OAuth2Providers = map[string]authboss.OAuth2Provider{ "fake": authboss.OAuth2Provider{ OAuth2Config: &oauth2.Config{ ClientID: `jazz`, ClientSecret: `hands`, Scopes: []string{`profile`, `email`}, Endpoint: oauth2.Endpoint{ AuthURL: "fakeauth", TokenURL: "faketoken", }, }, Callback: fakeCallback, AdditionalParams: url.Values{"include_requested_scopes": []string{"true"}}, }, } values := make(url.Values) values.Set("code", "code") values.Set("state", "state") url := fmt.Sprintf("/oauth2/fake?%s", values.Encode()) r, _ := http.NewRequest("GET", url, nil) w := httptest.NewRecorder() 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 ab.OAuth2Storer = storer ab.AuthLoginOKPath = "/fakeloginok" if err := oauth.oauthCallback(ctx, w, r); err != nil { t.Error(err) } key := "uidfake" user, ok := storer.Users[key] if !ok { t.Error("Couldn't find user.") } if val, _ := user.String(authboss.StoreEmail); val != "email" { t.Error("Email was wrong:", val) } if val, _ := user.String(authboss.StoreOAuth2Token); val != "token" { t.Error("Token was wrong:", val) } if val, _ := user.String(authboss.StoreOAuth2Refresh); val != "refresh" { t.Error("Refresh was wrong:", val) } if val, _ := user.DateTime(authboss.StoreOAuth2Expiry); !val.Equal(expiry) { t.Error("Expiry was wrong:", val) } if val, _ := session.Get(authboss.SessionKey); val != "uid;fake" { t.Error("User was not logged in:", val) } if _, ok := session.Get(authboss.SessionOAuth2State); ok { t.Error("Expected state to be deleted.") } if w.Code != http.StatusFound { t.Error("It should redirect") } else if loc := w.Header().Get("Location"); loc != "/myurl?myparam=5" { t.Error("Redirect is wrong:", loc) } }