1 // Copyright 2021 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 ////////////////////////////////////////////////////////////////////////////////
16
17 #include "tink/jwt/jwt_validator.h"
18
19
20 #include "tink/jwt/raw_jwt.h"
21 #include "gtest/gtest.h"
22 #include "absl/strings/escaping.h"
23 #include "tink/util/test_matchers.h"
24 #include "tink/util/test_util.h"
25
26 using ::crypto::tink::test::IsOk;
27
28 namespace crypto {
29 namespace tink {
30
TEST(JwtValidator,ExpiredTokenNotOK)31 TEST(JwtValidator, ExpiredTokenNotOK) {
32 absl::Time now = absl::Now();
33 util::StatusOr<RawJwt> jwt =
34 RawJwtBuilder().SetExpiration(now - absl::Seconds(100)).Build();
35 ASSERT_THAT(jwt, IsOk());
36
37 util::StatusOr<JwtValidator> validator = JwtValidatorBuilder().Build();
38 ASSERT_THAT(validator, IsOk());
39 EXPECT_FALSE(validator->Validate(*jwt).ok());
40 }
41
TEST(JwtValidator,NotExpiredTokenOK)42 TEST(JwtValidator, NotExpiredTokenOK) {
43 absl::Time now = absl::Now();
44 util::StatusOr<RawJwt> jwt =
45 RawJwtBuilder().SetExpiration(now + absl::Seconds(100)).Build();
46 ASSERT_THAT(jwt, IsOk());
47
48 util::StatusOr<JwtValidator> validator = JwtValidatorBuilder().Build();
49 ASSERT_THAT(validator, IsOk());
50 EXPECT_THAT(validator->Validate(*jwt), IsOk());
51 }
52
TEST(JwtValidator,TokenWithExpEqualToNowIsExpired)53 TEST(JwtValidator, TokenWithExpEqualToNowIsExpired) {
54 absl::Time now = absl::FromUnixSeconds(12345);
55 util::StatusOr<RawJwt> jwt = RawJwtBuilder().SetExpiration(now).Build();
56 ASSERT_THAT(jwt, IsOk());
57
58 util::StatusOr<JwtValidator> validator =
59 JwtValidatorBuilder().SetFixedNow(now).Build();
60 ASSERT_THAT(validator, IsOk());
61 EXPECT_FALSE(validator->Validate(*jwt).ok());
62 }
63
TEST(JwtValidator,ClockSkewIsToLarge)64 TEST(JwtValidator, ClockSkewIsToLarge) {
65 EXPECT_FALSE(
66 JwtValidatorBuilder().SetClockSkew(absl::Minutes(11)).Build().ok());
67 }
68
TEST(JwtValidator,RecentlyExpiredTokenWithClockSkewOK)69 TEST(JwtValidator, RecentlyExpiredTokenWithClockSkewOK) {
70 absl::Time now = absl::Now();
71 util::StatusOr<RawJwt> jwt =
72 RawJwtBuilder().SetExpiration(now - absl::Seconds(100)).Build();
73 ASSERT_THAT(jwt, IsOk());
74
75 util::StatusOr<JwtValidator> validator =
76 JwtValidatorBuilder().SetClockSkew(absl::Seconds(200)).Build();
77 ASSERT_THAT(validator, IsOk());
78 EXPECT_THAT(validator->Validate(*jwt), IsOk());
79 }
80
TEST(JwtValidator,NotBeforeInTheFutureNotOK)81 TEST(JwtValidator, NotBeforeInTheFutureNotOK) {
82 absl::Time now = absl::Now();
83 util::StatusOr<RawJwt> jwt = RawJwtBuilder()
84 .SetNotBefore(now + absl::Seconds(100))
85 .WithoutExpiration()
86 .Build();
87 ASSERT_THAT(jwt, IsOk());
88
89 util::StatusOr<JwtValidator> validator =
90 JwtValidatorBuilder().AllowMissingExpiration().Build();
91 ASSERT_THAT(validator, IsOk());
92 EXPECT_FALSE(validator->Validate(*jwt).ok());
93 }
94
TEST(JwtValidator,NotBeforeInThePastOK)95 TEST(JwtValidator, NotBeforeInThePastOK) {
96 absl::Time now = absl::Now();
97 util::StatusOr<RawJwt> jwt = RawJwtBuilder()
98 .SetNotBefore(now - absl::Seconds(100))
99 .WithoutExpiration()
100 .Build();
101 ASSERT_THAT(jwt, IsOk());
102
103 util::StatusOr<JwtValidator> validator =
104 JwtValidatorBuilder().AllowMissingExpiration().Build();
105 ASSERT_THAT(validator, IsOk());
106 EXPECT_THAT(validator->Validate(*jwt), IsOk());
107 }
108
TEST(JwtValidator,TokenWithNotBeforeEqualToNowIsValid)109 TEST(JwtValidator, TokenWithNotBeforeEqualToNowIsValid) {
110 absl::Time now = absl::FromUnixSeconds(12345);
111 util::StatusOr<RawJwt> jwt =
112 RawJwtBuilder().SetNotBefore(now).WithoutExpiration().Build();
113 ASSERT_THAT(jwt, IsOk());
114
115 util::StatusOr<JwtValidator> validator =
116 JwtValidatorBuilder().SetFixedNow(now).AllowMissingExpiration().Build();
117 ASSERT_THAT(validator, IsOk());
118 EXPECT_THAT(validator->Validate(*jwt), IsOk());
119 }
120
TEST(JwtValidator,NotBeforeInTheNearFutureWithClockSkewOK)121 TEST(JwtValidator, NotBeforeInTheNearFutureWithClockSkewOK) {
122 absl::Time now = absl::Now();
123 util::StatusOr<RawJwt> jwt = RawJwtBuilder()
124 .SetNotBefore(now + absl::Seconds(100))
125 .WithoutExpiration()
126 .Build();
127 ASSERT_THAT(jwt, IsOk());
128
129 util::StatusOr<JwtValidator> validator = JwtValidatorBuilder()
130 .AllowMissingExpiration()
131 .SetClockSkew(absl::Seconds(200))
132 .Build();
133 ASSERT_THAT(validator, IsOk());
134 EXPECT_THAT(validator->Validate(*jwt), IsOk());
135 }
136
TEST(JwtValidator,IssuedAt)137 TEST(JwtValidator, IssuedAt) {
138 absl::Time now = absl::Now();
139 util::StatusOr<RawJwt> tokenIssuedInTheFuture = RawJwtBuilder()
140 .SetIssuedAt(now + absl::Seconds(100))
141 .WithoutExpiration()
142 .Build();
143 ASSERT_THAT(tokenIssuedInTheFuture, IsOk());
144 util::StatusOr<RawJwt> tokenIssuedInThePast = RawJwtBuilder()
145 .SetIssuedAt(now - absl::Seconds(100))
146 .WithoutExpiration()
147 .Build();
148 ASSERT_THAT(tokenIssuedInThePast, IsOk());
149 util::StatusOr<RawJwt> tokenWithoutIssuedAt = RawJwtBuilder()
150 .WithoutExpiration()
151 .Build();
152 ASSERT_THAT(tokenWithoutIssuedAt, IsOk());
153
154 util::StatusOr<JwtValidator> validator = JwtValidatorBuilder()
155 .AllowMissingExpiration()
156 .Build();
157 ASSERT_THAT(validator, IsOk());
158 EXPECT_THAT(validator->Validate(*tokenIssuedInTheFuture), IsOk());
159 EXPECT_THAT(validator->Validate(*tokenIssuedInThePast), IsOk());
160 EXPECT_THAT(validator->Validate(*tokenWithoutIssuedAt), IsOk());
161
162 util::StatusOr<JwtValidator> issued_at_validator =
163 JwtValidatorBuilder()
164 .ExpectIssuedInThePast()
165 .AllowMissingExpiration()
166 .Build();
167 ASSERT_THAT(issued_at_validator, IsOk());
168 EXPECT_FALSE(issued_at_validator->Validate(*tokenIssuedInTheFuture).ok());
169 EXPECT_THAT(issued_at_validator->Validate(*tokenIssuedInThePast), IsOk());
170 EXPECT_FALSE(issued_at_validator->Validate(*tokenWithoutIssuedAt).ok());
171 }
172
TEST(JwtValidator,IssuedAtWithClockSkew)173 TEST(JwtValidator, IssuedAtWithClockSkew) {
174 absl::Time now = absl::Now();
175 util::StatusOr<RawJwt> tokenOneMinuteInTheFuture = RawJwtBuilder()
176 .SetIssuedAt(now + absl::Minutes(1))
177 .WithoutExpiration()
178 .Build();
179 ASSERT_THAT(tokenOneMinuteInTheFuture, IsOk());
180
181 util::StatusOr<JwtValidator> validator_without_clock_skew =
182 JwtValidatorBuilder()
183 .ExpectIssuedInThePast()
184 .AllowMissingExpiration()
185 .Build();
186 ASSERT_THAT(validator_without_clock_skew, IsOk());
187 EXPECT_FALSE(
188 validator_without_clock_skew->Validate(*tokenOneMinuteInTheFuture).ok());
189
190 util::StatusOr<JwtValidator> validator_with_clock_skew =
191 JwtValidatorBuilder()
192 .ExpectIssuedInThePast()
193 .AllowMissingExpiration()
194 .SetClockSkew(absl::Minutes(2))
195 .Build();
196 ASSERT_THAT(validator_with_clock_skew, IsOk());
197 EXPECT_THAT(validator_with_clock_skew->Validate(*tokenOneMinuteInTheFuture),
198 IsOk());
199 }
200
TEST(JwtValidator,RequiresTypeHeaderButNotTypHeaderNotOK)201 TEST(JwtValidator, RequiresTypeHeaderButNotTypHeaderNotOK) {
202 util::StatusOr<RawJwt> jwt = RawJwtBuilder().WithoutExpiration().Build();
203 ASSERT_THAT(jwt, IsOk());
204
205 util::StatusOr<JwtValidator> validator =
206 JwtValidatorBuilder().ExpectTypeHeader("typeHeader").Build();
207 ASSERT_THAT(validator, IsOk());
208 EXPECT_FALSE(validator->Validate(*jwt).ok());
209 }
210
TEST(JwtValidator,InvalidTypeHeaderNotOK)211 TEST(JwtValidator, InvalidTypeHeaderNotOK) {
212 util::StatusOr<RawJwt> jwt =
213 RawJwtBuilder().SetTypeHeader("unknown").WithoutExpiration().Build();
214 ASSERT_THAT(jwt, IsOk());
215
216 util::StatusOr<JwtValidator> validator = JwtValidatorBuilder()
217 .ExpectTypeHeader("JWT")
218 .AllowMissingExpiration()
219 .Build();
220 ASSERT_THAT(validator, IsOk());
221 EXPECT_FALSE(validator->Validate(*jwt).ok());
222 }
223
TEST(JwtValidator,CorrectTypeHeaderOK)224 TEST(JwtValidator, CorrectTypeHeaderOK) {
225 util::StatusOr<RawJwt> jwt =
226 RawJwtBuilder().SetTypeHeader("typeHeader").WithoutExpiration().Build();
227 ASSERT_THAT(jwt, IsOk());
228
229 util::StatusOr<JwtValidator> validator = JwtValidatorBuilder()
230 .ExpectTypeHeader("typeHeader")
231 .AllowMissingExpiration()
232 .Build();
233 ASSERT_THAT(validator, IsOk());
234 EXPECT_THAT(validator->Validate(*jwt), IsOk());
235 }
236
TEST(JwtValidator,TypeHeaderInTokenButNotInValiatorNotOK)237 TEST(JwtValidator, TypeHeaderInTokenButNotInValiatorNotOK) {
238 util::StatusOr<RawJwt> jwt =
239 RawJwtBuilder().SetTypeHeader("typeHeader").WithoutExpiration().Build();
240 ASSERT_THAT(jwt, IsOk());
241
242 util::StatusOr<JwtValidator> validator =
243 JwtValidatorBuilder().AllowMissingExpiration().Build();
244 ASSERT_THAT(validator, IsOk());
245 EXPECT_FALSE(validator->Validate(*jwt).ok());
246 }
247
TEST(JwtValidator,IgnoreTypeHeaderOK)248 TEST(JwtValidator, IgnoreTypeHeaderOK) {
249 util::StatusOr<RawJwt> jwt =
250 RawJwtBuilder().SetTypeHeader("typeHeader").WithoutExpiration().Build();
251 ASSERT_THAT(jwt, IsOk());
252
253 util::StatusOr<JwtValidator> validator =
254 JwtValidatorBuilder().IgnoreTypeHeader().AllowMissingExpiration().Build();
255 ASSERT_THAT(validator, IsOk());
256 EXPECT_THAT(validator->Validate(*jwt), IsOk());
257 }
258
TEST(JwtValidator,RequiresIssuerButNotIssuerNotOK)259 TEST(JwtValidator, RequiresIssuerButNotIssuerNotOK) {
260 util::StatusOr<RawJwt> jwt = RawJwtBuilder().WithoutExpiration().Build();
261 ASSERT_THAT(jwt, IsOk());
262
263 util::StatusOr<JwtValidator> validator = JwtValidatorBuilder()
264 .ExpectIssuer("issuer")
265 .AllowMissingExpiration()
266 .Build();
267 ASSERT_THAT(validator, IsOk());
268 EXPECT_FALSE(validator->Validate(*jwt).ok());
269 }
270
TEST(JwtValidator,InvalidIssuerNotOK)271 TEST(JwtValidator, InvalidIssuerNotOK) {
272 util::StatusOr<RawJwt> jwt =
273 RawJwtBuilder().SetIssuer("unknown").WithoutExpiration().Build();
274 ASSERT_THAT(jwt, IsOk());
275
276 util::StatusOr<JwtValidator> validator = JwtValidatorBuilder()
277 .ExpectIssuer("issuer")
278 .AllowMissingExpiration()
279 .Build();
280 ASSERT_THAT(validator, IsOk());
281 EXPECT_FALSE(validator->Validate(*jwt).ok());
282 }
283
TEST(JwtValidator,CorrectIssuerOK)284 TEST(JwtValidator, CorrectIssuerOK) {
285 util::StatusOr<RawJwt> jwt =
286 RawJwtBuilder().SetIssuer("issuer").WithoutExpiration().Build();
287 ASSERT_THAT(jwt, IsOk());
288
289 util::StatusOr<JwtValidator> validator = JwtValidatorBuilder()
290 .ExpectIssuer("issuer")
291 .AllowMissingExpiration()
292 .Build();
293 ASSERT_THAT(validator, IsOk());
294 EXPECT_THAT(validator->Validate(*jwt), IsOk());
295 }
296
TEST(JwtValidator,IssuerInTokenButNotInValiatorNotOK)297 TEST(JwtValidator, IssuerInTokenButNotInValiatorNotOK) {
298 util::StatusOr<RawJwt> jwt =
299 RawJwtBuilder().SetIssuer("issuer").WithoutExpiration().Build();
300 ASSERT_THAT(jwt, IsOk());
301
302 util::StatusOr<JwtValidator> validator =
303 JwtValidatorBuilder().AllowMissingExpiration().Build();
304 ASSERT_THAT(validator, IsOk());
305 EXPECT_FALSE(validator->Validate(*jwt).ok());
306 }
307
TEST(JwtValidator,IgnoreIssuerOK)308 TEST(JwtValidator, IgnoreIssuerOK) {
309 util::StatusOr<RawJwt> jwt =
310 RawJwtBuilder().SetIssuer("issuer").WithoutExpiration().Build();
311 ASSERT_THAT(jwt, IsOk());
312
313 util::StatusOr<JwtValidator> validator =
314 JwtValidatorBuilder().IgnoreIssuer().AllowMissingExpiration().Build();
315 ASSERT_THAT(validator, IsOk());
316 EXPECT_THAT(validator->Validate(*jwt), IsOk());
317 }
318
TEST(JwtValidator,RequiresAudienceButNotAudienceNotOK)319 TEST(JwtValidator, RequiresAudienceButNotAudienceNotOK) {
320 util::StatusOr<RawJwt> jwt = RawJwtBuilder().WithoutExpiration().Build();
321 ASSERT_THAT(jwt, IsOk());
322
323 util::StatusOr<JwtValidator> validator = JwtValidatorBuilder()
324 .ExpectAudience("audience")
325 .AllowMissingExpiration()
326 .Build();
327 ASSERT_THAT(validator, IsOk());
328 EXPECT_FALSE(validator->Validate(*jwt).ok());
329 }
330
TEST(JwtValidator,InvalidAudienceNotOK)331 TEST(JwtValidator, InvalidAudienceNotOK) {
332 util::StatusOr<RawJwt> jwt =
333 RawJwtBuilder().SetSubject("unknown").WithoutExpiration().Build();
334 ASSERT_THAT(jwt, IsOk());
335
336 util::StatusOr<JwtValidator> validator = JwtValidatorBuilder()
337 .ExpectAudience("audience")
338 .AllowMissingExpiration()
339 .Build();
340 ASSERT_THAT(validator, IsOk());
341 EXPECT_FALSE(validator->Validate(*jwt).ok());
342 }
343
TEST(JwtValidator,CorrectAudienceOK)344 TEST(JwtValidator, CorrectAudienceOK) {
345 util::StatusOr<RawJwt> jwt = RawJwtBuilder()
346 .AddAudience("otherAudience")
347 .AddAudience("audience")
348 .WithoutExpiration()
349 .Build();
350 ASSERT_THAT(jwt, IsOk());
351
352 util::StatusOr<JwtValidator> validator = JwtValidatorBuilder()
353 .ExpectAudience("audience")
354 .AllowMissingExpiration()
355 .Build();
356 ASSERT_THAT(validator, IsOk());
357 EXPECT_THAT(validator->Validate(*jwt), IsOk());
358 }
359
TEST(JwtValidator,AudienceInTokenButNotInValiatorNotOK)360 TEST(JwtValidator, AudienceInTokenButNotInValiatorNotOK) {
361 util::StatusOr<RawJwt> jwt =
362 RawJwtBuilder().AddAudience("audience").WithoutExpiration().Build();
363 ASSERT_THAT(jwt, IsOk());
364
365 util::StatusOr<JwtValidator> validator =
366 JwtValidatorBuilder().AllowMissingExpiration().Build();
367 ASSERT_THAT(validator, IsOk());
368 EXPECT_FALSE(validator->Validate(*jwt).ok());
369 }
370
TEST(JwtValidator,NoAudienceOK)371 TEST(JwtValidator, NoAudienceOK) {
372 util::StatusOr<RawJwt> jwt = RawJwtBuilder().WithoutExpiration().Build();
373 ASSERT_THAT(jwt, IsOk());
374
375 util::StatusOr<JwtValidator> validator =
376 JwtValidatorBuilder().AllowMissingExpiration().Build();
377 ASSERT_THAT(validator, IsOk());
378 EXPECT_THAT(validator->Validate(*jwt), IsOk());
379 }
380
TEST(JwtValidator,IgnoreAudiencesOK)381 TEST(JwtValidator, IgnoreAudiencesOK) {
382 util::StatusOr<RawJwt> jwt =
383 RawJwtBuilder().AddAudience("audience").WithoutExpiration().Build();
384 ASSERT_THAT(jwt, IsOk());
385
386 util::StatusOr<JwtValidator> validator =
387 JwtValidatorBuilder().IgnoreAudiences().AllowMissingExpiration().Build();
388 ASSERT_THAT(validator, IsOk());
389 EXPECT_THAT(validator->Validate(*jwt), IsOk());
390 }
391
TEST(JwtValidator,FixedNowExpiredNotOk)392 TEST(JwtValidator, FixedNowExpiredNotOk) {
393 absl::Time now = absl::Now();
394 util::StatusOr<RawJwt> jwt =
395 RawJwtBuilder().SetExpiration(now + absl::Seconds(100)).Build();
396 ASSERT_THAT(jwt, IsOk());
397
398 util::StatusOr<JwtValidator> validator =
399 JwtValidatorBuilder()
400 .SetFixedNow(now + absl::Seconds(200))
401 .AllowMissingExpiration()
402 .Build();
403 ASSERT_THAT(validator, IsOk());
404 EXPECT_FALSE(validator->Validate(*jwt).ok());
405 }
406
TEST(JwtValidator,FixedNowNotYetValidNotOk)407 TEST(JwtValidator, FixedNowNotYetValidNotOk) {
408 absl::Time now = absl::Now();
409 util::StatusOr<RawJwt> jwt = RawJwtBuilder()
410 .SetNotBefore(now - absl::Seconds(100))
411 .WithoutExpiration()
412 .Build();
413 ASSERT_THAT(jwt, IsOk());
414
415 util::StatusOr<JwtValidator> validator =
416 JwtValidatorBuilder()
417 .SetFixedNow(now - absl::Seconds(200))
418 .AllowMissingExpiration()
419 .Build();
420 ASSERT_THAT(validator, IsOk());
421 EXPECT_FALSE(validator->Validate(*jwt).ok());
422 }
423
TEST(JwtValidator,FixedNowValidOk)424 TEST(JwtValidator, FixedNowValidOk) {
425 absl::Time now = absl::FromUnixSeconds(12345);
426 util::StatusOr<RawJwt> jwt = RawJwtBuilder()
427 .SetExpiration(now + absl::Seconds(100))
428 .SetNotBefore(now - absl::Seconds(100))
429 .Build();
430 ASSERT_THAT(jwt, IsOk());
431
432 util::StatusOr<JwtValidator> validator =
433 JwtValidatorBuilder().SetFixedNow(now).Build();
434 ASSERT_THAT(validator, IsOk());
435 EXPECT_THAT(validator->Validate(*jwt), IsOk());
436 }
437
TEST(JwtValidator,CallBuildTwiceOk)438 TEST(JwtValidator, CallBuildTwiceOk) {
439 JwtValidatorBuilder builder = JwtValidatorBuilder().AllowMissingExpiration();
440
441 builder.ExpectIssuer("issuer1");
442 util::StatusOr<JwtValidator> validator1 = builder.Build();
443 ASSERT_THAT(validator1, IsOk());
444
445 builder.ExpectIssuer("issuer2");
446 util::StatusOr<JwtValidator> validator2 = builder.Build();
447 ASSERT_THAT(validator2, IsOk());
448
449 util::StatusOr<RawJwt> jwt1 =
450 RawJwtBuilder().SetIssuer("issuer1").WithoutExpiration().Build();
451 ASSERT_THAT(jwt1, IsOk());
452 util::StatusOr<RawJwt> jwt2 =
453 RawJwtBuilder().SetIssuer("issuer2").WithoutExpiration().Build();
454 ASSERT_THAT(jwt2, IsOk());
455
456 EXPECT_THAT(validator1->Validate(*jwt1), IsOk());
457 EXPECT_FALSE(validator1->Validate(*jwt2).ok());
458 EXPECT_THAT(validator2->Validate(*jwt2), IsOk());
459 EXPECT_FALSE(validator2->Validate(*jwt1).ok());
460 }
461
TEST(JwtValidator,InvalidValidators)462 TEST(JwtValidator, InvalidValidators) {
463 EXPECT_FALSE(JwtValidatorBuilder()
464 .ExpectTypeHeader("a")
465 .IgnoreTypeHeader()
466 .AllowMissingExpiration()
467 .Build()
468 .ok());
469 EXPECT_FALSE(JwtValidatorBuilder()
470 .ExpectIssuer("a")
471 .IgnoreIssuer()
472 .AllowMissingExpiration()
473 .Build()
474 .ok());
475 EXPECT_FALSE(JwtValidatorBuilder()
476 .ExpectAudience("a")
477 .IgnoreAudiences()
478 .AllowMissingExpiration()
479 .Build()
480 .ok());
481 }
482
483
484 } // namespace tink
485 } // namespace crypto
486