RefreshSessions immediately when called

This commit is contained in:
Nick Meves
2021-06-21 21:54:52 -07:00
parent 5f4ac25b1e
commit 7e80e5596b
13 changed files with 74 additions and 79 deletions
+25 -24
View File
@@ -24,12 +24,12 @@ type StoredSessionLoaderOptions struct {
RefreshPeriod time.Duration
// Provider based sesssion refreshing
RefreshSessionIfNeeded func(context.Context, *sessionsapi.SessionState) (bool, error)
RefreshSession func(context.Context, *sessionsapi.SessionState) (bool, error)
// Provider based session validation.
// If the sesssion is older than `RefreshPeriod` but the provider doesn't
// refresh it, we must re-validate using this validation.
ValidateSessionState func(context.Context, *sessionsapi.SessionState) bool
ValidateSession func(context.Context, *sessionsapi.SessionState) bool
}
// NewStoredSessionLoader creates a new storedSessionLoader which loads
@@ -38,10 +38,10 @@ type StoredSessionLoaderOptions struct {
// If a session was loader by a previous handler, it will not be replaced.
func NewStoredSessionLoader(opts *StoredSessionLoaderOptions) alice.Constructor {
ss := &storedSessionLoader{
store: opts.SessionStore,
refreshPeriod: opts.RefreshPeriod,
refreshSessionWithProviderIfNeeded: opts.RefreshSessionIfNeeded,
validateSessionState: opts.ValidateSessionState,
store: opts.SessionStore,
refreshPeriod: opts.RefreshPeriod,
sessionRefresher: opts.RefreshSession,
sessionValidator: opts.ValidateSession,
}
return ss.loadSession
}
@@ -49,10 +49,10 @@ func NewStoredSessionLoader(opts *StoredSessionLoaderOptions) alice.Constructor
// storedSessionLoader is responsible for loading sessions from cookie
// identified sessions in the session store.
type storedSessionLoader struct {
store sessionsapi.SessionStore
refreshPeriod time.Duration
refreshSessionWithProviderIfNeeded func(context.Context, *sessionsapi.SessionState) (bool, error)
validateSessionState func(context.Context, *sessionsapi.SessionState) bool
store sessionsapi.SessionStore
refreshPeriod time.Duration
sessionRefresher func(context.Context, *sessionsapi.SessionState) (bool, error)
sessionValidator func(context.Context, *sessionsapi.SessionState) bool
}
// loadSession attempts to load a session as identified by the request cookies.
@@ -120,37 +120,38 @@ func (s *storedSessionLoader) refreshSessionIfNeeded(rw http.ResponseWriter, req
}
logger.Printf("Refreshing %s old session cookie for %s (refresh after %s)", session.Age(), session, s.refreshPeriod)
refreshed, err := s.refreshSessionWithProvider(rw, req, session)
err := s.refreshSession(rw, req, session)
if err != nil {
return err
}
if !refreshed {
// Session wasn't refreshed, so make sure it's still valid
return s.validateSession(req.Context(), session)
}
return nil
// Validate all sessions after any Redeem/Refresh operation
return s.validateSession(req.Context(), session)
}
// refreshSessionWithProvider attempts to refresh the sessinon with the provider
// refreshSession attempts to refresh the session with the provider
// and will save the session if it was updated.
func (s *storedSessionLoader) refreshSessionWithProvider(rw http.ResponseWriter, req *http.Request, session *sessionsapi.SessionState) (bool, error) {
refreshed, err := s.refreshSessionWithProviderIfNeeded(req.Context(), session)
func (s *storedSessionLoader) refreshSession(rw http.ResponseWriter, req *http.Request, session *sessionsapi.SessionState) error {
refreshed, err := s.sessionRefresher(req.Context(), session)
if err != nil {
return false, fmt.Errorf("error refreshing access token: %v", err)
return fmt.Errorf("error refreshing access token: %v", err)
}
if !refreshed {
return false, nil
return nil
}
// If we refreshed, update the `CreatedAt` time to reset the refresh timer
// TODO: Implement
// session.CreatedAtNow()
// Because the session was refreshed, make sure to save it
err = s.store.Save(rw, req, session)
if err != nil {
logger.PrintAuthf(session.Email, req, logger.AuthError, "error saving session: %v", err)
return false, fmt.Errorf("error saving session: %v", err)
return fmt.Errorf("error saving session: %v", err)
}
return true, nil
return nil
}
// validateSession checks whether the session has expired and performs
@@ -161,7 +162,7 @@ func (s *storedSessionLoader) validateSession(ctx context.Context, session *sess
return errors.New("session is expired")
}
if !s.validateSessionState(ctx, session) {
if !s.sessionValidator(ctx, session) {
return errors.New("session is invalid")
}
+10 -15
View File
@@ -109,10 +109,10 @@ var _ = Describe("Stored Session Suite", func() {
rw := httptest.NewRecorder()
opts := &StoredSessionLoaderOptions{
SessionStore: in.store,
RefreshPeriod: in.refreshPeriod,
RefreshSessionIfNeeded: in.refreshSession,
ValidateSessionState: in.validateSession,
SessionStore: in.store,
RefreshPeriod: in.refreshPeriod,
RefreshSession: in.refreshSession,
ValidateSession: in.validateSession,
}
// Create the handler with a next handler that will capture the session
@@ -261,7 +261,7 @@ var _ = Describe("Stored Session Suite", func() {
s := &storedSessionLoader{
refreshPeriod: in.refreshPeriod,
store: &fakeSessionStore{},
refreshSessionWithProviderIfNeeded: func(_ context.Context, ss *sessionsapi.SessionState) (bool, error) {
sessionRefresher: func(_ context.Context, ss *sessionsapi.SessionState) (bool, error) {
refreshed = true
switch ss.RefreshToken {
case refresh:
@@ -272,7 +272,7 @@ var _ = Describe("Stored Session Suite", func() {
return false, errors.New("error refreshing session")
}
},
validateSessionState: func(_ context.Context, ss *sessionsapi.SessionState) bool {
sessionValidator: func(_ context.Context, ss *sessionsapi.SessionState) bool {
validated = true
return ss.AccessToken != "Invalid"
},
@@ -364,7 +364,7 @@ var _ = Describe("Stored Session Suite", func() {
)
})
Context("refreshSessionWithProvider", func() {
Context("refreshSession", func() {
type refreshSessionWithProviderTableInput struct {
session *sessionsapi.SessionState
expectedErr error
@@ -388,7 +388,7 @@ var _ = Describe("Stored Session Suite", func() {
return nil
},
},
refreshSessionWithProviderIfNeeded: func(_ context.Context, ss *sessionsapi.SessionState) (bool, error) {
sessionRefresher: func(_ context.Context, ss *sessionsapi.SessionState) (bool, error) {
switch ss.RefreshToken {
case refresh:
return true, nil
@@ -402,13 +402,12 @@ var _ = Describe("Stored Session Suite", func() {
req := httptest.NewRequest("", "/", nil)
req = middlewareapi.AddRequestScope(req, &middlewareapi.RequestScope{})
refreshed, err := s.refreshSessionWithProvider(nil, req, in.session)
err := s.refreshSession(nil, req, in.session)
if in.expectedErr != nil {
Expect(err).To(MatchError(in.expectedErr))
} else {
Expect(err).ToNot(HaveOccurred())
}
Expect(refreshed).To(Equal(in.expectRefreshed))
Expect(saved).To(Equal(in.expectSaved))
},
Entry("when the provider does not refresh the session", refreshSessionWithProviderTableInput{
@@ -416,7 +415,6 @@ var _ = Describe("Stored Session Suite", func() {
RefreshToken: noRefresh,
},
expectedErr: nil,
expectRefreshed: false,
expectSaved: false,
}),
Entry("when the provider refreshes the session", refreshSessionWithProviderTableInput{
@@ -424,7 +422,6 @@ var _ = Describe("Stored Session Suite", func() {
RefreshToken: refresh,
},
expectedErr: nil,
expectRefreshed: true,
expectSaved: true,
}),
Entry("when the provider returns an error", refreshSessionWithProviderTableInput{
@@ -434,7 +431,6 @@ var _ = Describe("Stored Session Suite", func() {
ExpiresOn: &now,
},
expectedErr: errors.New("error refreshing access token: error refreshing session"),
expectRefreshed: false,
expectSaved: false,
}),
Entry("when the saving the session returns an error", refreshSessionWithProviderTableInput{
@@ -443,7 +439,6 @@ var _ = Describe("Stored Session Suite", func() {
AccessToken: "NoSave",
},
expectedErr: errors.New("error saving session: unable to save session"),
expectRefreshed: false,
expectSaved: true,
}),
)
@@ -454,7 +449,7 @@ var _ = Describe("Stored Session Suite", func() {
BeforeEach(func() {
s = &storedSessionLoader{
validateSessionState: func(_ context.Context, ss *sessionsapi.SessionState) bool {
sessionValidator: func(_ context.Context, ss *sessionsapi.SessionState) bool {
return ss.AccessToken == "Valid"
},
}