Line data Source code
1 : /*
2 : *
3 : *Copyright 2015, Google Inc.
4 : *All rights reserved.
5 : *
6 : *Redistribution and use in source and binary forms, with or without
7 : *modification, are permitted provided that the following conditions are
8 : *met:
9 : *
10 : * * Redistributions of source code must retain the above copyright
11 : *notice, this list of conditions and the following disclaimer.
12 : * * Redistributions in binary form must reproduce the above
13 : *copyright notice, this list of conditions and the following disclaimer
14 : *in the documentation and/or other materials provided with the
15 : *distribution.
16 : * * Neither the name of Google Inc. nor the names of its
17 : *contributors may be used to endorse or promote products derived from
18 : *this software without specific prior written permission.
19 : *
20 : *THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 : *"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 : *LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 : *A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 : *OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 : *SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 : *LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 : *DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 : *THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 : *(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 : *OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 : *
32 : */
33 :
34 : #include "src/core/security/jwt_verifier.h"
35 :
36 : #include <string.h>
37 :
38 : #include "src/core/httpcli/httpcli.h"
39 : #include "src/core/security/base64.h"
40 : #include "src/core/security/json_token.h"
41 : #include "test/core/util/test_config.h"
42 :
43 : #include <grpc/support/alloc.h>
44 : #include <grpc/support/log.h>
45 : #include <grpc/support/slice.h>
46 : #include <grpc/support/string_util.h>
47 :
48 : /* This JSON key was generated with the GCE console and revoked immediately.
49 : The identifiers have been changed as well.
50 : Maximum size for a string literal is 509 chars in C89, yay! */
51 : static const char json_key_str_part1[] =
52 : "{ \"private_key\": \"-----BEGIN PRIVATE KEY-----"
53 : "\\nMIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAOEvJsnoHnyHkXcp\\n7mJE"
54 : "qg"
55 : "WGjiw71NfXByguekSKho65FxaGbsnSM9SMQAqVk7Q2rG+I0OpsT0LrWQtZ\\nyjSeg/"
56 : "rWBQvS4hle4LfijkP3J5BG+"
57 : "IXDMP8RfziNRQsenAXDNPkY4kJCvKux2xdD\\nOnVF6N7dL3nTYZg+"
58 : "uQrNsMTz9UxVAgMBAAECgYEAzbLewe1xe9vy+2GoSsfib+28\\nDZgSE6Bu/"
59 : "zuFoPrRc6qL9p2SsnV7txrunTyJkkOnPLND9ABAXybRTlcVKP/sGgza\\n/"
60 : "8HpCqFYM9V8f34SBWfD4fRFT+n/"
61 : "73cfRUtGXdXpseva2lh8RilIQfPhNZAncenU\\ngqXjDvpkypEusgXAykECQQD+";
62 : static const char json_key_str_part2[] =
63 : "53XxNVnxBHsYb+AYEfklR96yVi8HywjVHP34+OQZ\\nCslxoHQM8s+"
64 : "dBnjfScLu22JqkPv04xyxmt0QAKm9+vTdAkEA4ib7YvEAn2jXzcCI\\nEkoy2L/"
65 : "XydR1GCHoacdfdAwiL2npOdnbvi4ZmdYRPY1LSTO058tQHKVXV7NLeCa3\\nAARh2QJBAMKeDA"
66 : "G"
67 : "W303SQv2cZTdbeaLKJbB5drz3eo3j7dDKjrTD9JupixFbzcGw\\n8FZi5c8idxiwC36kbAL6Hz"
68 : "A"
69 : "ZoX+ofI0CQE6KCzPJTtYNqyShgKAZdJ8hwOcvCZtf\\n6z8RJm0+"
70 : "6YBd38lfh5j8mZd7aHFf6I17j5AQY7oPEc47TjJj/"
71 : "5nZ68ECQQDvYuI3\\nLyK5fS8g0SYbmPOL9TlcHDOqwG0mrX9qpg5DC2fniXNSrrZ64GTDKdzZ"
72 : "Y"
73 : "Ap6LI9W\\nIqv4vr6y38N79TTC\\n-----END PRIVATE KEY-----\\n\", ";
74 : static const char json_key_str_part3_for_google_email_issuer[] =
75 : "\"private_key_id\": \"e6b5137873db8d2ef81e06a47289e6434ec8a165\", "
76 : "\"client_email\": "
77 : "\"777-abaslkan11hlb6nmim3bpspl31ud@developer.gserviceaccount."
78 : "com\", \"client_id\": "
79 : "\"777-abaslkan11hlb6nmim3bpspl31ud.apps.googleusercontent."
80 : "com\", \"type\": \"service_account\" }";
81 : /* Trick our JWT library into issuing a JWT with iss=accounts.google.com. */
82 : static const char json_key_str_part3_for_url_issuer[] =
83 : "\"private_key_id\": \"e6b5137873db8d2ef81e06a47289e6434ec8a165\", "
84 : "\"client_email\": \"accounts.google.com\", "
85 : "\"client_id\": "
86 : "\"777-abaslkan11hlb6nmim3bpspl31ud.apps.googleusercontent."
87 : "com\", \"type\": \"service_account\" }";
88 : static const char json_key_str_part3_for_custom_email_issuer[] =
89 : "\"private_key_id\": \"e6b5137873db8d2ef81e06a47289e6434ec8a165\", "
90 : "\"client_email\": "
91 : "\"foo@bar.com\", \"client_id\": "
92 : "\"777-abaslkan11hlb6nmim3bpspl31ud.apps.googleusercontent."
93 : "com\", \"type\": \"service_account\" }";
94 :
95 : static grpc_jwt_verifier_email_domain_key_url_mapping custom_mapping = {
96 : "bar.com", "keys.bar.com/jwk"};
97 :
98 : static const char expected_user_data[] = "user data";
99 :
100 : static const char good_jwk_set[] =
101 : "{"
102 : " \"keys\": ["
103 : " {"
104 : " \"kty\": \"RSA\","
105 : " \"alg\": \"RS256\","
106 : " \"use\": \"sig\","
107 : " \"kid\": \"e6b5137873db8d2ef81e06a47289e6434ec8a165\","
108 : " \"n\": "
109 : "\"4S8myegefIeRdynuYkSqBYaOLDvU19cHKC56RIqGjrkXFoZuydIz1IxACpWTtDasb4jQ6mxP"
110 : "QutZC1nKNJ6D-tYFC9LiGV7gt-KOQ_cnkEb4hcMw_xF_OI1FCx6cBcM0-"
111 : "RjiQkK8q7HbF0M6dUXo3t0vedNhmD65Cs2wxPP1TFU=\","
112 : " \"e\": \"AQAB\""
113 : " }"
114 : " ]"
115 : "}";
116 :
117 : static gpr_timespec expected_lifetime = {3600, 0, GPR_TIMESPAN};
118 :
119 : static const char good_google_email_keys_part1[] =
120 : "{\"e6b5137873db8d2ef81e06a47289e6434ec8a165\": \"-----BEGIN "
121 : "CERTIFICATE-----"
122 : "\\nMIICATCCAWoCCQDEywLhxvHjnDANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB\\nVTET"
123 : "MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0\\ncyBQdHkgTHR"
124 : "kMB4XDTE1MDYyOTA4Mzk1MFoXDTI1MDYyNjA4Mzk1MFowRTELMAkG\\nA1UEBhMCQVUxEzARBg"
125 : "NVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0\\nIFdpZGdpdHMgUHR5IEx0ZDCBn"
126 : "zANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4S8m\\nyegefIeRdynuYkSqBYaOLDvU19cHKC56"
127 : "RIqGjrkXFoZuydIz1IxACpWTtDasb4jQ\\n6mxPQutZC1nKNJ6D+tYFC9LiGV7gt+KOQ/";
128 :
129 : static const char good_google_email_keys_part2[] =
130 : "cnkEb4hcMw/xF/OI1FCx6cBcM0+"
131 : "Rji\\nQkK8q7HbF0M6dUXo3t0vedNhmD65Cs2wxPP1TFUCAwEAATANBgkqhkiG9w0BAQsF\\nA"
132 : "AOBgQBfu69FkPmBknbKNFgurPz78kbs3VNN+k/"
133 : "PUgO5DHKskJmgK2TbtvX2VMpx\\nkftmHGzgzMzUlOtigCaGMgHWjfqjpP9uuDbahXrZBJzB8c"
134 : "Oq7MrQF8r17qVvo3Ue\\nPjTKQMAsU8uxTEMmeuz9L6yExs0rfd6bPOrQkAoVfFfiYB3/"
135 : "pA==\\n-----END CERTIFICATE-----\\n\"}";
136 :
137 : static const char expected_audience[] = "https://foo.com";
138 :
139 : static const char good_openid_config[] =
140 : "{"
141 : " \"issuer\": \"https://accounts.google.com\","
142 : " \"authorization_endpoint\": "
143 : "\"https://accounts.google.com/o/oauth2/v2/auth\","
144 : " \"token_endpoint\": \"https://www.googleapis.com/oauth2/v4/token\","
145 : " \"userinfo_endpoint\": \"https://www.googleapis.com/oauth2/v3/userinfo\","
146 : " \"revocation_endpoint\": \"https://accounts.google.com/o/oauth2/revoke\","
147 : " \"jwks_uri\": \"https://www.googleapis.com/oauth2/v3/certs\""
148 : "}";
149 :
150 : static const char expired_claims[] =
151 : "{ \"aud\": \"https://foo.com\","
152 : " \"iss\": \"blah.foo.com\","
153 : " \"sub\": \"juju@blah.foo.com\","
154 : " \"jti\": \"jwtuniqueid\","
155 : " \"iat\": 100," /* Way back in the past... */
156 : " \"exp\": 120,"
157 : " \"nbf\": 60,"
158 : " \"foo\": \"bar\"}";
159 :
160 : static const char claims_without_time_constraint[] =
161 : "{ \"aud\": \"https://foo.com\","
162 : " \"iss\": \"blah.foo.com\","
163 : " \"sub\": \"juju@blah.foo.com\","
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\": \"juju@blah.foo.com\","
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 :
180 1 : static void test_claims_success(void) {
181 : grpc_jwt_claims *claims;
182 1 : gpr_slice s = gpr_slice_from_copied_string(claims_without_time_constraint);
183 2 : grpc_json *json = grpc_json_parse_string_with_len(
184 2 : (char *)GPR_SLICE_START_PTR(s), GPR_SLICE_LENGTH(s));
185 1 : GPR_ASSERT(json != NULL);
186 1 : claims = grpc_jwt_claims_from_json(json, s);
187 1 : GPR_ASSERT(claims != NULL);
188 1 : GPR_ASSERT(grpc_jwt_claims_json(claims) == json);
189 1 : GPR_ASSERT(strcmp(grpc_jwt_claims_audience(claims), "https://foo.com") == 0);
190 1 : GPR_ASSERT(strcmp(grpc_jwt_claims_issuer(claims), "blah.foo.com") == 0);
191 1 : GPR_ASSERT(strcmp(grpc_jwt_claims_subject(claims), "juju@blah.foo.com") == 0);
192 1 : GPR_ASSERT(strcmp(grpc_jwt_claims_id(claims), "jwtuniqueid") == 0);
193 1 : GPR_ASSERT(grpc_jwt_claims_check(claims, "https://foo.com") ==
194 : GRPC_JWT_VERIFIER_OK);
195 1 : grpc_jwt_claims_destroy(claims);
196 1 : }
197 :
198 1 : static void test_expired_claims_failure(void) {
199 : grpc_jwt_claims *claims;
200 1 : gpr_slice s = gpr_slice_from_copied_string(expired_claims);
201 2 : grpc_json *json = grpc_json_parse_string_with_len(
202 2 : (char *)GPR_SLICE_START_PTR(s), GPR_SLICE_LENGTH(s));
203 1 : gpr_timespec exp_iat = {100, 0, GPR_CLOCK_REALTIME};
204 1 : gpr_timespec exp_exp = {120, 0, GPR_CLOCK_REALTIME};
205 1 : gpr_timespec exp_nbf = {60, 0, GPR_CLOCK_REALTIME};
206 1 : GPR_ASSERT(json != NULL);
207 1 : claims = grpc_jwt_claims_from_json(json, s);
208 1 : GPR_ASSERT(claims != NULL);
209 1 : GPR_ASSERT(grpc_jwt_claims_json(claims) == json);
210 1 : GPR_ASSERT(strcmp(grpc_jwt_claims_audience(claims), "https://foo.com") == 0);
211 1 : GPR_ASSERT(strcmp(grpc_jwt_claims_issuer(claims), "blah.foo.com") == 0);
212 1 : GPR_ASSERT(strcmp(grpc_jwt_claims_subject(claims), "juju@blah.foo.com") == 0);
213 1 : GPR_ASSERT(strcmp(grpc_jwt_claims_id(claims), "jwtuniqueid") == 0);
214 1 : GPR_ASSERT(gpr_time_cmp(grpc_jwt_claims_issued_at(claims), exp_iat) == 0);
215 1 : GPR_ASSERT(gpr_time_cmp(grpc_jwt_claims_expires_at(claims), exp_exp) == 0);
216 1 : GPR_ASSERT(gpr_time_cmp(grpc_jwt_claims_not_before(claims), exp_nbf) == 0);
217 :
218 1 : GPR_ASSERT(grpc_jwt_claims_check(claims, "https://foo.com") ==
219 : GRPC_JWT_VERIFIER_TIME_CONSTRAINT_FAILURE);
220 1 : grpc_jwt_claims_destroy(claims);
221 1 : }
222 :
223 1 : static void test_invalid_claims_failure(void) {
224 1 : gpr_slice s = gpr_slice_from_copied_string(invalid_claims);
225 2 : grpc_json *json = grpc_json_parse_string_with_len(
226 2 : (char *)GPR_SLICE_START_PTR(s), GPR_SLICE_LENGTH(s));
227 1 : GPR_ASSERT(grpc_jwt_claims_from_json(json, s) == NULL);
228 1 : }
229 :
230 1 : static void test_bad_audience_claims_failure(void) {
231 : grpc_jwt_claims *claims;
232 1 : gpr_slice s = gpr_slice_from_copied_string(claims_without_time_constraint);
233 2 : grpc_json *json = grpc_json_parse_string_with_len(
234 2 : (char *)GPR_SLICE_START_PTR(s), GPR_SLICE_LENGTH(s));
235 1 : GPR_ASSERT(json != NULL);
236 1 : claims = grpc_jwt_claims_from_json(json, s);
237 1 : GPR_ASSERT(claims != NULL);
238 1 : GPR_ASSERT(grpc_jwt_claims_check(claims, "https://bar.com") ==
239 : GRPC_JWT_VERIFIER_BAD_AUDIENCE);
240 1 : grpc_jwt_claims_destroy(claims);
241 1 : }
242 :
243 6 : static char *json_key_str(const char *last_part) {
244 6 : size_t result_len = strlen(json_key_str_part1) + strlen(json_key_str_part2) +
245 6 : strlen(last_part);
246 6 : char *result = gpr_malloc(result_len + 1);
247 6 : char *current = result;
248 6 : strcpy(result, json_key_str_part1);
249 6 : current += strlen(json_key_str_part1);
250 6 : strcpy(current, json_key_str_part2);
251 6 : current += strlen(json_key_str_part2);
252 6 : strcpy(current, last_part);
253 6 : return result;
254 : }
255 :
256 1 : static char *good_google_email_keys(void) {
257 1 : size_t result_len = strlen(good_google_email_keys_part1) +
258 : strlen(good_google_email_keys_part2);
259 1 : char *result = gpr_malloc(result_len + 1);
260 1 : char *current = result;
261 1 : strcpy(result, good_google_email_keys_part1);
262 1 : current += strlen(good_google_email_keys_part1);
263 1 : strcpy(current, good_google_email_keys_part2);
264 1 : return result;
265 : }
266 :
267 8 : static grpc_httpcli_response http_response(int status, char *body) {
268 : grpc_httpcli_response response;
269 8 : memset(&response, 0, sizeof(grpc_httpcli_response));
270 8 : response.status = status;
271 8 : response.body = body;
272 8 : response.body_length = strlen(body);
273 8 : return response;
274 : }
275 :
276 0 : static int httpcli_post_should_not_be_called(
277 : grpc_exec_ctx *exec_ctx, const grpc_httpcli_request *request,
278 : const char *body_bytes, size_t body_size, gpr_timespec deadline,
279 : grpc_httpcli_response_cb on_response, void *user_data) {
280 0 : GPR_ASSERT("HTTP POST should not be called" == NULL);
281 : return 1;
282 : }
283 :
284 1 : static int httpcli_get_google_keys_for_email(
285 : grpc_exec_ctx *exec_ctx, const grpc_httpcli_request *request,
286 : gpr_timespec deadline, grpc_httpcli_response_cb on_response,
287 : void *user_data) {
288 1 : grpc_httpcli_response response = http_response(200, good_google_email_keys());
289 1 : GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl);
290 1 : GPR_ASSERT(strcmp(request->host, "www.googleapis.com") == 0);
291 1 : GPR_ASSERT(strcmp(request->path,
292 : "/robot/v1/metadata/x509/"
293 : "777-abaslkan11hlb6nmim3bpspl31ud@developer."
294 : "gserviceaccount.com") == 0);
295 1 : on_response(exec_ctx, user_data, &response);
296 1 : gpr_free(response.body);
297 1 : return 1;
298 : }
299 :
300 3 : static void on_verification_success(void *user_data,
301 : grpc_jwt_verifier_status status,
302 : grpc_jwt_claims *claims) {
303 3 : GPR_ASSERT(status == GRPC_JWT_VERIFIER_OK);
304 3 : GPR_ASSERT(claims != NULL);
305 3 : GPR_ASSERT(user_data == (void *)expected_user_data);
306 3 : GPR_ASSERT(strcmp(grpc_jwt_claims_audience(claims), expected_audience) == 0);
307 3 : grpc_jwt_claims_destroy(claims);
308 3 : }
309 :
310 1 : static void test_jwt_verifier_google_email_issuer_success(void) {
311 1 : grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
312 1 : grpc_jwt_verifier *verifier = grpc_jwt_verifier_create(NULL, 0);
313 1 : char *jwt = NULL;
314 1 : char *key_str = json_key_str(json_key_str_part3_for_google_email_issuer);
315 1 : grpc_auth_json_key key = grpc_auth_json_key_create_from_string(key_str);
316 1 : gpr_free(key_str);
317 1 : GPR_ASSERT(grpc_auth_json_key_is_valid(&key));
318 1 : grpc_httpcli_set_override(httpcli_get_google_keys_for_email,
319 : httpcli_post_should_not_be_called);
320 1 : jwt = grpc_jwt_encode_and_sign(&key, expected_audience, expected_lifetime,
321 : NULL);
322 1 : grpc_auth_json_key_destruct(&key);
323 1 : GPR_ASSERT(jwt != NULL);
324 1 : grpc_jwt_verifier_verify(&exec_ctx, verifier, NULL, jwt, expected_audience,
325 : on_verification_success, (void *)expected_user_data);
326 1 : gpr_free(jwt);
327 1 : grpc_jwt_verifier_destroy(verifier);
328 1 : grpc_httpcli_set_override(NULL, NULL);
329 1 : grpc_exec_ctx_finish(&exec_ctx);
330 1 : }
331 :
332 1 : static int httpcli_get_custom_keys_for_email(
333 : grpc_exec_ctx *exec_ctx, const grpc_httpcli_request *request,
334 : gpr_timespec deadline, grpc_httpcli_response_cb on_response,
335 : void *user_data) {
336 1 : grpc_httpcli_response response = http_response(200, gpr_strdup(good_jwk_set));
337 1 : GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl);
338 1 : GPR_ASSERT(strcmp(request->host, "keys.bar.com") == 0);
339 1 : GPR_ASSERT(strcmp(request->path, "/jwk/foo@bar.com") == 0);
340 1 : on_response(exec_ctx, user_data, &response);
341 1 : gpr_free(response.body);
342 1 : return 1;
343 : }
344 :
345 1 : static void test_jwt_verifier_custom_email_issuer_success(void) {
346 1 : grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
347 1 : grpc_jwt_verifier *verifier = grpc_jwt_verifier_create(&custom_mapping, 1);
348 1 : char *jwt = NULL;
349 1 : char *key_str = json_key_str(json_key_str_part3_for_custom_email_issuer);
350 1 : grpc_auth_json_key key = grpc_auth_json_key_create_from_string(key_str);
351 1 : gpr_free(key_str);
352 1 : GPR_ASSERT(grpc_auth_json_key_is_valid(&key));
353 1 : grpc_httpcli_set_override(httpcli_get_custom_keys_for_email,
354 : httpcli_post_should_not_be_called);
355 1 : jwt = grpc_jwt_encode_and_sign(&key, expected_audience, expected_lifetime,
356 : NULL);
357 1 : grpc_auth_json_key_destruct(&key);
358 1 : GPR_ASSERT(jwt != NULL);
359 1 : grpc_jwt_verifier_verify(&exec_ctx, verifier, NULL, jwt, expected_audience,
360 : on_verification_success, (void *)expected_user_data);
361 1 : gpr_free(jwt);
362 1 : grpc_jwt_verifier_destroy(verifier);
363 1 : grpc_httpcli_set_override(NULL, NULL);
364 1 : grpc_exec_ctx_finish(&exec_ctx);
365 1 : }
366 :
367 2 : static int httpcli_get_jwk_set(grpc_exec_ctx *exec_ctx,
368 : const grpc_httpcli_request *request,
369 : gpr_timespec deadline,
370 : grpc_httpcli_response_cb on_response,
371 : void *user_data) {
372 2 : grpc_httpcli_response response = http_response(200, gpr_strdup(good_jwk_set));
373 2 : GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl);
374 2 : GPR_ASSERT(strcmp(request->host, "www.googleapis.com") == 0);
375 2 : GPR_ASSERT(strcmp(request->path, "/oauth2/v3/certs") == 0);
376 2 : on_response(exec_ctx, user_data, &response);
377 2 : gpr_free(response.body);
378 2 : return 1;
379 : }
380 :
381 2 : static int httpcli_get_openid_config(grpc_exec_ctx *exec_ctx,
382 : const grpc_httpcli_request *request,
383 : gpr_timespec deadline,
384 : grpc_httpcli_response_cb on_response,
385 : void *user_data) {
386 2 : grpc_httpcli_response response =
387 2 : http_response(200, gpr_strdup(good_openid_config));
388 2 : GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl);
389 2 : GPR_ASSERT(strcmp(request->host, "accounts.google.com") == 0);
390 2 : GPR_ASSERT(strcmp(request->path, GRPC_OPENID_CONFIG_URL_SUFFIX) == 0);
391 2 : grpc_httpcli_set_override(httpcli_get_jwk_set,
392 : httpcli_post_should_not_be_called);
393 2 : on_response(exec_ctx, user_data, &response);
394 2 : gpr_free(response.body);
395 2 : return 1;
396 : }
397 :
398 1 : static void test_jwt_verifier_url_issuer_success(void) {
399 1 : grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
400 1 : grpc_jwt_verifier *verifier = grpc_jwt_verifier_create(NULL, 0);
401 1 : char *jwt = NULL;
402 1 : char *key_str = json_key_str(json_key_str_part3_for_url_issuer);
403 1 : grpc_auth_json_key key = grpc_auth_json_key_create_from_string(key_str);
404 1 : gpr_free(key_str);
405 1 : GPR_ASSERT(grpc_auth_json_key_is_valid(&key));
406 1 : grpc_httpcli_set_override(httpcli_get_openid_config,
407 : httpcli_post_should_not_be_called);
408 1 : jwt = grpc_jwt_encode_and_sign(&key, expected_audience, expected_lifetime,
409 : NULL);
410 1 : grpc_auth_json_key_destruct(&key);
411 1 : GPR_ASSERT(jwt != NULL);
412 1 : grpc_jwt_verifier_verify(&exec_ctx, verifier, NULL, jwt, expected_audience,
413 : on_verification_success, (void *)expected_user_data);
414 1 : gpr_free(jwt);
415 1 : grpc_jwt_verifier_destroy(verifier);
416 1 : grpc_httpcli_set_override(NULL, NULL);
417 1 : grpc_exec_ctx_finish(&exec_ctx);
418 1 : }
419 :
420 2 : static void on_verification_key_retrieval_error(void *user_data,
421 : grpc_jwt_verifier_status status,
422 : grpc_jwt_claims *claims) {
423 2 : GPR_ASSERT(status == GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR);
424 2 : GPR_ASSERT(claims == NULL);
425 2 : GPR_ASSERT(user_data == (void *)expected_user_data);
426 2 : }
427 :
428 2 : static int httpcli_get_bad_json(grpc_exec_ctx *exec_ctx,
429 : const grpc_httpcli_request *request,
430 : gpr_timespec deadline,
431 : grpc_httpcli_response_cb on_response,
432 : void *user_data) {
433 2 : grpc_httpcli_response response =
434 2 : http_response(200, gpr_strdup("{\"bad\": \"stuff\"}"));
435 2 : GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl);
436 2 : on_response(exec_ctx, user_data, &response);
437 2 : gpr_free(response.body);
438 2 : return 1;
439 : }
440 :
441 1 : static void test_jwt_verifier_url_issuer_bad_config(void) {
442 1 : grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
443 1 : grpc_jwt_verifier *verifier = grpc_jwt_verifier_create(NULL, 0);
444 1 : char *jwt = NULL;
445 1 : char *key_str = json_key_str(json_key_str_part3_for_url_issuer);
446 1 : grpc_auth_json_key key = grpc_auth_json_key_create_from_string(key_str);
447 1 : gpr_free(key_str);
448 1 : GPR_ASSERT(grpc_auth_json_key_is_valid(&key));
449 1 : grpc_httpcli_set_override(httpcli_get_bad_json,
450 : httpcli_post_should_not_be_called);
451 1 : jwt = grpc_jwt_encode_and_sign(&key, expected_audience, expected_lifetime,
452 : NULL);
453 1 : grpc_auth_json_key_destruct(&key);
454 1 : GPR_ASSERT(jwt != NULL);
455 1 : grpc_jwt_verifier_verify(&exec_ctx, verifier, NULL, jwt, expected_audience,
456 : on_verification_key_retrieval_error,
457 : (void *)expected_user_data);
458 1 : gpr_free(jwt);
459 1 : grpc_jwt_verifier_destroy(verifier);
460 1 : grpc_httpcli_set_override(NULL, NULL);
461 1 : grpc_exec_ctx_finish(&exec_ctx);
462 1 : }
463 :
464 1 : static void test_jwt_verifier_bad_json_key(void) {
465 1 : grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
466 1 : grpc_jwt_verifier *verifier = grpc_jwt_verifier_create(NULL, 0);
467 1 : char *jwt = NULL;
468 1 : char *key_str = json_key_str(json_key_str_part3_for_google_email_issuer);
469 1 : grpc_auth_json_key key = grpc_auth_json_key_create_from_string(key_str);
470 1 : gpr_free(key_str);
471 1 : GPR_ASSERT(grpc_auth_json_key_is_valid(&key));
472 1 : grpc_httpcli_set_override(httpcli_get_bad_json,
473 : httpcli_post_should_not_be_called);
474 1 : jwt = grpc_jwt_encode_and_sign(&key, expected_audience, expected_lifetime,
475 : NULL);
476 1 : grpc_auth_json_key_destruct(&key);
477 1 : GPR_ASSERT(jwt != NULL);
478 1 : grpc_jwt_verifier_verify(&exec_ctx, verifier, NULL, jwt, expected_audience,
479 : on_verification_key_retrieval_error,
480 : (void *)expected_user_data);
481 1 : gpr_free(jwt);
482 1 : grpc_jwt_verifier_destroy(verifier);
483 1 : grpc_httpcli_set_override(NULL, NULL);
484 1 : grpc_exec_ctx_finish(&exec_ctx);
485 1 : }
486 :
487 1 : static void corrupt_jwt_sig(char *jwt) {
488 : gpr_slice sig;
489 : char *bad_b64_sig;
490 : gpr_uint8 *sig_bytes;
491 1 : char *last_dot = strrchr(jwt, '.');
492 1 : GPR_ASSERT(last_dot != NULL);
493 1 : sig = grpc_base64_decode(last_dot + 1, 1);
494 1 : GPR_ASSERT(!GPR_SLICE_IS_EMPTY(sig));
495 1 : sig_bytes = GPR_SLICE_START_PTR(sig);
496 1 : (*sig_bytes)++; /* Corrupt first byte. */
497 1 : bad_b64_sig =
498 1 : grpc_base64_encode(GPR_SLICE_START_PTR(sig), GPR_SLICE_LENGTH(sig), 1, 0);
499 1 : memcpy(last_dot + 1, bad_b64_sig, strlen(bad_b64_sig));
500 1 : gpr_free(bad_b64_sig);
501 1 : gpr_slice_unref(sig);
502 1 : }
503 :
504 1 : static void on_verification_bad_signature(void *user_data,
505 : grpc_jwt_verifier_status status,
506 : grpc_jwt_claims *claims) {
507 1 : GPR_ASSERT(status == GRPC_JWT_VERIFIER_BAD_SIGNATURE);
508 1 : GPR_ASSERT(claims == NULL);
509 1 : GPR_ASSERT(user_data == (void *)expected_user_data);
510 1 : }
511 :
512 1 : static void test_jwt_verifier_bad_signature(void) {
513 1 : grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
514 1 : grpc_jwt_verifier *verifier = grpc_jwt_verifier_create(NULL, 0);
515 1 : char *jwt = NULL;
516 1 : char *key_str = json_key_str(json_key_str_part3_for_url_issuer);
517 1 : grpc_auth_json_key key = grpc_auth_json_key_create_from_string(key_str);
518 1 : gpr_free(key_str);
519 1 : GPR_ASSERT(grpc_auth_json_key_is_valid(&key));
520 1 : grpc_httpcli_set_override(httpcli_get_openid_config,
521 : httpcli_post_should_not_be_called);
522 1 : jwt = grpc_jwt_encode_and_sign(&key, expected_audience, expected_lifetime,
523 : NULL);
524 1 : grpc_auth_json_key_destruct(&key);
525 1 : corrupt_jwt_sig(jwt);
526 1 : GPR_ASSERT(jwt != NULL);
527 1 : grpc_jwt_verifier_verify(&exec_ctx, verifier, NULL, jwt, expected_audience,
528 : on_verification_bad_signature,
529 : (void *)expected_user_data);
530 1 : gpr_free(jwt);
531 1 : grpc_jwt_verifier_destroy(verifier);
532 1 : grpc_httpcli_set_override(NULL, NULL);
533 1 : grpc_exec_ctx_finish(&exec_ctx);
534 1 : }
535 :
536 0 : static int httpcli_get_should_not_be_called(
537 : grpc_exec_ctx *exec_ctx, const grpc_httpcli_request *request,
538 : gpr_timespec deadline, grpc_httpcli_response_cb on_response,
539 : void *user_data) {
540 0 : GPR_ASSERT(0);
541 : return 1;
542 : }
543 :
544 1 : static void on_verification_bad_format(void *user_data,
545 : grpc_jwt_verifier_status status,
546 : grpc_jwt_claims *claims) {
547 1 : GPR_ASSERT(status == GRPC_JWT_VERIFIER_BAD_FORMAT);
548 1 : GPR_ASSERT(claims == NULL);
549 1 : GPR_ASSERT(user_data == (void *)expected_user_data);
550 1 : }
551 :
552 1 : static void test_jwt_verifier_bad_format(void) {
553 1 : grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
554 1 : grpc_jwt_verifier *verifier = grpc_jwt_verifier_create(NULL, 0);
555 1 : grpc_httpcli_set_override(httpcli_get_should_not_be_called,
556 : httpcli_post_should_not_be_called);
557 1 : grpc_jwt_verifier_verify(&exec_ctx, verifier, NULL, "bad jwt",
558 : expected_audience, on_verification_bad_format,
559 : (void *)expected_user_data);
560 1 : grpc_jwt_verifier_destroy(verifier);
561 1 : grpc_httpcli_set_override(NULL, NULL);
562 1 : grpc_exec_ctx_finish(&exec_ctx);
563 1 : }
564 :
565 : /* find verification key: bad jks, cannot find key in jks */
566 : /* bad signature custom provided email*/
567 : /* bad key */
568 :
569 1 : int main(int argc, char **argv) {
570 1 : grpc_test_init(argc, argv);
571 1 : test_claims_success();
572 1 : test_expired_claims_failure();
573 1 : test_invalid_claims_failure();
574 1 : test_bad_audience_claims_failure();
575 1 : test_jwt_verifier_google_email_issuer_success();
576 1 : test_jwt_verifier_custom_email_issuer_success();
577 1 : test_jwt_verifier_url_issuer_success();
578 1 : test_jwt_verifier_url_issuer_bad_config();
579 1 : test_jwt_verifier_bad_json_key();
580 1 : test_jwt_verifier_bad_signature();
581 1 : test_jwt_verifier_bad_format();
582 1 : return 0;
583 : }
|