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