1
21
22 package oauth2
23
24 import (
25 "context"
26 "fmt"
27 "net/url"
28 "testing"
29 "time"
30
31 "github.com/golang/mock/gomock"
32
33 "github.com/ory/fosite/internal"
34
35 "github.com/pkg/errors"
36 "github.com/stretchr/testify/assert"
37 "github.com/stretchr/testify/require"
38
39 "github.com/ory/fosite"
40 "github.com/ory/fosite/storage"
41 )
42
43 func TestRefreshFlow_HandleTokenEndpointRequest(t *testing.T) {
44 var areq *fosite.AccessRequest
45 sess := &fosite.DefaultSession{Subject: "othersub"}
46 expiredSess := &fosite.DefaultSession{
47 ExpiresAt: map[fosite.TokenType]time.Time{
48 fosite.RefreshToken: time.Now().UTC().Add(-time.Hour),
49 },
50 }
51
52 for k, strategy := range map[string]RefreshTokenStrategy{
53 "hmac": &hmacshaStrategy,
54 } {
55 t.Run("strategy="+k, func(t *testing.T) {
56
57 store := storage.NewMemoryStore()
58 var h RefreshTokenGrantHandler
59
60 for _, c := range []struct {
61 description string
62 setup func()
63 expectErr error
64 expect func(t *testing.T)
65 }{
66 {
67 description: "should fail because not responsible",
68 expectErr: fosite.ErrUnknownRequest,
69 setup: func() {
70 areq.GrantTypes = fosite.Arguments{"123"}
71 },
72 },
73 {
74 description: "should fail because token invalid",
75 setup: func() {
76 areq.GrantTypes = fosite.Arguments{"refresh_token"}
77 areq.Client = &fosite.DefaultClient{GrantTypes: fosite.Arguments{"refresh_token"}}
78
79 areq.Form.Add("refresh_token", "some.refreshtokensig")
80 },
81 expectErr: fosite.ErrInvalidGrant,
82 },
83 {
84 description: "should fail because token is valid but does not exist",
85 setup: func() {
86 areq.GrantTypes = fosite.Arguments{"refresh_token"}
87 areq.Client = &fosite.DefaultClient{GrantTypes: fosite.Arguments{"refresh_token"}}
88
89 token, _, err := strategy.GenerateRefreshToken(nil, nil)
90 require.NoError(t, err)
91 areq.Form.Add("refresh_token", token)
92 },
93 expectErr: fosite.ErrInvalidGrant,
94 },
95 {
96 description: "should fail because client mismatches",
97 setup: func() {
98 areq.GrantTypes = fosite.Arguments{"refresh_token"}
99 areq.Client = &fosite.DefaultClient{
100 ID: "foo",
101 GrantTypes: fosite.Arguments{"refresh_token"},
102 }
103
104 token, sig, err := strategy.GenerateRefreshToken(nil, nil)
105 require.NoError(t, err)
106
107 areq.Form.Add("refresh_token", token)
108 err = store.CreateRefreshTokenSession(nil, sig, &fosite.Request{
109 Client: &fosite.DefaultClient{ID: ""},
110 GrantedScope: []string{"offline"},
111 Session: sess,
112 })
113 require.NoError(t, err)
114 },
115 expectErr: fosite.ErrInvalidGrant,
116 },
117 {
118 description: "should fail because token is expired",
119 setup: func() {
120 areq.GrantTypes = fosite.Arguments{"refresh_token"}
121 areq.Client = &fosite.DefaultClient{
122 ID: "foo",
123 GrantTypes: fosite.Arguments{"refresh_token"},
124 Scopes: []string{"foo", "bar", "offline"},
125 }
126
127 token, sig, err := strategy.GenerateRefreshToken(nil, nil)
128 require.NoError(t, err)
129
130 areq.Form.Add("refresh_token", token)
131 err = store.CreateRefreshTokenSession(nil, sig, &fosite.Request{
132 Client: areq.Client,
133 GrantedScope: fosite.Arguments{"foo", "offline"},
134 RequestedScope: fosite.Arguments{"foo", "bar", "offline"},
135 Session: expiredSess,
136 Form: url.Values{"foo": []string{"bar"}},
137 RequestedAt: time.Now().UTC().Add(-time.Hour).Round(time.Hour),
138 })
139 require.NoError(t, err)
140 },
141 expectErr: fosite.ErrInvalidGrant,
142 },
143 {
144 description: "should fail because offline scope has been granted but client no longer allowed to request it",
145 setup: func() {
146 areq.GrantTypes = fosite.Arguments{"refresh_token"}
147 areq.Client = &fosite.DefaultClient{
148 ID: "foo",
149 GrantTypes: fosite.Arguments{"refresh_token"},
150 }
151
152 token, sig, err := strategy.GenerateRefreshToken(nil, nil)
153 require.NoError(t, err)
154
155 areq.Form.Add("refresh_token", token)
156 err = store.CreateRefreshTokenSession(nil, sig, &fosite.Request{
157 Client: areq.Client,
158 GrantedScope: fosite.Arguments{"foo", "offline"},
159 RequestedScope: fosite.Arguments{"foo", "offline"},
160 Session: sess,
161 Form: url.Values{"foo": []string{"bar"}},
162 RequestedAt: time.Now().UTC().Add(-time.Hour).Round(time.Hour),
163 })
164 require.NoError(t, err)
165 },
166 expectErr: fosite.ErrInvalidScope,
167 },
168 {
169 description: "should pass",
170 setup: func() {
171 areq.GrantTypes = fosite.Arguments{"refresh_token"}
172 areq.Client = &fosite.DefaultClient{
173 ID: "foo",
174 GrantTypes: fosite.Arguments{"refresh_token"},
175 Scopes: []string{"foo", "bar", "offline"},
176 }
177
178 token, sig, err := strategy.GenerateRefreshToken(nil, nil)
179 require.NoError(t, err)
180
181 areq.Form.Add("refresh_token", token)
182 err = store.CreateRefreshTokenSession(nil, sig, &fosite.Request{
183 Client: areq.Client,
184 GrantedScope: fosite.Arguments{"foo", "offline"},
185 RequestedScope: fosite.Arguments{"foo", "bar", "offline"},
186 Session: sess,
187 Form: url.Values{"foo": []string{"bar"}},
188 RequestedAt: time.Now().UTC().Add(-time.Hour).Round(time.Hour),
189 })
190 require.NoError(t, err)
191 },
192 expect: func(t *testing.T) {
193 assert.NotEqual(t, sess, areq.Session)
194 assert.NotEqual(t, time.Now().UTC().Add(-time.Hour).Round(time.Hour), areq.RequestedAt)
195 assert.Equal(t, fosite.Arguments{"foo", "offline"}, areq.GrantedScope)
196 assert.Equal(t, fosite.Arguments{"foo", "bar", "offline"}, areq.RequestedScope)
197 assert.NotEqual(t, url.Values{"foo": []string{"bar"}}, areq.Form)
198 assert.Equal(t, time.Now().Add(time.Hour).UTC().Round(time.Second), areq.GetSession().GetExpiresAt(fosite.AccessToken))
199 assert.Equal(t, time.Now().Add(time.Hour).UTC().Round(time.Second), areq.GetSession().GetExpiresAt(fosite.RefreshToken))
200 },
201 },
202 {
203 description: "should fail without offline scope",
204 setup: func() {
205 areq.GrantTypes = fosite.Arguments{"refresh_token"}
206 areq.Client = &fosite.DefaultClient{
207 ID: "foo",
208 GrantTypes: fosite.Arguments{"refresh_token"},
209 Scopes: []string{"foo", "bar"},
210 }
211
212 token, sig, err := strategy.GenerateRefreshToken(nil, nil)
213 require.NoError(t, err)
214
215 areq.Form.Add("refresh_token", token)
216 err = store.CreateRefreshTokenSession(nil, sig, &fosite.Request{
217 Client: areq.Client,
218 GrantedScope: fosite.Arguments{"foo"},
219 RequestedScope: fosite.Arguments{"foo", "bar"},
220 Session: sess,
221 Form: url.Values{"foo": []string{"bar"}},
222 RequestedAt: time.Now().UTC().Add(-time.Hour).Round(time.Hour),
223 })
224 require.NoError(t, err)
225 },
226 expectErr: fosite.ErrScopeNotGranted,
227 },
228 {
229 description: "should pass without offline scope when configured to allow refresh tokens",
230 setup: func() {
231 h.RefreshTokenScopes = []string{}
232 areq.GrantTypes = fosite.Arguments{"refresh_token"}
233 areq.Client = &fosite.DefaultClient{
234 ID: "foo",
235 GrantTypes: fosite.Arguments{"refresh_token"},
236 Scopes: []string{"foo", "bar"},
237 }
238
239 token, sig, err := strategy.GenerateRefreshToken(nil, nil)
240 require.NoError(t, err)
241
242 areq.Form.Add("refresh_token", token)
243 err = store.CreateRefreshTokenSession(nil, sig, &fosite.Request{
244 Client: areq.Client,
245 GrantedScope: fosite.Arguments{"foo"},
246 RequestedScope: fosite.Arguments{"foo", "bar"},
247 Session: sess,
248 Form: url.Values{"foo": []string{"bar"}},
249 RequestedAt: time.Now().UTC().Add(-time.Hour).Round(time.Hour),
250 })
251 require.NoError(t, err)
252 },
253 expect: func(t *testing.T) {
254 assert.NotEqual(t, sess, areq.Session)
255 assert.NotEqual(t, time.Now().UTC().Add(-time.Hour).Round(time.Hour), areq.RequestedAt)
256 assert.Equal(t, fosite.Arguments{"foo"}, areq.GrantedScope)
257 assert.Equal(t, fosite.Arguments{"foo", "bar"}, areq.RequestedScope)
258 assert.NotEqual(t, url.Values{"foo": []string{"bar"}}, areq.Form)
259 assert.Equal(t, time.Now().Add(time.Hour).UTC().Round(time.Second), areq.GetSession().GetExpiresAt(fosite.AccessToken))
260 assert.Equal(t, time.Now().Add(time.Hour).UTC().Round(time.Second), areq.GetSession().GetExpiresAt(fosite.RefreshToken))
261 },
262 },
263 {
264 description: "should deny access on token reuse",
265 setup: func() {
266 areq.GrantTypes = fosite.Arguments{"refresh_token"}
267 areq.Client = &fosite.DefaultClient{
268 ID: "foo",
269 GrantTypes: fosite.Arguments{"refresh_token"},
270 Scopes: []string{"foo", "bar", "offline"},
271 }
272
273 token, sig, err := strategy.GenerateRefreshToken(nil, nil)
274 require.NoError(t, err)
275
276 areq.Form.Add("refresh_token", token)
277 req := &fosite.Request{
278 Client: areq.Client,
279 GrantedScope: fosite.Arguments{"foo", "offline"},
280 RequestedScope: fosite.Arguments{"foo", "bar", "offline"},
281 Session: sess,
282 Form: url.Values{"foo": []string{"bar"}},
283 RequestedAt: time.Now().UTC().Add(-time.Hour).Round(time.Hour),
284 }
285 err = store.CreateRefreshTokenSession(nil, sig, req)
286 require.NoError(t, err)
287
288 err = store.RevokeRefreshToken(nil, req.ID)
289 require.NoError(t, err)
290 },
291 expectErr: fosite.ErrInactiveToken,
292 },
293 } {
294 t.Run("case="+c.description, func(t *testing.T) {
295 h = RefreshTokenGrantHandler{
296 TokenRevocationStorage: store,
297 RefreshTokenStrategy: strategy,
298 AccessTokenLifespan: time.Hour,
299 RefreshTokenLifespan: time.Hour,
300 ScopeStrategy: fosite.HierarchicScopeStrategy,
301 AudienceMatchingStrategy: fosite.DefaultAudienceMatchingStrategy,
302 RefreshTokenScopes: []string{"offline"},
303 }
304
305 areq = fosite.NewAccessRequest(&fosite.DefaultSession{})
306 areq.Form = url.Values{}
307 c.setup()
308
309 err := h.HandleTokenEndpointRequest(nil, areq)
310 if c.expectErr != nil {
311 require.EqualError(t, err, c.expectErr.Error())
312 } else {
313 require.NoError(t, err)
314 }
315
316 if c.expect != nil {
317 c.expect(t)
318 }
319 })
320 }
321 })
322 }
323 }
324
325 func TestRefreshFlowTransactional_HandleTokenEndpointRequest(t *testing.T) {
326 var mockTransactional *internal.MockTransactional
327 var mockRevocationStore *internal.MockTokenRevocationStorage
328 request := fosite.NewAccessRequest(&fosite.DefaultSession{})
329 propagatedContext := context.Background()
330
331 type transactionalStore struct {
332 storage.Transactional
333 TokenRevocationStorage
334 }
335
336 for _, testCase := range []struct {
337 description string
338 setup func()
339 expectError error
340 }{
341 {
342 description: "should revoke session on token reuse",
343 setup: func() {
344 request.GrantTypes = fosite.Arguments{"refresh_token"}
345 request.Client = &fosite.DefaultClient{
346 ID: "foo",
347 GrantTypes: fosite.Arguments{"refresh_token"},
348 }
349 mockRevocationStore.
350 EXPECT().
351 GetRefreshTokenSession(propagatedContext, gomock.Any(), gomock.Any()).
352 Return(request, fosite.ErrInactiveToken).
353 Times(1)
354 mockTransactional.
355 EXPECT().
356 BeginTX(propagatedContext).
357 Return(propagatedContext, nil).
358 Times(1)
359 mockRevocationStore.
360 EXPECT().
361 DeleteRefreshTokenSession(propagatedContext, gomock.Any()).
362 Return(nil).
363 Times(1)
364 mockRevocationStore.
365 EXPECT().
366 RevokeRefreshToken(propagatedContext, gomock.Any()).
367 Return(nil).
368 Times(1)
369 mockRevocationStore.
370 EXPECT().
371 RevokeAccessToken(propagatedContext, gomock.Any()).
372 Return(nil).
373 Times(1)
374 mockTransactional.
375 EXPECT().
376 Commit(propagatedContext).
377 Return(nil).
378 Times(1)
379 },
380 expectError: fosite.ErrInactiveToken,
381 },
382 } {
383 t.Run(fmt.Sprintf("scenario=%s", testCase.description), func(t *testing.T) {
384 ctrl := gomock.NewController(t)
385 defer ctrl.Finish()
386
387 mockTransactional = internal.NewMockTransactional(ctrl)
388 mockRevocationStore = internal.NewMockTokenRevocationStorage(ctrl)
389 testCase.setup()
390
391 handler := RefreshTokenGrantHandler{
392 TokenRevocationStorage: transactionalStore{
393 mockTransactional,
394 mockRevocationStore,
395 },
396 AccessTokenStrategy: &hmacshaStrategy,
397 RefreshTokenStrategy: &hmacshaStrategy,
398 AccessTokenLifespan: time.Hour,
399 ScopeStrategy: fosite.HierarchicScopeStrategy,
400 AudienceMatchingStrategy: fosite.DefaultAudienceMatchingStrategy,
401 }
402
403 if err := handler.HandleTokenEndpointRequest(propagatedContext, request); testCase.expectError != nil {
404 assert.EqualError(t, err, testCase.expectError.Error())
405 }
406 })
407 }
408 }
409
410 func TestRefreshFlow_PopulateTokenEndpointResponse(t *testing.T) {
411 var areq *fosite.AccessRequest
412 var aresp *fosite.AccessResponse
413
414 for k, strategy := range map[string]CoreStrategy{
415 "hmac": &hmacshaStrategy,
416 } {
417 t.Run("strategy="+k, func(t *testing.T) {
418 store := storage.NewMemoryStore()
419
420 h := RefreshTokenGrantHandler{
421 TokenRevocationStorage: store,
422 RefreshTokenStrategy: strategy,
423 AccessTokenStrategy: strategy,
424 AccessTokenLifespan: time.Hour,
425 ScopeStrategy: fosite.HierarchicScopeStrategy,
426 AudienceMatchingStrategy: fosite.DefaultAudienceMatchingStrategy,
427 }
428 for _, c := range []struct {
429 description string
430 setup func()
431 check func()
432 expectErr error
433 }{
434 {
435 description: "should fail because not responsible",
436 expectErr: fosite.ErrUnknownRequest,
437 setup: func() {
438 areq.GrantTypes = fosite.Arguments{"313"}
439 },
440 },
441 {
442 description: "should pass",
443 setup: func() {
444 areq.ID = "req-id"
445 areq.GrantTypes = fosite.Arguments{"refresh_token"}
446 areq.RequestedScope = fosite.Arguments{"foo", "bar"}
447 areq.GrantedScope = fosite.Arguments{"foo", "bar"}
448
449 token, signature, err := strategy.GenerateRefreshToken(nil, nil)
450 require.NoError(t, err)
451 require.NoError(t, store.CreateRefreshTokenSession(nil, signature, areq))
452 areq.Form.Add("refresh_token", token)
453 },
454 check: func() {
455 signature := strategy.RefreshTokenSignature(areq.Form.Get("refresh_token"))
456
457
458 _, err := store.GetRefreshTokenSession(nil, signature, nil)
459 require.Error(t, err)
460
461 assert.Equal(t, "req-id", areq.ID)
462 require.NoError(t, strategy.ValidateAccessToken(nil, areq, aresp.GetAccessToken()))
463 require.NoError(t, strategy.ValidateRefreshToken(nil, areq, aresp.ToMap()["refresh_token"].(string)))
464 assert.Equal(t, "bearer", aresp.GetTokenType())
465 assert.NotEmpty(t, aresp.ToMap()["expires_in"])
466 assert.Equal(t, "foo bar", aresp.ToMap()["scope"])
467 },
468 },
469 } {
470 t.Run("case="+c.description, func(t *testing.T) {
471 areq = fosite.NewAccessRequest(&fosite.DefaultSession{})
472 aresp = fosite.NewAccessResponse()
473 areq.Client = &fosite.DefaultClient{}
474 areq.Form = url.Values{}
475
476 c.setup()
477
478 err := h.PopulateTokenEndpointResponse(nil, areq, aresp)
479 if c.expectErr != nil {
480 assert.EqualError(t, err, c.expectErr.Error())
481 } else {
482 assert.NoError(t, err)
483 }
484
485 if c.check != nil {
486 c.check()
487 }
488 })
489 }
490 })
491 }
492 }
493
494 func TestRefreshFlowTransactional_PopulateTokenEndpointResponse(t *testing.T) {
495 var mockTransactional *internal.MockTransactional
496 var mockRevocationStore *internal.MockTokenRevocationStorage
497 request := fosite.NewAccessRequest(&fosite.DefaultSession{})
498 response := fosite.NewAccessResponse()
499 propagatedContext := context.Background()
500
501
502 type transactionalStore struct {
503 storage.Transactional
504 TokenRevocationStorage
505 }
506
507 for _, testCase := range []struct {
508 description string
509 setup func()
510 expectError error
511 }{
512 {
513 description: "transaction should be committed successfully if no errors occur",
514 setup: func() {
515 request.GrantTypes = fosite.Arguments{"refresh_token"}
516 mockTransactional.
517 EXPECT().
518 BeginTX(propagatedContext).
519 Return(propagatedContext, nil).
520 Times(1)
521 mockRevocationStore.
522 EXPECT().
523 GetRefreshTokenSession(propagatedContext, gomock.Any(), nil).
524 Return(request, nil).
525 Times(1)
526 mockRevocationStore.
527 EXPECT().
528 RevokeAccessToken(propagatedContext, gomock.Any()).
529 Return(nil).
530 Times(1)
531 mockRevocationStore.
532 EXPECT().
533 RevokeRefreshTokenMaybeGracePeriod(propagatedContext, gomock.Any(), gomock.Any()).
534 Return(nil).
535 Times(1)
536 mockRevocationStore.
537 EXPECT().
538 CreateAccessTokenSession(propagatedContext, gomock.Any(), gomock.Any()).
539 Return(nil).
540 Times(1)
541 mockRevocationStore.
542 EXPECT().
543 CreateRefreshTokenSession(propagatedContext, gomock.Any(), gomock.Any()).
544 Return(nil).
545 Times(1)
546 mockTransactional.
547 EXPECT().
548 Commit(propagatedContext).
549 Return(nil).
550 Times(1)
551 },
552 },
553 {
554 description: "transaction should be rolled back if call to `GetRefreshTokenSession` results in an error",
555 setup: func() {
556 request.GrantTypes = fosite.Arguments{"refresh_token"}
557 mockTransactional.
558 EXPECT().
559 BeginTX(propagatedContext).
560 Return(propagatedContext, nil).
561 Times(1)
562 mockRevocationStore.
563 EXPECT().
564 GetRefreshTokenSession(propagatedContext, gomock.Any(), nil).
565 Return(nil, errors.New("Whoops, a nasty database error occurred!")).
566 Times(1)
567 mockTransactional.
568 EXPECT().
569 Rollback(propagatedContext).
570 Return(nil).
571 Times(1)
572 },
573 expectError: fosite.ErrServerError,
574 },
575 {
576 description: "should result in a fosite.ErrInvalidRequest if `GetRefreshTokenSession` results in a " +
577 "fosite.ErrNotFound error",
578 setup: func() {
579 request.GrantTypes = fosite.Arguments{"refresh_token"}
580 mockTransactional.
581 EXPECT().
582 BeginTX(propagatedContext).
583 Return(propagatedContext, nil).
584 Times(1)
585 mockRevocationStore.
586 EXPECT().
587 GetRefreshTokenSession(propagatedContext, gomock.Any(), nil).
588 Return(nil, fosite.ErrNotFound).
589 Times(1)
590 mockTransactional.
591 EXPECT().
592 Rollback(propagatedContext).
593 Return(nil).
594 Times(1)
595 },
596 expectError: fosite.ErrInvalidRequest,
597 },
598 {
599 description: "transaction should be rolled back if call to `RevokeAccessToken` results in an error",
600 setup: func() {
601 request.GrantTypes = fosite.Arguments{"refresh_token"}
602 mockTransactional.
603 EXPECT().
604 BeginTX(propagatedContext).
605 Return(propagatedContext, nil).
606 Times(1)
607 mockRevocationStore.
608 EXPECT().
609 GetRefreshTokenSession(propagatedContext, gomock.Any(), nil).
610 Return(request, nil).
611 Times(1)
612 mockRevocationStore.
613 EXPECT().
614 RevokeAccessToken(propagatedContext, gomock.Any()).
615 Return(errors.New("Whoops, a nasty database error occurred!")).
616 Times(1)
617 mockTransactional.
618 EXPECT().
619 Rollback(propagatedContext).
620 Return(nil).
621 Times(1)
622 },
623 expectError: fosite.ErrServerError,
624 },
625 {
626 description: "should result in a fosite.ErrInvalidRequest if call to `RevokeAccessToken` results in a " +
627 "fosite.ErrSerializationFailure error",
628 setup: func() {
629 request.GrantTypes = fosite.Arguments{"refresh_token"}
630 mockTransactional.
631 EXPECT().
632 BeginTX(propagatedContext).
633 Return(propagatedContext, nil).
634 Times(1)
635 mockRevocationStore.
636 EXPECT().
637 GetRefreshTokenSession(propagatedContext, gomock.Any(), nil).
638 Return(request, nil).
639 Times(1)
640 mockRevocationStore.
641 EXPECT().
642 RevokeAccessToken(propagatedContext, gomock.Any()).
643 Return(fosite.ErrSerializationFailure).
644 Times(1)
645 mockTransactional.
646 EXPECT().
647 Rollback(propagatedContext).
648 Return(nil).
649 Times(1)
650 },
651 expectError: fosite.ErrInvalidRequest,
652 },
653 {
654 description: "should result in a fosite.ErrInactiveToken if call to `RevokeAccessToken` results in a " +
655 "fosite.ErrInvalidRequest error",
656 setup: func() {
657 request.GrantTypes = fosite.Arguments{"refresh_token"}
658 mockTransactional.
659 EXPECT().
660 BeginTX(propagatedContext).
661 Return(propagatedContext, nil).
662 Times(1)
663 mockRevocationStore.
664 EXPECT().
665 GetRefreshTokenSession(propagatedContext, gomock.Any(), nil).
666 Return(nil, fosite.ErrInactiveToken).
667 Times(1)
668 mockTransactional.
669 EXPECT().
670 Rollback(propagatedContext).
671 Return(nil).
672 Times(1)
673 },
674 expectError: fosite.ErrInvalidRequest,
675 },
676 {
677 description: "transaction should be rolled back if call to `RevokeRefreshTokenMaybeGracePeriod` results in an error",
678 setup: func() {
679 request.GrantTypes = fosite.Arguments{"refresh_token"}
680 mockTransactional.
681 EXPECT().
682 BeginTX(propagatedContext).
683 Return(propagatedContext, nil).
684 Times(1)
685 mockRevocationStore.
686 EXPECT().
687 GetRefreshTokenSession(propagatedContext, gomock.Any(), nil).
688 Return(request, nil).
689 Times(1)
690 mockRevocationStore.
691 EXPECT().
692 RevokeAccessToken(propagatedContext, gomock.Any()).
693 Return(nil).
694 Times(1)
695 mockRevocationStore.
696 EXPECT().
697 RevokeRefreshTokenMaybeGracePeriod(propagatedContext, gomock.Any(), gomock.Any()).
698 Return(errors.New("Whoops, a nasty database error occurred!")).
699 Times(1)
700 mockTransactional.
701 EXPECT().
702 Rollback(propagatedContext).
703 Return(nil).
704 Times(1)
705 },
706 expectError: fosite.ErrServerError,
707 },
708 {
709 description: "should result in a fosite.ErrInvalidRequest if call to `RevokeRefreshTokenMaybeGracePeriod` results in a " +
710 "fosite.ErrSerializationFailure error",
711 setup: func() {
712 request.GrantTypes = fosite.Arguments{"refresh_token"}
713 mockTransactional.
714 EXPECT().
715 BeginTX(propagatedContext).
716 Return(propagatedContext, nil).
717 Times(1)
718 mockRevocationStore.
719 EXPECT().
720 GetRefreshTokenSession(propagatedContext, gomock.Any(), nil).
721 Return(request, nil).
722 Times(1)
723 mockRevocationStore.
724 EXPECT().
725 RevokeAccessToken(propagatedContext, gomock.Any()).
726 Return(nil).
727 Times(1)
728 mockRevocationStore.
729 EXPECT().
730 RevokeRefreshTokenMaybeGracePeriod(propagatedContext, gomock.Any(), gomock.Any()).
731 Return(fosite.ErrSerializationFailure).
732 Times(1)
733 mockTransactional.
734 EXPECT().
735 Rollback(propagatedContext).
736 Return(nil).
737 Times(1)
738 },
739 expectError: fosite.ErrInvalidRequest,
740 },
741 {
742 description: "should result in a fosite.ErrInvalidRequest if call to `CreateAccessTokenSession` results in " +
743 "a fosite.ErrSerializationFailure error",
744 setup: func() {
745 mockTransactional.
746 EXPECT().
747 BeginTX(propagatedContext).
748 Return(propagatedContext, nil).
749 Times(1)
750 mockRevocationStore.
751 EXPECT().
752 GetRefreshTokenSession(propagatedContext, gomock.Any(), nil).
753 Return(request, nil).
754 Times(1)
755 mockRevocationStore.
756 EXPECT().
757 RevokeAccessToken(propagatedContext, gomock.Any()).
758 Return(nil).
759 Times(1)
760 mockRevocationStore.
761 EXPECT().
762 RevokeRefreshTokenMaybeGracePeriod(propagatedContext, gomock.Any(), gomock.Any()).
763 Return(nil).
764 Times(1)
765 mockRevocationStore.
766 EXPECT().
767 CreateAccessTokenSession(propagatedContext, gomock.Any(), gomock.Any()).
768 Return(fosite.ErrSerializationFailure).
769 Times(1)
770 mockTransactional.
771 EXPECT().
772 Rollback(propagatedContext).
773 Return(nil).
774 Times(1)
775 },
776 expectError: fosite.ErrInvalidRequest,
777 },
778 {
779 description: "transaction should be rolled back if call to `CreateAccessTokenSession` results in an error",
780 setup: func() {
781 mockTransactional.
782 EXPECT().
783 BeginTX(propagatedContext).
784 Return(propagatedContext, nil).
785 Times(1)
786 mockRevocationStore.
787 EXPECT().
788 GetRefreshTokenSession(propagatedContext, gomock.Any(), nil).
789 Return(request, nil).
790 Times(1)
791 mockRevocationStore.
792 EXPECT().
793 RevokeAccessToken(propagatedContext, gomock.Any()).
794 Return(nil).
795 Times(1)
796 mockRevocationStore.
797 EXPECT().
798 RevokeRefreshTokenMaybeGracePeriod(propagatedContext, gomock.Any(), gomock.Any()).
799 Return(nil).
800 Times(1)
801 mockRevocationStore.
802 EXPECT().
803 CreateAccessTokenSession(propagatedContext, gomock.Any(), gomock.Any()).
804 Return(errors.New("Whoops, a nasty database error occurred!")).
805 Times(1)
806 mockTransactional.
807 EXPECT().
808 Rollback(propagatedContext).
809 Return(nil).
810 Times(1)
811 },
812 expectError: fosite.ErrServerError,
813 },
814 {
815 description: "transaction should be rolled back if call to `CreateRefreshTokenSession` results in an error",
816 setup: func() {
817 request.GrantTypes = fosite.Arguments{"refresh_token"}
818 mockTransactional.
819 EXPECT().
820 BeginTX(propagatedContext).
821 Return(propagatedContext, nil).
822 Times(1)
823 mockRevocationStore.
824 EXPECT().
825 GetRefreshTokenSession(propagatedContext, gomock.Any(), nil).
826 Return(request, nil).
827 Times(1)
828 mockRevocationStore.
829 EXPECT().
830 RevokeAccessToken(propagatedContext, gomock.Any()).
831 Return(nil).
832 Times(1)
833 mockRevocationStore.
834 EXPECT().
835 RevokeRefreshTokenMaybeGracePeriod(propagatedContext, gomock.Any(), gomock.Any()).
836 Return(nil).
837 Times(1)
838 mockRevocationStore.
839 EXPECT().
840 CreateAccessTokenSession(propagatedContext, gomock.Any(), gomock.Any()).
841 Return(nil).
842 Times(1)
843 mockRevocationStore.
844 EXPECT().
845 CreateRefreshTokenSession(propagatedContext, gomock.Any(), gomock.Any()).
846 Return(errors.New("Whoops, a nasty database error occurred!")).
847 Times(1)
848 mockTransactional.
849 EXPECT().
850 Rollback(propagatedContext).
851 Return(nil).
852 Times(1)
853 },
854 expectError: fosite.ErrServerError,
855 },
856 {
857 description: "should result in a fosite.ErrInvalidRequest if call to `CreateRefreshTokenSession` results in " +
858 "a fosite.ErrSerializationFailure error",
859 setup: func() {
860 request.GrantTypes = fosite.Arguments{"refresh_token"}
861 mockTransactional.
862 EXPECT().
863 BeginTX(propagatedContext).
864 Return(propagatedContext, nil).
865 Times(1)
866 mockRevocationStore.
867 EXPECT().
868 GetRefreshTokenSession(propagatedContext, gomock.Any(), nil).
869 Return(request, nil).
870 Times(1)
871 mockRevocationStore.
872 EXPECT().
873 RevokeAccessToken(propagatedContext, gomock.Any()).
874 Return(nil).
875 Times(1)
876 mockRevocationStore.
877 EXPECT().
878 RevokeRefreshTokenMaybeGracePeriod(propagatedContext, gomock.Any(), gomock.Any()).
879 Return(nil).
880 Times(1)
881 mockRevocationStore.
882 EXPECT().
883 CreateAccessTokenSession(propagatedContext, gomock.Any(), gomock.Any()).
884 Return(nil).
885 Times(1)
886 mockRevocationStore.
887 EXPECT().
888 CreateRefreshTokenSession(propagatedContext, gomock.Any(), gomock.Any()).
889 Return(fosite.ErrSerializationFailure).
890 Times(1)
891 mockTransactional.
892 EXPECT().
893 Rollback(propagatedContext).
894 Return(nil).
895 Times(1)
896 },
897 expectError: fosite.ErrInvalidRequest,
898 },
899 {
900 description: "should result in a server error if transaction cannot be created",
901 setup: func() {
902 request.GrantTypes = fosite.Arguments{"refresh_token"}
903 mockTransactional.
904 EXPECT().
905 BeginTX(propagatedContext).
906 Return(nil, errors.New("Could not create transaction!")).
907 Times(1)
908 },
909 expectError: fosite.ErrServerError,
910 },
911 {
912 description: "should result in a server error if transaction cannot be rolled back",
913 setup: func() {
914 request.GrantTypes = fosite.Arguments{"refresh_token"}
915 mockTransactional.
916 EXPECT().
917 BeginTX(propagatedContext).
918 Return(propagatedContext, nil).
919 Times(1)
920 mockRevocationStore.
921 EXPECT().
922 GetRefreshTokenSession(propagatedContext, gomock.Any(), nil).
923 Return(nil, fosite.ErrNotFound).
924 Times(1)
925 mockTransactional.
926 EXPECT().
927 Rollback(propagatedContext).
928 Return(errors.New("Could not rollback transaction!")).
929 Times(1)
930 },
931 expectError: fosite.ErrServerError,
932 },
933 {
934 description: "should result in a server error if transaction cannot be committed",
935 setup: func() {
936 request.GrantTypes = fosite.Arguments{"refresh_token"}
937 mockTransactional.
938 EXPECT().
939 BeginTX(propagatedContext).
940 Return(propagatedContext, nil).
941 Times(1)
942 mockRevocationStore.
943 EXPECT().
944 GetRefreshTokenSession(propagatedContext, gomock.Any(), nil).
945 Return(request, nil).
946 Times(1)
947 mockRevocationStore.
948 EXPECT().
949 RevokeAccessToken(propagatedContext, gomock.Any()).
950 Return(nil).
951 Times(1)
952 mockRevocationStore.
953 EXPECT().
954 RevokeRefreshTokenMaybeGracePeriod(propagatedContext, gomock.Any(), gomock.Any()).
955 Return(nil).
956 Times(1)
957 mockRevocationStore.
958 EXPECT().
959 CreateAccessTokenSession(propagatedContext, gomock.Any(), gomock.Any()).
960 Return(nil).
961 Times(1)
962 mockRevocationStore.
963 EXPECT().
964 CreateRefreshTokenSession(propagatedContext, gomock.Any(), gomock.Any()).
965 Return(nil).
966 Times(1)
967 mockTransactional.
968 EXPECT().
969 Commit(propagatedContext).
970 Return(errors.New("Could not commit transaction!")).
971 Times(1)
972 mockTransactional.
973 EXPECT().
974 Rollback(propagatedContext).
975 Return(nil).
976 Times(1)
977 },
978 expectError: fosite.ErrServerError,
979 },
980 {
981 description: "should result in a `fosite.ErrInvalidRequest` if transaction fails to commit due to a " +
982 "`fosite.ErrSerializationFailure` error",
983 setup: func() {
984 request.GrantTypes = fosite.Arguments{"refresh_token"}
985 mockTransactional.
986 EXPECT().
987 BeginTX(propagatedContext).
988 Return(propagatedContext, nil).
989 Times(1)
990 mockRevocationStore.
991 EXPECT().
992 GetRefreshTokenSession(propagatedContext, gomock.Any(), nil).
993 Return(request, nil).
994 Times(1)
995 mockRevocationStore.
996 EXPECT().
997 RevokeAccessToken(propagatedContext, gomock.Any()).
998 Return(nil).
999 Times(1)
1000 mockRevocationStore.
1001 EXPECT().
1002 RevokeRefreshTokenMaybeGracePeriod(propagatedContext, gomock.Any(), gomock.Any()).
1003 Return(nil).
1004 Times(1)
1005 mockRevocationStore.
1006 EXPECT().
1007 CreateAccessTokenSession(propagatedContext, gomock.Any(), gomock.Any()).
1008 Return(nil).
1009 Times(1)
1010 mockRevocationStore.
1011 EXPECT().
1012 CreateRefreshTokenSession(propagatedContext, gomock.Any(), gomock.Any()).
1013 Return(nil).
1014 Times(1)
1015 mockTransactional.
1016 EXPECT().
1017 Commit(propagatedContext).
1018 Return(fosite.ErrSerializationFailure).
1019 Times(1)
1020 mockTransactional.
1021 EXPECT().
1022 Rollback(propagatedContext).
1023 Return(nil).
1024 Times(1)
1025 },
1026 expectError: fosite.ErrInvalidRequest,
1027 },
1028 } {
1029 t.Run(fmt.Sprintf("scenario=%s", testCase.description), func(t *testing.T) {
1030 ctrl := gomock.NewController(t)
1031 defer ctrl.Finish()
1032
1033 mockTransactional = internal.NewMockTransactional(ctrl)
1034 mockRevocationStore = internal.NewMockTokenRevocationStorage(ctrl)
1035 testCase.setup()
1036
1037 handler := RefreshTokenGrantHandler{
1038
1039 TokenRevocationStorage: transactionalStore{
1040 mockTransactional,
1041 mockRevocationStore,
1042 },
1043 AccessTokenStrategy: &hmacshaStrategy,
1044 RefreshTokenStrategy: &hmacshaStrategy,
1045 AccessTokenLifespan: time.Hour,
1046 ScopeStrategy: fosite.HierarchicScopeStrategy,
1047 AudienceMatchingStrategy: fosite.DefaultAudienceMatchingStrategy,
1048 }
1049
1050 if err := handler.PopulateTokenEndpointResponse(propagatedContext, request, response); testCase.expectError != nil {
1051 assert.EqualError(t, err, testCase.expectError.Error())
1052 }
1053 })
1054 }
1055 }
1056
View as plain text