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 (at) 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 (at) 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 (at) 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 (at) 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 (at) blah.foo.com\"," 157 " \"sub\": \"juju (at) 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 (at) 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 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 (at) foo.com"); 186 GPR_ASSERT(strcmp(d, "foo.com") == 0); 187 d = grpc_jwt_issuer_email_domain("bar (at) blah.foo.com"); 188 GPR_ASSERT(strcmp(d, "foo.com") == 0); 189 d = grpc_jwt_issuer_email_domain("bar.blah (at) blah.foo.com"); 190 GPR_ASSERT(strcmp(d, "foo.com") == 0); 191 d = grpc_jwt_issuer_email_domain("bar.blah (at) 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 (at) ..."); 203 GPR_ASSERT(d != nullptr); 204 } 205 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 (at) 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 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 (at) 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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