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