1 //
2 //
3 // Copyright 2015 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18
19 #include "src/core/lib/security/credentials/jwt/jwt_verifier.h"
20
21 #include <grpc/grpc.h>
22 #include <grpc/slice.h>
23 #include <grpc/support/alloc.h>
24 #include <grpc/support/string_util.h>
25 #include <gtest/gtest.h>
26 #include <string.h>
27
28 #include "absl/strings/escaping.h"
29 #include "src/core/lib/security/credentials/jwt/json_token.h"
30 #include "src/core/util/crash.h"
31 #include "src/core/util/http_client/httpcli.h"
32 #include "src/core/util/json/json_reader.h"
33 #include "test/core/test_util/test_config.h"
34
35 using grpc_core::Json;
36
37 // This JSON key was generated with the GCE console and revoked immediately.
38 // The identifiers have been changed as well.
39 // Maximum size for a string literal is 509 chars in C89, yay!
40 static const char json_key_str_part1[] =
41 "{ \"private_key\": \"-----BEGIN PRIVATE KEY-----"
42 "\\nMIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAOEvJsnoHnyHkXcp\\n7mJE"
43 "qg"
44 "WGjiw71NfXByguekSKho65FxaGbsnSM9SMQAqVk7Q2rG+I0OpsT0LrWQtZ\\nyjSeg/"
45 "rWBQvS4hle4LfijkP3J5BG+"
46 "IXDMP8RfziNRQsenAXDNPkY4kJCvKux2xdD\\nOnVF6N7dL3nTYZg+"
47 "uQrNsMTz9UxVAgMBAAECgYEAzbLewe1xe9vy+2GoSsfib+28\\nDZgSE6Bu/"
48 "zuFoPrRc6qL9p2SsnV7txrunTyJkkOnPLND9ABAXybRTlcVKP/sGgza\\n/"
49 "8HpCqFYM9V8f34SBWfD4fRFT+n/"
50 "73cfRUtGXdXpseva2lh8RilIQfPhNZAncenU\\ngqXjDvpkypEusgXAykECQQD+";
51 static const char json_key_str_part2[] =
52 "53XxNVnxBHsYb+AYEfklR96yVi8HywjVHP34+OQZ\\nCslxoHQM8s+"
53 "dBnjfScLu22JqkPv04xyxmt0QAKm9+vTdAkEA4ib7YvEAn2jXzcCI\\nEkoy2L/"
54 "XydR1GCHoacdfdAwiL2npOdnbvi4ZmdYRPY1LSTO058tQHKVXV7NLeCa3\\nAARh2QJBAMKeDA"
55 "G"
56 "W303SQv2cZTdbeaLKJbB5drz3eo3j7dDKjrTD9JupixFbzcGw\\n8FZi5c8idxiwC36kbAL6Hz"
57 "A"
58 "ZoX+ofI0CQE6KCzPJTtYNqyShgKAZdJ8hwOcvCZtf\\n6z8RJm0+"
59 "6YBd38lfh5j8mZd7aHFf6I17j5AQY7oPEc47TjJj/"
60 "5nZ68ECQQDvYuI3\\nLyK5fS8g0SYbmPOL9TlcHDOqwG0mrX9qpg5DC2fniXNSrrZ64GTDKdzZ"
61 "Y"
62 "Ap6LI9W\\nIqv4vr6y38N79TTC\\n-----END PRIVATE KEY-----\\n\", ";
63 static const char json_key_str_part3_for_google_email_issuer[] =
64 "\"private_key_id\": \"e6b5137873db8d2ef81e06a47289e6434ec8a165\", "
65 "\"client_email\": "
66 "\"777-abaslkan11hlb6nmim3bpspl31ud@developer.gserviceaccount."
67 "com\", \"client_id\": "
68 "\"777-abaslkan11hlb6nmim3bpspl31ud.apps.googleusercontent."
69 "com\", \"type\": \"service_account\" }";
70 // Trick our JWT library into issuing a JWT with iss=accounts.google.com.
71 static const char json_key_str_part3_for_url_issuer[] =
72 "\"private_key_id\": \"e6b5137873db8d2ef81e06a47289e6434ec8a165\", "
73 "\"client_email\": \"accounts.google.com\", "
74 "\"client_id\": "
75 "\"777-abaslkan11hlb6nmim3bpspl31ud.apps.googleusercontent."
76 "com\", \"type\": \"service_account\" }";
77 static const char json_key_str_part3_for_custom_email_issuer[] =
78 "\"private_key_id\": \"e6b5137873db8d2ef81e06a47289e6434ec8a165\", "
79 "\"client_email\": "
80 "\"foo@bar.com\", \"client_id\": "
81 "\"777-abaslkan11hlb6nmim3bpspl31ud.apps.googleusercontent."
82 "com\", \"type\": \"service_account\" }";
83
84 static grpc_jwt_verifier_email_domain_key_url_mapping custom_mapping = {
85 "bar.com", "keys.bar.com/jwk"};
86
87 static const char expected_user_data[] = "user data";
88
89 static const char good_jwk_set[] =
90 "{"
91 " \"keys\": ["
92 " {"
93 " \"kty\": \"RSA\","
94 " \"alg\": \"RS256\","
95 " \"use\": \"sig\","
96 " \"kid\": \"e6b5137873db8d2ef81e06a47289e6434ec8a165\","
97 " \"n\": "
98 "\"4S8myegefIeRdynuYkSqBYaOLDvU19cHKC56RIqGjrkXFoZuydIz1IxACpWTtDasb4jQ6mxP"
99 "QutZC1nKNJ6D-tYFC9LiGV7gt-KOQ_cnkEb4hcMw_xF_OI1FCx6cBcM0-"
100 "RjiQkK8q7HbF0M6dUXo3t0vedNhmD65Cs2wxPP1TFU=\","
101 " \"e\": \"AQAB\""
102 " }"
103 " ]"
104 "}";
105
106 static gpr_timespec expected_lifetime = {3600, 0, GPR_TIMESPAN};
107
108 static const char good_google_email_keys_part1[] =
109 "{\"e6b5137873db8d2ef81e06a47289e6434ec8a165\": \"-----BEGIN "
110 "CERTIFICATE-----"
111 "\\nMIICATCCAWoCCQDEywLhxvHjnDANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB\\nVTET"
112 "MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0\\ncyBQdHkgTHR"
113 "kMB4XDTE1MDYyOTA4Mzk1MFoXDTI1MDYyNjA4Mzk1MFowRTELMAkG\\nA1UEBhMCQVUxEzARBg"
114 "NVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0\\nIFdpZGdpdHMgUHR5IEx0ZDCBn"
115 "zANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4S8m\\nyegefIeRdynuYkSqBYaOLDvU19cHKC56"
116 "RIqGjrkXFoZuydIz1IxACpWTtDasb4jQ\\n6mxPQutZC1nKNJ6D+tYFC9LiGV7gt+KOQ/";
117
118 static const char good_google_email_keys_part2[] =
119 "cnkEb4hcMw/xF/OI1FCx6cBcM0+"
120 "Rji\\nQkK8q7HbF0M6dUXo3t0vedNhmD65Cs2wxPP1TFUCAwEAATANBgkqhkiG9w0BAQsF\\nA"
121 "AOBgQBfu69FkPmBknbKNFgurPz78kbs3VNN+k/"
122 "PUgO5DHKskJmgK2TbtvX2VMpx\\nkftmHGzgzMzUlOtigCaGMgHWjfqjpP9uuDbahXrZBJzB8c"
123 "Oq7MrQF8r17qVvo3Ue\\nPjTKQMAsU8uxTEMmeuz9L6yExs0rfd6bPOrQkAoVfFfiYB3/"
124 "pA==\\n-----END CERTIFICATE-----\\n\"}";
125
126 static const char expected_audience[] = "https://foo.com";
127
128 static const char good_openid_config[] =
129 "{"
130 " \"issuer\": \"https://accounts.google.com\","
131 " \"authorization_endpoint\": "
132 "\"https://accounts.google.com/o/oauth2/v2/auth\","
133 " \"token_endpoint\": \"https://oauth2.googleapis.com/token\","
134 " \"userinfo_endpoint\": \"https://www.googleapis.com/oauth2/v3/userinfo\","
135 " \"revocation_endpoint\": \"https://oauth2.googleapis.com/revoke\","
136 " \"jwks_uri\": \"https://www.googleapis.com/oauth2/v3/certs\""
137 "}";
138
139 static const char expired_claims[] =
140 "{ \"aud\": \"https://foo.com\","
141 " \"iss\": \"blah.foo.com\","
142 " \"sub\": \"juju@blah.foo.com\","
143 " \"jti\": \"jwtuniqueid\","
144 " \"iat\": 100," // Way back in the past...
145 " \"exp\": 120,"
146 " \"nbf\": 60,"
147 " \"foo\": \"bar\"}";
148
149 static const char claims_without_time_constraint[] =
150 "{ \"aud\": \"https://foo.com\","
151 " \"iss\": \"blah.foo.com\","
152 " \"sub\": \"juju@blah.foo.com\","
153 " \"jti\": \"jwtuniqueid\","
154 " \"foo\": \"bar\"}";
155
156 static const char claims_with_bad_subject[] =
157 "{ \"aud\": \"https://foo.com\","
158 " \"iss\": \"evil@blah.foo.com\","
159 " \"sub\": \"juju@blah.foo.com\","
160 " \"jti\": \"jwtuniqueid\","
161 " \"foo\": \"bar\"}";
162
163 static const char invalid_claims[] =
164 "{ \"aud\": \"https://foo.com\","
165 " \"iss\": 46," // Issuer cannot be a number.
166 " \"sub\": \"juju@blah.foo.com\","
167 " \"jti\": \"jwtuniqueid\","
168 " \"foo\": \"bar\"}";
169
170 typedef struct {
171 grpc_jwt_verifier_status expected_status;
172 const char* expected_issuer;
173 const char* expected_subject;
174 } verifier_test_config;
175
TEST(JwtVerifierTest,JwtIssuerEmailDomain)176 TEST(JwtVerifierTest, JwtIssuerEmailDomain) {
177 const char* d = grpc_jwt_issuer_email_domain("https://foo.com");
178 ASSERT_EQ(d, nullptr);
179 d = grpc_jwt_issuer_email_domain("foo.com");
180 ASSERT_EQ(d, nullptr);
181 d = grpc_jwt_issuer_email_domain("");
182 ASSERT_EQ(d, nullptr);
183 d = grpc_jwt_issuer_email_domain("@");
184 ASSERT_EQ(d, nullptr);
185 d = grpc_jwt_issuer_email_domain("bar@foo");
186 ASSERT_STREQ(d, "foo");
187 d = grpc_jwt_issuer_email_domain("bar@foo.com");
188 ASSERT_STREQ(d, "foo.com");
189 d = grpc_jwt_issuer_email_domain("bar@blah.foo.com");
190 ASSERT_STREQ(d, "foo.com");
191 d = grpc_jwt_issuer_email_domain("bar.blah@blah.foo.com");
192 ASSERT_STREQ(d, "foo.com");
193 d = grpc_jwt_issuer_email_domain("bar.blah@baz.blah.foo.com");
194 ASSERT_STREQ(d, "foo.com");
195
196 // This is not a very good parser but make sure we do not crash on these weird
197 // inputs.
198 d = grpc_jwt_issuer_email_domain("@foo");
199 ASSERT_STREQ(d, "foo");
200 d = grpc_jwt_issuer_email_domain("bar@.");
201 ASSERT_NE(d, nullptr);
202 d = grpc_jwt_issuer_email_domain("bar@..");
203 ASSERT_NE(d, nullptr);
204 d = grpc_jwt_issuer_email_domain("bar@...");
205 ASSERT_NE(d, nullptr);
206 }
207
TEST(JwtVerifierTest,ClaimsSuccess)208 TEST(JwtVerifierTest, ClaimsSuccess) {
209 grpc_jwt_claims* claims;
210 auto json = grpc_core::JsonParse(claims_without_time_constraint);
211 ASSERT_TRUE(json.ok()) << json.status();
212 ASSERT_EQ(json->type(), Json::Type::kObject);
213 grpc_core::ExecCtx exec_ctx;
214 claims = grpc_jwt_claims_from_json(*json);
215 ASSERT_NE(claims, nullptr);
216 ASSERT_EQ(*grpc_jwt_claims_json(claims), *json);
217 ASSERT_STREQ(grpc_jwt_claims_audience(claims), "https://foo.com");
218 ASSERT_STREQ(grpc_jwt_claims_issuer(claims), "blah.foo.com");
219 ASSERT_STREQ(grpc_jwt_claims_subject(claims), "juju@blah.foo.com");
220 ASSERT_STREQ(grpc_jwt_claims_id(claims), "jwtuniqueid");
221 ASSERT_EQ(grpc_jwt_claims_check(claims, "https://foo.com"),
222 GRPC_JWT_VERIFIER_OK);
223 grpc_jwt_claims_destroy(claims);
224 }
225
TEST(JwtVerifierTest,ExpiredClaimsFailure)226 TEST(JwtVerifierTest, ExpiredClaimsFailure) {
227 grpc_jwt_claims* claims;
228 auto json = grpc_core::JsonParse(expired_claims);
229 ASSERT_TRUE(json.ok()) << json.status();
230 ASSERT_EQ(json->type(), Json::Type::kObject);
231 gpr_timespec exp_iat = {100, 0, GPR_CLOCK_REALTIME};
232 gpr_timespec exp_exp = {120, 0, GPR_CLOCK_REALTIME};
233 gpr_timespec exp_nbf = {60, 0, GPR_CLOCK_REALTIME};
234 grpc_core::ExecCtx exec_ctx;
235 claims = grpc_jwt_claims_from_json(*json);
236 ASSERT_NE(claims, nullptr);
237 ASSERT_EQ(*grpc_jwt_claims_json(claims), *json);
238 ASSERT_STREQ(grpc_jwt_claims_audience(claims), "https://foo.com");
239 ASSERT_STREQ(grpc_jwt_claims_issuer(claims), "blah.foo.com");
240 ASSERT_STREQ(grpc_jwt_claims_subject(claims), "juju@blah.foo.com");
241 ASSERT_STREQ(grpc_jwt_claims_id(claims), "jwtuniqueid");
242 ASSERT_EQ(gpr_time_cmp(grpc_jwt_claims_issued_at(claims), exp_iat), 0);
243 ASSERT_EQ(gpr_time_cmp(grpc_jwt_claims_expires_at(claims), exp_exp), 0);
244 ASSERT_EQ(gpr_time_cmp(grpc_jwt_claims_not_before(claims), exp_nbf), 0);
245 ASSERT_EQ(grpc_jwt_claims_check(claims, "https://foo.com"),
246 GRPC_JWT_VERIFIER_TIME_CONSTRAINT_FAILURE);
247 grpc_jwt_claims_destroy(claims);
248 }
249
TEST(JwtVerifierTest,InvalidClaimsFailure)250 TEST(JwtVerifierTest, InvalidClaimsFailure) {
251 auto json = grpc_core::JsonParse(invalid_claims);
252 ASSERT_TRUE(json.ok()) << json.status();
253 ASSERT_EQ(json->type(), Json::Type::kObject);
254 grpc_core::ExecCtx exec_ctx;
255 ASSERT_EQ(grpc_jwt_claims_from_json(*json), nullptr);
256 }
257
TEST(JwtVerifierTest,BadAudienceClaimsFailure)258 TEST(JwtVerifierTest, BadAudienceClaimsFailure) {
259 grpc_jwt_claims* claims;
260 auto json = grpc_core::JsonParse(claims_without_time_constraint);
261 ASSERT_TRUE(json.ok()) << json.status();
262 ASSERT_EQ(json->type(), Json::Type::kObject);
263 grpc_core::ExecCtx exec_ctx;
264 claims = grpc_jwt_claims_from_json(*json);
265 ASSERT_NE(claims, nullptr);
266 ASSERT_EQ(grpc_jwt_claims_check(claims, "https://bar.com"),
267 GRPC_JWT_VERIFIER_BAD_AUDIENCE);
268 grpc_jwt_claims_destroy(claims);
269 }
270
TEST(JwtVerifierTest,BadSubjectClaimsFailure)271 TEST(JwtVerifierTest, BadSubjectClaimsFailure) {
272 grpc_jwt_claims* claims;
273 auto json = grpc_core::JsonParse(claims_with_bad_subject);
274 ASSERT_TRUE(json.ok()) << json.status();
275 ASSERT_EQ(json->type(), Json::Type::kObject);
276 grpc_core::ExecCtx exec_ctx;
277 claims = grpc_jwt_claims_from_json(*json);
278 ASSERT_NE(claims, nullptr);
279 ASSERT_EQ(grpc_jwt_claims_check(claims, "https://foo.com"),
280 GRPC_JWT_VERIFIER_BAD_SUBJECT);
281 grpc_jwt_claims_destroy(claims);
282 }
283
json_key_str(const char * last_part)284 static char* json_key_str(const char* last_part) {
285 size_t result_len = strlen(json_key_str_part1) + strlen(json_key_str_part2) +
286 strlen(last_part);
287 char* result = static_cast<char*>(gpr_malloc(result_len + 1));
288 char* current = result;
289 strcpy(result, json_key_str_part1);
290 current += strlen(json_key_str_part1);
291 strcpy(current, json_key_str_part2);
292 current += strlen(json_key_str_part2);
293 strcpy(current, last_part);
294 return result;
295 }
296
good_google_email_keys(void)297 static char* good_google_email_keys(void) {
298 size_t result_len = strlen(good_google_email_keys_part1) +
299 strlen(good_google_email_keys_part2);
300 char* result = static_cast<char*>(gpr_malloc(result_len + 1));
301 char* current = result;
302 strcpy(result, good_google_email_keys_part1);
303 current += strlen(good_google_email_keys_part1);
304 strcpy(current, good_google_email_keys_part2);
305 return result;
306 }
307
http_response(int status,char * body)308 static grpc_http_response http_response(int status, char* body) {
309 grpc_http_response response;
310 response = {};
311 response.status = status;
312 response.body = body;
313 response.body_length = strlen(body);
314 return response;
315 }
316
httpcli_post_should_not_be_called(const grpc_http_request *,const grpc_core::URI &,absl::string_view,grpc_core::Timestamp,grpc_closure *,grpc_http_response *)317 static int httpcli_post_should_not_be_called(
318 const grpc_http_request* /*request*/, const grpc_core::URI& /*uri*/,
319 absl::string_view /*body*/, grpc_core::Timestamp /*deadline*/,
320 grpc_closure* /*on_done*/, grpc_http_response* /*response*/) {
321 EXPECT_EQ("HTTP POST should not be called", nullptr);
322 return 1;
323 }
324
httpcli_put_should_not_be_called(const grpc_http_request *,const grpc_core::URI &,absl::string_view,grpc_core::Timestamp,grpc_closure *,grpc_http_response *)325 static int httpcli_put_should_not_be_called(
326 const grpc_http_request* /*request*/, const grpc_core::URI& /*uri*/,
327 absl::string_view /*body*/, grpc_core::Timestamp /*deadline*/,
328 grpc_closure* /*on_done*/, grpc_http_response* /*response*/) {
329 EXPECT_EQ("HTTP PUT should not be called", nullptr);
330 return 1;
331 }
332
httpcli_get_google_keys_for_email(const grpc_http_request *,const grpc_core::URI & uri,grpc_core::Timestamp,grpc_closure * on_done,grpc_http_response * response)333 static int httpcli_get_google_keys_for_email(
334 const grpc_http_request* /*request*/, const grpc_core::URI& uri,
335 grpc_core::Timestamp /*deadline*/, grpc_closure* on_done,
336 grpc_http_response* response) {
337 *response = http_response(200, good_google_email_keys());
338 EXPECT_EQ(uri.authority(), "www.googleapis.com");
339 EXPECT_EQ(uri.path(),
340 "/robot/v1/metadata/x509/"
341 "777-abaslkan11hlb6nmim3bpspl31ud@developer."
342 "gserviceaccount.com");
343 grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, absl::OkStatus());
344 return 1;
345 }
346
on_verification_success(void * user_data,grpc_jwt_verifier_status status,grpc_jwt_claims * claims)347 static void on_verification_success(void* user_data,
348 grpc_jwt_verifier_status status,
349 grpc_jwt_claims* claims) {
350 ASSERT_EQ(status, GRPC_JWT_VERIFIER_OK);
351 ASSERT_NE(claims, nullptr);
352 ASSERT_EQ(user_data, (void*)expected_user_data);
353 ASSERT_STREQ(grpc_jwt_claims_audience(claims), expected_audience);
354 grpc_jwt_claims_destroy(claims);
355 }
356
TEST(JwtVerifierTest,JwtVerifierGoogleEmailIssuerSuccess)357 TEST(JwtVerifierTest, JwtVerifierGoogleEmailIssuerSuccess) {
358 grpc_core::ExecCtx exec_ctx;
359 grpc_jwt_verifier* verifier = grpc_jwt_verifier_create(nullptr, 0);
360 char* jwt = nullptr;
361 char* key_str = json_key_str(json_key_str_part3_for_google_email_issuer);
362 grpc_auth_json_key key = grpc_auth_json_key_create_from_string(key_str);
363 gpr_free(key_str);
364 ASSERT_TRUE(grpc_auth_json_key_is_valid(&key));
365 grpc_core::HttpRequest::SetOverride(httpcli_get_google_keys_for_email,
366 httpcli_post_should_not_be_called,
367 httpcli_put_should_not_be_called);
368 jwt = grpc_jwt_encode_and_sign(&key, expected_audience, expected_lifetime,
369 nullptr);
370 grpc_auth_json_key_destruct(&key);
371 ASSERT_NE(jwt, nullptr);
372 grpc_jwt_verifier_verify(verifier, nullptr, jwt, expected_audience,
373 on_verification_success,
374 const_cast<char*>(expected_user_data));
375 grpc_jwt_verifier_destroy(verifier);
376 grpc_core::ExecCtx::Get()->Flush();
377 gpr_free(jwt);
378 grpc_core::HttpRequest::SetOverride(nullptr, nullptr, nullptr);
379 }
380
httpcli_get_custom_keys_for_email(const grpc_http_request *,const grpc_core::URI & uri,grpc_core::Timestamp,grpc_closure * on_done,grpc_http_response * response)381 static int httpcli_get_custom_keys_for_email(
382 const grpc_http_request* /*request*/, const grpc_core::URI& uri,
383 grpc_core::Timestamp /*deadline*/, grpc_closure* on_done,
384 grpc_http_response* response) {
385 *response = http_response(200, gpr_strdup(good_jwk_set));
386 EXPECT_EQ(uri.authority(), "keys.bar.com");
387 EXPECT_EQ(uri.path(), "/jwk/foo@bar.com");
388 grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, absl::OkStatus());
389 return 1;
390 }
391
TEST(JwtVerifierTest,JwtVerifierCustomEmailIssuerSuccess)392 TEST(JwtVerifierTest, JwtVerifierCustomEmailIssuerSuccess) {
393 grpc_core::ExecCtx exec_ctx;
394 grpc_jwt_verifier* verifier = grpc_jwt_verifier_create(&custom_mapping, 1);
395 char* jwt = nullptr;
396 char* key_str = json_key_str(json_key_str_part3_for_custom_email_issuer);
397 grpc_auth_json_key key = grpc_auth_json_key_create_from_string(key_str);
398 gpr_free(key_str);
399 ASSERT_TRUE(grpc_auth_json_key_is_valid(&key));
400 grpc_core::HttpRequest::SetOverride(httpcli_get_custom_keys_for_email,
401 httpcli_post_should_not_be_called,
402 httpcli_put_should_not_be_called);
403 jwt = grpc_jwt_encode_and_sign(&key, expected_audience, expected_lifetime,
404 nullptr);
405 grpc_auth_json_key_destruct(&key);
406 ASSERT_NE(jwt, nullptr);
407 grpc_jwt_verifier_verify(verifier, nullptr, jwt, expected_audience,
408 on_verification_success,
409 const_cast<char*>(expected_user_data));
410 grpc_jwt_verifier_destroy(verifier);
411 grpc_core::ExecCtx::Get()->Flush();
412 gpr_free(jwt);
413 grpc_core::HttpRequest::SetOverride(nullptr, nullptr, nullptr);
414 }
415
httpcli_get_jwk_set(const grpc_http_request *,const grpc_core::URI & uri,grpc_core::Timestamp,grpc_closure * on_done,grpc_http_response * response)416 static int httpcli_get_jwk_set(const grpc_http_request* /*request*/,
417 const grpc_core::URI& uri,
418 grpc_core::Timestamp /*deadline*/,
419 grpc_closure* on_done,
420 grpc_http_response* response) {
421 *response = http_response(200, gpr_strdup(good_jwk_set));
422 EXPECT_EQ(uri.authority(), "www.googleapis.com");
423 EXPECT_EQ(uri.path(), "/oauth2/v3/certs");
424 grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, absl::OkStatus());
425 return 1;
426 }
427
httpcli_get_openid_config(const grpc_http_request *,const grpc_core::URI & uri,grpc_core::Timestamp,grpc_closure * on_done,grpc_http_response * response)428 static int httpcli_get_openid_config(const grpc_http_request* /*request*/,
429 const grpc_core::URI& uri,
430 grpc_core::Timestamp /*deadline*/,
431 grpc_closure* on_done,
432 grpc_http_response* response) {
433 *response = http_response(200, gpr_strdup(good_openid_config));
434 EXPECT_EQ(uri.authority(), "accounts.google.com");
435 EXPECT_EQ(uri.path(), GRPC_OPENID_CONFIG_URL_SUFFIX);
436 grpc_core::HttpRequest::SetOverride(httpcli_get_jwk_set,
437 httpcli_post_should_not_be_called,
438 httpcli_put_should_not_be_called);
439 grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, absl::OkStatus());
440 return 1;
441 }
442
TEST(JwtVerifierTest,JwtVerifierUrlIssuerSuccess)443 TEST(JwtVerifierTest, JwtVerifierUrlIssuerSuccess) {
444 grpc_core::ExecCtx exec_ctx;
445 grpc_jwt_verifier* verifier = grpc_jwt_verifier_create(nullptr, 0);
446 char* jwt = nullptr;
447 char* key_str = json_key_str(json_key_str_part3_for_url_issuer);
448 grpc_auth_json_key key = grpc_auth_json_key_create_from_string(key_str);
449 gpr_free(key_str);
450 ASSERT_TRUE(grpc_auth_json_key_is_valid(&key));
451 grpc_core::HttpRequest::SetOverride(httpcli_get_openid_config,
452 httpcli_post_should_not_be_called,
453 httpcli_put_should_not_be_called);
454 jwt = grpc_jwt_encode_and_sign(&key, expected_audience, expected_lifetime,
455 nullptr);
456 grpc_auth_json_key_destruct(&key);
457 ASSERT_NE(jwt, nullptr);
458 grpc_jwt_verifier_verify(verifier, nullptr, jwt, expected_audience,
459 on_verification_success,
460 const_cast<char*>(expected_user_data));
461 grpc_jwt_verifier_destroy(verifier);
462 grpc_core::ExecCtx::Get()->Flush();
463 gpr_free(jwt);
464 grpc_core::HttpRequest::SetOverride(nullptr, nullptr, nullptr);
465 }
466
on_verification_key_retrieval_error(void * user_data,grpc_jwt_verifier_status status,grpc_jwt_claims * claims)467 static void on_verification_key_retrieval_error(void* user_data,
468 grpc_jwt_verifier_status status,
469 grpc_jwt_claims* claims) {
470 ASSERT_EQ(status, GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR);
471 ASSERT_EQ(claims, nullptr);
472 ASSERT_EQ(user_data, (void*)expected_user_data);
473 }
474
httpcli_get_bad_json(const grpc_http_request *,const grpc_core::URI &,grpc_core::Timestamp,grpc_closure * on_done,grpc_http_response * response)475 static int httpcli_get_bad_json(const grpc_http_request* /* request */,
476 const grpc_core::URI& /*uri*/,
477 grpc_core::Timestamp /*deadline*/,
478 grpc_closure* on_done,
479 grpc_http_response* response) {
480 *response = http_response(200, gpr_strdup("{\"bad\": \"stuff\"}"));
481 grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, absl::OkStatus());
482 return 1;
483 }
484
TEST(JwtVerifierTest,JwtVerifierUrlIssuerBadConfig)485 TEST(JwtVerifierTest, JwtVerifierUrlIssuerBadConfig) {
486 grpc_core::ExecCtx exec_ctx;
487 grpc_jwt_verifier* verifier = grpc_jwt_verifier_create(nullptr, 0);
488 char* jwt = nullptr;
489 char* key_str = json_key_str(json_key_str_part3_for_url_issuer);
490 grpc_auth_json_key key = grpc_auth_json_key_create_from_string(key_str);
491 gpr_free(key_str);
492 ASSERT_TRUE(grpc_auth_json_key_is_valid(&key));
493 grpc_core::HttpRequest::SetOverride(httpcli_get_bad_json,
494 httpcli_post_should_not_be_called,
495 httpcli_put_should_not_be_called);
496 jwt = grpc_jwt_encode_and_sign(&key, expected_audience, expected_lifetime,
497 nullptr);
498 grpc_auth_json_key_destruct(&key);
499 ASSERT_NE(jwt, nullptr);
500 grpc_jwt_verifier_verify(verifier, nullptr, jwt, expected_audience,
501 on_verification_key_retrieval_error,
502 const_cast<char*>(expected_user_data));
503 grpc_jwt_verifier_destroy(verifier);
504 grpc_core::ExecCtx::Get()->Flush();
505 gpr_free(jwt);
506 grpc_core::HttpRequest::SetOverride(nullptr, nullptr, nullptr);
507 }
508
TEST(JwtVerifierTest,JwtVerifierBadJsonKey)509 TEST(JwtVerifierTest, JwtVerifierBadJsonKey) {
510 grpc_core::ExecCtx exec_ctx;
511 grpc_jwt_verifier* verifier = grpc_jwt_verifier_create(nullptr, 0);
512 char* jwt = nullptr;
513 char* key_str = json_key_str(json_key_str_part3_for_google_email_issuer);
514 grpc_auth_json_key key = grpc_auth_json_key_create_from_string(key_str);
515 gpr_free(key_str);
516 ASSERT_TRUE(grpc_auth_json_key_is_valid(&key));
517 grpc_core::HttpRequest::SetOverride(httpcli_get_bad_json,
518 httpcli_post_should_not_be_called,
519 httpcli_put_should_not_be_called);
520 jwt = grpc_jwt_encode_and_sign(&key, expected_audience, expected_lifetime,
521 nullptr);
522 grpc_auth_json_key_destruct(&key);
523 ASSERT_NE(jwt, nullptr);
524 grpc_jwt_verifier_verify(verifier, nullptr, jwt, expected_audience,
525 on_verification_key_retrieval_error,
526 const_cast<char*>(expected_user_data));
527 grpc_jwt_verifier_destroy(verifier);
528 grpc_core::ExecCtx::Get()->Flush();
529 gpr_free(jwt);
530 grpc_core::HttpRequest::SetOverride(nullptr, nullptr, nullptr);
531 }
532
corrupt_jwt_sig(char * jwt)533 static void corrupt_jwt_sig(char* jwt) {
534 char* last_dot = strrchr(jwt, '.');
535 ASSERT_NE(last_dot, nullptr);
536 std::string decoded;
537 absl::WebSafeBase64Unescape(last_dot + 1, &decoded);
538 ASSERT_FALSE(decoded.empty());
539 ++decoded[0]; // Corrupt first byte.
540 std::string bad_encoding = absl::WebSafeBase64Escape(decoded);
541 memcpy(last_dot + 1, bad_encoding.data(), bad_encoding.size());
542 }
543
on_verification_bad_signature(void * user_data,grpc_jwt_verifier_status status,grpc_jwt_claims * claims)544 static void on_verification_bad_signature(void* user_data,
545 grpc_jwt_verifier_status status,
546 grpc_jwt_claims* claims) {
547 ASSERT_EQ(status, GRPC_JWT_VERIFIER_BAD_SIGNATURE);
548 ASSERT_EQ(claims, nullptr);
549 ASSERT_EQ(user_data, (void*)expected_user_data);
550 }
551
TEST(JwtVerifierTest,JwtVerifierBadSignature)552 TEST(JwtVerifierTest, JwtVerifierBadSignature) {
553 grpc_core::ExecCtx exec_ctx;
554 grpc_jwt_verifier* verifier = grpc_jwt_verifier_create(nullptr, 0);
555 char* jwt = nullptr;
556 char* key_str = json_key_str(json_key_str_part3_for_url_issuer);
557 grpc_auth_json_key key = grpc_auth_json_key_create_from_string(key_str);
558 gpr_free(key_str);
559 ASSERT_TRUE(grpc_auth_json_key_is_valid(&key));
560 grpc_core::HttpRequest::SetOverride(httpcli_get_openid_config,
561 httpcli_post_should_not_be_called,
562 httpcli_put_should_not_be_called);
563 jwt = grpc_jwt_encode_and_sign(&key, expected_audience, expected_lifetime,
564 nullptr);
565 grpc_auth_json_key_destruct(&key);
566 corrupt_jwt_sig(jwt);
567 ASSERT_NE(jwt, nullptr);
568 grpc_jwt_verifier_verify(verifier, nullptr, jwt, expected_audience,
569 on_verification_bad_signature,
570 const_cast<char*>(expected_user_data));
571 gpr_free(jwt);
572 grpc_jwt_verifier_destroy(verifier);
573 grpc_core::ExecCtx::Get()->Flush();
574 grpc_core::HttpRequest::SetOverride(nullptr, nullptr, nullptr);
575 }
576
httpcli_get_should_not_be_called(const grpc_http_request *,const grpc_core::URI &,grpc_core::Timestamp,grpc_closure *,grpc_http_response *)577 static int httpcli_get_should_not_be_called(
578 const grpc_http_request* /*request*/, const grpc_core::URI& /*uri*/,
579 grpc_core::Timestamp /*deadline*/, grpc_closure* /*on_done*/,
580 grpc_http_response* /*response*/) {
581 EXPECT_TRUE(0);
582 return 1;
583 }
584
on_verification_bad_format(void * user_data,grpc_jwt_verifier_status status,grpc_jwt_claims * claims)585 static void on_verification_bad_format(void* user_data,
586 grpc_jwt_verifier_status status,
587 grpc_jwt_claims* claims) {
588 ASSERT_EQ(status, GRPC_JWT_VERIFIER_BAD_FORMAT);
589 ASSERT_EQ(claims, nullptr);
590 ASSERT_EQ(user_data, (void*)expected_user_data);
591 }
592
TEST(JwtVerifierTest,JwtVerifierBadFormat)593 TEST(JwtVerifierTest, JwtVerifierBadFormat) {
594 grpc_core::ExecCtx exec_ctx;
595 grpc_jwt_verifier* verifier = grpc_jwt_verifier_create(nullptr, 0);
596 grpc_core::HttpRequest::SetOverride(httpcli_get_should_not_be_called,
597 httpcli_post_should_not_be_called,
598 httpcli_put_should_not_be_called);
599 grpc_jwt_verifier_verify(verifier, nullptr, "bad jwt", expected_audience,
600 on_verification_bad_format,
601 const_cast<char*>(expected_user_data));
602 grpc_jwt_verifier_destroy(verifier);
603 grpc_core::ExecCtx::Get()->Flush();
604 grpc_core::HttpRequest::SetOverride(nullptr, nullptr, nullptr);
605 }
606
607 // find verification key: bad jks, cannot find key in jks
608 // bad signature custom provided email
609 // bad key
610
main(int argc,char ** argv)611 int main(int argc, char** argv) {
612 grpc::testing::TestEnvironment env(&argc, argv);
613 ::testing::InitGoogleTest(&argc, argv);
614 grpc::testing::TestGrpcScope grpc_scope;
615 return RUN_ALL_TESTS();
616 }
617