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