@@ -10,6 +10,8 @@ import (
1010
1111 middlewareapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware"
1212 sessionsapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
13+ "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/clock"
14+ "github.com/oauth2-proxy/oauth2-proxy/v7/providers"
1315 . "github.com/onsi/ginkgo"
1416 . "github.com/onsi/ginkgo/extensions/table"
1517 . "github.com/onsi/gomega"
@@ -17,15 +19,17 @@ import (
1719
1820var _ = Describe("Stored Session Suite", func() {
1921 const (
20− refresh = "Refresh"
21− noRefresh = "NoRefresh"
22+ refresh = "Refresh"
23+ noRefresh = "NoRefresh"
24+ notImplemented = "NotImplemented"
2225 )
2326
2427 var ctx = context.Background()
2528
2629 Context("StoredSessionLoader", func() {
27− createdPast := time.Now().Add(-5 * time.Minute)
28− createdFuture := time.Now().Add(5 * time.Minute)
30+ now := time.Now()
31+ createdPast := now.Add(-5 * time.Minute)
32+ createdFuture := now.Add(5 * time.Minute)
2933
3034 var defaultRefreshFunc = func(_ context.Context, ss *sessionsapi.SessionState) (bool, error) {
3135 switch ss.RefreshToken {
@@ -85,6 +89,14 @@ var _ = Describe("Stored Session Suite", func() {
8589 },
8690 }
8791
92+ BeforeEach(func() {
93+ clock.Set(now)
94+ })
95+
96+ AfterEach(func() {
97+ clock.Reset()
98+ })
99+
88100 type storedSessionLoaderTableInput struct {
89101 requestHeaders http.Header
90102 existingSession *sessionsapi.SessionState
@@ -109,10 +121,10 @@ var _ = Describe("Stored Session Suite", func() {
109121 rw := httptest.NewRecorder()
110122
111123 opts := &StoredSessionLoaderOptions{
112− SessionStore: in.store,
113− RefreshPeriod: in.refreshPeriod,
114− RefreshSessionIfNeeded: in.refreshSession,
115− ValidateSessionState: in.validateSession,
124+ SessionStore: in.store,
125+ RefreshPeriod: in.refreshPeriod,
126+ RefreshSession: in.refreshSession,
127+ ValidateSession: in.validateSession,
116128 }
117129
118130 // Create the handler with a next handler that will capture the session
@@ -208,6 +220,21 @@ var _ = Describe("Stored Session Suite", func() {
208220 existingSession: nil,
209221 expectedSession: &sessionsapi.SessionState{
210222 RefreshToken: "Refreshed",
223+ CreatedAt: &now,
224+ ExpiresOn: &createdFuture,
225+ },
226+ store: defaultSessionStore,
227+ refreshPeriod: 1 * time.Minute,
228+ refreshSession: defaultRefreshFunc,
229+ validateSession: defaultValidateFunc,
230+ }),
231+ Entry("when the provider refresh fails but validation succeeds", storedSessionLoaderTableInput{
232+ requestHeaders: http.Header{
233+ "Cookie": []string{"_oauth2_proxy=RefreshError"},
234+ },
235+ existingSession: nil,
236+ expectedSession: &sessionsapi.SessionState{
237+ RefreshToken: "RefreshError",
211238 CreatedAt: &createdPast,
212239 ExpiresOn: &createdFuture,
213240 },
@@ -216,7 +243,7 @@ var _ = Describe("Stored Session Suite", func() {
216243 refreshSession: defaultRefreshFunc,
217244 validateSession: defaultValidateFunc,
218245 }),
219− Entry("when the provider refresh fails", storedSessionLoaderTableInput{
246+ Entry("when the provider refresh fails and validation fails", storedSessionLoaderTableInput{
220247 requestHeaders: http.Header{
221248 "Cookie": []string{"_oauth2_proxy=RefreshError"},
222249 },
@@ -225,7 +252,7 @@ var _ = Describe("Stored Session Suite", func() {
225252 store: defaultSessionStore,
226253 refreshPeriod: 1 * time.Minute,
227254 refreshSession: defaultRefreshFunc,
228− validateSession: defaultValidateFunc,
255+ validateSession: func(context.Context, *sessionsapi.SessionState) bool { return false },
229256 }),
230257 Entry("when the session is not refreshed and is no longer valid", storedSessionLoaderTableInput{
231258 requestHeaders: http.Header{
@@ -261,18 +288,20 @@ var _ = Describe("Stored Session Suite", func() {
261288 s := &storedSessionLoader{
262289 refreshPeriod: in.refreshPeriod,
263290 store: &fakeSessionStore{},
264− refreshSessionWithProviderIfNeeded: func(_ context.Context, ss *sessionsapi.SessionState) (bool, error) {
291+ sessionRefresher: func(_ context.Context, ss *sessionsapi.SessionState) (bool, error) {
265292 refreshed = true
266293 switch ss.RefreshToken {
267294 case refresh:
268295 return true, nil
269296 case noRefresh:
270297 return false, nil
298+ case notImplemented:
299+ return false, providers.ErrNotImplemented
271300 default:
272301 return false, errors.New("error refreshing session")
273302 }
274303 },
275− validateSessionState: func(_ context.Context, ss *sessionsapi.SessionState) bool {
304+ sessionValidator: func(_ context.Context, ss *sessionsapi.SessionState) bool {
276305 validated = true
277306 return ss.AccessToken != "Invalid"
278307 },
@@ -326,7 +355,7 @@ var _ = Describe("Stored Session Suite", func() {
326355 },
327356 expectedErr: nil,
328357 expectRefreshed: true,
329− expectValidated: false,
358+ expectValidated: true,
330359 }),
331360 Entry("when the session is not refreshed by the provider", refreshSessionIfNeededTableInput{
332361 refreshPeriod: 1 * time.Minute,
@@ -339,15 +368,25 @@ var _ = Describe("Stored Session Suite", func() {
339368 expectRefreshed: true,
340369 expectValidated: true,
341370 }),
342− Entry("when the provider refresh fails", refreshSessionIfNeededTableInput{
371+ Entry("when the provider doesn't implement refresh but validation succeeds", refreshSessionIfNeededTableInput{
372+ refreshPeriod: 1 * time.Minute,
373+ session: &sessionsapi.SessionState{
374+ RefreshToken: notImplemented,
375+ CreatedAt: &createdPast,
376+ },
377+ expectedErr: nil,
378+ expectRefreshed: true,
379+ expectValidated: true,
380+ }),
381+ Entry("when the provider refresh fails but validation succeeds", refreshSessionIfNeededTableInput{
343382 refreshPeriod: 1 * time.Minute,
344383 session: &sessionsapi.SessionState{
345384 RefreshToken: "RefreshError",
346385 CreatedAt: &createdPast,
347386 },
348− expectedErr: errors.New("error refreshing access token: error refreshing session"),
387+ expectedErr: nil,
349388 expectRefreshed: true,
350− expectValidated: false,
389+ expectValidated: true,
351390 }),
352391 Entry("when the session is not refreshed by the provider and validation fails", refreshSessionIfNeededTableInput{
353392 refreshPeriod: 1 * time.Minute,
@@ -364,12 +403,11 @@ var _ = Describe("Stored Session Suite", func() {
364403 )
365404 })
366405
367− Context("refreshSessionWithProvider", func() {
406+ Context("refreshSession", func() {
368407 type refreshSessionWithProviderTableInput struct {
369− session *sessionsapi.SessionState
370− expectedErr error
371− expectRefreshed bool
372− expectSaved bool
408+ session *sessionsapi.SessionState
409+ expectedErr error
410+ expectSaved bool
373411 }
374412
375413 now := time.Now()
@@ -388,12 +426,14 @@ var _ = Describe("Stored Session Suite", func() {
388426 return nil
389427 },
390428 },
391− refreshSessionWithProviderIfNeeded: func(_ context.Context, ss *sessionsapi.SessionState) (bool, error) {
429+ sessionRefresher: func(_ context.Context, ss *sessionsapi.SessionState) (bool, error) {
392430 switch ss.RefreshToken {
393431 case refresh:
394432 return true, nil
395433 case noRefresh:
396434 return false, nil
435+ case notImplemented:
436+ return false, providers.ErrNotImplemented
397437 default:
398438 return false, errors.New("error refreshing session")
399439 }
@@ -402,30 +442,34 @@ var _ = Describe("Stored Session Suite", func() {
402442
403443 req := httptest.NewRequest("", "/", nil)
404444 req = middlewareapi.AddRequestScope(req, &middlewareapi.RequestScope{})
405− refreshed, err := s.refreshSessionWithProvider(nil, req, in.session)
445+ err := s.refreshSession(nil, req, in.session)
406446 if in.expectedErr != nil {
407447 Expect(err).To(MatchError(in.expectedErr))
408448 } else {
409449 Expect(err).ToNot(HaveOccurred())
410450 }
411− Expect(refreshed).To(Equal(in.expectRefreshed))
412451 Expect(saved).To(Equal(in.expectSaved))
413452 },
414453 Entry("when the provider does not refresh the session", refreshSessionWithProviderTableInput{
415454 session: &sessionsapi.SessionState{
416455 RefreshToken: noRefresh,
417456 },
418− expectedErr: nil,
419− expectRefreshed: false,
420− expectSaved: false,
457+ expectedErr: nil,
458+ expectSaved: false,
421459 }),
422460 Entry("when the provider refreshes the session", refreshSessionWithProviderTableInput{
423461 session: &sessionsapi.SessionState{
424462 RefreshToken: refresh,
425463 },
426− expectedErr: nil,
427− expectRefreshed: true,
428− expectSaved: true,
464+ expectedErr: nil,
465+ expectSaved: true,
466+ }),
467+ Entry("when the provider doesn't implement refresh", refreshSessionWithProviderTableInput{
468+ session: &sessionsapi.SessionState{
469+ RefreshToken: notImplemented,
470+ },
471+ expectedErr: nil,
472+ expectSaved: true,
429473 }),
430474 Entry("when the provider returns an error", refreshSessionWithProviderTableInput{
431475 session: &sessionsapi.SessionState{
@@ -433,18 +477,16 @@ var _ = Describe("Stored Session Suite", func() {
433477 CreatedAt: &now,
434478 ExpiresOn: &now,
435479 },
436− expectedErr: errors.New("error refreshing access token: error refreshing session"),
437− expectRefreshed: false,
438− expectSaved: false,
480+ expectedErr: errors.New("error refreshing tokens: error refreshing session"),
481+ expectSaved: false,
439482 }),
440483 Entry("when the saving the session returns an error", refreshSessionWithProviderTableInput{
441484 session: &sessionsapi.SessionState{
442485 RefreshToken: refresh,
443486 AccessToken: "NoSave",
444487 },
445− expectedErr: errors.New("error saving session: unable to save session"),
446− expectRefreshed: false,
447− expectSaved: true,
488+ expectedErr: errors.New("error saving session: unable to save session"),
489+ expectSaved: true,
448490 }),
449491 )
450492 })
@@ -454,7 +496,7 @@ var _ = Describe("Stored Session Suite", func() {
454496
455497 BeforeEach(func() {
456498 s = &storedSessionLoader{
457− validateSessionState: func(_ context.Context, ss *sessionsapi.SessionState) bool {
499+ sessionValidator: func(_ context.Context, ss *sessionsapi.SessionState) bool {
458500 return ss.AccessToken == "Valid"
459501 },
460502 }