mirror of
https://github.com/volatiletech/authboss.git
synced 2024-11-28 08:58:38 +02:00
Move expiry module
- Remove the errors from User interfaces
This commit is contained in:
parent
726204d809
commit
23e1e849d3
@ -124,7 +124,7 @@ func (a *Authboss) LoadClientState(w http.ResponseWriter, r *http.Request) (*htt
|
||||
return r, nil
|
||||
}
|
||||
|
||||
ctx := context.WithValue(r.Context(), ctxKeySessionState, state)
|
||||
ctx := context.WithValue(r.Context(), CTXKeySessionState, state)
|
||||
r = r.WithContext(ctx)
|
||||
}
|
||||
if a.Storage.CookieState != nil {
|
||||
@ -134,7 +134,7 @@ func (a *Authboss) LoadClientState(w http.ResponseWriter, r *http.Request) (*htt
|
||||
} else if state == nil {
|
||||
return r, nil
|
||||
}
|
||||
ctx := context.WithValue(r.Context(), ctxKeyCookieState, state)
|
||||
ctx := context.WithValue(r.Context(), CTXKeyCookieState, state)
|
||||
r = r.WithContext(ctx)
|
||||
}
|
||||
|
||||
@ -200,7 +200,7 @@ func (c *ClientStateResponseWriter) putClientState() error {
|
||||
}
|
||||
|
||||
if c.sessionState != nil && len(c.sessionStateEvents) > 0 {
|
||||
sessionStateIntf := c.ctx.Value(ctxKeySessionState)
|
||||
sessionStateIntf := c.ctx.Value(CTXKeySessionState)
|
||||
|
||||
var session ClientState
|
||||
if sessionStateIntf != nil {
|
||||
@ -213,7 +213,7 @@ func (c *ClientStateResponseWriter) putClientState() error {
|
||||
}
|
||||
}
|
||||
if c.cookieState != nil && len(c.cookieStateEvents) > 0 {
|
||||
cookieStateIntf := c.ctx.Value(ctxKeyCookieState)
|
||||
cookieStateIntf := c.ctx.Value(CTXKeyCookieState)
|
||||
|
||||
var cookie ClientState
|
||||
if cookieStateIntf != nil {
|
||||
@ -231,43 +231,43 @@ func (c *ClientStateResponseWriter) putClientState() error {
|
||||
|
||||
// PutSession puts a value into the session
|
||||
func PutSession(w http.ResponseWriter, key, val string) {
|
||||
putState(w, ctxKeySessionState, key, val)
|
||||
putState(w, CTXKeySessionState, key, val)
|
||||
}
|
||||
|
||||
// DelSession deletes a key-value from the session.
|
||||
func DelSession(w http.ResponseWriter, key string) {
|
||||
delState(w, ctxKeySessionState, key)
|
||||
delState(w, CTXKeySessionState, key)
|
||||
}
|
||||
|
||||
// GetSession fetches a value from the session
|
||||
func GetSession(r *http.Request, key string) (string, bool) {
|
||||
return getState(r, ctxKeySessionState, key)
|
||||
return getState(r, CTXKeySessionState, key)
|
||||
}
|
||||
|
||||
// PutCookie puts a value into the session
|
||||
func PutCookie(w http.ResponseWriter, key, val string) {
|
||||
putState(w, ctxKeyCookieState, key, val)
|
||||
putState(w, CTXKeyCookieState, key, val)
|
||||
}
|
||||
|
||||
// DelCookie deletes a key-value from the session.
|
||||
func DelCookie(w http.ResponseWriter, key string) {
|
||||
delState(w, ctxKeyCookieState, key)
|
||||
delState(w, CTXKeyCookieState, key)
|
||||
}
|
||||
|
||||
// GetCookie fetches a value from the session
|
||||
func GetCookie(r *http.Request, key string) (string, bool) {
|
||||
return getState(r, ctxKeyCookieState, key)
|
||||
return getState(r, CTXKeyCookieState, key)
|
||||
}
|
||||
|
||||
func putState(w http.ResponseWriter, ctxKey contextKey, key, val string) {
|
||||
setState(w, ctxKey, ClientStateEventPut, key, val)
|
||||
func putState(w http.ResponseWriter, CTXKey contextKey, key, val string) {
|
||||
setState(w, CTXKey, ClientStateEventPut, key, val)
|
||||
}
|
||||
|
||||
func delState(w http.ResponseWriter, ctxKey contextKey, key string) {
|
||||
setState(w, ctxKey, ClientStateEventDel, key, "")
|
||||
func delState(w http.ResponseWriter, CTXKey contextKey, key string) {
|
||||
setState(w, CTXKey, ClientStateEventDel, key, "")
|
||||
}
|
||||
|
||||
func setState(w http.ResponseWriter, ctxKey contextKey, op ClientStateEventKind, key, val string) {
|
||||
func setState(w http.ResponseWriter, CTXKey contextKey, op ClientStateEventKind, key, val string) {
|
||||
csrw := MustClientStateResponseWriter(w)
|
||||
ev := ClientStateEvent{
|
||||
Kind: op,
|
||||
@ -278,16 +278,16 @@ func setState(w http.ResponseWriter, ctxKey contextKey, op ClientStateEventKind,
|
||||
ev.Value = val
|
||||
}
|
||||
|
||||
switch ctxKey {
|
||||
case ctxKeySessionState:
|
||||
switch CTXKey {
|
||||
case CTXKeySessionState:
|
||||
csrw.sessionStateEvents = append(csrw.sessionStateEvents, ev)
|
||||
case ctxKeyCookieState:
|
||||
case CTXKeyCookieState:
|
||||
csrw.cookieStateEvents = append(csrw.cookieStateEvents, ev)
|
||||
}
|
||||
}
|
||||
|
||||
func getState(r *http.Request, ctxKey contextKey, key string) (string, bool) {
|
||||
val := r.Context().Value(ctxKey)
|
||||
func getState(r *http.Request, CTXKey contextKey, key string) (string, bool) {
|
||||
val := r.Context().Value(CTXKey)
|
||||
if val == nil {
|
||||
return "", false
|
||||
}
|
||||
|
21
context.go
21
context.go
@ -7,12 +7,13 @@ import (
|
||||
|
||||
type contextKey string
|
||||
|
||||
// CTX Keys for authboss
|
||||
const (
|
||||
ctxKeyPID contextKey = "pid"
|
||||
ctxKeyUser contextKey = "user"
|
||||
CTXKeyPID contextKey = "pid"
|
||||
CTXKeyUser contextKey = "user"
|
||||
|
||||
ctxKeySessionState contextKey = "session"
|
||||
ctxKeyCookieState contextKey = "cookie"
|
||||
CTXKeySessionState contextKey = "session"
|
||||
CTXKeyCookieState contextKey = "cookie"
|
||||
|
||||
// CTXKeyData is a context key for the accumulating
|
||||
// map[string]interface{} (authboss.HTMLData) to pass to the
|
||||
@ -26,7 +27,7 @@ func (c contextKey) String() string {
|
||||
|
||||
// CurrentUserID retrieves the current user from the session.
|
||||
func (a *Authboss) CurrentUserID(w http.ResponseWriter, r *http.Request) (string, error) {
|
||||
if pid := r.Context().Value(ctxKeyPID); pid != nil {
|
||||
if pid := r.Context().Value(CTXKeyPID); pid != nil {
|
||||
return pid.(string), nil
|
||||
}
|
||||
|
||||
@ -49,7 +50,7 @@ func (a *Authboss) CurrentUserIDP(w http.ResponseWriter, r *http.Request) string
|
||||
|
||||
// CurrentUser retrieves the current user from the session and the database.
|
||||
func (a *Authboss) CurrentUser(w http.ResponseWriter, r *http.Request) (User, error) {
|
||||
if user := r.Context().Value(ctxKeyUser); user != nil {
|
||||
if user := r.Context().Value(CTXKeyUser); user != nil {
|
||||
return user.(User), nil
|
||||
}
|
||||
|
||||
@ -88,7 +89,7 @@ func (a *Authboss) currentUser(ctx context.Context, pid string) (User, error) {
|
||||
// change the current method's request pointer itself to the new request that
|
||||
// contains the new context that has the pid in it.
|
||||
func (a *Authboss) LoadCurrentUserID(w http.ResponseWriter, r **http.Request) (string, error) {
|
||||
if pid := (*r).Context().Value(ctxKeyPID); pid != nil {
|
||||
if pid := (*r).Context().Value(CTXKeyPID); pid != nil {
|
||||
return pid.(string), nil
|
||||
}
|
||||
|
||||
@ -101,7 +102,7 @@ func (a *Authboss) LoadCurrentUserID(w http.ResponseWriter, r **http.Request) (s
|
||||
return "", nil
|
||||
}
|
||||
|
||||
ctx := context.WithValue((**r).Context(), ctxKeyPID, pid)
|
||||
ctx := context.WithValue((**r).Context(), CTXKeyPID, pid)
|
||||
*r = (**r).WithContext(ctx)
|
||||
|
||||
return pid, nil
|
||||
@ -124,7 +125,7 @@ func (a *Authboss) LoadCurrentUserIDP(w http.ResponseWriter, r **http.Request) s
|
||||
// contains the new context that has the user in it. Calls LoadCurrentUserID
|
||||
// so the primary id is also put in the context.
|
||||
func (a *Authboss) LoadCurrentUser(w http.ResponseWriter, r **http.Request) (User, error) {
|
||||
if user := (*r).Context().Value(ctxKeyUser); user != nil {
|
||||
if user := (*r).Context().Value(CTXKeyUser); user != nil {
|
||||
return user.(User), nil
|
||||
}
|
||||
|
||||
@ -143,7 +144,7 @@ func (a *Authboss) LoadCurrentUser(w http.ResponseWriter, r **http.Request) (Use
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx = context.WithValue(ctx, ctxKeyUser, user)
|
||||
ctx = context.WithValue(ctx, CTXKeyUser, user)
|
||||
*r = (**r).WithContext(ctx)
|
||||
return user, nil
|
||||
}
|
||||
|
@ -1,9 +1,12 @@
|
||||
package authboss
|
||||
// Package expire helps expire user's logged in sessions
|
||||
package expire
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/volatiletech/authboss"
|
||||
)
|
||||
|
||||
var nowTime = time.Now
|
||||
@ -15,7 +18,7 @@ func TimeToExpiry(r *http.Request, expireAfter time.Duration) time.Duration {
|
||||
}
|
||||
|
||||
func timeToExpiry(r *http.Request, expireAfter time.Duration) time.Duration {
|
||||
dateStr, ok := GetSession(r, SessionLastAction)
|
||||
dateStr, ok := authboss.GetSession(r, authboss.SessionLastAction)
|
||||
if !ok {
|
||||
return expireAfter
|
||||
}
|
||||
@ -40,33 +43,33 @@ func RefreshExpiry(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func refreshExpiry(w http.ResponseWriter) {
|
||||
PutSession(w, SessionLastAction, nowTime().UTC().Format(time.RFC3339))
|
||||
authboss.PutSession(w, authboss.SessionLastAction, nowTime().UTC().Format(time.RFC3339))
|
||||
}
|
||||
|
||||
type expireMiddleware struct {
|
||||
ab *Authboss
|
||||
next http.Handler
|
||||
expireAfter time.Duration
|
||||
next http.Handler
|
||||
}
|
||||
|
||||
// ExpireMiddleware ensures that the user's expiry information is kept up-to-date
|
||||
// Middleware ensures that the user's expiry information is kept up-to-date
|
||||
// on each request. Deletes the SessionKey from the session if the user is
|
||||
// expired (a.ExpireAfter duration since SessionLastAction).
|
||||
// This middleware conflicts with use of the Remember module, don't enable both
|
||||
// at the same time.
|
||||
func (a *Authboss) ExpireMiddleware(next http.Handler) http.Handler {
|
||||
return expireMiddleware{a, next}
|
||||
func Middleware(ab *authboss.Authboss, next http.Handler) http.Handler {
|
||||
return expireMiddleware{ab.Config.Modules.ExpireAfter, next}
|
||||
}
|
||||
|
||||
// ServeHTTP removes the session and hides the loaded user from the handlers
|
||||
// below it.
|
||||
func (m expireMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if _, ok := GetSession(r, SessionKey); ok {
|
||||
ttl := timeToExpiry(r, m.ab.Modules.ExpireAfter)
|
||||
if _, ok := authboss.GetSession(r, authboss.SessionKey); ok {
|
||||
ttl := timeToExpiry(r, m.expireAfter)
|
||||
if ttl == 0 {
|
||||
DelSession(w, SessionKey)
|
||||
DelSession(w, SessionLastAction)
|
||||
ctx := context.WithValue(r.Context(), ctxKeyPID, nil)
|
||||
ctx = context.WithValue(ctx, ctxKeyUser, nil)
|
||||
authboss.DelSession(w, authboss.SessionKey)
|
||||
authboss.DelSession(w, authboss.SessionLastAction)
|
||||
ctx := context.WithValue(r.Context(), authboss.CTXKeyPID, nil)
|
||||
ctx = context.WithValue(ctx, authboss.CTXKeyUser, nil)
|
||||
r = r.WithContext(ctx)
|
||||
} else {
|
||||
refreshExpiry(w)
|
154
expire/expire_test.go
Normal file
154
expire/expire_test.go
Normal file
@ -0,0 +1,154 @@
|
||||
package expire
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/volatiletech/authboss"
|
||||
"github.com/volatiletech/authboss/internal/mocks"
|
||||
)
|
||||
|
||||
func TestExpireIsExpired(t *testing.T) {
|
||||
ab := authboss.New()
|
||||
|
||||
clientRW := mocks.NewClientRW()
|
||||
clientRW.ClientValues[authboss.SessionKey] = "username"
|
||||
clientRW.ClientValues[authboss.SessionLastAction] = time.Now().UTC().Format(time.RFC3339)
|
||||
ab.Storage.SessionState = clientRW
|
||||
|
||||
r := httptest.NewRequest("GET", "/", nil)
|
||||
r = r.WithContext(context.WithValue(r.Context(), authboss.CTXKeyPID, "primaryid"))
|
||||
r = r.WithContext(context.WithValue(r.Context(), authboss.CTXKeyUser, struct{}{}))
|
||||
w := ab.NewResponse(httptest.NewRecorder(), r)
|
||||
r, err := ab.LoadClientState(w, r)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// No t.Parallel() - Also must be after refreshExpiry() call
|
||||
nowTime = func() time.Time {
|
||||
return time.Now().UTC().Add(time.Hour * 2)
|
||||
}
|
||||
defer func() {
|
||||
nowTime = time.Now
|
||||
}()
|
||||
|
||||
called := false
|
||||
hadUser := false
|
||||
m := Middleware(ab, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
|
||||
if r.Context().Value(authboss.CTXKeyPID) != nil {
|
||||
hadUser = true
|
||||
}
|
||||
if r.Context().Value(authboss.CTXKeyUser) != nil {
|
||||
hadUser = true
|
||||
}
|
||||
}))
|
||||
|
||||
m.ServeHTTP(w, r)
|
||||
|
||||
if !called {
|
||||
t.Error("expected middleware to call handler")
|
||||
}
|
||||
if hadUser {
|
||||
t.Error("expected user not to be present")
|
||||
}
|
||||
|
||||
w.WriteHeader(200)
|
||||
if _, ok := clientRW.ClientValues[authboss.SessionKey]; ok {
|
||||
t.Error("this key should have been deleted\n", clientRW)
|
||||
}
|
||||
if _, ok := clientRW.ClientValues[authboss.SessionLastAction]; ok {
|
||||
t.Error("this key should have been deleted\n", clientRW)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExpireNotExpired(t *testing.T) {
|
||||
ab := authboss.New()
|
||||
clientRW := mocks.NewClientRW()
|
||||
clientRW.ClientValues[authboss.SessionKey] = "username"
|
||||
clientRW.ClientValues[authboss.SessionLastAction] = time.Now().UTC().Format(time.RFC3339)
|
||||
ab.Storage.SessionState = clientRW
|
||||
|
||||
var err error
|
||||
|
||||
r := httptest.NewRequest("GET", "/", nil)
|
||||
r = r.WithContext(context.WithValue(r.Context(), authboss.CTXKeyPID, "primaryid"))
|
||||
r = r.WithContext(context.WithValue(r.Context(), authboss.CTXKeyUser, struct{}{}))
|
||||
w := ab.NewResponse(httptest.NewRecorder(), r)
|
||||
r, err = ab.LoadClientState(w, r)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// No t.Parallel() - Also must be after refreshExpiry() call
|
||||
newTime := time.Now().UTC().Add(ab.Modules.ExpireAfter / 2)
|
||||
nowTime = func() time.Time {
|
||||
return newTime
|
||||
}
|
||||
defer func() {
|
||||
nowTime = time.Now
|
||||
}()
|
||||
|
||||
called := false
|
||||
hadUser := true
|
||||
m := Middleware(ab, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
|
||||
if r.Context().Value(authboss.CTXKeyPID) == nil {
|
||||
hadUser = false
|
||||
}
|
||||
if r.Context().Value(authboss.CTXKeyUser) == nil {
|
||||
hadUser = false
|
||||
}
|
||||
}))
|
||||
|
||||
m.ServeHTTP(w, r)
|
||||
|
||||
if !called {
|
||||
t.Error("expected middleware to call handler")
|
||||
}
|
||||
if !hadUser {
|
||||
t.Error("expected user to be present")
|
||||
}
|
||||
|
||||
want := newTime.Format(time.RFC3339)
|
||||
w.WriteHeader(200)
|
||||
if last, ok := clientRW.ClientValues[authboss.SessionLastAction]; !ok {
|
||||
t.Error("this key should be present", clientRW)
|
||||
} else if want != last {
|
||||
t.Error("want:", want, "got:", last)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExpireTimeToExpiry(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
r := httptest.NewRequest("GET", "/", nil)
|
||||
|
||||
want := 5 * time.Second
|
||||
dur := TimeToExpiry(r, want)
|
||||
if dur != want {
|
||||
t.Error("duration was wrong:", dur)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExpireRefreshExpiry(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ab := authboss.New()
|
||||
clientRW := mocks.NewClientRW()
|
||||
ab.Storage.SessionState = clientRW
|
||||
r := httptest.NewRequest("GET", "/", nil)
|
||||
w := ab.NewResponse(httptest.NewRecorder(), r)
|
||||
|
||||
RefreshExpiry(w, r)
|
||||
w.WriteHeader(200)
|
||||
if _, ok := clientRW.ClientValues[authboss.SessionLastAction]; !ok {
|
||||
t.Error("this key should have been set")
|
||||
}
|
||||
}
|
160
expire_test.go
160
expire_test.go
@ -1,160 +0,0 @@
|
||||
package authboss
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestExpireIsExpired(t *testing.T) {
|
||||
ab := New()
|
||||
ab.Storage.SessionState = newMockClientStateRW(
|
||||
SessionKey, "username",
|
||||
SessionLastAction, time.Now().UTC().Format(time.RFC3339),
|
||||
)
|
||||
|
||||
r := httptest.NewRequest("GET", "/", nil)
|
||||
r = r.WithContext(context.WithValue(r.Context(), ctxKeyPID, "primaryid"))
|
||||
r = r.WithContext(context.WithValue(r.Context(), ctxKeyUser, struct{}{}))
|
||||
w := ab.NewResponse(httptest.NewRecorder(), r)
|
||||
r, err := ab.LoadClientState(w, r)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// No t.Parallel() - Also must be after refreshExpiry() call
|
||||
nowTime = func() time.Time {
|
||||
return time.Now().UTC().Add(ab.Modules.ExpireAfter * 2)
|
||||
}
|
||||
defer func() {
|
||||
nowTime = time.Now
|
||||
}()
|
||||
|
||||
called := false
|
||||
hadUser := false
|
||||
m := ab.ExpireMiddleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
|
||||
if r.Context().Value(ctxKeyPID) != nil {
|
||||
hadUser = true
|
||||
}
|
||||
if r.Context().Value(ctxKeyUser) != nil {
|
||||
hadUser = true
|
||||
}
|
||||
}))
|
||||
|
||||
m.ServeHTTP(w, r)
|
||||
|
||||
if !called {
|
||||
t.Error("expected middleware to call handler")
|
||||
}
|
||||
if hadUser {
|
||||
t.Error("expected user not to be present")
|
||||
}
|
||||
|
||||
want := ClientStateEvent{
|
||||
Kind: ClientStateEventDel,
|
||||
Key: SessionKey,
|
||||
}
|
||||
if got := w.sessionStateEvents[0]; got != want {
|
||||
t.Error("want:", want, "got:", got)
|
||||
}
|
||||
want = ClientStateEvent{
|
||||
Kind: ClientStateEventDel,
|
||||
Key: SessionLastAction,
|
||||
}
|
||||
if got := w.sessionStateEvents[1]; got != want {
|
||||
t.Error("want:", want, "got:", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExpireNotExpired(t *testing.T) {
|
||||
ab := New()
|
||||
ab.Config.Modules.ExpireAfter = time.Hour
|
||||
ab.Storage.SessionState = newMockClientStateRW(
|
||||
SessionKey, "username",
|
||||
SessionLastAction, time.Now().UTC().Format(time.RFC3339),
|
||||
)
|
||||
|
||||
var err error
|
||||
|
||||
r := httptest.NewRequest("GET", "/", nil)
|
||||
r = r.WithContext(context.WithValue(r.Context(), ctxKeyPID, "primaryid"))
|
||||
r = r.WithContext(context.WithValue(r.Context(), ctxKeyUser, struct{}{}))
|
||||
w := ab.NewResponse(httptest.NewRecorder(), r)
|
||||
r, err = ab.LoadClientState(w, r)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// No t.Parallel() - Also must be after refreshExpiry() call
|
||||
newTime := time.Now().UTC().Add(ab.Modules.ExpireAfter / 2)
|
||||
nowTime = func() time.Time {
|
||||
return newTime
|
||||
}
|
||||
defer func() {
|
||||
nowTime = time.Now
|
||||
}()
|
||||
|
||||
called := false
|
||||
hadUser := true
|
||||
m := ab.ExpireMiddleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
called = true
|
||||
|
||||
if r.Context().Value(ctxKeyPID) == nil {
|
||||
hadUser = false
|
||||
}
|
||||
if r.Context().Value(ctxKeyUser) == nil {
|
||||
hadUser = false
|
||||
}
|
||||
}))
|
||||
|
||||
m.ServeHTTP(w, r)
|
||||
|
||||
if !called {
|
||||
t.Error("expected middleware to call handler")
|
||||
}
|
||||
if !hadUser {
|
||||
t.Error("expected user to be present")
|
||||
}
|
||||
|
||||
want := ClientStateEvent{
|
||||
Kind: ClientStateEventPut,
|
||||
Key: SessionLastAction,
|
||||
Value: newTime.Format(time.RFC3339),
|
||||
}
|
||||
|
||||
if got := w.sessionStateEvents[0]; got != want {
|
||||
t.Error("want:", want, "got:", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExpireTimeToExpiry(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
r := httptest.NewRequest("GET", "/", nil)
|
||||
|
||||
want := 5 * time.Second
|
||||
dur := TimeToExpiry(r, want)
|
||||
if dur != want {
|
||||
t.Error("duration was wrong:", dur)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExpireRefreshExpiry(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ab := New()
|
||||
r := httptest.NewRequest("GET", "/", nil)
|
||||
w := ab.NewResponse(httptest.NewRecorder(), r)
|
||||
|
||||
RefreshExpiry(w, r)
|
||||
if got := w.sessionStateEvents[0].Kind; got != ClientStateEventPut {
|
||||
t.Error("wrong event:", got)
|
||||
}
|
||||
if got := w.sessionStateEvents[0].Key; got != SessionLastAction {
|
||||
t.Error("wrong key:", got)
|
||||
}
|
||||
}
|
@ -278,6 +278,15 @@ func (c *ClientStateRW) ReadState(http.ResponseWriter, *http.Request) (authboss.
|
||||
|
||||
// WriteState to memory
|
||||
func (c *ClientStateRW) WriteState(w http.ResponseWriter, cstate authboss.ClientState, cse []authboss.ClientStateEvent) error {
|
||||
for _, e := range cse {
|
||||
switch e.Kind {
|
||||
case authboss.ClientStateEventPut:
|
||||
c.ClientValues[e.Key] = e.Value
|
||||
case authboss.ClientStateEventDel:
|
||||
delete(c.ClientValues, e.Key)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
46
storage.go
46
storage.go
@ -48,28 +48,32 @@ type ServerStorer interface {
|
||||
// User has a PID (primary ID) that is used on the site as
|
||||
// a single unique identifier to any given user (very typically e-mail
|
||||
// or username).
|
||||
//
|
||||
// User interfaces return no errors or bools to signal that a value was
|
||||
// not present. Instead 0-value = null = not present, this puts the onus
|
||||
// on Authboss code to check for this.
|
||||
type User interface {
|
||||
GetPID(ctx context.Context) (pid string, err error)
|
||||
PutPID(ctx context.Context, pid string) error
|
||||
GetPID(ctx context.Context) (pid string)
|
||||
PutPID(ctx context.Context, pid string)
|
||||
}
|
||||
|
||||
// AuthableUser is identified by a password
|
||||
type AuthableUser interface {
|
||||
User
|
||||
|
||||
GetPassword(ctx context.Context) (password string, err error)
|
||||
PutPassword(ctx context.Context, password string) error
|
||||
GetPassword(ctx context.Context) (password string)
|
||||
PutPassword(ctx context.Context, password string)
|
||||
}
|
||||
|
||||
// ConfirmableUser can be in a state of confirmed or not
|
||||
type ConfirmableUser interface {
|
||||
User
|
||||
|
||||
GetConfirmed(ctx context.Context) (confirmed bool, err error)
|
||||
GetConfirmToken(ctx context.Context) (token string, err error)
|
||||
GetConfirmed(ctx context.Context) (confirmed bool)
|
||||
GetConfirmToken(ctx context.Context) (token string)
|
||||
|
||||
PutConfirmed(ctx context.Context, confirmed bool) error
|
||||
PutConfirmToken(ctx context.Context, token string) error
|
||||
PutConfirmed(ctx context.Context, confirmed bool)
|
||||
PutConfirmToken(ctx context.Context, token string)
|
||||
}
|
||||
|
||||
// ArbitraryUser allows arbitrary data from the web form through. You should
|
||||
@ -80,10 +84,10 @@ type ArbitraryUser interface {
|
||||
|
||||
// GetArbitrary is used only to display the arbitrary data back to the user
|
||||
// when the form is reset.
|
||||
GetArbitrary(ctx context.Context) (arbitrary map[string]string, err error)
|
||||
GetArbitrary(ctx context.Context) (arbitrary map[string]string)
|
||||
// PutArbitrary allows arbitrary fields defined by the authboss library
|
||||
// consumer to add fields to the user registration piece.
|
||||
PutArbitrary(ctx context.Context, arbitrary map[string]string) error
|
||||
PutArbitrary(ctx context.Context, arbitrary map[string]string)
|
||||
}
|
||||
|
||||
// OAuth2User allows reading and writing values relating to OAuth2
|
||||
@ -92,19 +96,19 @@ type OAuth2User interface {
|
||||
|
||||
// IsOAuth2User checks to see if a user was registered in the site as an
|
||||
// oauth2 user.
|
||||
IsOAuth2User(ctx context.Context) (bool, error)
|
||||
IsOAuth2User(ctx context.Context) bool
|
||||
|
||||
GetUID(ctx context.Context) (uid string, err error)
|
||||
GetProvider(ctx context.Context) (provider string, err error)
|
||||
GetToken(ctx context.Context) (token string, err error)
|
||||
GetRefreshToken(ctx context.Context) (refreshToken string, err error)
|
||||
GetExpiry(ctx context.Context) (expiry time.Duration, err error)
|
||||
GetUID(ctx context.Context) (uid string)
|
||||
GetProvider(ctx context.Context) (provider string)
|
||||
GetToken(ctx context.Context) (token string)
|
||||
GetRefreshToken(ctx context.Context) (refreshToken string)
|
||||
GetExpiry(ctx context.Context) (expiry time.Duration)
|
||||
|
||||
PutUID(ctx context.Context, uid string) error
|
||||
PutProvider(ctx context.Context, provider string) error
|
||||
PutToken(ctx context.Context, token string) error
|
||||
PutRefreshToken(ctx context.Context, refreshToken string) error
|
||||
PutExpiry(ctx context.Context, expiry time.Duration) error
|
||||
PutUID(ctx context.Context, uid string)
|
||||
PutProvider(ctx context.Context, provider string)
|
||||
PutToken(ctx context.Context, token string)
|
||||
PutRefreshToken(ctx context.Context, refreshToken string)
|
||||
PutExpiry(ctx context.Context, expiry time.Duration)
|
||||
}
|
||||
|
||||
// MustBeAuthable forces an upgrade conversion to Authable
|
||||
|
Loading…
Reference in New Issue
Block a user