1 package rfc7523
2
3 import (
4 "context"
5 "crypto/rand"
6 "crypto/rsa"
7 "errors"
8 "fmt"
9 mrand "math/rand"
10 "net/url"
11 "strconv"
12 "testing"
13 "time"
14
15 "github.com/ory/fosite/handler/oauth2"
16
17 "github.com/golang/mock/gomock"
18 "github.com/stretchr/testify/suite"
19 "gopkg.in/square/go-jose.v2"
20 "gopkg.in/square/go-jose.v2/jwt"
21
22 "github.com/ory/fosite"
23 "github.com/ory/fosite/internal"
24 )
25
26
27
28
29 type AuthorizeJWTGrantRequestHandlerTestSuite struct {
30 suite.Suite
31
32 privateKey *rsa.PrivateKey
33 mockCtrl *gomock.Controller
34 mockStore *internal.MockRFC7523KeyStorage
35 mockAccessTokenStrategy *internal.MockAccessTokenStrategy
36 mockAccessTokenStore *internal.MockAccessTokenStorage
37 accessRequest *fosite.AccessRequest
38 handler *Handler
39 }
40
41
42 func (s *AuthorizeJWTGrantRequestHandlerTestSuite) SetupSuite() {
43 privateKey, err := rsa.GenerateKey(rand.Reader, 512)
44 if err != nil {
45 s.FailNowf("failed to setup test suite", "failed to generate RSA private key: %s", err.Error())
46 }
47 s.privateKey = privateKey
48 }
49
50
51 func (s *AuthorizeJWTGrantRequestHandlerTestSuite) TearDownSuite() {
52 }
53
54
55 func (s *AuthorizeJWTGrantRequestHandlerTestSuite) TearDownTest() {
56 s.mockCtrl.Finish()
57 }
58
59
60 func (s *AuthorizeJWTGrantRequestHandlerTestSuite) SetupTest() {
61 s.mockCtrl = gomock.NewController(s.T())
62 s.mockStore = internal.NewMockRFC7523KeyStorage(s.mockCtrl)
63 s.mockAccessTokenStrategy = internal.NewMockAccessTokenStrategy(s.mockCtrl)
64 s.mockAccessTokenStore = internal.NewMockAccessTokenStorage(s.mockCtrl)
65 s.accessRequest = fosite.NewAccessRequest(new(fosite.DefaultSession))
66 s.accessRequest.Form = url.Values{}
67 s.accessRequest.Client = &fosite.DefaultClient{GrantTypes: []string{grantTypeJWTBearer}}
68 s.handler = &Handler{
69 Storage: s.mockStore,
70 ScopeStrategy: fosite.HierarchicScopeStrategy,
71 AudienceMatchingStrategy: fosite.DefaultAudienceMatchingStrategy,
72 TokenURL: "https://www.example.com/token",
73 SkipClientAuth: false,
74 JWTIDOptional: false,
75 JWTIssuedDateOptional: false,
76 JWTMaxDuration: time.Hour * 24 * 30,
77 HandleHelper: &oauth2.HandleHelper{
78 AccessTokenStrategy: s.mockAccessTokenStrategy,
79 AccessTokenStorage: s.mockAccessTokenStore,
80 AccessTokenLifespan: time.Hour,
81 },
82 }
83 }
84
85
86
87 func TestAuthorizeJWTGrantRequestHandlerTestSuite(t *testing.T) {
88 suite.Run(t, new(AuthorizeJWTGrantRequestHandlerTestSuite))
89 }
90
91 func (s *AuthorizeJWTGrantRequestHandlerTestSuite) TestRequestWithInvalidGrantType() {
92
93 s.accessRequest.GrantTypes = []string{"authorization_code"}
94
95
96 err := s.handler.HandleTokenEndpointRequest(context.Background(), s.accessRequest)
97
98
99 s.True(errors.Is(err, fosite.ErrUnknownRequest))
100 s.EqualError(err, fosite.ErrUnknownRequest.Error(), "expected error, because of invalid grant type")
101 }
102
103 func (s *AuthorizeJWTGrantRequestHandlerTestSuite) TestClientIsNotRegisteredForGrantType() {
104
105 s.accessRequest.GrantTypes = []string{grantTypeJWTBearer}
106 s.accessRequest.Client = &fosite.DefaultClient{GrantTypes: []string{"authorization_code"}}
107 s.handler.SkipClientAuth = false
108
109
110 err := s.handler.HandleTokenEndpointRequest(context.Background(), s.accessRequest)
111
112
113 s.True(errors.Is(err, fosite.ErrUnauthorizedClient))
114 s.EqualError(err, fosite.ErrUnauthorizedClient.Error(), "expected error, because client is not registered to use this grant type")
115 s.Equal(
116 "The OAuth 2.0 Client is not allowed to use authorization grant \"urn:ietf:params:oauth:grant-type:jwt-bearer\".",
117 err.(*fosite.RFC6749Error).HintField,
118 )
119 }
120
121 func (s *AuthorizeJWTGrantRequestHandlerTestSuite) TestRequestWithoutAssertion() {
122
123 s.accessRequest.GrantTypes = []string{grantTypeJWTBearer}
124
125
126 err := s.handler.HandleTokenEndpointRequest(context.Background(), s.accessRequest)
127
128
129 s.True(errors.Is(err, fosite.ErrInvalidRequest))
130 s.EqualError(err, fosite.ErrInvalidRequest.Error(), "expected error, because of missing assertion")
131 s.Equal(
132 "The assertion request parameter must be set when using grant_type of 'urn:ietf:params:oauth:grant-type:jwt-bearer'.",
133 err.(*fosite.RFC6749Error).HintField,
134 )
135 }
136
137 func (s *AuthorizeJWTGrantRequestHandlerTestSuite) TestRequestWithMalformedAssertion() {
138
139 s.accessRequest.GrantTypes = []string{grantTypeJWTBearer}
140 s.accessRequest.Form.Add("assertion", "fjigjgfkjgkf")
141
142
143 err := s.handler.HandleTokenEndpointRequest(context.Background(), s.accessRequest)
144
145
146 s.True(errors.Is(err, fosite.ErrInvalidGrant))
147 s.EqualError(err, fosite.ErrInvalidGrant.Error(), "expected error, because of malformed assertion")
148 s.Equal(
149 "Unable to parse JSON Web Token passed in \"assertion\" request parameter.",
150 err.(*fosite.RFC6749Error).HintField,
151 )
152 }
153
154 func (s *AuthorizeJWTGrantRequestHandlerTestSuite) TestRequestAssertionWithoutIssuer() {
155
156 s.accessRequest.GrantTypes = []string{grantTypeJWTBearer}
157 keyID := "my_key"
158 cl := s.createStandardClaim()
159 cl.Issuer = ""
160 s.accessRequest.Form.Add("assertion", s.createTestAssertion(cl, keyID))
161
162
163 err := s.handler.HandleTokenEndpointRequest(context.Background(), s.accessRequest)
164
165
166 s.True(errors.Is(err, fosite.ErrInvalidGrant))
167 s.EqualError(err, fosite.ErrInvalidGrant.Error(), "expected error, because of missing issuer claim in assertion")
168 s.Equal(
169 "The JWT in \"assertion\" request parameter MUST contain an \"iss\" (issuer) claim.",
170 err.(*fosite.RFC6749Error).HintField,
171 )
172 }
173
174 func (s *AuthorizeJWTGrantRequestHandlerTestSuite) TestRequestAssertionWithoutSubject() {
175
176 s.accessRequest.GrantTypes = []string{grantTypeJWTBearer}
177 keyID := "my_key"
178 cl := s.createStandardClaim()
179 cl.Subject = ""
180 s.accessRequest.Form.Add("assertion", s.createTestAssertion(cl, keyID))
181
182
183 err := s.handler.HandleTokenEndpointRequest(context.Background(), s.accessRequest)
184
185
186 s.True(errors.Is(err, fosite.ErrInvalidGrant))
187 s.EqualError(err, fosite.ErrInvalidGrant.Error(), "expected error, because of missing subject claim in assertion")
188 s.Equal(
189 "The JWT in \"assertion\" request parameter MUST contain a \"sub\" (subject) claim.",
190 err.(*fosite.RFC6749Error).HintField,
191 )
192 }
193
194 func (s *AuthorizeJWTGrantRequestHandlerTestSuite) TestNoMatchingPublicKeyToCheckAssertionSignature() {
195
196 ctx := context.Background()
197 s.accessRequest.GrantTypes = []string{grantTypeJWTBearer}
198 cl := s.createStandardClaim()
199 keyID := "my_key"
200 s.accessRequest.Form.Add("assertion", s.createTestAssertion(cl, keyID))
201 s.mockStore.EXPECT().GetPublicKey(ctx, cl.Issuer, cl.Subject, keyID).Return(nil, fosite.ErrNotFound)
202
203
204 err := s.handler.HandleTokenEndpointRequest(ctx, s.accessRequest)
205
206
207 s.True(errors.Is(err, fosite.ErrInvalidGrant))
208 s.EqualError(err, fosite.ErrInvalidGrant.Error(), "expected error, because of missing public key to check assertion")
209 s.Equal(
210 fmt.Sprintf(
211 "No public JWK was registered for issuer \"%s\" and subject \"%s\", and public key is required to check signature of JWT in \"assertion\" request parameter.",
212 cl.Issuer, cl.Subject,
213 ),
214 err.(*fosite.RFC6749Error).HintField,
215 )
216 }
217
218 func (s *AuthorizeJWTGrantRequestHandlerTestSuite) TestNoMatchingPublicKeysToCheckAssertionSignature() {
219
220 ctx := context.Background()
221 s.accessRequest.GrantTypes = []string{grantTypeJWTBearer}
222 keyID := ""
223 cl := s.createStandardClaim()
224 s.accessRequest.Form.Add("assertion", s.createTestAssertion(cl, keyID))
225 s.mockStore.EXPECT().GetPublicKeys(ctx, cl.Issuer, cl.Subject).Return(nil, fosite.ErrNotFound)
226
227
228 err := s.handler.HandleTokenEndpointRequest(ctx, s.accessRequest)
229
230
231 s.True(errors.Is(err, fosite.ErrInvalidGrant))
232 s.EqualError(err, fosite.ErrInvalidGrant.Error(), "expected error, because of missing public keys to check assertion")
233 s.Equal(
234 fmt.Sprintf(
235 "No public JWK was registered for issuer \"%s\" and subject \"%s\", and public key is required to check signature of JWT in \"assertion\" request parameter.",
236 cl.Issuer, cl.Subject,
237 ),
238 err.(*fosite.RFC6749Error).HintField,
239 )
240 }
241
242 func (s *AuthorizeJWTGrantRequestHandlerTestSuite) TestWrongPublicKeyToCheckAssertionSignature() {
243
244 ctx := context.Background()
245 s.accessRequest.GrantTypes = []string{grantTypeJWTBearer}
246 keyID := "wrong_key"
247 cl := s.createStandardClaim()
248 s.accessRequest.Form.Add("assertion", s.createTestAssertion(cl, keyID))
249 jwk := s.createRandomTestJWK()
250 s.mockStore.EXPECT().GetPublicKey(ctx, cl.Issuer, cl.Subject, keyID).Return(&jwk, nil)
251
252
253 err := s.handler.HandleTokenEndpointRequest(ctx, s.accessRequest)
254
255
256 s.True(errors.Is(err, fosite.ErrInvalidGrant))
257 s.EqualError(err, fosite.ErrInvalidGrant.Error(), "expected error, because wrong public key was registered for assertion")
258 s.Equal("Unable to verify the integrity of the 'assertion' value.", err.(*fosite.RFC6749Error).HintField)
259 }
260
261 func (s *AuthorizeJWTGrantRequestHandlerTestSuite) TestWrongPublicKeysToCheckAssertionSignature() {
262
263 ctx := context.Background()
264 s.accessRequest.GrantTypes = []string{grantTypeJWTBearer}
265 keyID := ""
266 cl := s.createStandardClaim()
267 s.accessRequest.Form.Add("assertion", s.createTestAssertion(cl, keyID))
268 s.mockStore.EXPECT().GetPublicKeys(ctx, cl.Issuer, cl.Subject).Return(s.createJWS(s.createRandomTestJWK(), s.createRandomTestJWK()), nil)
269
270
271 err := s.handler.HandleTokenEndpointRequest(ctx, s.accessRequest)
272
273
274 s.True(errors.Is(err, fosite.ErrInvalidGrant))
275 s.EqualError(err, fosite.ErrInvalidGrant.Error(), "expected error, because wrong public keys was registered for assertion")
276 s.Equal(
277 fmt.Sprintf(
278 "No public JWK was registered for issuer \"%s\" and subject \"%s\", and public key is required to check signature of JWT in \"assertion\" request parameter.",
279 cl.Issuer, cl.Subject,
280 ),
281 err.(*fosite.RFC6749Error).HintField,
282 )
283 }
284
285 func (s *AuthorizeJWTGrantRequestHandlerTestSuite) TestNoAudienceInAssertion() {
286
287 ctx := context.Background()
288 s.accessRequest.GrantTypes = []string{grantTypeJWTBearer}
289 keyID := "my_key"
290 pubKey := s.createJWK(s.privateKey.Public(), keyID)
291 cl := s.createStandardClaim()
292 cl.Audience = []string{}
293 s.accessRequest.Form.Add("assertion", s.createTestAssertion(cl, keyID))
294 s.mockStore.EXPECT().GetPublicKey(ctx, cl.Issuer, cl.Subject, keyID).Return(&pubKey, nil)
295
296
297 err := s.handler.HandleTokenEndpointRequest(ctx, s.accessRequest)
298
299
300 s.True(errors.Is(err, fosite.ErrInvalidGrant))
301 s.EqualError(err, fosite.ErrInvalidGrant.Error(), "expected error, because of missing audience claim in assertion")
302 s.Equal(
303 "The JWT in \"assertion\" request parameter MUST contain an \"aud\" (audience) claim.",
304 err.(*fosite.RFC6749Error).HintField,
305 )
306 }
307
308 func (s *AuthorizeJWTGrantRequestHandlerTestSuite) TestNotValidAudienceInAssertion() {
309
310 ctx := context.Background()
311 s.accessRequest.GrantTypes = []string{grantTypeJWTBearer}
312 keyID := "my_key"
313 pubKey := s.createJWK(s.privateKey.Public(), keyID)
314 cl := s.createStandardClaim()
315 cl.Audience = jwt.Audience{"leela", "fry"}
316 s.accessRequest.Form.Add("assertion", s.createTestAssertion(cl, keyID))
317 s.mockStore.EXPECT().GetPublicKey(ctx, cl.Issuer, cl.Subject, keyID).Return(&pubKey, nil)
318
319
320 err := s.handler.HandleTokenEndpointRequest(ctx, s.accessRequest)
321
322
323 s.True(errors.Is(err, fosite.ErrInvalidGrant))
324 s.EqualError(err, fosite.ErrInvalidGrant.Error(), "expected error, because of invalid audience claim in assertion")
325 s.Equal(
326 fmt.Sprintf(
327 "The JWT in \"assertion\" request parameter MUST contain an \"aud\" (audience) claim containing a value \"%s\" that identifies the authorization server as an intended audience.",
328 s.handler.TokenURL,
329 ),
330 err.(*fosite.RFC6749Error).HintField,
331 )
332 }
333
334 func (s *AuthorizeJWTGrantRequestHandlerTestSuite) TestNoExpirationInAssertion() {
335
336 ctx := context.Background()
337 s.accessRequest.GrantTypes = []string{grantTypeJWTBearer}
338 keyID := "my_key"
339 pubKey := s.createJWK(s.privateKey.Public(), keyID)
340 cl := s.createStandardClaim()
341 cl.Expiry = nil
342 s.accessRequest.Form.Add("assertion", s.createTestAssertion(cl, keyID))
343 s.mockStore.EXPECT().GetPublicKey(ctx, cl.Issuer, cl.Subject, keyID).Return(&pubKey, nil)
344
345
346 err := s.handler.HandleTokenEndpointRequest(ctx, s.accessRequest)
347
348
349 s.True(errors.Is(err, fosite.ErrInvalidGrant))
350 s.EqualError(err, fosite.ErrInvalidGrant.Error(), "expected error, because of missing expiration claim in assertion")
351 s.Equal(
352 "The JWT in \"assertion\" request parameter MUST contain an \"exp\" (expiration time) claim.",
353 err.(*fosite.RFC6749Error).HintField,
354 )
355 }
356
357 func (s *AuthorizeJWTGrantRequestHandlerTestSuite) TestExpiredAssertion() {
358
359 ctx := context.Background()
360 s.accessRequest.GrantTypes = []string{grantTypeJWTBearer}
361 keyID := "my_key"
362 pubKey := s.createJWK(s.privateKey.Public(), keyID)
363 cl := s.createStandardClaim()
364 cl.Expiry = jwt.NewNumericDate(time.Now().AddDate(0, -1, 0))
365 s.accessRequest.Form.Add("assertion", s.createTestAssertion(cl, keyID))
366 s.mockStore.EXPECT().GetPublicKey(ctx, cl.Issuer, cl.Subject, keyID).Return(&pubKey, nil)
367
368
369 err := s.handler.HandleTokenEndpointRequest(ctx, s.accessRequest)
370
371
372 s.True(errors.Is(err, fosite.ErrInvalidGrant))
373 s.EqualError(err, fosite.ErrInvalidGrant.Error(), "expected error, because assertion expired")
374 s.Equal(
375 "The JWT in \"assertion\" request parameter expired.",
376 err.(*fosite.RFC6749Error).HintField,
377 )
378 }
379
380 func (s *AuthorizeJWTGrantRequestHandlerTestSuite) TestAssertionNotAcceptedBeforeDate() {
381
382 ctx := context.Background()
383 s.accessRequest.GrantTypes = []string{grantTypeJWTBearer}
384 keyID := "my_key"
385 pubKey := s.createJWK(s.privateKey.Public(), keyID)
386 nbf := time.Now().AddDate(0, 1, 0)
387 cl := s.createStandardClaim()
388 cl.NotBefore = jwt.NewNumericDate(nbf)
389 s.accessRequest.Form.Add("assertion", s.createTestAssertion(cl, keyID))
390 s.mockStore.EXPECT().GetPublicKey(ctx, cl.Issuer, cl.Subject, keyID).Return(&pubKey, nil)
391
392
393 err := s.handler.HandleTokenEndpointRequest(ctx, s.accessRequest)
394
395
396 s.True(errors.Is(err, fosite.ErrInvalidGrant))
397 s.EqualError(err, fosite.ErrInvalidGrant.Error(), "expected error, nbf claim in assertion indicates, that assertion can not be accepted now")
398 s.Equal(
399 fmt.Sprintf(
400 "The JWT in \"assertion\" request parameter contains an \"nbf\" (not before) claim, that identifies the time '%s' before which the token MUST NOT be accepted.",
401 nbf.Format(time.RFC3339),
402 ),
403 err.(*fosite.RFC6749Error).HintField,
404 )
405 }
406
407 func (s *AuthorizeJWTGrantRequestHandlerTestSuite) TestAssertionWithoutRequiredIssueDate() {
408
409 ctx := context.Background()
410 s.accessRequest.GrantTypes = []string{grantTypeJWTBearer}
411 keyID := "my_key"
412 pubKey := s.createJWK(s.privateKey.Public(), keyID)
413 cl := s.createStandardClaim()
414 cl.IssuedAt = nil
415 s.handler.JWTIssuedDateOptional = false
416 s.accessRequest.Form.Add("assertion", s.createTestAssertion(cl, keyID))
417 s.mockStore.EXPECT().GetPublicKey(ctx, cl.Issuer, cl.Subject, keyID).Return(&pubKey, nil)
418
419
420 err := s.handler.HandleTokenEndpointRequest(ctx, s.accessRequest)
421
422
423 s.True(errors.Is(err, fosite.ErrInvalidGrant))
424 s.EqualError(err, fosite.ErrInvalidGrant.Error(), "expected error, because of missing iat claim in assertion")
425 s.Equal(
426 "The JWT in \"assertion\" request parameter MUST contain an \"iat\" (issued at) claim.",
427 err.(*fosite.RFC6749Error).HintField,
428 )
429 }
430
431 func (s *AuthorizeJWTGrantRequestHandlerTestSuite) TestAssertionWithIssueDateFarInPast() {
432
433 ctx := context.Background()
434 s.accessRequest.GrantTypes = []string{grantTypeJWTBearer}
435 keyID := "my_key"
436 pubKey := s.createJWK(s.privateKey.Public(), keyID)
437 issuedAt := time.Now().AddDate(0, 0, -31)
438 cl := s.createStandardClaim()
439 cl.IssuedAt = jwt.NewNumericDate(issuedAt)
440 s.handler.JWTIssuedDateOptional = false
441 s.handler.JWTMaxDuration = time.Hour * 24 * 30
442 s.accessRequest.Form.Add("assertion", s.createTestAssertion(cl, keyID))
443 s.mockStore.EXPECT().GetPublicKey(ctx, cl.Issuer, cl.Subject, keyID).Return(&pubKey, nil)
444
445
446 err := s.handler.HandleTokenEndpointRequest(ctx, s.accessRequest)
447
448
449 s.True(errors.Is(err, fosite.ErrInvalidGrant))
450 s.EqualError(err, fosite.ErrInvalidGrant.Error(), "expected error, because assertion was issued far in the past")
451 s.Equal(
452 fmt.Sprintf(
453 "The JWT in \"assertion\" request parameter contains an \"exp\" (expiration time) claim with value \"%s\" that is unreasonably far in the future, considering token issued at \"%s\".",
454 cl.Expiry.Time().Format(time.RFC3339),
455 cl.IssuedAt.Time().Format(time.RFC3339),
456 ),
457 err.(*fosite.RFC6749Error).HintField,
458 )
459 }
460
461 func (s *AuthorizeJWTGrantRequestHandlerTestSuite) TestAssertionWithExpirationDateFarInFuture() {
462
463 ctx := context.Background()
464 s.accessRequest.GrantTypes = []string{grantTypeJWTBearer}
465 keyID := "my_key"
466 pubKey := s.createJWK(s.privateKey.Public(), keyID)
467 cl := s.createStandardClaim()
468 cl.IssuedAt = jwt.NewNumericDate(time.Now().AddDate(0, 0, -15))
469 cl.Expiry = jwt.NewNumericDate(time.Now().AddDate(0, 0, 20))
470 s.handler.JWTIssuedDateOptional = false
471 s.handler.JWTMaxDuration = time.Hour * 24 * 30
472 s.accessRequest.Form.Add("assertion", s.createTestAssertion(cl, keyID))
473 s.mockStore.EXPECT().GetPublicKey(ctx, cl.Issuer, cl.Subject, keyID).Return(&pubKey, nil)
474
475
476 err := s.handler.HandleTokenEndpointRequest(ctx, s.accessRequest)
477
478
479 s.True(errors.Is(err, fosite.ErrInvalidGrant))
480 s.EqualError(err, fosite.ErrInvalidGrant.Error(), "expected error, because assertion will expire unreasonably far in the future.")
481 s.Equal(
482 fmt.Sprintf(
483 "The JWT in \"assertion\" request parameter contains an \"exp\" (expiration time) claim with value \"%s\" that is unreasonably far in the future, considering token issued at \"%s\".",
484 cl.Expiry.Time().Format(time.RFC3339),
485 cl.IssuedAt.Time().Format(time.RFC3339),
486 ),
487 err.(*fosite.RFC6749Error).HintField,
488 )
489 }
490
491 func (s *AuthorizeJWTGrantRequestHandlerTestSuite) TestAssertionWithExpirationDateFarInFutureWithNoIssuerDate() {
492
493 ctx := context.Background()
494 s.accessRequest.GrantTypes = []string{grantTypeJWTBearer}
495 keyID := "my_key"
496 pubKey := s.createJWK(s.privateKey.Public(), keyID)
497 cl := s.createStandardClaim()
498 cl.IssuedAt = nil
499 cl.Expiry = jwt.NewNumericDate(time.Now().AddDate(0, 0, 31))
500 s.handler.JWTIssuedDateOptional = true
501 s.handler.JWTMaxDuration = time.Hour * 24 * 30
502 s.accessRequest.Form.Add("assertion", s.createTestAssertion(cl, keyID))
503 s.mockStore.EXPECT().GetPublicKey(ctx, cl.Issuer, cl.Subject, keyID).Return(&pubKey, nil)
504
505
506 err := s.handler.HandleTokenEndpointRequest(ctx, s.accessRequest)
507
508
509 s.True(errors.Is(err, fosite.ErrInvalidGrant))
510 s.EqualError(err, fosite.ErrInvalidGrant.Error(), "expected error, because assertion will expire unreasonably far in the future.")
511 }
512
513 func (s *AuthorizeJWTGrantRequestHandlerTestSuite) TestAssertionWithoutRequiredTokenID() {
514
515 ctx := context.Background()
516 s.accessRequest.GrantTypes = []string{grantTypeJWTBearer}
517 keyID := "my_key"
518 pubKey := s.createJWK(s.privateKey.Public(), keyID)
519 cl := s.createStandardClaim()
520 cl.ID = ""
521 s.accessRequest.Form.Add("assertion", s.createTestAssertion(cl, keyID))
522 s.mockStore.EXPECT().GetPublicKey(ctx, cl.Issuer, cl.Subject, keyID).Return(&pubKey, nil)
523
524
525 err := s.handler.HandleTokenEndpointRequest(ctx, s.accessRequest)
526
527
528 s.True(errors.Is(err, fosite.ErrInvalidGrant))
529 s.EqualError(err, fosite.ErrInvalidGrant.Error(), "expected error, because of missing jti claim in assertion")
530 s.Equal(
531 "The JWT in \"assertion\" request parameter MUST contain an \"jti\" (JWT ID) claim.",
532 err.(*fosite.RFC6749Error).HintField,
533 )
534 }
535
536 func (s *AuthorizeJWTGrantRequestHandlerTestSuite) TestAssertionAlreadyUsed() {
537
538 ctx := context.Background()
539 s.accessRequest.GrantTypes = []string{grantTypeJWTBearer}
540 keyID := "my_key"
541 pubKey := s.createJWK(s.privateKey.Public(), keyID)
542 cl := s.createStandardClaim()
543 s.accessRequest.Form.Add("assertion", s.createTestAssertion(cl, keyID))
544 s.mockStore.EXPECT().GetPublicKey(ctx, cl.Issuer, cl.Subject, keyID).Return(&pubKey, nil)
545 s.mockStore.EXPECT().IsJWTUsed(ctx, cl.ID).Return(true, nil)
546
547
548 err := s.handler.HandleTokenEndpointRequest(ctx, s.accessRequest)
549
550
551 s.True(errors.Is(err, fosite.ErrJTIKnown))
552 s.EqualError(err, fosite.ErrJTIKnown.Error(), "expected error, because assertion was used")
553 }
554
555 func (s *AuthorizeJWTGrantRequestHandlerTestSuite) TestErrWhenCheckingIfJWTWasUsed() {
556
557 ctx := context.Background()
558 s.accessRequest.GrantTypes = []string{grantTypeJWTBearer}
559 keyID := "my_key"
560 pubKey := s.createJWK(s.privateKey.Public(), keyID)
561 cl := s.createStandardClaim()
562 s.accessRequest.Form.Add("assertion", s.createTestAssertion(cl, keyID))
563 s.mockStore.EXPECT().GetPublicKey(ctx, cl.Issuer, cl.Subject, keyID).Return(&pubKey, nil)
564 s.mockStore.EXPECT().IsJWTUsed(ctx, cl.ID).Return(false, fosite.ErrServerError)
565
566
567 err := s.handler.HandleTokenEndpointRequest(ctx, s.accessRequest)
568
569
570 s.True(errors.Is(err, fosite.ErrServerError))
571 s.EqualError(err, fosite.ErrServerError.Error(), "expected error, because error occurred while trying to check if jwt was used")
572 }
573
574 func (s *AuthorizeJWTGrantRequestHandlerTestSuite) TestErrWhenMarkingJWTAsUsed() {
575
576 ctx := context.Background()
577 s.accessRequest.GrantTypes = []string{grantTypeJWTBearer}
578 keyID := "my_key"
579 pubKey := s.createJWK(s.privateKey.Public(), keyID)
580 cl := s.createStandardClaim()
581 s.accessRequest.Form.Add("assertion", s.createTestAssertion(cl, keyID))
582 s.mockStore.EXPECT().GetPublicKey(ctx, cl.Issuer, cl.Subject, keyID).Return(&pubKey, nil)
583 s.mockStore.EXPECT().GetPublicKeyScopes(ctx, cl.Issuer, cl.Subject, keyID).Return([]string{"valid_scope"}, nil)
584 s.mockStore.EXPECT().IsJWTUsed(ctx, cl.ID).Return(false, nil)
585 s.mockStore.EXPECT().MarkJWTUsedForTime(ctx, cl.ID, cl.Expiry.Time()).Return(fosite.ErrServerError)
586
587
588 err := s.handler.HandleTokenEndpointRequest(ctx, s.accessRequest)
589
590
591 s.True(errors.Is(err, fosite.ErrServerError))
592 s.EqualError(err, fosite.ErrServerError.Error(), "expected error, because error occurred while trying to mark jwt as used")
593 }
594
595 func (s *AuthorizeJWTGrantRequestHandlerTestSuite) TestErrWhileFetchingPublicKeyScope() {
596
597 ctx := context.Background()
598 s.accessRequest.GrantTypes = []string{grantTypeJWTBearer}
599 keyID := "my_key"
600 pubKey := s.createJWK(s.privateKey.Public(), keyID)
601 cl := s.createStandardClaim()
602
603 s.accessRequest.Form.Add("assertion", s.createTestAssertion(cl, keyID))
604 s.mockStore.EXPECT().GetPublicKey(ctx, cl.Issuer, cl.Subject, keyID).Return(&pubKey, nil)
605 s.mockStore.EXPECT().GetPublicKeyScopes(ctx, cl.Issuer, cl.Subject, keyID).Return([]string{}, fosite.ErrServerError)
606 s.mockStore.EXPECT().IsJWTUsed(ctx, cl.ID).Return(false, nil)
607
608
609 err := s.handler.HandleTokenEndpointRequest(ctx, s.accessRequest)
610
611
612 s.True(errors.Is(err, fosite.ErrServerError))
613 s.EqualError(err, fosite.ErrServerError.Error(), "expected error, because error occurred while fetching public key scopes")
614 }
615
616 func (s *AuthorizeJWTGrantRequestHandlerTestSuite) TestAssertionWithInvalidScopes() {
617
618 ctx := context.Background()
619 s.accessRequest.GrantTypes = []string{grantTypeJWTBearer}
620 keyID := "my_key"
621 pubKey := s.createJWK(s.privateKey.Public(), keyID)
622 cl := s.createStandardClaim()
623
624 s.accessRequest.Form.Add("assertion", s.createTestAssertion(cl, keyID))
625 s.accessRequest.RequestedScope = []string{"some_scope"}
626 s.mockStore.EXPECT().GetPublicKey(ctx, cl.Issuer, cl.Subject, keyID).Return(&pubKey, nil)
627 s.mockStore.EXPECT().GetPublicKeyScopes(ctx, cl.Issuer, cl.Subject, keyID).Return([]string{"valid_scope"}, nil)
628 s.mockStore.EXPECT().IsJWTUsed(ctx, cl.ID).Return(false, nil)
629
630
631 err := s.handler.HandleTokenEndpointRequest(ctx, s.accessRequest)
632
633
634 s.True(errors.Is(err, fosite.ErrInvalidScope))
635 s.EqualError(err, fosite.ErrInvalidScope.Error(), "expected error, because requested scopes don't match allowed scope for this assertion")
636 s.Equal(
637 "The public key registered for issuer \"trusted_issuer\" and subject \"some_ro\" is not allowed to request scope \"some_scope\".",
638 err.(*fosite.RFC6749Error).HintField,
639 )
640 }
641
642 func (s *AuthorizeJWTGrantRequestHandlerTestSuite) TestValidAssertion() {
643
644 ctx := context.Background()
645 s.accessRequest.GrantTypes = []string{grantTypeJWTBearer}
646 keyID := "my_key"
647 pubKey := s.createJWK(s.privateKey.Public(), keyID)
648 cl := s.createStandardClaim()
649
650 s.accessRequest.Form.Add("assertion", s.createTestAssertion(cl, keyID))
651 s.accessRequest.RequestedScope = []string{"valid_scope"}
652 s.mockStore.EXPECT().GetPublicKey(ctx, cl.Issuer, cl.Subject, keyID).Return(&pubKey, nil)
653 s.mockStore.EXPECT().GetPublicKeyScopes(ctx, cl.Issuer, cl.Subject, keyID).Return([]string{"valid_scope", "openid"}, nil)
654 s.mockStore.EXPECT().IsJWTUsed(ctx, cl.ID).Return(false, nil)
655 s.mockStore.EXPECT().MarkJWTUsedForTime(ctx, cl.ID, cl.Expiry.Time()).Return(nil)
656
657
658 err := s.handler.HandleTokenEndpointRequest(ctx, s.accessRequest)
659
660
661 s.NoError(err, "no error expected, because assertion must be valid")
662 }
663
664 func (s *AuthorizeJWTGrantRequestHandlerTestSuite) TestAssertionIsValidWhenNoScopesPassed() {
665
666 ctx := context.Background()
667 s.accessRequest.GrantTypes = []string{grantTypeJWTBearer}
668 keyID := "my_key"
669 pubKey := s.createJWK(s.privateKey.Public(), keyID)
670 cl := s.createStandardClaim()
671 s.accessRequest.Form.Add("assertion", s.createTestAssertion(cl, keyID))
672 s.mockStore.EXPECT().GetPublicKey(ctx, cl.Issuer, cl.Subject, keyID).Return(&pubKey, nil)
673 s.mockStore.EXPECT().GetPublicKeyScopes(ctx, cl.Issuer, cl.Subject, keyID).Return([]string{"valid_scope"}, nil)
674 s.mockStore.EXPECT().IsJWTUsed(ctx, cl.ID).Return(false, nil)
675 s.mockStore.EXPECT().MarkJWTUsedForTime(ctx, cl.ID, cl.Expiry.Time()).Return(nil)
676
677
678 err := s.handler.HandleTokenEndpointRequest(ctx, s.accessRequest)
679
680
681 s.NoError(err, "no error expected, because assertion must be valid")
682 }
683
684 func (s *AuthorizeJWTGrantRequestHandlerTestSuite) TestAssertionIsValidWhenJWTIDIsOptional() {
685
686 ctx := context.Background()
687 s.accessRequest.GrantTypes = []string{grantTypeJWTBearer}
688 keyID := "my_key"
689 pubKey := s.createJWK(s.privateKey.Public(), keyID)
690 cl := s.createStandardClaim()
691 s.handler.JWTIDOptional = true
692 cl.ID = ""
693 s.accessRequest.Form.Add("assertion", s.createTestAssertion(cl, keyID))
694 s.mockStore.EXPECT().GetPublicKey(ctx, cl.Issuer, cl.Subject, keyID).Return(&pubKey, nil)
695 s.mockStore.EXPECT().GetPublicKeyScopes(ctx, cl.Issuer, cl.Subject, keyID).Return([]string{"valid_scope"}, nil)
696
697
698 err := s.handler.HandleTokenEndpointRequest(ctx, s.accessRequest)
699
700
701 s.NoError(err, "no error expected, because assertion must be valid, when no jti claim and it is allowed by option")
702 }
703
704 func (s *AuthorizeJWTGrantRequestHandlerTestSuite) TestAssertionIsValidWhenJWTIssuedDateOptional() {
705
706 ctx := context.Background()
707 s.accessRequest.GrantTypes = []string{grantTypeJWTBearer}
708 keyID := "my_key"
709 pubKey := s.createJWK(s.privateKey.Public(), keyID)
710 cl := s.createStandardClaim()
711 cl.IssuedAt = nil
712 s.handler.JWTIssuedDateOptional = true
713 s.accessRequest.Form.Add("assertion", s.createTestAssertion(cl, keyID))
714 s.mockStore.EXPECT().GetPublicKey(ctx, cl.Issuer, cl.Subject, keyID).Return(&pubKey, nil)
715 s.mockStore.EXPECT().GetPublicKeyScopes(ctx, cl.Issuer, cl.Subject, keyID).Return([]string{"valid_scope"}, nil)
716 s.mockStore.EXPECT().IsJWTUsed(ctx, cl.ID).Return(false, nil)
717 s.mockStore.EXPECT().MarkJWTUsedForTime(ctx, cl.ID, cl.Expiry.Time()).Return(nil)
718
719
720 err := s.handler.HandleTokenEndpointRequest(ctx, s.accessRequest)
721
722
723 s.NoError(err, "no error expected, because assertion must be valid, when no iss claim and it is allowed by option")
724 }
725
726 func (s *AuthorizeJWTGrantRequestHandlerTestSuite) TestRequestIsValidWhenClientAuthOptional() {
727
728 ctx := context.Background()
729 s.accessRequest.GrantTypes = []string{grantTypeJWTBearer}
730 keyID := "my_key"
731 pubKey := s.createJWK(s.privateKey.Public(), keyID)
732 cl := s.createStandardClaim()
733 s.accessRequest.Client = &fosite.DefaultClient{}
734 s.handler.SkipClientAuth = true
735 s.accessRequest.Form.Add("assertion", s.createTestAssertion(cl, keyID))
736 s.mockStore.EXPECT().GetPublicKey(ctx, cl.Issuer, cl.Subject, keyID).Return(&pubKey, nil)
737 s.mockStore.EXPECT().GetPublicKeyScopes(ctx, cl.Issuer, cl.Subject, keyID).Return([]string{"valid_scope"}, nil)
738 s.mockStore.EXPECT().IsJWTUsed(ctx, cl.ID).Return(false, nil)
739 s.mockStore.EXPECT().MarkJWTUsedForTime(ctx, cl.ID, cl.Expiry.Time()).Return(nil)
740
741
742 err := s.handler.HandleTokenEndpointRequest(ctx, s.accessRequest)
743
744
745 s.NoError(err, "no error expected, because request must be valid, when no client unauthenticated and it is allowed by option")
746 }
747
748 func (s *AuthorizeJWTGrantRequestHandlerTestSuite) createTestAssertion(cl jwt.Claims, keyID string) string {
749 jwk := jose.JSONWebKey{Key: s.privateKey, KeyID: keyID, Algorithm: string(jose.RS256)}
750 sig, err := jose.NewSigner(jose.SigningKey{Algorithm: jose.RS256, Key: jwk}, (&jose.SignerOptions{}).WithType("JWT"))
751 if err != nil {
752 s.FailNowf("failed to create test assertion", "failed to create signer: %s", err.Error())
753 }
754
755 raw, err := jwt.Signed(sig).Claims(cl).CompactSerialize()
756 if err != nil {
757 s.FailNowf("failed to create test assertion", "failed to sign assertion: %s", err.Error())
758 }
759
760 return raw
761 }
762
763 func (s *AuthorizeJWTGrantRequestHandlerTestSuite) createStandardClaim() jwt.Claims {
764 return jwt.Claims{
765 Issuer: "trusted_issuer",
766 Subject: "some_ro",
767 Audience: jwt.Audience{"https://www.example.com/token", "leela", "fry"},
768 Expiry: jwt.NewNumericDate(time.Now().AddDate(0, 0, 23)),
769 NotBefore: nil,
770 IssuedAt: jwt.NewNumericDate(time.Now().AddDate(0, 0, -7)),
771 ID: "my_token",
772 }
773 }
774
775 func (s *AuthorizeJWTGrantRequestHandlerTestSuite) createRandomTestJWK() jose.JSONWebKey {
776 privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
777 if err != nil {
778 s.FailNowf("failed to create random test JWK", "failed to generate RSA private key: %s", err.Error())
779 }
780
781 return s.createJWK(privateKey.Public(), strconv.Itoa(mrand.Int()))
782 }
783
784 func (s *AuthorizeJWTGrantRequestHandlerTestSuite) createJWK(key interface{}, keyID string) jose.JSONWebKey {
785 return jose.JSONWebKey{
786 Key: key,
787 KeyID: keyID,
788 Algorithm: string(jose.RS256),
789 Use: "sig",
790 }
791 }
792
793 func (s *AuthorizeJWTGrantRequestHandlerTestSuite) createJWS(keys ...jose.JSONWebKey) *jose.JSONWebKeySet {
794 return &jose.JSONWebKeySet{Keys: keys}
795 }
796
797
798
799
800 type AuthorizeJWTGrantPopulateTokenEndpointTestSuite struct {
801 suite.Suite
802
803 privateKey *rsa.PrivateKey
804 mockCtrl *gomock.Controller
805 mockStore *internal.MockRFC7523KeyStorage
806 mockAccessTokenStrategy *internal.MockAccessTokenStrategy
807 mockAccessTokenStore *internal.MockAccessTokenStorage
808 accessRequest *fosite.AccessRequest
809 accessResponse *fosite.AccessResponse
810 handler *Handler
811 }
812
813
814 func (s *AuthorizeJWTGrantPopulateTokenEndpointTestSuite) SetupSuite() {
815 privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
816 if err != nil {
817 s.FailNowf("failed to setup test suite", "failed to generate RSA private key: %s", err.Error())
818 }
819 s.privateKey = privateKey
820 }
821
822
823 func (s *AuthorizeJWTGrantPopulateTokenEndpointTestSuite) TearDownSuite() {
824 }
825
826
827 func (s *AuthorizeJWTGrantPopulateTokenEndpointTestSuite) TearDownTest() {
828 s.mockCtrl.Finish()
829 }
830
831
832 func (s *AuthorizeJWTGrantPopulateTokenEndpointTestSuite) SetupTest() {
833 s.mockCtrl = gomock.NewController(s.T())
834 s.mockStore = internal.NewMockRFC7523KeyStorage(s.mockCtrl)
835 s.mockAccessTokenStrategy = internal.NewMockAccessTokenStrategy(s.mockCtrl)
836 s.mockAccessTokenStore = internal.NewMockAccessTokenStorage(s.mockCtrl)
837 s.accessRequest = fosite.NewAccessRequest(new(fosite.DefaultSession))
838 s.accessRequest.Form = url.Values{}
839 s.accessRequest.Client = &fosite.DefaultClient{GrantTypes: []string{grantTypeJWTBearer}}
840 s.accessResponse = fosite.NewAccessResponse()
841 s.handler = &Handler{
842 Storage: s.mockStore,
843 ScopeStrategy: fosite.HierarchicScopeStrategy,
844 AudienceMatchingStrategy: fosite.DefaultAudienceMatchingStrategy,
845 TokenURL: "https://www.example.com/token",
846 SkipClientAuth: false,
847 JWTIDOptional: false,
848 JWTIssuedDateOptional: false,
849 JWTMaxDuration: time.Hour * 24 * 30,
850 HandleHelper: &oauth2.HandleHelper{
851 AccessTokenStrategy: s.mockAccessTokenStrategy,
852 AccessTokenStorage: s.mockAccessTokenStore,
853 AccessTokenLifespan: time.Hour,
854 },
855 }
856 }
857
858
859
860 func TestAuthorizeJWTGrantPopulateTokenEndpointTestSuite(t *testing.T) {
861 suite.Run(t, new(AuthorizeJWTGrantPopulateTokenEndpointTestSuite))
862 }
863
864 func (s *AuthorizeJWTGrantPopulateTokenEndpointTestSuite) TestRequestWithInvalidGrantType() {
865
866 s.accessRequest.GrantTypes = []string{"authorization_code"}
867
868
869 err := s.handler.PopulateTokenEndpointResponse(context.Background(), s.accessRequest, s.accessResponse)
870
871
872 s.True(errors.Is(err, fosite.ErrUnknownRequest))
873 s.EqualError(err, fosite.ErrUnknownRequest.Error(), "expected error, because of invalid grant type")
874 }
875
876 func (s *AuthorizeJWTGrantPopulateTokenEndpointTestSuite) TestClientIsNotRegisteredForGrantType() {
877
878 s.accessRequest.GrantTypes = []string{grantTypeJWTBearer}
879 s.accessRequest.Client = &fosite.DefaultClient{GrantTypes: []string{"authorization_code"}}
880 s.handler.SkipClientAuth = false
881
882
883 err := s.handler.PopulateTokenEndpointResponse(context.Background(), s.accessRequest, s.accessResponse)
884
885
886 s.True(errors.Is(err, fosite.ErrUnauthorizedClient))
887 s.EqualError(err, fosite.ErrUnauthorizedClient.Error(), "expected error, because client is not registered to use this grant type")
888 s.Equal(
889 "The OAuth 2.0 Client is not allowed to use authorization grant \"urn:ietf:params:oauth:grant-type:jwt-bearer\".",
890 err.(*fosite.RFC6749Error).HintField,
891 )
892 }
893
894 func (s *AuthorizeJWTGrantPopulateTokenEndpointTestSuite) TestAccessTokenIssuedSuccessfully() {
895
896 ctx := context.Background()
897 s.accessRequest.GrantTypes = []string{grantTypeJWTBearer}
898 token := "token"
899 sig := "sig"
900 s.mockAccessTokenStrategy.EXPECT().GenerateAccessToken(ctx, s.accessRequest).Return(token, sig, nil)
901 s.mockAccessTokenStore.EXPECT().CreateAccessTokenSession(ctx, sig, s.accessRequest.Sanitize([]string{}))
902
903
904 err := s.handler.PopulateTokenEndpointResponse(context.Background(), s.accessRequest, s.accessResponse)
905
906
907 s.NoError(err, "no error expected")
908 s.Equal(s.accessResponse.AccessToken, token, "access token expected in response")
909 s.Equal(s.accessResponse.TokenType, "bearer", "token type expected to be \"bearer\"")
910 s.Equal(
911 s.accessResponse.GetExtra("expires_in"), int64(s.handler.HandleHelper.AccessTokenLifespan.Seconds()),
912 "token expiration time expected in response to be equal to AccessTokenLifespan setting in handler",
913 )
914 s.Equal(s.accessResponse.GetExtra("scope"), "", "no scopes expected in response")
915 s.Nil(s.accessResponse.GetExtra("refresh_token"), "refresh token not expected in response")
916 }
917
View as plain text