• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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