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

Make "remember" value passing unobtrusive

- Remove RM context key for Values.
- Add values types and code to be able to pull the remember me bool
  checkbox from the user.
This commit is contained in:
Aaron L 2018-03-07 15:17:22 -08:00
parent ac3d2846f8
commit ce2d3dac09
7 changed files with 38 additions and 8 deletions

View File

@ -87,6 +87,8 @@ func (a *Auth) LoginPost(w http.ResponseWriter, r *http.Request) error {
return a.Authboss.Core.Responder.Respond(w, r, http.StatusOK, PageLogin, data) return a.Authboss.Core.Responder.Respond(w, r, http.StatusOK, PageLogin, data)
} }
r = r.WithContext(context.WithValue(r.Context(), authboss.CTXKeyValues, validatable))
handled, err = a.Events.FireBefore(authboss.EventAuth, w, r) handled, err = a.Events.FireBefore(authboss.EventAuth, w, r)
if err != nil { if err != nil {
return err return err

View File

@ -114,12 +114,15 @@ func TestAuthPostSuccess(t *testing.T) {
h := setupMore(testSetup()) h := setupMore(testSetup())
var beforeCalled, afterCalled bool var beforeCalled, afterCalled bool
var beforeHasValues, afterHasValues bool
h.ab.Events.Before(authboss.EventAuth, func(w http.ResponseWriter, r *http.Request, handled bool) (bool, error) { h.ab.Events.Before(authboss.EventAuth, func(w http.ResponseWriter, r *http.Request, handled bool) (bool, error) {
beforeCalled = true beforeCalled = true
beforeHasValues = r.Context().Value(authboss.CTXKeyValues) != nil
return false, nil return false, nil
}) })
h.ab.Events.After(authboss.EventAuth, func(w http.ResponseWriter, r *http.Request, handled bool) (bool, error) { h.ab.Events.After(authboss.EventAuth, func(w http.ResponseWriter, r *http.Request, handled bool) (bool, error) {
afterCalled = true afterCalled = true
afterHasValues = r.Context().Value(authboss.CTXKeyValues) != nil
return false, nil return false, nil
}) })
@ -151,6 +154,12 @@ func TestAuthPostSuccess(t *testing.T) {
if !afterCalled { if !afterCalled {
t.Error("after should have been called") t.Error("after should have been called")
} }
if !beforeHasValues {
t.Error("before callback should have access to values")
}
if !afterHasValues {
t.Error("after callback should have access to values")
}
}) })
t.Run("handledBefore", func(t *testing.T) { t.Run("handledBefore", func(t *testing.T) {

View File

@ -20,10 +20,11 @@ const (
// renderer // renderer
CTXKeyData contextKey = "data" CTXKeyData contextKey = "data"
// CTXKeyRM is used to flag the remember me module to actually do the // CTXKeyValues is to pass the data submitted from API request or form
// remembering, since this is a per-user operation, authentication modules // along in the context in case modules need it. The only module that needs
// need to supply this key if they wish to allow users to be remembered. // user information currently is remember so only auth/oauth2 are currently
CTXKeyRM contextKey = "rm" // going to use this.
CTXKeyValues contextKey = "values"
) )
func (c contextKey) String() string { func (c contextKey) String() string {

View File

@ -421,6 +421,7 @@ type Values struct {
PID string PID string
Password string Password string
Token string Token string
Remember bool
Errors []error Errors []error
} }
@ -440,6 +441,12 @@ func (v Values) GetToken() string {
return v.Token return v.Token
} }
// GetShouldRemember gets the value that tells
// the remember module if it should remember the user
func (v Values) GetShouldRemember() bool {
return v.Remember
}
// Validate the values // Validate the values
func (v Values) Validate() []error { func (v Values) Validate() []error {
return v.Errors return v.Errors

View File

@ -44,10 +44,10 @@ func (r *Remember) Init(ab *authboss.Authboss) error {
// RememberAfterAuth creates a remember token and saves it in the user's cookies. // RememberAfterAuth creates a remember token and saves it in the user's cookies.
func (r *Remember) RememberAfterAuth(w http.ResponseWriter, req *http.Request, handled bool) (bool, error) { func (r *Remember) RememberAfterAuth(w http.ResponseWriter, req *http.Request, handled bool) (bool, error) {
rmIntf := req.Context().Value(authboss.CTXKeyRM) rmIntf := req.Context().Value(authboss.CTXKeyValues)
if rmIntf == nil { if rmIntf == nil {
return false, nil return false, nil
} else if rm, ok := rmIntf.(bool); ok && !rm { } else if rm, ok := rmIntf.(authboss.RememberValuer); ok && !rm.GetShouldRemember() {
return false, nil return false, nil
} }

View File

@ -59,7 +59,7 @@ func TestRememberAfterAuth(t *testing.T) {
user := &mocks.User{Email: "test@test.com"} user := &mocks.User{Email: "test@test.com"}
r := mocks.Request("POST") r := mocks.Request("POST")
r = r.WithContext(context.WithValue(r.Context(), authboss.CTXKeyRM, true)) r = r.WithContext(context.WithValue(r.Context(), authboss.CTXKeyValues, mocks.Values{Remember: true}))
r = r.WithContext(context.WithValue(r.Context(), authboss.CTXKeyUser, user)) r = r.WithContext(context.WithValue(r.Context(), authboss.CTXKeyUser, user))
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
w := h.ab.NewResponse(rec, r) w := h.ab.NewResponse(rec, r)
@ -101,7 +101,7 @@ func TestRememberAfterAuthSkip(t *testing.T) {
t.Error("expected no tokens to be created") t.Error("expected no tokens to be created")
} }
r = r.WithContext(context.WithValue(r.Context(), authboss.CTXKeyRM, false)) r = r.WithContext(context.WithValue(r.Context(), authboss.CTXKeyValues, mocks.Values{Remember: false}))
if handled, err := h.remember.RememberAfterAuth(w, r, false); err != nil { if handled, err := h.remember.RememberAfterAuth(w, r, false); err != nil {
t.Fatal(err) t.Fatal(err)

View File

@ -65,6 +65,17 @@ type RecoverEndValuer interface {
GetToken() string GetToken() string
} }
// RememberValuer allows auth/oauth2 to pass along the remember
// bool from the user to the remember module unobtrusively.
type RememberValuer interface {
// Intentionally omitting validator
// GetShouldRemember is the checkbox or what have you that
// tells the remember module if it should remember that user's
// authentication or not.
GetShouldRemember() bool
}
// ArbitraryValuer provides the "rest" of the fields // ArbitraryValuer provides the "rest" of the fields
// that aren't strictly needed for anything in particular, // that aren't strictly needed for anything in particular,
// address, secondary e-mail, etc. // address, secondary e-mail, etc.