Home | History | Annotate | Download | only in security
      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/json_token.h"
     20 
     21 #include <openssl/evp.h>
     22 #include <string.h>
     23 
     24 #include <grpc/grpc_security.h>
     25 #include <grpc/slice.h>
     26 #include <grpc/support/alloc.h>
     27 #include <grpc/support/log.h>
     28 
     29 #include "src/core/lib/json/json.h"
     30 #include "src/core/lib/security/credentials/oauth2/oauth2_credentials.h"
     31 #include "src/core/lib/slice/b64.h"
     32 #include "src/core/lib/slice/slice_internal.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 test_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 test_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 test_json_key_str_part3[] =
     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 
     69 /* Test refresh token. */
     70 static const char test_refresh_token_str[] =
     71     "{ \"client_id\": \"32555999999.apps.googleusercontent.com\","
     72     "  \"client_secret\": \"EmssLNjJy1332hD4KFsecret\","
     73     "  \"refresh_token\": \"1/Blahblasj424jladJDSGNf-u4Sua3HDA2ngjd42\","
     74     "  \"type\": \"authorized_user\"}";
     75 
     76 static const char test_scope[] = "myperm1 myperm2";
     77 
     78 static const char test_service_url[] = "https://foo.com/foo.v1";
     79 
     80 static char* test_json_key_str(const char* bad_part3) {
     81   const char* part3 =
     82       bad_part3 != nullptr ? bad_part3 : test_json_key_str_part3;
     83   size_t result_len = strlen(test_json_key_str_part1) +
     84                       strlen(test_json_key_str_part2) + strlen(part3);
     85   char* result = static_cast<char*>(gpr_malloc(result_len + 1));
     86   char* current = result;
     87   strcpy(result, test_json_key_str_part1);
     88   current += strlen(test_json_key_str_part1);
     89   strcpy(current, test_json_key_str_part2);
     90   current += strlen(test_json_key_str_part2);
     91   strcpy(current, part3);
     92   return result;
     93 }
     94 
     95 static void test_parse_json_key_success(void) {
     96   char* json_string = test_json_key_str(nullptr);
     97   grpc_auth_json_key json_key =
     98       grpc_auth_json_key_create_from_string(json_string);
     99   GPR_ASSERT(grpc_auth_json_key_is_valid(&json_key));
    100   GPR_ASSERT(json_key.type != nullptr &&
    101              strcmp(json_key.type, "service_account") == 0);
    102   GPR_ASSERT(json_key.private_key_id != nullptr &&
    103              strcmp(json_key.private_key_id,
    104                     "e6b5137873db8d2ef81e06a47289e6434ec8a165") == 0);
    105   GPR_ASSERT(json_key.client_id != nullptr &&
    106              strcmp(json_key.client_id,
    107                     "777-abaslkan11hlb6nmim3bpspl31ud.apps."
    108                     "googleusercontent.com") == 0);
    109   GPR_ASSERT(json_key.client_email != nullptr &&
    110              strcmp(json_key.client_email,
    111                     "777-abaslkan11hlb6nmim3bpspl31ud@developer."
    112                     "gserviceaccount.com") == 0);
    113   GPR_ASSERT(json_key.private_key != nullptr);
    114   gpr_free(json_string);
    115   grpc_auth_json_key_destruct(&json_key);
    116 }
    117 
    118 static void test_parse_json_key_failure_bad_json(void) {
    119   const char non_closing_part3[] =
    120       "\"private_key_id\": \"e6b5137873db8d2ef81e06a47289e6434ec8a165\", "
    121       "\"client_email\": "
    122       "\"777-abaslkan11hlb6nmim3bpspl31ud (at) developer.gserviceaccount."
    123       "com\", \"client_id\": "
    124       "\"777-abaslkan11hlb6nmim3bpspl31ud.apps.googleusercontent."
    125       "com\", \"type\": \"service_account\" ";
    126   char* json_string = test_json_key_str(non_closing_part3);
    127   grpc_auth_json_key json_key =
    128       grpc_auth_json_key_create_from_string(json_string);
    129   GPR_ASSERT(!grpc_auth_json_key_is_valid(&json_key));
    130   gpr_free(json_string);
    131   grpc_auth_json_key_destruct(&json_key);
    132 }
    133 
    134 static void test_parse_json_key_failure_no_type(void) {
    135   const char no_type_part3[] =
    136       "\"private_key_id\": \"e6b5137873db8d2ef81e06a47289e6434ec8a165\", "
    137       "\"client_email\": "
    138       "\"777-abaslkan11hlb6nmim3bpspl31ud (at) developer.gserviceaccount."
    139       "com\", \"client_id\": "
    140       "\"777-abaslkan11hlb6nmim3bpspl31ud.apps.googleusercontent."
    141       "com\" }";
    142   char* json_string = test_json_key_str(no_type_part3);
    143   grpc_auth_json_key json_key =
    144       grpc_auth_json_key_create_from_string(json_string);
    145   GPR_ASSERT(!grpc_auth_json_key_is_valid(&json_key));
    146   gpr_free(json_string);
    147   grpc_auth_json_key_destruct(&json_key);
    148 }
    149 
    150 static void test_parse_json_key_failure_no_client_id(void) {
    151   const char no_client_id_part3[] =
    152       "\"private_key_id\": \"e6b5137873db8d2ef81e06a47289e6434ec8a165\", "
    153       "\"client_email\": "
    154       "\"777-abaslkan11hlb6nmim3bpspl31ud (at) developer.gserviceaccount."
    155       "com\", "
    156       "\"type\": \"service_account\" }";
    157   char* json_string = test_json_key_str(no_client_id_part3);
    158   grpc_auth_json_key json_key =
    159       grpc_auth_json_key_create_from_string(json_string);
    160   GPR_ASSERT(!grpc_auth_json_key_is_valid(&json_key));
    161   gpr_free(json_string);
    162   grpc_auth_json_key_destruct(&json_key);
    163 }
    164 
    165 static void test_parse_json_key_failure_no_client_email(void) {
    166   const char no_client_email_part3[] =
    167       "\"private_key_id\": \"e6b5137873db8d2ef81e06a47289e6434ec8a165\", "
    168       "\"client_id\": "
    169       "\"777-abaslkan11hlb6nmim3bpspl31ud.apps.googleusercontent."
    170       "com\", \"type\": \"service_account\" }";
    171   char* json_string = test_json_key_str(no_client_email_part3);
    172   grpc_auth_json_key json_key =
    173       grpc_auth_json_key_create_from_string(json_string);
    174   GPR_ASSERT(!grpc_auth_json_key_is_valid(&json_key));
    175   gpr_free(json_string);
    176   grpc_auth_json_key_destruct(&json_key);
    177 }
    178 
    179 static void test_parse_json_key_failure_no_private_key_id(void) {
    180   const char no_private_key_id_part3[] =
    181       "\"client_email\": "
    182       "\"777-abaslkan11hlb6nmim3bpspl31ud (at) developer.gserviceaccount."
    183       "com\", \"client_id\": "
    184       "\"777-abaslkan11hlb6nmim3bpspl31ud.apps.googleusercontent."
    185       "com\", \"type\": \"service_account\" }";
    186   char* json_string = test_json_key_str(no_private_key_id_part3);
    187   grpc_auth_json_key json_key =
    188       grpc_auth_json_key_create_from_string(json_string);
    189   GPR_ASSERT(!grpc_auth_json_key_is_valid(&json_key));
    190   gpr_free(json_string);
    191   grpc_auth_json_key_destruct(&json_key);
    192 }
    193 
    194 static void test_parse_json_key_failure_no_private_key(void) {
    195   const char no_private_key_json_string[] =
    196       "{ \"private_key_id\": \"e6b5137873db8d2ef81e06a47289e6434ec8a165\", "
    197       "\"client_email\": "
    198       "\"777-abaslkan11hlb6nmim3bpspl31ud (at) developer.gserviceaccount."
    199       "com\", \"client_id\": "
    200       "\"777-abaslkan11hlb6nmim3bpspl31ud.apps.googleusercontent."
    201       "com\", \"type\": \"service_account\" }";
    202   grpc_auth_json_key json_key =
    203       grpc_auth_json_key_create_from_string(no_private_key_json_string);
    204   GPR_ASSERT(!grpc_auth_json_key_is_valid(&json_key));
    205   grpc_auth_json_key_destruct(&json_key);
    206 }
    207 
    208 static grpc_json* parse_json_part_from_jwt(const char* str, size_t len,
    209                                            char** scratchpad) {
    210   grpc_core::ExecCtx exec_ctx;
    211   char* b64;
    212   char* decoded;
    213   grpc_json* json;
    214   grpc_slice slice;
    215   b64 = static_cast<char*>(gpr_malloc(len + 1));
    216   strncpy(b64, str, len);
    217   b64[len] = '\0';
    218   slice = grpc_base64_decode(b64, 1);
    219   GPR_ASSERT(!GRPC_SLICE_IS_EMPTY(slice));
    220   decoded = static_cast<char*>(gpr_malloc(GRPC_SLICE_LENGTH(slice) + 1));
    221   strncpy(decoded, reinterpret_cast<const char*> GRPC_SLICE_START_PTR(slice),
    222           GRPC_SLICE_LENGTH(slice));
    223   decoded[GRPC_SLICE_LENGTH(slice)] = '\0';
    224   json = grpc_json_parse_string(decoded);
    225   gpr_free(b64);
    226   *scratchpad = decoded;
    227   grpc_slice_unref(slice);
    228 
    229   return json;
    230 }
    231 
    232 static void check_jwt_header(grpc_json* header) {
    233   grpc_json* ptr;
    234   grpc_json* alg = nullptr;
    235   grpc_json* typ = nullptr;
    236   grpc_json* kid = nullptr;
    237 
    238   for (ptr = header->child; ptr; ptr = ptr->next) {
    239     if (strcmp(ptr->key, "alg") == 0) {
    240       alg = ptr;
    241     } else if (strcmp(ptr->key, "typ") == 0) {
    242       typ = ptr;
    243     } else if (strcmp(ptr->key, "kid") == 0) {
    244       kid = ptr;
    245     }
    246   }
    247   GPR_ASSERT(alg != nullptr);
    248   GPR_ASSERT(alg->type == GRPC_JSON_STRING);
    249   GPR_ASSERT(strcmp(alg->value, "RS256") == 0);
    250 
    251   GPR_ASSERT(typ != nullptr);
    252   GPR_ASSERT(typ->type == GRPC_JSON_STRING);
    253   GPR_ASSERT(strcmp(typ->value, "JWT") == 0);
    254 
    255   GPR_ASSERT(kid != nullptr);
    256   GPR_ASSERT(kid->type == GRPC_JSON_STRING);
    257   GPR_ASSERT(strcmp(kid->value, "e6b5137873db8d2ef81e06a47289e6434ec8a165") ==
    258              0);
    259 }
    260 
    261 static void check_jwt_claim(grpc_json* claim, const char* expected_audience,
    262                             const char* expected_scope) {
    263   gpr_timespec expiration = gpr_time_0(GPR_CLOCK_REALTIME);
    264   gpr_timespec issue_time = gpr_time_0(GPR_CLOCK_REALTIME);
    265   gpr_timespec parsed_lifetime;
    266   grpc_json* iss = nullptr;
    267   grpc_json* scope = nullptr;
    268   grpc_json* aud = nullptr;
    269   grpc_json* exp = nullptr;
    270   grpc_json* iat = nullptr;
    271   grpc_json* sub = nullptr;
    272   grpc_json* ptr;
    273 
    274   for (ptr = claim->child; ptr; ptr = ptr->next) {
    275     if (strcmp(ptr->key, "iss") == 0) {
    276       iss = ptr;
    277     } else if (strcmp(ptr->key, "sub") == 0) {
    278       sub = ptr;
    279     } else if (strcmp(ptr->key, "scope") == 0) {
    280       scope = ptr;
    281     } else if (strcmp(ptr->key, "aud") == 0) {
    282       aud = ptr;
    283     } else if (strcmp(ptr->key, "exp") == 0) {
    284       exp = ptr;
    285     } else if (strcmp(ptr->key, "iat") == 0) {
    286       iat = ptr;
    287     }
    288   }
    289 
    290   GPR_ASSERT(iss != nullptr);
    291   GPR_ASSERT(iss->type == GRPC_JSON_STRING);
    292   GPR_ASSERT(
    293       strcmp(
    294           iss->value,
    295           "777-abaslkan11hlb6nmim3bpspl31ud (at) developer.gserviceaccount.com") ==
    296       0);
    297 
    298   if (expected_scope != nullptr) {
    299     GPR_ASSERT(scope != nullptr);
    300     GPR_ASSERT(sub == nullptr);
    301     GPR_ASSERT(scope->type == GRPC_JSON_STRING);
    302     GPR_ASSERT(strcmp(scope->value, expected_scope) == 0);
    303   } else {
    304     /* Claims without scope must have a sub. */
    305     GPR_ASSERT(scope == nullptr);
    306     GPR_ASSERT(sub != nullptr);
    307     GPR_ASSERT(sub->type == GRPC_JSON_STRING);
    308     GPR_ASSERT(strcmp(iss->value, sub->value) == 0);
    309   }
    310 
    311   GPR_ASSERT(aud != nullptr);
    312   GPR_ASSERT(aud->type == GRPC_JSON_STRING);
    313   GPR_ASSERT(strcmp(aud->value, expected_audience) == 0);
    314 
    315   GPR_ASSERT(exp != nullptr);
    316   GPR_ASSERT(exp->type == GRPC_JSON_NUMBER);
    317   expiration.tv_sec = strtol(exp->value, nullptr, 10);
    318 
    319   GPR_ASSERT(iat != nullptr);
    320   GPR_ASSERT(iat->type == GRPC_JSON_NUMBER);
    321   issue_time.tv_sec = strtol(iat->value, nullptr, 10);
    322 
    323   parsed_lifetime = gpr_time_sub(expiration, issue_time);
    324   GPR_ASSERT(parsed_lifetime.tv_sec == grpc_max_auth_token_lifetime().tv_sec);
    325 }
    326 
    327 static void check_jwt_signature(const char* b64_signature, RSA* rsa_key,
    328                                 const char* signed_data,
    329                                 size_t signed_data_size) {
    330   grpc_core::ExecCtx exec_ctx;
    331 
    332   EVP_MD_CTX* md_ctx = EVP_MD_CTX_create();
    333   EVP_PKEY* key = EVP_PKEY_new();
    334 
    335   grpc_slice sig = grpc_base64_decode(b64_signature, 1);
    336   GPR_ASSERT(!GRPC_SLICE_IS_EMPTY(sig));
    337   GPR_ASSERT(GRPC_SLICE_LENGTH(sig) == 128);
    338 
    339   GPR_ASSERT(md_ctx != nullptr);
    340   GPR_ASSERT(key != nullptr);
    341   EVP_PKEY_set1_RSA(key, rsa_key);
    342 
    343   GPR_ASSERT(
    344       EVP_DigestVerifyInit(md_ctx, nullptr, EVP_sha256(), nullptr, key) == 1);
    345   GPR_ASSERT(EVP_DigestVerifyUpdate(md_ctx, signed_data, signed_data_size) ==
    346              1);
    347   GPR_ASSERT(EVP_DigestVerifyFinal(md_ctx, GRPC_SLICE_START_PTR(sig),
    348                                    GRPC_SLICE_LENGTH(sig)) == 1);
    349 
    350   grpc_slice_unref_internal(sig);
    351   if (key != nullptr) EVP_PKEY_free(key);
    352   if (md_ctx != nullptr) EVP_MD_CTX_destroy(md_ctx);
    353 }
    354 
    355 static char* service_account_creds_jwt_encode_and_sign(
    356     const grpc_auth_json_key* key) {
    357   return grpc_jwt_encode_and_sign(key, GRPC_JWT_OAUTH2_AUDIENCE,
    358                                   grpc_max_auth_token_lifetime(), test_scope);
    359 }
    360 
    361 static char* jwt_creds_jwt_encode_and_sign(const grpc_auth_json_key* key) {
    362   return grpc_jwt_encode_and_sign(key, test_service_url,
    363                                   grpc_max_auth_token_lifetime(), nullptr);
    364 }
    365 
    366 static void service_account_creds_check_jwt_claim(grpc_json* claim) {
    367   check_jwt_claim(claim, GRPC_JWT_OAUTH2_AUDIENCE, test_scope);
    368 }
    369 
    370 static void jwt_creds_check_jwt_claim(grpc_json* claim) {
    371   check_jwt_claim(claim, test_service_url, nullptr);
    372 }
    373 
    374 static void test_jwt_encode_and_sign(
    375     char* (*jwt_encode_and_sign_func)(const grpc_auth_json_key*),
    376     void (*check_jwt_claim_func)(grpc_json*)) {
    377   char* json_string = test_json_key_str(nullptr);
    378   grpc_json* parsed_header = nullptr;
    379   grpc_json* parsed_claim = nullptr;
    380   char* scratchpad;
    381   grpc_auth_json_key json_key =
    382       grpc_auth_json_key_create_from_string(json_string);
    383   const char* b64_signature;
    384   size_t offset = 0;
    385   char* jwt = jwt_encode_and_sign_func(&json_key);
    386   const char* dot = strchr(jwt, '.');
    387   GPR_ASSERT(dot != nullptr);
    388   parsed_header = parse_json_part_from_jwt(jwt, static_cast<size_t>(dot - jwt),
    389                                            &scratchpad);
    390   GPR_ASSERT(parsed_header != nullptr);
    391   check_jwt_header(parsed_header);
    392   offset = static_cast<size_t>(dot - jwt) + 1;
    393   grpc_json_destroy(parsed_header);
    394   gpr_free(scratchpad);
    395 
    396   dot = strchr(jwt + offset, '.');
    397   GPR_ASSERT(dot != nullptr);
    398   parsed_claim = parse_json_part_from_jwt(
    399       jwt + offset, static_cast<size_t>(dot - (jwt + offset)), &scratchpad);
    400   GPR_ASSERT(parsed_claim != nullptr);
    401   check_jwt_claim_func(parsed_claim);
    402   offset = static_cast<size_t>(dot - jwt) + 1;
    403   grpc_json_destroy(parsed_claim);
    404   gpr_free(scratchpad);
    405 
    406   dot = strchr(jwt + offset, '.');
    407   GPR_ASSERT(dot == nullptr); /* no more part. */
    408   b64_signature = jwt + offset;
    409   check_jwt_signature(b64_signature, json_key.private_key, jwt, offset - 1);
    410 
    411   gpr_free(json_string);
    412   grpc_auth_json_key_destruct(&json_key);
    413   gpr_free(jwt);
    414 }
    415 
    416 static void test_service_account_creds_jwt_encode_and_sign(void) {
    417   test_jwt_encode_and_sign(service_account_creds_jwt_encode_and_sign,
    418                            service_account_creds_check_jwt_claim);
    419 }
    420 
    421 static void test_jwt_creds_jwt_encode_and_sign(void) {
    422   test_jwt_encode_and_sign(jwt_creds_jwt_encode_and_sign,
    423                            jwt_creds_check_jwt_claim);
    424 }
    425 
    426 static void test_parse_refresh_token_success(void) {
    427   grpc_auth_refresh_token refresh_token =
    428       grpc_auth_refresh_token_create_from_string(test_refresh_token_str);
    429   GPR_ASSERT(grpc_auth_refresh_token_is_valid(&refresh_token));
    430   GPR_ASSERT(refresh_token.type != nullptr &&
    431              (strcmp(refresh_token.type, "authorized_user") == 0));
    432   GPR_ASSERT(refresh_token.client_id != nullptr &&
    433              (strcmp(refresh_token.client_id,
    434                      "32555999999.apps.googleusercontent.com") == 0));
    435   GPR_ASSERT(
    436       refresh_token.client_secret != nullptr &&
    437       (strcmp(refresh_token.client_secret, "EmssLNjJy1332hD4KFsecret") == 0));
    438   GPR_ASSERT(refresh_token.refresh_token != nullptr &&
    439              (strcmp(refresh_token.refresh_token,
    440                      "1/Blahblasj424jladJDSGNf-u4Sua3HDA2ngjd42") == 0));
    441   grpc_auth_refresh_token_destruct(&refresh_token);
    442 }
    443 
    444 static void test_parse_refresh_token_failure_no_type(void) {
    445   const char refresh_token_str[] =
    446       "{ \"client_id\": \"32555999999.apps.googleusercontent.com\","
    447       "  \"client_secret\": \"EmssLNjJy1332hD4KFsecret\","
    448       "  \"refresh_token\": \"1/Blahblasj424jladJDSGNf-u4Sua3HDA2ngjd42\"}";
    449   grpc_auth_refresh_token refresh_token =
    450       grpc_auth_refresh_token_create_from_string(refresh_token_str);
    451   GPR_ASSERT(!grpc_auth_refresh_token_is_valid(&refresh_token));
    452 }
    453 
    454 static void test_parse_refresh_token_failure_no_client_id(void) {
    455   const char refresh_token_str[] =
    456       "{ \"client_secret\": \"EmssLNjJy1332hD4KFsecret\","
    457       "  \"refresh_token\": \"1/Blahblasj424jladJDSGNf-u4Sua3HDA2ngjd42\","
    458       "  \"type\": \"authorized_user\"}";
    459   grpc_auth_refresh_token refresh_token =
    460       grpc_auth_refresh_token_create_from_string(refresh_token_str);
    461   GPR_ASSERT(!grpc_auth_refresh_token_is_valid(&refresh_token));
    462 }
    463 
    464 static void test_parse_refresh_token_failure_no_client_secret(void) {
    465   const char refresh_token_str[] =
    466       "{ \"client_id\": \"32555999999.apps.googleusercontent.com\","
    467       "  \"refresh_token\": \"1/Blahblasj424jladJDSGNf-u4Sua3HDA2ngjd42\","
    468       "  \"type\": \"authorized_user\"}";
    469   grpc_auth_refresh_token refresh_token =
    470       grpc_auth_refresh_token_create_from_string(refresh_token_str);
    471   GPR_ASSERT(!grpc_auth_refresh_token_is_valid(&refresh_token));
    472 }
    473 
    474 static void test_parse_refresh_token_failure_no_refresh_token(void) {
    475   const char refresh_token_str[] =
    476       "{ \"client_id\": \"32555999999.apps.googleusercontent.com\","
    477       "  \"client_secret\": \"EmssLNjJy1332hD4KFsecret\","
    478       "  \"type\": \"authorized_user\"}";
    479   grpc_auth_refresh_token refresh_token =
    480       grpc_auth_refresh_token_create_from_string(refresh_token_str);
    481   GPR_ASSERT(!grpc_auth_refresh_token_is_valid(&refresh_token));
    482 }
    483 
    484 int main(int argc, char** argv) {
    485   grpc_test_init(argc, argv);
    486   grpc_init();
    487   test_parse_json_key_success();
    488   test_parse_json_key_failure_bad_json();
    489   test_parse_json_key_failure_no_type();
    490   test_parse_json_key_failure_no_client_id();
    491   test_parse_json_key_failure_no_client_email();
    492   test_parse_json_key_failure_no_private_key_id();
    493   test_parse_json_key_failure_no_private_key();
    494   test_service_account_creds_jwt_encode_and_sign();
    495   test_jwt_creds_jwt_encode_and_sign();
    496   test_parse_refresh_token_success();
    497   test_parse_refresh_token_failure_no_type();
    498   test_parse_refresh_token_failure_no_client_id();
    499   test_parse_refresh_token_failure_no_client_secret();
    500   test_parse_refresh_token_failure_no_refresh_token();
    501   grpc_shutdown();
    502   return 0;
    503 }
    504