xref: /aosp_15_r20/external/tink/cc/jwt/verified_jwt_test.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
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/verified_jwt.h"
18 
19 #include <memory>
20 #include <string>
21 #include <utility>
22 #include <vector>
23 
24 #include "gtest/gtest.h"
25 #include "absl/status/status.h"
26 #include "absl/strings/escaping.h"
27 #include "tink/jwt/internal/jwt_mac_impl.h"
28 #include "tink/jwt/internal/jwt_mac_internal.h"
29 #include "tink/jwt/jwt_mac.h"
30 #include "tink/jwt/jwt_validator.h"
31 #include "tink/jwt/raw_jwt.h"
32 #include "tink/subtle/hmac_boringssl.h"
33 #include "tink/util/constants.h"
34 #include "tink/util/enums.h"
35 #include "tink/util/errors.h"
36 #include "tink/util/protobuf_helper.h"
37 #include "tink/util/secret_data.h"
38 #include "tink/util/test_matchers.h"
39 #include "tink/util/test_util.h"
40 
41 using ::crypto::tink::test::IsOk;
42 using ::crypto::tink::test::IsOkAndHolds;
43 
44 namespace crypto {
45 namespace tink {
46 
47 namespace {
48 
CreateVerifiedJwt(const RawJwt & raw_jwt)49 util::StatusOr<VerifiedJwt> CreateVerifiedJwt(const RawJwt& raw_jwt) {
50   // Creating a VerifiedJwt is a bit complicated since it can only be created
51   // JWT primitives.
52   std::string key_value;
53   if (!absl::WebSafeBase64Unescape(
54           "AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1"
55           "qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow",
56           &key_value)) {
57     return util::Status(absl::StatusCode::kInvalidArgument,
58                         "failed to parse key");
59   }
60   crypto::tink::util::StatusOr<std::unique_ptr<Mac>> mac =
61       subtle::HmacBoringSsl::New(
62           util::Enums::ProtoToSubtle(google::crypto::tink::HashType::SHA256),
63           32, util::SecretDataFromStringView(key_value));
64   if (!mac.ok()) {
65     return mac.status();
66   }
67   std::unique_ptr<jwt_internal::JwtMacInternal> jwt_mac =
68       absl::make_unique<jwt_internal::JwtMacImpl>(std::move(*mac), "HS256",
69                                                   absl::nullopt);
70 
71   util::StatusOr<std::string> compact =
72       jwt_mac->ComputeMacAndEncodeWithKid(raw_jwt, "kid-123");
73   if (!compact.ok()) {
74     return compact.status();
75   }
76   JwtValidatorBuilder validator_builder = JwtValidatorBuilder()
77                                               .IgnoreTypeHeader()
78                                               .IgnoreIssuer()
79                                               .IgnoreAudiences()
80                                               .AllowMissingExpiration();
81   util::StatusOr<absl::Time> issued_at = raw_jwt.GetIssuedAt();
82   if (issued_at.ok()) {
83     validator_builder.SetFixedNow(*issued_at);
84   }
85   util::StatusOr<JwtValidator> validator = validator_builder.Build();
86   if (!validator.ok()) {
87     return validator.status();
88   }
89   return jwt_mac->VerifyMacAndDecodeWithKid(*compact, *validator, "kid-123");
90 }
91 
TEST(VerifiedJwt,GetTypeIssuerSubjectJwtIdOK)92 TEST(VerifiedJwt, GetTypeIssuerSubjectJwtIdOK) {
93   util::StatusOr<RawJwt> raw_jwt = RawJwtBuilder()
94                                           .SetTypeHeader("typeHeader")
95                                           .SetIssuer("issuer")
96                                           .SetSubject("subject")
97                                           .SetJwtId("jwt_id")
98                                           .WithoutExpiration()
99                                           .Build();
100   ASSERT_THAT(raw_jwt, IsOk());
101   util::StatusOr<crypto::tink::VerifiedJwt> jwt =
102       CreateVerifiedJwt(*raw_jwt);
103   ASSERT_THAT(jwt, IsOk());
104 
105   EXPECT_TRUE(jwt->HasTypeHeader());
106   EXPECT_THAT(jwt->GetTypeHeader(), IsOkAndHolds("typeHeader"));
107   EXPECT_TRUE(jwt->HasIssuer());
108   EXPECT_THAT(jwt->GetIssuer(), IsOkAndHolds("issuer"));
109   EXPECT_TRUE(jwt->HasSubject());
110   EXPECT_THAT(jwt->GetSubject(), IsOkAndHolds("subject"));
111   EXPECT_TRUE(jwt->HasJwtId());
112   EXPECT_THAT(jwt->GetJwtId(), IsOkAndHolds("jwt_id"));
113 }
114 
TEST(VerifiedJwt,TimestampsOK)115 TEST(VerifiedJwt, TimestampsOK) {
116   absl::Time now = absl::Now();
117   util::StatusOr<RawJwt> raw_jwt =
118       RawJwtBuilder()
119           .SetIssuer("issuer")
120           .SetNotBefore(now - absl::Seconds(300))
121           .SetIssuedAt(now)
122           .SetExpiration(now + absl::Seconds(300))
123           .Build();
124   ASSERT_THAT(raw_jwt, IsOk());
125   util::StatusOr<crypto::tink::VerifiedJwt> jwt = CreateVerifiedJwt(*raw_jwt);
126   ASSERT_THAT(jwt, IsOk());
127 
128   EXPECT_TRUE(jwt->HasNotBefore());
129   util::StatusOr<absl::Time> nbf = jwt->GetNotBefore();
130   ASSERT_THAT(nbf, IsOk());
131   EXPECT_LT(*nbf, now - absl::Seconds(299));
132   EXPECT_GT(*nbf, now - absl::Seconds(301));
133 
134   EXPECT_TRUE(jwt->HasIssuedAt());
135   util::StatusOr<absl::Time> iat = jwt->GetIssuedAt();
136   ASSERT_THAT(iat, IsOk());
137   EXPECT_LT(*iat, now + absl::Seconds(1));
138   EXPECT_GT(*iat, now - absl::Seconds(1));
139 
140   EXPECT_TRUE(jwt->HasExpiration());
141   util::StatusOr<absl::Time> exp = jwt->GetExpiration();
142   ASSERT_THAT(exp, IsOk());
143   EXPECT_LT(*exp, now + absl::Seconds(301));
144   EXPECT_GT(*exp, now + absl::Seconds(299));
145 }
146 
TEST(VerifiedJwt,GetAudiencesOK)147 TEST(VerifiedJwt, GetAudiencesOK) {
148   util::StatusOr<RawJwt> raw_jwt = RawJwtBuilder()
149                                           .AddAudience("audience1")
150                                           .AddAudience("audience2")
151                                           .WithoutExpiration()
152                                           .Build();
153   ASSERT_THAT(raw_jwt, IsOk());
154   util::StatusOr<VerifiedJwt> jwt = CreateVerifiedJwt(*raw_jwt);
155   ASSERT_THAT(jwt, IsOk());
156 
157   std::vector<std::string> expected = {"audience1", "audience2"};
158   EXPECT_TRUE(jwt->HasAudiences());
159   EXPECT_THAT(jwt->GetAudiences(), IsOkAndHolds(expected));
160 }
161 
TEST(VerifiedJwt,GetCustomClaimOK)162 TEST(VerifiedJwt, GetCustomClaimOK) {
163   util::StatusOr<RawJwt> raw_jwt =
164       RawJwtBuilder()
165           .WithoutExpiration()
166           .AddNullClaim("null_claim")
167           .AddBooleanClaim("boolean_claim", true)
168           .AddNumberClaim("number_claim", 123.456)
169           .AddStringClaim("string_claim", "a string")
170           .AddJsonObjectClaim("object_claim", R"({ "number": 123.456})")
171           .AddJsonArrayClaim("array_claim", R"([1, "one", 1.2, true])")
172           .Build();
173   ASSERT_THAT(raw_jwt, IsOk());
174   util::StatusOr<VerifiedJwt> jwt = CreateVerifiedJwt(*raw_jwt);
175   ASSERT_THAT(jwt, IsOk());
176 
177   EXPECT_TRUE(jwt->IsNullClaim("null_claim"));
178   EXPECT_TRUE(jwt->HasBooleanClaim("boolean_claim"));
179   EXPECT_THAT(jwt->GetBooleanClaim("boolean_claim"), IsOkAndHolds(true));
180   EXPECT_TRUE(jwt->HasNumberClaim("number_claim"));
181   EXPECT_THAT(jwt->GetNumberClaim("number_claim"), IsOkAndHolds(123.456));
182   EXPECT_TRUE(jwt->HasStringClaim("string_claim"));
183   EXPECT_THAT(jwt->GetStringClaim("string_claim"), IsOkAndHolds("a string"));
184   EXPECT_TRUE(jwt->HasJsonObjectClaim("object_claim"));
185   EXPECT_THAT(jwt->GetJsonObjectClaim("object_claim"),
186               IsOkAndHolds(R"({"number":123.456})"));
187   EXPECT_TRUE(jwt->HasJsonArrayClaim("array_claim"));
188   EXPECT_THAT(jwt->GetJsonArrayClaim("array_claim"),
189               IsOkAndHolds(R"([1,"one",1.2,true])"));
190 
191   std::vector<std::string> expected_claim_names = {
192       "object_claim", "number_claim", "boolean_claim",
193       "array_claim",  "null_claim",   "string_claim"};
194   EXPECT_THAT(jwt->CustomClaimNames(),
195               testing::UnorderedElementsAreArray(expected_claim_names));
196 }
197 
TEST(VerifiedJwt,HasCustomClaimIsFalseForWrongType)198 TEST(VerifiedJwt, HasCustomClaimIsFalseForWrongType) {
199   util::StatusOr<RawJwt> raw_jwt =
200       RawJwtBuilder()
201           .WithoutExpiration()
202           .AddNullClaim("null_claim")
203           .AddBooleanClaim("boolean_claim", true)
204           .AddNumberClaim("number_claim", 123.456)
205           .AddStringClaim("string_claim", "a string")
206           .Build();
207   ASSERT_THAT(raw_jwt, IsOk());
208   util::StatusOr<VerifiedJwt> jwt = CreateVerifiedJwt(*raw_jwt);
209   ASSERT_THAT(jwt, IsOk());
210 
211   EXPECT_FALSE(jwt->IsNullClaim("boolean_claim"));
212   EXPECT_FALSE(jwt->HasBooleanClaim("number_claim"));
213   EXPECT_FALSE(jwt->HasNumberClaim("string_claim"));
214   EXPECT_FALSE(jwt->HasStringClaim("null_claim"));
215 }
216 
TEST(VerifiedJwt,HasAlwaysReturnsFalseForRegisteredClaims)217 TEST(VerifiedJwt, HasAlwaysReturnsFalseForRegisteredClaims) {
218   absl::Time now = absl::Now();
219   util::StatusOr<RawJwt> raw_jwt =
220       RawJwtBuilder()
221           .SetIssuer("issuer")
222           .SetSubject("subject")
223           .SetJwtId("jwt_id")
224           .SetNotBefore(now - absl::Seconds(300))
225           .SetIssuedAt(now)
226           .SetExpiration(now + absl::Seconds(300))
227           .Build();
228   ASSERT_THAT(raw_jwt, IsOk());
229   util::StatusOr<VerifiedJwt> jwt = CreateVerifiedJwt(*raw_jwt);
230   ASSERT_THAT(jwt, IsOk());
231 
232   EXPECT_FALSE(jwt->HasStringClaim("iss"));
233   EXPECT_FALSE(jwt->HasStringClaim("sub"));
234   EXPECT_FALSE(jwt->HasStringClaim("jti"));
235   EXPECT_FALSE(jwt->HasNumberClaim("nbf"));
236   EXPECT_FALSE(jwt->HasNumberClaim("iat"));
237   EXPECT_FALSE(jwt->HasNumberClaim("exp"));
238 
239   EXPECT_THAT(jwt->CustomClaimNames(), testing::IsEmpty());
240 }
241 
TEST(VerifiedJwt,GetRegisteredCustomClaimNotOK)242 TEST(VerifiedJwt, GetRegisteredCustomClaimNotOK) {
243   absl::Time now = absl::Now();
244   util::StatusOr<RawJwt> raw_jwt =
245       RawJwtBuilder()
246           .SetIssuer("issuer")
247           .SetSubject("subject")
248           .SetJwtId("jwt_id")
249           .SetNotBefore(now - absl::Seconds(300))
250           .SetIssuedAt(now)
251           .SetExpiration(now + absl::Seconds(300))
252           .Build();
253   ASSERT_THAT(raw_jwt, IsOk());
254   util::StatusOr<VerifiedJwt> jwt = CreateVerifiedJwt(*raw_jwt);
255   ASSERT_THAT(jwt, IsOk());
256 
257   EXPECT_FALSE(jwt->GetStringClaim("iss").ok());
258   EXPECT_FALSE(jwt->GetStringClaim("sub").ok());
259   EXPECT_FALSE(jwt->GetStringClaim("jti").ok());
260   EXPECT_FALSE(jwt->GetNumberClaim("nbf").ok());
261   EXPECT_FALSE(jwt->GetNumberClaim("iat").ok());
262   EXPECT_FALSE(jwt->GetNumberClaim("exp").ok());
263 }
264 
TEST(VerifiedJwt,EmptyTokenHasAndIsReturnsFalse)265 TEST(VerifiedJwt, EmptyTokenHasAndIsReturnsFalse) {
266   util::StatusOr<RawJwt> raw_jwt =
267       RawJwtBuilder().WithoutExpiration().Build();
268   ASSERT_THAT(raw_jwt, IsOk());
269   util::StatusOr<VerifiedJwt> jwt = CreateVerifiedJwt(*raw_jwt);
270   ASSERT_THAT(jwt, IsOk());
271 
272   EXPECT_FALSE(jwt->HasTypeHeader());
273   EXPECT_FALSE(jwt->HasIssuer());
274   EXPECT_FALSE(jwt->HasSubject());
275   EXPECT_FALSE(jwt->HasAudiences());
276   EXPECT_FALSE(jwt->HasJwtId());
277   EXPECT_FALSE(jwt->HasExpiration());
278   EXPECT_FALSE(jwt->HasNotBefore());
279   EXPECT_FALSE(jwt->HasIssuedAt());
280   EXPECT_FALSE(jwt->IsNullClaim("null_claim"));
281   EXPECT_FALSE(jwt->HasBooleanClaim("boolean_claim"));
282   EXPECT_FALSE(jwt->HasNumberClaim("number_claim"));
283   EXPECT_FALSE(jwt->HasStringClaim("string_claim"));
284   EXPECT_FALSE(jwt->HasJsonObjectClaim("object_claim"));
285   EXPECT_FALSE(jwt->HasJsonArrayClaim("array_claim"));
286 }
287 
TEST(VerifiedJwt,EmptyTokenGetReturnsNotOK)288 TEST(VerifiedJwt, EmptyTokenGetReturnsNotOK) {
289   util::StatusOr<RawJwt> raw_jwt =
290       RawJwtBuilder().WithoutExpiration().Build();
291   ASSERT_THAT(raw_jwt, IsOk());
292   util::StatusOr<VerifiedJwt> jwt = CreateVerifiedJwt(*raw_jwt);
293   ASSERT_THAT(jwt, IsOk());
294 
295   EXPECT_FALSE(jwt->GetTypeHeader().ok());
296   EXPECT_FALSE(jwt->GetIssuer().ok());
297   EXPECT_FALSE(jwt->GetSubject().ok());
298   EXPECT_FALSE(jwt->GetAudiences().ok());
299   EXPECT_FALSE(jwt->GetJwtId().ok());
300   EXPECT_FALSE(jwt->GetExpiration().ok());
301   EXPECT_FALSE(jwt->GetNotBefore().ok());
302   EXPECT_FALSE(jwt->GetIssuedAt().ok());
303   EXPECT_FALSE(jwt->IsNullClaim("null_claim"));
304   EXPECT_FALSE(jwt->GetBooleanClaim("boolean_claim").ok());
305   EXPECT_FALSE(jwt->GetNumberClaim("number_claim").ok());
306   EXPECT_FALSE(jwt->GetStringClaim("string_claim").ok());
307   EXPECT_FALSE(jwt->GetJsonObjectClaim("object_claim").ok());
308   EXPECT_FALSE(jwt->GetJsonArrayClaim("array_claim").ok());
309 }
310 
TEST(VerifiedJwt,GetJsonPayload)311 TEST(VerifiedJwt, GetJsonPayload) {
312   util::StatusOr<RawJwt> raw_jwt =
313       RawJwtBuilder().SetIssuer("issuer").WithoutExpiration().Build();
314   ASSERT_THAT(raw_jwt, IsOk());
315   util::StatusOr<VerifiedJwt> jwt = CreateVerifiedJwt(*raw_jwt);
316   ASSERT_THAT(jwt, IsOk());
317 
318   EXPECT_THAT(jwt->GetJsonPayload(), IsOkAndHolds(R"({"iss":"issuer"})"));
319 }
320 
TEST(VerifiedJwt,MoveMakesCopy)321 TEST(VerifiedJwt, MoveMakesCopy) {
322   util::StatusOr<RawJwt> raw_jwt =
323       RawJwtBuilder().SetIssuer("issuer").WithoutExpiration().Build();
324   ASSERT_THAT(raw_jwt, IsOk());
325   util::StatusOr<VerifiedJwt> jwt = CreateVerifiedJwt(*raw_jwt);
326   ASSERT_THAT(jwt, IsOk());
327   VerifiedJwt jwt1 = *jwt;
328   VerifiedJwt jwt2 = std::move(jwt1);
329   // We want that a VerifiedJwt object remains a valid object, even after
330   // std::moved has been called.
331   EXPECT_TRUE(jwt1.HasIssuer());  // NOLINT(bugprone-use-after-move)
332   EXPECT_THAT(jwt1.GetIssuer(), IsOkAndHolds("issuer"));
333   EXPECT_TRUE(jwt2.HasIssuer());
334   EXPECT_THAT(jwt2.GetIssuer(), IsOkAndHolds("issuer"));
335 }
336 
337 }  // namespace
338 
339 }  // namespace tink
340 }  // namespace crypto
341