LCOV - code coverage report
Current view: top level - src/core/security - credentials.c (source / functions) Hit Total Coverage
Test: tmp.zDYK9MVh93 Lines: 657 717 91.6 %
Date: 2015-10-10 Functions: 89 91 97.8 %

          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/credentials.h"
      35             : 
      36             : #include <string.h>
      37             : #include <stdio.h>
      38             : 
      39             : #include "src/core/channel/channel_args.h"
      40             : #include "src/core/channel/http_client_filter.h"
      41             : #include "src/core/json/json.h"
      42             : #include "src/core/httpcli/httpcli.h"
      43             : #include "src/core/iomgr/iomgr.h"
      44             : #include "src/core/surface/api_trace.h"
      45             : #include "src/core/support/string.h"
      46             : 
      47             : #include <grpc/support/alloc.h>
      48             : #include <grpc/support/log.h>
      49             : #include <grpc/support/string_util.h>
      50             : #include <grpc/support/sync.h>
      51             : #include <grpc/support/thd.h>
      52             : #include <grpc/support/time.h>
      53             : 
      54             : /* -- Common. -- */
      55             : 
      56             : struct grpc_credentials_metadata_request {
      57             :   grpc_credentials *creds;
      58             :   grpc_credentials_metadata_cb cb;
      59             :   void *user_data;
      60             : };
      61             : 
      62             : static grpc_credentials_metadata_request *
      63         112 : grpc_credentials_metadata_request_create(grpc_credentials *creds,
      64             :                                          grpc_credentials_metadata_cb cb,
      65             :                                          void *user_data) {
      66         112 :   grpc_credentials_metadata_request *r =
      67             :       gpr_malloc(sizeof(grpc_credentials_metadata_request));
      68         112 :   r->creds = grpc_credentials_ref(creds);
      69         112 :   r->cb = cb;
      70         112 :   r->user_data = user_data;
      71         112 :   return r;
      72             : }
      73             : 
      74         112 : static void grpc_credentials_metadata_request_destroy(
      75             :     grpc_credentials_metadata_request *r) {
      76         112 :   grpc_credentials_unref(r->creds);
      77         112 :   gpr_free(r);
      78         112 : }
      79             : 
      80         983 : grpc_credentials *grpc_credentials_ref(grpc_credentials *creds) {
      81         983 :   if (creds == NULL) return NULL;
      82         544 :   gpr_ref(&creds->refcount);
      83         544 :   return creds;
      84             : }
      85             : 
      86        3318 : void grpc_credentials_unref(grpc_credentials *creds) {
      87        6636 :   if (creds == NULL) return;
      88        1293 :   if (gpr_unref(&creds->refcount)) {
      89         749 :     creds->vtable->destruct(creds);
      90         749 :     gpr_free(creds);
      91             :   }
      92             : }
      93             : 
      94         727 : void grpc_credentials_release(grpc_credentials *creds) {
      95         727 :   GRPC_API_TRACE("grpc_credentials_release(creds=%p)", 1, (creds));
      96         727 :   grpc_credentials_unref(creds);
      97         727 : }
      98             : 
      99        1645 : int grpc_credentials_has_request_metadata(grpc_credentials *creds) {
     100        1645 :   if (creds == NULL) return 0;
     101        1645 :   return creds->vtable->has_request_metadata(creds);
     102             : }
     103             : 
     104         924 : int grpc_credentials_has_request_metadata_only(grpc_credentials *creds) {
     105         924 :   if (creds == NULL) return 0;
     106         924 :   return creds->vtable->has_request_metadata_only(creds);
     107             : }
     108             : 
     109         258 : void grpc_credentials_get_request_metadata(
     110             :     grpc_exec_ctx *exec_ctx, grpc_credentials *creds, grpc_pollset *pollset,
     111             :     const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) {
     112         516 :   if (creds == NULL || !grpc_credentials_has_request_metadata(creds) ||
     113         258 :       creds->vtable->get_request_metadata == NULL) {
     114           0 :     if (cb != NULL) {
     115           0 :       cb(exec_ctx, user_data, NULL, 0, GRPC_CREDENTIALS_OK);
     116             :     }
     117         258 :     return;
     118             :   }
     119         258 :   creds->vtable->get_request_metadata(exec_ctx, creds, pollset, service_url, cb,
     120             :                                       user_data);
     121             : }
     122             : 
     123         602 : grpc_security_status grpc_credentials_create_security_connector(
     124             :     grpc_credentials *creds, const char *target, const grpc_channel_args *args,
     125             :     grpc_credentials *request_metadata_creds,
     126             :     grpc_channel_security_connector **sc, grpc_channel_args **new_args) {
     127         602 :   *new_args = NULL;
     128        1204 :   if (creds == NULL || creds->vtable->create_security_connector == NULL ||
     129         602 :       grpc_credentials_has_request_metadata_only(creds)) {
     130           0 :     gpr_log(GPR_ERROR,
     131             :             "Invalid credentials for creating a security connector.");
     132           0 :     return GRPC_SECURITY_ERROR;
     133             :   }
     134         602 :   return creds->vtable->create_security_connector(
     135             :       creds, target, args, request_metadata_creds, sc, new_args);
     136             : }
     137             : 
     138        1403 : grpc_server_credentials *grpc_server_credentials_ref(
     139             :     grpc_server_credentials *creds) {
     140        1403 :   if (creds == NULL) return NULL;
     141        1403 :   gpr_ref(&creds->refcount);
     142        1403 :   return creds;
     143             : }
     144             : 
     145        1926 : void grpc_server_credentials_unref(grpc_server_credentials *creds) {
     146        3852 :   if (creds == NULL) return;
     147        1926 :   if (gpr_unref(&creds->refcount)) {
     148         523 :     creds->vtable->destruct(creds);
     149         523 :     if (creds->processor.destroy != NULL && creds->processor.state != NULL) {
     150         131 :       creds->processor.destroy(creds->processor.state);
     151             :     }
     152         523 :     gpr_free(creds);
     153             :   }
     154             : }
     155             : 
     156         523 : void grpc_server_credentials_release(grpc_server_credentials *creds) {
     157         523 :   GRPC_API_TRACE("grpc_server_credentials_release(creds=%p)", 1, (creds));
     158         523 :   grpc_server_credentials_unref(creds);
     159         523 : }
     160             : 
     161         523 : grpc_security_status grpc_server_credentials_create_security_connector(
     162             :     grpc_server_credentials *creds, grpc_security_connector **sc) {
     163         523 :   if (creds == NULL || creds->vtable->create_security_connector == NULL) {
     164           0 :     gpr_log(GPR_ERROR, "Server credentials cannot create security context.");
     165           0 :     return GRPC_SECURITY_ERROR;
     166             :   }
     167         523 :   return creds->vtable->create_security_connector(creds, sc);
     168             : }
     169             : 
     170         135 : void grpc_server_credentials_set_auth_metadata_processor(
     171             :     grpc_server_credentials *creds, grpc_auth_metadata_processor processor) {
     172         135 :   GRPC_API_TRACE(
     173             :       "grpc_server_credentials_set_auth_metadata_processor("
     174             :       "creds=%p, "
     175             :       "processor=grpc_auth_metadata_processor { process: %lx, state: %p })",
     176             :       3, (creds, (unsigned long)processor.process, processor.state));
     177         270 :   if (creds == NULL) return;
     178         135 :   if (creds->processor.destroy != NULL && creds->processor.state != NULL) {
     179           0 :     creds->processor.destroy(creds->processor.state);
     180             :   }
     181         135 :   creds->processor = processor;
     182             : }
     183             : 
     184         440 : static void server_credentials_pointer_arg_destroy(void *p) {
     185         440 :   grpc_server_credentials_unref(p);
     186         440 : }
     187             : 
     188         440 : static void *server_credentials_pointer_arg_copy(void *p) {
     189         440 :   return grpc_server_credentials_ref(p);
     190             : }
     191             : 
     192         440 : grpc_arg grpc_server_credentials_to_arg(grpc_server_credentials *p) {
     193             :   grpc_arg arg;
     194         440 :   memset(&arg, 0, sizeof(grpc_arg));
     195         440 :   arg.type = GRPC_ARG_POINTER;
     196         440 :   arg.key = GRPC_SERVER_CREDENTIALS_ARG;
     197         440 :   arg.value.pointer.p = p;
     198         440 :   arg.value.pointer.copy = server_credentials_pointer_arg_copy;
     199         440 :   arg.value.pointer.destroy = server_credentials_pointer_arg_destroy;
     200         440 :   return arg;
     201             : }
     202             : 
     203         565 : grpc_server_credentials *grpc_server_credentials_from_arg(
     204             :     const grpc_arg *arg) {
     205         565 :   if (strcmp(arg->key, GRPC_SERVER_CREDENTIALS_ARG) != 0) return NULL;
     206         440 :   if (arg->type != GRPC_ARG_POINTER) {
     207           0 :     gpr_log(GPR_ERROR, "Invalid type %d for arg %s", arg->type,
     208             :             GRPC_SERVER_CREDENTIALS_ARG);
     209           0 :     return NULL;
     210             :   }
     211         440 :   return arg->value.pointer.p;
     212             : }
     213             : 
     214         440 : grpc_server_credentials *grpc_find_server_credentials_in_args(
     215             :     const grpc_channel_args *args) {
     216             :   size_t i;
     217         440 :   if (args == NULL) return NULL;
     218         565 :   for (i = 0; i < args->num_args; i++) {
     219         565 :     grpc_server_credentials *p =
     220         565 :         grpc_server_credentials_from_arg(&args->args[i]);
     221         565 :     if (p != NULL) return p;
     222             :   }
     223           0 :   return NULL;
     224             : }
     225             : 
     226             : /* -- Ssl credentials. -- */
     227             : 
     228         437 : static void ssl_destruct(grpc_credentials *creds) {
     229         437 :   grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds;
     230         437 :   if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs);
     231         437 :   if (c->config.pem_private_key != NULL) gpr_free(c->config.pem_private_key);
     232         437 :   if (c->config.pem_cert_chain != NULL) gpr_free(c->config.pem_cert_chain);
     233         437 : }
     234             : 
     235         438 : static void ssl_server_destruct(grpc_server_credentials *creds) {
     236         438 :   grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds;
     237             :   size_t i;
     238         876 :   for (i = 0; i < c->config.num_key_cert_pairs; i++) {
     239         438 :     if (c->config.pem_private_keys[i] != NULL) {
     240         438 :       gpr_free(c->config.pem_private_keys[i]);
     241             :     }
     242         438 :     if (c->config.pem_cert_chains[i] != NULL) {
     243         438 :       gpr_free(c->config.pem_cert_chains[i]);
     244             :     }
     245             :   }
     246         438 :   if (c->config.pem_private_keys != NULL) gpr_free(c->config.pem_private_keys);
     247         438 :   if (c->config.pem_private_keys_sizes != NULL) {
     248         438 :     gpr_free(c->config.pem_private_keys_sizes);
     249             :   }
     250         438 :   if (c->config.pem_cert_chains != NULL) gpr_free(c->config.pem_cert_chains);
     251         438 :   if (c->config.pem_cert_chains_sizes != NULL) {
     252         438 :     gpr_free(c->config.pem_cert_chains_sizes);
     253             :   }
     254         438 :   if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs);
     255         438 : }
     256             : 
     257         524 : static int ssl_has_request_metadata(const grpc_credentials *creds) { return 0; }
     258             : 
     259         612 : static int ssl_has_request_metadata_only(const grpc_credentials *creds) {
     260         612 :   return 0;
     261             : }
     262             : 
     263         434 : static grpc_security_status ssl_create_security_connector(
     264             :     grpc_credentials *creds, const char *target, const grpc_channel_args *args,
     265             :     grpc_credentials *request_metadata_creds,
     266             :     grpc_channel_security_connector **sc, grpc_channel_args **new_args) {
     267         434 :   grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds;
     268         434 :   grpc_security_status status = GRPC_SECURITY_OK;
     269         434 :   size_t i = 0;
     270         434 :   const char *overridden_target_name = NULL;
     271             :   grpc_arg new_arg;
     272             : 
     273         464 :   for (i = 0; args && i < args->num_args; i++) {
     274         464 :     grpc_arg *arg = &args->args[i];
     275         898 :     if (strcmp(arg->key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG) == 0 &&
     276         434 :         arg->type == GRPC_ARG_STRING) {
     277         434 :       overridden_target_name = arg->value.string;
     278         434 :       break;
     279             :     }
     280             :   }
     281         434 :   status = grpc_ssl_channel_security_connector_create(
     282         434 :       request_metadata_creds, &c->config, target, overridden_target_name, sc);
     283         434 :   if (status != GRPC_SECURITY_OK) {
     284           0 :     return status;
     285             :   }
     286         434 :   new_arg.type = GRPC_ARG_STRING;
     287         434 :   new_arg.key = GRPC_ARG_HTTP2_SCHEME;
     288         434 :   new_arg.value.string = "https";
     289         434 :   *new_args = grpc_channel_args_copy_and_add(args, &new_arg, 1);
     290         434 :   return status;
     291             : }
     292             : 
     293         438 : static grpc_security_status ssl_server_create_security_connector(
     294             :     grpc_server_credentials *creds, grpc_security_connector **sc) {
     295         438 :   grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds;
     296         438 :   return grpc_ssl_server_security_connector_create(&c->config, sc);
     297             : }
     298             : 
     299             : static grpc_credentials_vtable ssl_vtable = {
     300             :     ssl_destruct, ssl_has_request_metadata, ssl_has_request_metadata_only, NULL,
     301             :     ssl_create_security_connector};
     302             : 
     303             : static grpc_server_credentials_vtable ssl_server_vtable = {
     304             :     ssl_server_destruct, ssl_server_create_security_connector};
     305             : 
     306        1008 : static void ssl_copy_key_material(const char *input, unsigned char **output,
     307             :                                   size_t *output_size) {
     308        1008 :   *output_size = strlen(input);
     309        1008 :   *output = gpr_malloc(*output_size);
     310        1008 :   memcpy(*output, input, *output_size);
     311        1008 : }
     312             : 
     313         438 : static void ssl_build_config(const char *pem_root_certs,
     314             :                              grpc_ssl_pem_key_cert_pair *pem_key_cert_pair,
     315             :                              grpc_ssl_config *config) {
     316         438 :   if (pem_root_certs != NULL) {
     317         132 :     ssl_copy_key_material(pem_root_certs, &config->pem_root_certs,
     318             :                           &config->pem_root_certs_size);
     319             :   }
     320         438 :   if (pem_key_cert_pair != NULL) {
     321           0 :     GPR_ASSERT(pem_key_cert_pair->private_key != NULL);
     322           0 :     GPR_ASSERT(pem_key_cert_pair->cert_chain != NULL);
     323           0 :     ssl_copy_key_material(pem_key_cert_pair->private_key,
     324             :                           &config->pem_private_key,
     325             :                           &config->pem_private_key_size);
     326           0 :     ssl_copy_key_material(pem_key_cert_pair->cert_chain,
     327             :                           &config->pem_cert_chain,
     328             :                           &config->pem_cert_chain_size);
     329             :   }
     330         438 : }
     331             : 
     332         438 : static void ssl_build_server_config(
     333             :     const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs,
     334             :     size_t num_key_cert_pairs, int force_client_auth,
     335             :     grpc_ssl_server_config *config) {
     336             :   size_t i;
     337         438 :   config->force_client_auth = force_client_auth;
     338         438 :   if (pem_root_certs != NULL) {
     339           0 :     ssl_copy_key_material(pem_root_certs, &config->pem_root_certs,
     340             :                           &config->pem_root_certs_size);
     341             :   }
     342         438 :   if (num_key_cert_pairs > 0) {
     343         438 :     GPR_ASSERT(pem_key_cert_pairs != NULL);
     344         438 :     config->pem_private_keys =
     345         438 :         gpr_malloc(num_key_cert_pairs * sizeof(unsigned char *));
     346         438 :     config->pem_cert_chains =
     347         438 :         gpr_malloc(num_key_cert_pairs * sizeof(unsigned char *));
     348         438 :     config->pem_private_keys_sizes =
     349         438 :         gpr_malloc(num_key_cert_pairs * sizeof(size_t));
     350         438 :     config->pem_cert_chains_sizes =
     351         438 :         gpr_malloc(num_key_cert_pairs * sizeof(size_t));
     352             :   }
     353         438 :   config->num_key_cert_pairs = num_key_cert_pairs;
     354         876 :   for (i = 0; i < num_key_cert_pairs; i++) {
     355         438 :     GPR_ASSERT(pem_key_cert_pairs[i].private_key != NULL);
     356         438 :     GPR_ASSERT(pem_key_cert_pairs[i].cert_chain != NULL);
     357         876 :     ssl_copy_key_material(pem_key_cert_pairs[i].private_key,
     358         438 :                           &config->pem_private_keys[i],
     359         438 :                           &config->pem_private_keys_sizes[i]);
     360         876 :     ssl_copy_key_material(pem_key_cert_pairs[i].cert_chain,
     361         438 :                           &config->pem_cert_chains[i],
     362         438 :                           &config->pem_cert_chains_sizes[i]);
     363             :   }
     364         438 : }
     365             : 
     366         438 : grpc_credentials *grpc_ssl_credentials_create(
     367             :     const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair,
     368             :     void *reserved) {
     369         438 :   grpc_ssl_credentials *c = gpr_malloc(sizeof(grpc_ssl_credentials));
     370         438 :   GRPC_API_TRACE(
     371             :       "grpc_ssl_credentials_create(pem_root_certs=%s, "
     372             :       "pem_key_cert_pair=%p, "
     373             :       "reserved=%p)",
     374             :       3, (pem_root_certs, pem_key_cert_pair, reserved));
     375         438 :   GPR_ASSERT(reserved == NULL);
     376         438 :   memset(c, 0, sizeof(grpc_ssl_credentials));
     377         438 :   c->base.type = GRPC_CREDENTIALS_TYPE_SSL;
     378         438 :   c->base.vtable = &ssl_vtable;
     379         438 :   gpr_ref_init(&c->base.refcount, 1);
     380         438 :   ssl_build_config(pem_root_certs, pem_key_cert_pair, &c->config);
     381         438 :   return &c->base;
     382             : }
     383             : 
     384         438 : grpc_server_credentials *grpc_ssl_server_credentials_create(
     385             :     const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs,
     386             :     size_t num_key_cert_pairs, int force_client_auth, void *reserved) {
     387         438 :   grpc_ssl_server_credentials *c =
     388             :       gpr_malloc(sizeof(grpc_ssl_server_credentials));
     389         438 :   GRPC_API_TRACE(
     390             :       "grpc_ssl_server_credentials_create("
     391             :       "pem_root_certs=%s, pem_key_cert_pairs=%p, num_key_cert_pairs=%lu, "
     392             :       "force_client_auth=%d, reserved=%p)",
     393             :       5, (pem_root_certs, pem_key_cert_pairs, (unsigned long)num_key_cert_pairs,
     394             :           force_client_auth, reserved));
     395         438 :   GPR_ASSERT(reserved == NULL);
     396         438 :   memset(c, 0, sizeof(grpc_ssl_server_credentials));
     397         438 :   c->base.type = GRPC_CREDENTIALS_TYPE_SSL;
     398         438 :   gpr_ref_init(&c->base.refcount, 1);
     399         438 :   c->base.vtable = &ssl_server_vtable;
     400         438 :   ssl_build_server_config(pem_root_certs, pem_key_cert_pairs,
     401             :                           num_key_cert_pairs, force_client_auth, &c->config);
     402         438 :   return &c->base;
     403             : }
     404             : 
     405             : /* -- Jwt credentials -- */
     406             : 
     407           9 : static void jwt_reset_cache(grpc_service_account_jwt_access_credentials *c) {
     408           9 :   if (c->cached.jwt_md != NULL) {
     409           2 :     grpc_credentials_md_store_unref(c->cached.jwt_md);
     410           2 :     c->cached.jwt_md = NULL;
     411             :   }
     412           9 :   if (c->cached.service_url != NULL) {
     413           2 :     gpr_free(c->cached.service_url);
     414           2 :     c->cached.service_url = NULL;
     415             :   }
     416           9 :   c->cached.jwt_expiration = gpr_inf_past(GPR_CLOCK_REALTIME);
     417           9 : }
     418             : 
     419           3 : static void jwt_destruct(grpc_credentials *creds) {
     420           3 :   grpc_service_account_jwt_access_credentials *c =
     421             :       (grpc_service_account_jwt_access_credentials *)creds;
     422           3 :   grpc_auth_json_key_destruct(&c->key);
     423           3 :   jwt_reset_cache(c);
     424           3 :   gpr_mu_destroy(&c->cache_mu);
     425           3 : }
     426             : 
     427           6 : static int jwt_has_request_metadata(const grpc_credentials *creds) { return 1; }
     428             : 
     429           3 : static int jwt_has_request_metadata_only(const grpc_credentials *creds) {
     430           3 :   return 1;
     431             : }
     432             : 
     433           4 : static void jwt_get_request_metadata(
     434             :     grpc_exec_ctx *exec_ctx, grpc_credentials *creds, grpc_pollset *pollset,
     435             :     const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) {
     436           4 :   grpc_service_account_jwt_access_credentials *c =
     437             :       (grpc_service_account_jwt_access_credentials *)creds;
     438           4 :   gpr_timespec refresh_threshold = gpr_time_from_seconds(
     439             :       GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS, GPR_TIMESPAN);
     440             : 
     441             :   /* See if we can return a cached jwt. */
     442           4 :   grpc_credentials_md_store *jwt_md = NULL;
     443             :   {
     444           4 :     gpr_mu_lock(&c->cache_mu);
     445           6 :     if (c->cached.service_url != NULL &&
     446           3 :         strcmp(c->cached.service_url, service_url) == 0 &&
     447           2 :         c->cached.jwt_md != NULL &&
     448           1 :         (gpr_time_cmp(gpr_time_sub(c->cached.jwt_expiration,
     449             :                                    gpr_now(GPR_CLOCK_REALTIME)),
     450             :                       refresh_threshold) > 0)) {
     451           1 :       jwt_md = grpc_credentials_md_store_ref(c->cached.jwt_md);
     452             :     }
     453           4 :     gpr_mu_unlock(&c->cache_mu);
     454             :   }
     455             : 
     456           4 :   if (jwt_md == NULL) {
     457           3 :     char *jwt = NULL;
     458             :     /* Generate a new jwt. */
     459           3 :     gpr_mu_lock(&c->cache_mu);
     460           3 :     jwt_reset_cache(c);
     461           3 :     jwt = grpc_jwt_encode_and_sign(&c->key, service_url, c->jwt_lifetime, NULL);
     462           3 :     if (jwt != NULL) {
     463             :       char *md_value;
     464           2 :       gpr_asprintf(&md_value, "Bearer %s", jwt);
     465           2 :       gpr_free(jwt);
     466           2 :       c->cached.jwt_expiration =
     467           2 :           gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), c->jwt_lifetime);
     468           2 :       c->cached.service_url = gpr_strdup(service_url);
     469           2 :       c->cached.jwt_md = grpc_credentials_md_store_create(1);
     470           2 :       grpc_credentials_md_store_add_cstrings(
     471             :           c->cached.jwt_md, GRPC_AUTHORIZATION_METADATA_KEY, md_value);
     472           2 :       gpr_free(md_value);
     473           2 :       jwt_md = grpc_credentials_md_store_ref(c->cached.jwt_md);
     474             :     }
     475           3 :     gpr_mu_unlock(&c->cache_mu);
     476             :   }
     477             : 
     478           4 :   if (jwt_md != NULL) {
     479           3 :     cb(exec_ctx, user_data, jwt_md->entries, jwt_md->num_entries,
     480             :        GRPC_CREDENTIALS_OK);
     481           3 :     grpc_credentials_md_store_unref(jwt_md);
     482             :   } else {
     483           1 :     cb(exec_ctx, user_data, NULL, 0, GRPC_CREDENTIALS_ERROR);
     484             :   }
     485           4 : }
     486             : 
     487             : static grpc_credentials_vtable jwt_vtable = {
     488             :     jwt_destruct, jwt_has_request_metadata, jwt_has_request_metadata_only,
     489             :     jwt_get_request_metadata, NULL};
     490             : 
     491             : grpc_credentials *
     492           3 : grpc_service_account_jwt_access_credentials_create_from_auth_json_key(
     493             :     grpc_auth_json_key key, gpr_timespec token_lifetime) {
     494             :   grpc_service_account_jwt_access_credentials *c;
     495           3 :   if (!grpc_auth_json_key_is_valid(&key)) {
     496           0 :     gpr_log(GPR_ERROR, "Invalid input for jwt credentials creation");
     497           0 :     return NULL;
     498             :   }
     499           3 :   c = gpr_malloc(sizeof(grpc_service_account_jwt_access_credentials));
     500           3 :   memset(c, 0, sizeof(grpc_service_account_jwt_access_credentials));
     501           3 :   c->base.type = GRPC_CREDENTIALS_TYPE_JWT;
     502           3 :   gpr_ref_init(&c->base.refcount, 1);
     503           3 :   c->base.vtable = &jwt_vtable;
     504           3 :   c->key = key;
     505           3 :   c->jwt_lifetime = token_lifetime;
     506           3 :   gpr_mu_init(&c->cache_mu);
     507           3 :   jwt_reset_cache(c);
     508           3 :   return &c->base;
     509             : }
     510             : 
     511           2 : grpc_credentials *grpc_service_account_jwt_access_credentials_create(
     512             :     const char *json_key, gpr_timespec token_lifetime, void *reserved) {
     513           2 :   GRPC_API_TRACE(
     514             :       "grpc_service_account_jwt_access_credentials_create("
     515             :       "json_key=%s, "
     516             :       "token_lifetime="
     517             :       "gpr_timespec { tv_sec: %ld, tv_nsec: %d, clock_type: %d }, "
     518             :       "reserved=%p)",
     519             :       5, (json_key, (long)token_lifetime.tv_sec, token_lifetime.tv_nsec,
     520             :           (int)token_lifetime.clock_type, reserved));
     521           2 :   GPR_ASSERT(reserved == NULL);
     522           2 :   return grpc_service_account_jwt_access_credentials_create_from_auth_json_key(
     523             :       grpc_auth_json_key_create_from_string(json_key), token_lifetime);
     524             : }
     525             : 
     526             : /* -- Oauth2TokenFetcher credentials -- */
     527             : 
     528           4 : static void oauth2_token_fetcher_destruct(grpc_credentials *creds) {
     529           4 :   grpc_oauth2_token_fetcher_credentials *c =
     530             :       (grpc_oauth2_token_fetcher_credentials *)creds;
     531           4 :   grpc_credentials_md_store_unref(c->access_token_md);
     532           4 :   gpr_mu_destroy(&c->mu);
     533           4 :   grpc_httpcli_context_destroy(&c->httpcli_context);
     534           4 : }
     535             : 
     536          10 : static int oauth2_token_fetcher_has_request_metadata(
     537             :     const grpc_credentials *creds) {
     538          10 :   return 1;
     539             : }
     540             : 
     541           5 : static int oauth2_token_fetcher_has_request_metadata_only(
     542             :     const grpc_credentials *creds) {
     543           5 :   return 1;
     544             : }
     545             : 
     546             : grpc_credentials_status
     547          11 : grpc_oauth2_token_fetcher_credentials_parse_server_response(
     548             :     const grpc_httpcli_response *response, grpc_credentials_md_store **token_md,
     549             :     gpr_timespec *token_lifetime) {
     550          11 :   char *null_terminated_body = NULL;
     551          11 :   char *new_access_token = NULL;
     552          11 :   grpc_credentials_status status = GRPC_CREDENTIALS_OK;
     553          11 :   grpc_json *json = NULL;
     554             : 
     555          11 :   if (response == NULL) {
     556           0 :     gpr_log(GPR_ERROR, "Received NULL response.");
     557           0 :     status = GRPC_CREDENTIALS_ERROR;
     558           0 :     goto end;
     559             :   }
     560             : 
     561          11 :   if (response->body_length > 0) {
     562          10 :     null_terminated_body = gpr_malloc(response->body_length + 1);
     563          10 :     null_terminated_body[response->body_length] = '\0';
     564          10 :     memcpy(null_terminated_body, response->body, response->body_length);
     565             :   }
     566             : 
     567          11 :   if (response->status != 200) {
     568           3 :     gpr_log(GPR_ERROR, "Call to http server ended with error %d [%s].",
     569             :             response->status,
     570             :             null_terminated_body != NULL ? null_terminated_body : "");
     571           3 :     status = GRPC_CREDENTIALS_ERROR;
     572           3 :     goto end;
     573             :   } else {
     574           8 :     grpc_json *access_token = NULL;
     575           8 :     grpc_json *token_type = NULL;
     576           8 :     grpc_json *expires_in = NULL;
     577             :     grpc_json *ptr;
     578           8 :     json = grpc_json_parse_string(null_terminated_body);
     579           8 :     if (json == NULL) {
     580           3 :       gpr_log(GPR_ERROR, "Could not parse JSON from %s", null_terminated_body);
     581           3 :       status = GRPC_CREDENTIALS_ERROR;
     582           3 :       goto end;
     583             :     }
     584           5 :     if (json->type != GRPC_JSON_OBJECT) {
     585           0 :       gpr_log(GPR_ERROR, "Response should be a JSON object");
     586           0 :       status = GRPC_CREDENTIALS_ERROR;
     587           0 :       goto end;
     588             :     }
     589          18 :     for (ptr = json->child; ptr; ptr = ptr->next) {
     590          13 :       if (strcmp(ptr->key, "access_token") == 0) {
     591           4 :         access_token = ptr;
     592           9 :       } else if (strcmp(ptr->key, "token_type") == 0) {
     593           5 :         token_type = ptr;
     594           4 :       } else if (strcmp(ptr->key, "expires_in") == 0) {
     595           4 :         expires_in = ptr;
     596             :       }
     597             :     }
     598           5 :     if (access_token == NULL || access_token->type != GRPC_JSON_STRING) {
     599           1 :       gpr_log(GPR_ERROR, "Missing or invalid access_token in JSON.");
     600           1 :       status = GRPC_CREDENTIALS_ERROR;
     601           1 :       goto end;
     602             :     }
     603           4 :     if (token_type == NULL || token_type->type != GRPC_JSON_STRING) {
     604           0 :       gpr_log(GPR_ERROR, "Missing or invalid token_type in JSON.");
     605           0 :       status = GRPC_CREDENTIALS_ERROR;
     606           0 :       goto end;
     607             :     }
     608           4 :     if (expires_in == NULL || expires_in->type != GRPC_JSON_NUMBER) {
     609           1 :       gpr_log(GPR_ERROR, "Missing or invalid expires_in in JSON.");
     610           1 :       status = GRPC_CREDENTIALS_ERROR;
     611           1 :       goto end;
     612             :     }
     613           3 :     gpr_asprintf(&new_access_token, "%s %s", token_type->value,
     614             :                  access_token->value);
     615           3 :     token_lifetime->tv_sec = strtol(expires_in->value, NULL, 10);
     616           3 :     token_lifetime->tv_nsec = 0;
     617           3 :     token_lifetime->clock_type = GPR_TIMESPAN;
     618           3 :     if (*token_md != NULL) grpc_credentials_md_store_unref(*token_md);
     619           3 :     *token_md = grpc_credentials_md_store_create(1);
     620           3 :     grpc_credentials_md_store_add_cstrings(
     621             :         *token_md, GRPC_AUTHORIZATION_METADATA_KEY, new_access_token);
     622           3 :     status = GRPC_CREDENTIALS_OK;
     623             :   }
     624             : 
     625             : end:
     626          11 :   if (status != GRPC_CREDENTIALS_OK && (*token_md != NULL)) {
     627           0 :     grpc_credentials_md_store_unref(*token_md);
     628           0 :     *token_md = NULL;
     629             :   }
     630          11 :   if (null_terminated_body != NULL) gpr_free(null_terminated_body);
     631          11 :   if (new_access_token != NULL) gpr_free(new_access_token);
     632          11 :   if (json != NULL) grpc_json_destroy(json);
     633          11 :   return status;
     634             : }
     635             : 
     636           4 : static void on_oauth2_token_fetcher_http_response(
     637             :     grpc_exec_ctx *exec_ctx, void *user_data,
     638             :     const grpc_httpcli_response *response) {
     639           4 :   grpc_credentials_metadata_request *r =
     640             :       (grpc_credentials_metadata_request *)user_data;
     641           4 :   grpc_oauth2_token_fetcher_credentials *c =
     642             :       (grpc_oauth2_token_fetcher_credentials *)r->creds;
     643             :   gpr_timespec token_lifetime;
     644             :   grpc_credentials_status status;
     645             : 
     646           4 :   gpr_mu_lock(&c->mu);
     647           4 :   status = grpc_oauth2_token_fetcher_credentials_parse_server_response(
     648             :       response, &c->access_token_md, &token_lifetime);
     649           4 :   if (status == GRPC_CREDENTIALS_OK) {
     650           2 :     c->token_expiration =
     651           2 :         gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), token_lifetime);
     652           4 :     r->cb(exec_ctx, r->user_data, c->access_token_md->entries,
     653           2 :           c->access_token_md->num_entries, status);
     654             :   } else {
     655           2 :     c->token_expiration = gpr_inf_past(GPR_CLOCK_REALTIME);
     656           2 :     r->cb(exec_ctx, r->user_data, NULL, 0, status);
     657             :   }
     658           4 :   gpr_mu_unlock(&c->mu);
     659           4 :   grpc_credentials_metadata_request_destroy(r);
     660           4 : }
     661             : 
     662           6 : static void oauth2_token_fetcher_get_request_metadata(
     663             :     grpc_exec_ctx *exec_ctx, grpc_credentials *creds, grpc_pollset *pollset,
     664             :     const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) {
     665           6 :   grpc_oauth2_token_fetcher_credentials *c =
     666             :       (grpc_oauth2_token_fetcher_credentials *)creds;
     667           6 :   gpr_timespec refresh_threshold = gpr_time_from_seconds(
     668             :       GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS, GPR_TIMESPAN);
     669           6 :   grpc_credentials_md_store *cached_access_token_md = NULL;
     670             :   {
     671           6 :     gpr_mu_lock(&c->mu);
     672           8 :     if (c->access_token_md != NULL &&
     673           2 :         (gpr_time_cmp(
     674             :              gpr_time_sub(c->token_expiration, gpr_now(GPR_CLOCK_REALTIME)),
     675             :              refresh_threshold) > 0)) {
     676           2 :       cached_access_token_md =
     677           2 :           grpc_credentials_md_store_ref(c->access_token_md);
     678             :     }
     679           6 :     gpr_mu_unlock(&c->mu);
     680             :   }
     681           6 :   if (cached_access_token_md != NULL) {
     682           2 :     cb(exec_ctx, user_data, cached_access_token_md->entries,
     683             :        cached_access_token_md->num_entries, GRPC_CREDENTIALS_OK);
     684           2 :     grpc_credentials_md_store_unref(cached_access_token_md);
     685             :   } else {
     686           4 :     c->fetch_func(
     687             :         exec_ctx,
     688             :         grpc_credentials_metadata_request_create(creds, cb, user_data),
     689             :         &c->httpcli_context, pollset, on_oauth2_token_fetcher_http_response,
     690             :         gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), refresh_threshold));
     691             :   }
     692           6 : }
     693             : 
     694           5 : static void init_oauth2_token_fetcher(grpc_oauth2_token_fetcher_credentials *c,
     695             :                                       grpc_fetch_oauth2_func fetch_func) {
     696           5 :   memset(c, 0, sizeof(grpc_oauth2_token_fetcher_credentials));
     697           5 :   c->base.type = GRPC_CREDENTIALS_TYPE_OAUTH2;
     698           5 :   gpr_ref_init(&c->base.refcount, 1);
     699           5 :   gpr_mu_init(&c->mu);
     700           5 :   c->token_expiration = gpr_inf_past(GPR_CLOCK_REALTIME);
     701           5 :   c->fetch_func = fetch_func;
     702           5 :   grpc_httpcli_context_init(&c->httpcli_context);
     703           5 : }
     704             : 
     705             : /* -- GoogleComputeEngine credentials. -- */
     706             : 
     707             : static grpc_credentials_vtable compute_engine_vtable = {
     708             :     oauth2_token_fetcher_destruct, oauth2_token_fetcher_has_request_metadata,
     709             :     oauth2_token_fetcher_has_request_metadata_only,
     710             :     oauth2_token_fetcher_get_request_metadata, NULL};
     711             : 
     712           2 : static void compute_engine_fetch_oauth2(
     713             :     grpc_exec_ctx *exec_ctx, grpc_credentials_metadata_request *metadata_req,
     714             :     grpc_httpcli_context *httpcli_context, grpc_pollset *pollset,
     715             :     grpc_httpcli_response_cb response_cb, gpr_timespec deadline) {
     716           2 :   grpc_httpcli_header header = {"Metadata-Flavor", "Google"};
     717             :   grpc_httpcli_request request;
     718           2 :   memset(&request, 0, sizeof(grpc_httpcli_request));
     719           2 :   request.host = GRPC_COMPUTE_ENGINE_METADATA_HOST;
     720           2 :   request.path = GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH;
     721           2 :   request.hdr_count = 1;
     722           2 :   request.hdrs = &header;
     723           2 :   grpc_httpcli_get(exec_ctx, httpcli_context, pollset, &request, deadline,
     724             :                    response_cb, metadata_req);
     725           2 : }
     726             : 
     727           2 : grpc_credentials *grpc_google_compute_engine_credentials_create(
     728             :     void *reserved) {
     729           2 :   grpc_oauth2_token_fetcher_credentials *c =
     730             :       gpr_malloc(sizeof(grpc_oauth2_token_fetcher_credentials));
     731           2 :   GRPC_API_TRACE("grpc_compute_engine_credentials_create(reserved=%p)", 1,
     732             :                  (reserved));
     733           2 :   GPR_ASSERT(reserved == NULL);
     734           2 :   init_oauth2_token_fetcher(c, compute_engine_fetch_oauth2);
     735           2 :   c->base.vtable = &compute_engine_vtable;
     736           2 :   return &c->base;
     737             : }
     738             : 
     739             : /* -- GoogleRefreshToken credentials. -- */
     740             : 
     741           2 : static void refresh_token_destruct(grpc_credentials *creds) {
     742           2 :   grpc_google_refresh_token_credentials *c =
     743             :       (grpc_google_refresh_token_credentials *)creds;
     744           2 :   grpc_auth_refresh_token_destruct(&c->refresh_token);
     745           2 :   oauth2_token_fetcher_destruct(&c->base.base);
     746           2 : }
     747             : 
     748             : static grpc_credentials_vtable refresh_token_vtable = {
     749             :     refresh_token_destruct, oauth2_token_fetcher_has_request_metadata,
     750             :     oauth2_token_fetcher_has_request_metadata_only,
     751             :     oauth2_token_fetcher_get_request_metadata, NULL};
     752             : 
     753           2 : static void refresh_token_fetch_oauth2(
     754             :     grpc_exec_ctx *exec_ctx, grpc_credentials_metadata_request *metadata_req,
     755             :     grpc_httpcli_context *httpcli_context, grpc_pollset *pollset,
     756             :     grpc_httpcli_response_cb response_cb, gpr_timespec deadline) {
     757           2 :   grpc_google_refresh_token_credentials *c =
     758             :       (grpc_google_refresh_token_credentials *)metadata_req->creds;
     759           2 :   grpc_httpcli_header header = {"Content-Type",
     760             :                                 "application/x-www-form-urlencoded"};
     761             :   grpc_httpcli_request request;
     762           2 :   char *body = NULL;
     763           2 :   gpr_asprintf(&body, GRPC_REFRESH_TOKEN_POST_BODY_FORMAT_STRING,
     764             :                c->refresh_token.client_id, c->refresh_token.client_secret,
     765             :                c->refresh_token.refresh_token);
     766           2 :   memset(&request, 0, sizeof(grpc_httpcli_request));
     767           2 :   request.host = GRPC_GOOGLE_OAUTH2_SERVICE_HOST;
     768           2 :   request.path = GRPC_GOOGLE_OAUTH2_SERVICE_TOKEN_PATH;
     769           2 :   request.hdr_count = 1;
     770           2 :   request.hdrs = &header;
     771           2 :   request.handshaker = &grpc_httpcli_ssl;
     772           2 :   grpc_httpcli_post(exec_ctx, httpcli_context, pollset, &request, body,
     773             :                     strlen(body), deadline, response_cb, metadata_req);
     774           2 :   gpr_free(body);
     775           2 : }
     776             : 
     777           5 : grpc_credentials *grpc_refresh_token_credentials_create_from_auth_refresh_token(
     778             :     grpc_auth_refresh_token refresh_token) {
     779             :   grpc_google_refresh_token_credentials *c;
     780           5 :   if (!grpc_auth_refresh_token_is_valid(&refresh_token)) {
     781           2 :     gpr_log(GPR_ERROR, "Invalid input for refresh token credentials creation");
     782           2 :     return NULL;
     783             :   }
     784           3 :   c = gpr_malloc(sizeof(grpc_google_refresh_token_credentials));
     785           3 :   memset(c, 0, sizeof(grpc_google_refresh_token_credentials));
     786           3 :   init_oauth2_token_fetcher(&c->base, refresh_token_fetch_oauth2);
     787           3 :   c->base.base.vtable = &refresh_token_vtable;
     788           3 :   c->refresh_token = refresh_token;
     789           3 :   return &c->base.base;
     790             : }
     791             : 
     792           4 : grpc_credentials *grpc_google_refresh_token_credentials_create(
     793             :     const char *json_refresh_token, void *reserved) {
     794           4 :   GRPC_API_TRACE(
     795             :       "grpc_refresh_token_credentials_create(json_refresh_token=%s, "
     796             :       "reserved=%p)",
     797             :       2, (json_refresh_token, reserved));
     798           4 :   GPR_ASSERT(reserved == NULL);
     799           4 :   return grpc_refresh_token_credentials_create_from_auth_refresh_token(
     800             :       grpc_auth_refresh_token_create_from_string(json_refresh_token));
     801             : }
     802             : 
     803             : /* -- Metadata-only credentials. -- */
     804             : 
     805          86 : static void md_only_test_destruct(grpc_credentials *creds) {
     806          86 :   grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)creds;
     807          86 :   grpc_credentials_md_store_unref(c->md_store);
     808          86 : }
     809             : 
     810         634 : static int md_only_test_has_request_metadata(const grpc_credentials *creds) {
     811         634 :   return 1;
     812             : }
     813             : 
     814          90 : static int md_only_test_has_request_metadata_only(
     815             :     const grpc_credentials *creds) {
     816          90 :   return 1;
     817             : }
     818             : 
     819         108 : static void on_simulated_token_fetch_done(void *user_data) {
     820         108 :   grpc_credentials_metadata_request *r =
     821             :       (grpc_credentials_metadata_request *)user_data;
     822         108 :   grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)r->creds;
     823         108 :   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
     824         108 :   r->cb(&exec_ctx, r->user_data, c->md_store->entries, c->md_store->num_entries,
     825             :         GRPC_CREDENTIALS_OK);
     826         108 :   grpc_credentials_metadata_request_destroy(r);
     827         108 :   grpc_exec_ctx_finish(&exec_ctx);
     828         108 : }
     829             : 
     830         110 : static void md_only_test_get_request_metadata(
     831             :     grpc_exec_ctx *exec_ctx, grpc_credentials *creds, grpc_pollset *pollset,
     832             :     const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) {
     833         110 :   grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)creds;
     834             : 
     835         110 :   if (c->is_async) {
     836             :     gpr_thd_id thd_id;
     837         108 :     grpc_credentials_metadata_request *cb_arg =
     838             :         grpc_credentials_metadata_request_create(creds, cb, user_data);
     839         108 :     gpr_thd_new(&thd_id, on_simulated_token_fetch_done, cb_arg, NULL);
     840             :   } else {
     841           2 :     cb(exec_ctx, user_data, c->md_store->entries, 1, GRPC_CREDENTIALS_OK);
     842             :   }
     843         110 : }
     844             : 
     845             : static grpc_credentials_vtable md_only_test_vtable = {
     846             :     md_only_test_destruct, md_only_test_has_request_metadata,
     847             :     md_only_test_has_request_metadata_only, md_only_test_get_request_metadata,
     848             :     NULL};
     849             : 
     850          86 : grpc_credentials *grpc_md_only_test_credentials_create(const char *md_key,
     851             :                                                        const char *md_value,
     852             :                                                        int is_async) {
     853          86 :   grpc_md_only_test_credentials *c =
     854             :       gpr_malloc(sizeof(grpc_md_only_test_credentials));
     855          86 :   memset(c, 0, sizeof(grpc_md_only_test_credentials));
     856          86 :   c->base.type = GRPC_CREDENTIALS_TYPE_OAUTH2;
     857          86 :   c->base.vtable = &md_only_test_vtable;
     858          86 :   gpr_ref_init(&c->base.refcount, 1);
     859          86 :   c->md_store = grpc_credentials_md_store_create(1);
     860          86 :   grpc_credentials_md_store_add_cstrings(c->md_store, md_key, md_value);
     861          86 :   c->is_async = is_async;
     862          86 :   return &c->base;
     863             : }
     864             : 
     865             : /* -- Oauth2 Access Token credentials. -- */
     866             : 
     867           1 : static void access_token_destruct(grpc_credentials *creds) {
     868           1 :   grpc_access_token_credentials *c = (grpc_access_token_credentials *)creds;
     869           1 :   grpc_credentials_md_store_unref(c->access_token_md);
     870           1 : }
     871             : 
     872           2 : static int access_token_has_request_metadata(const grpc_credentials *creds) {
     873           2 :   return 1;
     874             : }
     875             : 
     876           1 : static int access_token_has_request_metadata_only(
     877             :     const grpc_credentials *creds) {
     878           1 :   return 1;
     879             : }
     880             : 
     881           1 : static void access_token_get_request_metadata(
     882             :     grpc_exec_ctx *exec_ctx, grpc_credentials *creds, grpc_pollset *pollset,
     883             :     const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) {
     884           1 :   grpc_access_token_credentials *c = (grpc_access_token_credentials *)creds;
     885           1 :   cb(exec_ctx, user_data, c->access_token_md->entries, 1, GRPC_CREDENTIALS_OK);
     886           1 : }
     887             : 
     888             : static grpc_credentials_vtable access_token_vtable = {
     889             :     access_token_destruct, access_token_has_request_metadata,
     890             :     access_token_has_request_metadata_only, access_token_get_request_metadata,
     891             :     NULL};
     892             : 
     893           1 : grpc_credentials *grpc_access_token_credentials_create(const char *access_token,
     894             :                                                        void *reserved) {
     895           1 :   grpc_access_token_credentials *c =
     896             :       gpr_malloc(sizeof(grpc_access_token_credentials));
     897             :   char *token_md_value;
     898           1 :   GRPC_API_TRACE(
     899             :       "grpc_access_token_credentials_create(access_token=%s, "
     900             :       "reserved=%p)",
     901             :       2, (access_token, reserved));
     902           1 :   GPR_ASSERT(reserved == NULL);
     903           1 :   memset(c, 0, sizeof(grpc_access_token_credentials));
     904           1 :   c->base.type = GRPC_CREDENTIALS_TYPE_OAUTH2;
     905           1 :   c->base.vtable = &access_token_vtable;
     906           1 :   gpr_ref_init(&c->base.refcount, 1);
     907           1 :   c->access_token_md = grpc_credentials_md_store_create(1);
     908           1 :   gpr_asprintf(&token_md_value, "Bearer %s", access_token);
     909           1 :   grpc_credentials_md_store_add_cstrings(
     910             :       c->access_token_md, GRPC_AUTHORIZATION_METADATA_KEY, token_md_value);
     911           1 :   gpr_free(token_md_value);
     912           1 :   return &c->base;
     913             : }
     914             : 
     915             : /* -- Fake transport security credentials. -- */
     916             : 
     917          89 : static void fake_transport_security_credentials_destruct(
     918             :     grpc_credentials *creds) {
     919             :   /* Nothing to do here. */
     920          89 : }
     921             : 
     922          85 : static void fake_transport_security_server_credentials_destruct(
     923             :     grpc_server_credentials *creds) {
     924             :   /* Nothing to do here. */
     925          85 : }
     926             : 
     927           0 : static int fake_transport_security_has_request_metadata(
     928             :     const grpc_credentials *creds) {
     929           0 :   return 0;
     930             : }
     931             : 
     932          89 : static int fake_transport_security_has_request_metadata_only(
     933             :     const grpc_credentials *creds) {
     934          89 :   return 0;
     935             : }
     936             : 
     937          84 : static grpc_security_status fake_transport_security_create_security_connector(
     938             :     grpc_credentials *c, const char *target, const grpc_channel_args *args,
     939             :     grpc_credentials *request_metadata_creds,
     940             :     grpc_channel_security_connector **sc, grpc_channel_args **new_args) {
     941          84 :   *sc = grpc_fake_channel_security_connector_create(request_metadata_creds, 1);
     942          84 :   return GRPC_SECURITY_OK;
     943             : }
     944             : 
     945             : static grpc_security_status
     946          85 : fake_transport_security_server_create_security_connector(
     947             :     grpc_server_credentials *c, grpc_security_connector **sc) {
     948          85 :   *sc = grpc_fake_server_security_connector_create();
     949          85 :   return GRPC_SECURITY_OK;
     950             : }
     951             : 
     952             : static grpc_credentials_vtable fake_transport_security_credentials_vtable = {
     953             :     fake_transport_security_credentials_destruct,
     954             :     fake_transport_security_has_request_metadata,
     955             :     fake_transport_security_has_request_metadata_only, NULL,
     956             :     fake_transport_security_create_security_connector};
     957             : 
     958             : static grpc_server_credentials_vtable
     959             :     fake_transport_security_server_credentials_vtable = {
     960             :         fake_transport_security_server_credentials_destruct,
     961             :         fake_transport_security_server_create_security_connector};
     962             : 
     963          89 : grpc_credentials *grpc_fake_transport_security_credentials_create(void) {
     964          89 :   grpc_credentials *c = gpr_malloc(sizeof(grpc_credentials));
     965          89 :   memset(c, 0, sizeof(grpc_credentials));
     966          89 :   c->type = GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY;
     967          89 :   c->vtable = &fake_transport_security_credentials_vtable;
     968          89 :   gpr_ref_init(&c->refcount, 1);
     969          89 :   return c;
     970             : }
     971             : 
     972          85 : grpc_server_credentials *grpc_fake_transport_security_server_credentials_create(
     973             :     void) {
     974          85 :   grpc_server_credentials *c = gpr_malloc(sizeof(grpc_server_credentials));
     975          85 :   memset(c, 0, sizeof(grpc_server_credentials));
     976          85 :   c->type = GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY;
     977          85 :   gpr_ref_init(&c->refcount, 1);
     978          85 :   c->vtable = &fake_transport_security_server_credentials_vtable;
     979          85 :   return c;
     980             : }
     981             : 
     982             : /* -- Composite credentials. -- */
     983             : 
     984             : typedef struct {
     985             :   grpc_composite_credentials *composite_creds;
     986             :   size_t creds_index;
     987             :   grpc_credentials_md_store *md_elems;
     988             :   char *service_url;
     989             :   void *user_data;
     990             :   grpc_pollset *pollset;
     991             :   grpc_credentials_metadata_cb cb;
     992             : } grpc_composite_credentials_metadata_context;
     993             : 
     994          91 : static void composite_destruct(grpc_credentials *creds) {
     995          91 :   grpc_composite_credentials *c = (grpc_composite_credentials *)creds;
     996             :   size_t i;
     997         277 :   for (i = 0; i < c->inner.num_creds; i++) {
     998         186 :     grpc_credentials_unref(c->inner.creds_array[i]);
     999             :   }
    1000          91 :   gpr_free(c->inner.creds_array);
    1001          91 : }
    1002             : 
    1003         414 : static int composite_has_request_metadata(const grpc_credentials *creds) {
    1004         414 :   const grpc_composite_credentials *c =
    1005             :       (const grpc_composite_credentials *)creds;
    1006             :   size_t i;
    1007         828 :   for (i = 0; i < c->inner.num_creds; i++) {
    1008         828 :     if (grpc_credentials_has_request_metadata(c->inner.creds_array[i])) {
    1009         414 :       return 1;
    1010             :     }
    1011             :   }
    1012           0 :   return 0;
    1013             : }
    1014             : 
    1015          86 : static int composite_has_request_metadata_only(const grpc_credentials *creds) {
    1016          86 :   const grpc_composite_credentials *c =
    1017             :       (const grpc_composite_credentials *)creds;
    1018             :   size_t i;
    1019          86 :   for (i = 0; i < c->inner.num_creds; i++) {
    1020          86 :     if (!grpc_credentials_has_request_metadata_only(c->inner.creds_array[i])) {
    1021          86 :       return 0;
    1022             :     }
    1023             :   }
    1024           0 :   return 1;
    1025             : }
    1026             : 
    1027         110 : static void composite_md_context_destroy(
    1028             :     grpc_composite_credentials_metadata_context *ctx) {
    1029         110 :   grpc_credentials_md_store_unref(ctx->md_elems);
    1030         110 :   if (ctx->service_url != NULL) gpr_free(ctx->service_url);
    1031         110 :   gpr_free(ctx);
    1032         110 : }
    1033             : 
    1034         114 : static void composite_metadata_cb(grpc_exec_ctx *exec_ctx, void *user_data,
    1035             :                                   grpc_credentials_md *md_elems, size_t num_md,
    1036             :                                   grpc_credentials_status status) {
    1037         114 :   grpc_composite_credentials_metadata_context *ctx =
    1038             :       (grpc_composite_credentials_metadata_context *)user_data;
    1039         114 :   if (status != GRPC_CREDENTIALS_OK) {
    1040           0 :     ctx->cb(exec_ctx, ctx->user_data, NULL, 0, status);
    1041           0 :     return;
    1042             :   }
    1043             : 
    1044             :   /* Copy the metadata in the context. */
    1045         114 :   if (num_md > 0) {
    1046             :     size_t i;
    1047         232 :     for (i = 0; i < num_md; i++) {
    1048         118 :       grpc_credentials_md_store_add(ctx->md_elems, md_elems[i].key,
    1049         118 :                                     md_elems[i].value);
    1050             :     }
    1051             :   }
    1052             : 
    1053             :   /* See if we need to get some more metadata. */
    1054         228 :   while (ctx->creds_index < ctx->composite_creds->inner.num_creds) {
    1055           4 :     grpc_credentials *inner_creds =
    1056           4 :         ctx->composite_creds->inner.creds_array[ctx->creds_index++];
    1057           4 :     if (grpc_credentials_has_request_metadata(inner_creds)) {
    1058           4 :       grpc_credentials_get_request_metadata(exec_ctx, inner_creds, ctx->pollset,
    1059           4 :                                             ctx->service_url,
    1060             :                                             composite_metadata_cb, ctx);
    1061           4 :       return;
    1062             :     }
    1063             :   }
    1064             : 
    1065             :   /* We're done!. */
    1066         220 :   ctx->cb(exec_ctx, ctx->user_data, ctx->md_elems->entries,
    1067         110 :           ctx->md_elems->num_entries, GRPC_CREDENTIALS_OK);
    1068         110 :   composite_md_context_destroy(ctx);
    1069             : }
    1070             : 
    1071         110 : static void composite_get_request_metadata(
    1072             :     grpc_exec_ctx *exec_ctx, grpc_credentials *creds, grpc_pollset *pollset,
    1073             :     const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) {
    1074         110 :   grpc_composite_credentials *c = (grpc_composite_credentials *)creds;
    1075             :   grpc_composite_credentials_metadata_context *ctx;
    1076         110 :   if (!grpc_credentials_has_request_metadata(creds)) {
    1077           0 :     cb(exec_ctx, user_data, NULL, 0, GRPC_CREDENTIALS_OK);
    1078           0 :     return;
    1079             :   }
    1080         110 :   ctx = gpr_malloc(sizeof(grpc_composite_credentials_metadata_context));
    1081         110 :   memset(ctx, 0, sizeof(grpc_composite_credentials_metadata_context));
    1082         110 :   ctx->service_url = gpr_strdup(service_url);
    1083         110 :   ctx->user_data = user_data;
    1084         110 :   ctx->cb = cb;
    1085         110 :   ctx->composite_creds = c;
    1086         110 :   ctx->pollset = pollset;
    1087         110 :   ctx->md_elems = grpc_credentials_md_store_create(c->inner.num_creds);
    1088         330 :   while (ctx->creds_index < c->inner.num_creds) {
    1089         220 :     grpc_credentials *inner_creds = c->inner.creds_array[ctx->creds_index++];
    1090         220 :     if (grpc_credentials_has_request_metadata(inner_creds)) {
    1091         110 :       grpc_credentials_get_request_metadata(exec_ctx, inner_creds, pollset,
    1092             :                                             service_url, composite_metadata_cb,
    1093             :                                             ctx);
    1094         110 :       return;
    1095             :     }
    1096             :   }
    1097           0 :   GPR_ASSERT(0); /* Should have exited before. */
    1098             : }
    1099             : 
    1100          84 : static grpc_security_status composite_create_security_connector(
    1101             :     grpc_credentials *creds, const char *target, const grpc_channel_args *args,
    1102             :     grpc_credentials *request_metadata_creds,
    1103             :     grpc_channel_security_connector **sc, grpc_channel_args **new_args) {
    1104          84 :   grpc_composite_credentials *c = (grpc_composite_credentials *)creds;
    1105          84 :   if (c->connector_creds == NULL) {
    1106           0 :     gpr_log(GPR_ERROR,
    1107             :             "Cannot create security connector, missing connector credentials.");
    1108           0 :     return GRPC_SECURITY_ERROR;
    1109             :   }
    1110          84 :   return grpc_credentials_create_security_connector(c->connector_creds, target,
    1111             :                                                     args, creds, sc, new_args);
    1112             : }
    1113             : 
    1114             : static grpc_credentials_vtable composite_credentials_vtable = {
    1115             :     composite_destruct, composite_has_request_metadata,
    1116             :     composite_has_request_metadata_only, composite_get_request_metadata,
    1117             :     composite_create_security_connector};
    1118             : 
    1119         184 : static grpc_credentials_array get_creds_array(grpc_credentials **creds_addr) {
    1120             :   grpc_credentials_array result;
    1121         184 :   grpc_credentials *creds = *creds_addr;
    1122         184 :   result.creds_array = creds_addr;
    1123         184 :   result.num_creds = 1;
    1124         184 :   if (strcmp(creds->type, GRPC_CREDENTIALS_TYPE_COMPOSITE) == 0) {
    1125           4 :     result = *grpc_composite_credentials_get_credentials(creds);
    1126             :   }
    1127         184 :   return result;
    1128             : }
    1129             : 
    1130          92 : grpc_credentials *grpc_composite_credentials_create(grpc_credentials *creds1,
    1131             :                                                     grpc_credentials *creds2,
    1132             :                                                     void *reserved) {
    1133             :   size_t i;
    1134             :   size_t creds_array_byte_size;
    1135             :   grpc_credentials_array creds1_array;
    1136             :   grpc_credentials_array creds2_array;
    1137             :   grpc_composite_credentials *c;
    1138          92 :   GRPC_API_TRACE(
    1139             :       "grpc_composite_credentials_create(creds1=%p, creds2=%p, "
    1140             :       "reserved=%p)",
    1141             :       3, (creds1, creds2, reserved));
    1142          92 :   GPR_ASSERT(reserved == NULL);
    1143          92 :   GPR_ASSERT(creds1 != NULL);
    1144          92 :   GPR_ASSERT(creds2 != NULL);
    1145          92 :   c = gpr_malloc(sizeof(grpc_composite_credentials));
    1146          92 :   memset(c, 0, sizeof(grpc_composite_credentials));
    1147          92 :   c->base.type = GRPC_CREDENTIALS_TYPE_COMPOSITE;
    1148          92 :   c->base.vtable = &composite_credentials_vtable;
    1149          92 :   gpr_ref_init(&c->base.refcount, 1);
    1150          92 :   creds1_array = get_creds_array(&creds1);
    1151          92 :   creds2_array = get_creds_array(&creds2);
    1152          92 :   c->inner.num_creds = creds1_array.num_creds + creds2_array.num_creds;
    1153          92 :   creds_array_byte_size = c->inner.num_creds * sizeof(grpc_credentials *);
    1154          92 :   c->inner.creds_array = gpr_malloc(creds_array_byte_size);
    1155          92 :   memset(c->inner.creds_array, 0, creds_array_byte_size);
    1156         188 :   for (i = 0; i < creds1_array.num_creds; i++) {
    1157          96 :     grpc_credentials *cur_creds = creds1_array.creds_array[i];
    1158          96 :     if (!grpc_credentials_has_request_metadata_only(cur_creds)) {
    1159          92 :       if (c->connector_creds == NULL) {
    1160          92 :         c->connector_creds = cur_creds;
    1161             :       } else {
    1162           0 :         gpr_log(GPR_ERROR, "Cannot compose multiple connector credentials.");
    1163           0 :         goto fail;
    1164             :       }
    1165             :     }
    1166          96 :     c->inner.creds_array[i] = grpc_credentials_ref(cur_creds);
    1167             :   }
    1168         184 :   for (i = 0; i < creds2_array.num_creds; i++) {
    1169          92 :     grpc_credentials *cur_creds = creds2_array.creds_array[i];
    1170          92 :     if (!grpc_credentials_has_request_metadata_only(cur_creds)) {
    1171           0 :       if (c->connector_creds == NULL) {
    1172           0 :         c->connector_creds = cur_creds;
    1173             :       } else {
    1174           0 :         gpr_log(GPR_ERROR, "Cannot compose multiple connector credentials.");
    1175           0 :         goto fail;
    1176             :       }
    1177             :     }
    1178         184 :     c->inner.creds_array[i + creds1_array.num_creds] =
    1179          92 :         grpc_credentials_ref(cur_creds);
    1180             :   }
    1181          92 :   return &c->base;
    1182             : 
    1183             : fail:
    1184           0 :   grpc_credentials_unref(&c->base);
    1185           0 :   return NULL;
    1186             : }
    1187             : 
    1188           6 : const grpc_credentials_array *grpc_composite_credentials_get_credentials(
    1189             :     grpc_credentials *creds) {
    1190           6 :   const grpc_composite_credentials *c =
    1191             :       (const grpc_composite_credentials *)creds;
    1192           6 :   GPR_ASSERT(strcmp(creds->type, GRPC_CREDENTIALS_TYPE_COMPOSITE) == 0);
    1193           6 :   return &c->inner;
    1194             : }
    1195             : 
    1196           0 : grpc_credentials *grpc_credentials_contains_type(
    1197             :     grpc_credentials *creds, const char *type,
    1198             :     grpc_credentials **composite_creds) {
    1199             :   size_t i;
    1200           0 :   if (strcmp(creds->type, type) == 0) {
    1201           0 :     if (composite_creds != NULL) *composite_creds = NULL;
    1202           0 :     return creds;
    1203           0 :   } else if (strcmp(creds->type, GRPC_CREDENTIALS_TYPE_COMPOSITE) == 0) {
    1204           0 :     const grpc_credentials_array *inner_creds_array =
    1205             :         grpc_composite_credentials_get_credentials(creds);
    1206           0 :     for (i = 0; i < inner_creds_array->num_creds; i++) {
    1207           0 :       if (strcmp(type, inner_creds_array->creds_array[i]->type) == 0) {
    1208           0 :         if (composite_creds != NULL) *composite_creds = creds;
    1209           0 :         return inner_creds_array->creds_array[i];
    1210             :       }
    1211             :     }
    1212             :   }
    1213           0 :   return NULL;
    1214             : }
    1215             : 
    1216             : /* -- IAM credentials. -- */
    1217             : 
    1218          30 : static void iam_destruct(grpc_credentials *creds) {
    1219          30 :   grpc_google_iam_credentials *c = (grpc_google_iam_credentials *)creds;
    1220          30 :   grpc_credentials_md_store_unref(c->iam_md);
    1221          30 : }
    1222             : 
    1223          41 : static int iam_has_request_metadata(const grpc_credentials *creds) { return 1; }
    1224             : 
    1225          32 : static int iam_has_request_metadata_only(const grpc_credentials *creds) {
    1226          32 :   return 1;
    1227             : }
    1228             : 
    1229          19 : static void iam_get_request_metadata(
    1230             :     grpc_exec_ctx *exec_ctx, grpc_credentials *creds, grpc_pollset *pollset,
    1231             :     const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) {
    1232          19 :   grpc_google_iam_credentials *c = (grpc_google_iam_credentials *)creds;
    1233          19 :   cb(exec_ctx, user_data, c->iam_md->entries, c->iam_md->num_entries,
    1234             :      GRPC_CREDENTIALS_OK);
    1235          19 : }
    1236             : 
    1237             : static grpc_credentials_vtable iam_vtable = {
    1238             :     iam_destruct, iam_has_request_metadata, iam_has_request_metadata_only,
    1239             :     iam_get_request_metadata, NULL};
    1240             : 
    1241          30 : grpc_credentials *grpc_google_iam_credentials_create(
    1242             :     const char *token, const char *authority_selector, void *reserved) {
    1243             :   grpc_google_iam_credentials *c;
    1244          30 :   GRPC_API_TRACE(
    1245             :       "grpc_iam_credentials_create(token=%s, authority_selector=%s, "
    1246             :       "reserved=%p)",
    1247             :       3, (token, authority_selector, reserved));
    1248          30 :   GPR_ASSERT(reserved == NULL);
    1249          30 :   GPR_ASSERT(token != NULL);
    1250          30 :   GPR_ASSERT(authority_selector != NULL);
    1251          30 :   c = gpr_malloc(sizeof(grpc_google_iam_credentials));
    1252          30 :   memset(c, 0, sizeof(grpc_google_iam_credentials));
    1253          30 :   c->base.type = GRPC_CREDENTIALS_TYPE_IAM;
    1254          30 :   c->base.vtable = &iam_vtable;
    1255          30 :   gpr_ref_init(&c->base.refcount, 1);
    1256          30 :   c->iam_md = grpc_credentials_md_store_create(2);
    1257          30 :   grpc_credentials_md_store_add_cstrings(
    1258             :       c->iam_md, GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY, token);
    1259          30 :   grpc_credentials_md_store_add_cstrings(
    1260             :       c->iam_md, GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY, authority_selector);
    1261          30 :   return &c->base;
    1262             : }
    1263             : 
    1264             : /* -- Plugin credentials. -- */
    1265             : 
    1266             : typedef struct {
    1267             :   void *user_data;
    1268             :   grpc_credentials_metadata_cb cb;
    1269             : } grpc_metadata_plugin_request;
    1270             : 
    1271           8 : static void plugin_destruct(grpc_credentials *creds) {
    1272           8 :   grpc_plugin_credentials *c = (grpc_plugin_credentials *)creds;
    1273           8 :   if (c->plugin.state != NULL && c->plugin.destroy != NULL) {
    1274           8 :     c->plugin.destroy(c->plugin.state);
    1275             :   }
    1276           8 : }
    1277             : 
    1278          14 : static int plugin_has_request_metadata(const grpc_credentials *creds) {
    1279          14 :   return 1;
    1280             : }
    1281             : 
    1282           6 : static int plugin_has_request_metadata_only(const grpc_credentials *creds) {
    1283           6 :   return 1;
    1284             : }
    1285             : 
    1286           8 : static void plugin_md_request_metadata_ready(void *request,
    1287             :                                              const grpc_metadata *md,
    1288             :                                              size_t num_md,
    1289             :                                              grpc_status_code status,
    1290             :                                              const char *error_details) {
    1291             :   /* called from application code */
    1292           8 :   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
    1293           8 :   grpc_metadata_plugin_request *r = (grpc_metadata_plugin_request *)request;
    1294           8 :   if (status != GRPC_STATUS_OK) {
    1295           3 :     if (error_details != NULL) {
    1296           3 :       gpr_log(GPR_ERROR, "Getting metadata from plugin failed with error: %s",
    1297             :               error_details);
    1298             :     }
    1299           3 :     r->cb(&exec_ctx, r->user_data, NULL, 0, GRPC_CREDENTIALS_ERROR);
    1300             :   } else {
    1301             :     size_t i;
    1302           5 :     grpc_credentials_md *md_array = NULL;
    1303           5 :     if (num_md > 0) {
    1304           5 :       md_array = gpr_malloc(num_md * sizeof(grpc_credentials_md));
    1305          11 :       for (i = 0; i < num_md; i++) {
    1306           6 :         md_array[i].key = gpr_slice_from_copied_string(md[i].key);
    1307          12 :         md_array[i].value =
    1308           6 :             gpr_slice_from_copied_buffer(md[i].value, md[i].value_length);
    1309             :       }
    1310             :     }
    1311           5 :     r->cb(&exec_ctx, r->user_data, md_array, num_md, GRPC_CREDENTIALS_OK);
    1312           5 :     if (md_array != NULL) {
    1313          11 :       for (i = 0; i < num_md; i++) {
    1314           6 :         gpr_slice_unref(md_array[i].key);
    1315           6 :         gpr_slice_unref(md_array[i].value);
    1316             :       }
    1317           5 :       gpr_free(md_array);
    1318             :     }
    1319             :   }
    1320           8 :   gpr_free(r);
    1321           8 :   grpc_exec_ctx_finish(&exec_ctx);
    1322           8 : }
    1323             : 
    1324           8 : static void plugin_get_request_metadata(
    1325             :     grpc_exec_ctx *exec_ctx, grpc_credentials *creds, grpc_pollset *pollset,
    1326             :     const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) {
    1327           8 :   grpc_plugin_credentials *c = (grpc_plugin_credentials *)creds;
    1328           8 :   if (c->plugin.get_metadata != NULL) {
    1329           8 :     grpc_metadata_plugin_request *request = gpr_malloc(sizeof(*request));
    1330           8 :     memset(request, 0, sizeof(*request));
    1331           8 :     request->user_data = user_data;
    1332           8 :     request->cb = cb;
    1333           8 :     c->plugin.get_metadata(c->plugin.state, service_url,
    1334             :                            plugin_md_request_metadata_ready, request);
    1335             :   } else {
    1336           0 :     cb(exec_ctx, user_data, NULL, 0, GRPC_CREDENTIALS_OK);
    1337             :   }
    1338           8 : }
    1339             : 
    1340             : static grpc_credentials_vtable plugin_vtable = {
    1341             :     plugin_destruct, plugin_has_request_metadata,
    1342             :     plugin_has_request_metadata_only, plugin_get_request_metadata, NULL};
    1343             : 
    1344           8 : grpc_credentials *grpc_metadata_credentials_create_from_plugin(
    1345             :     grpc_metadata_credentials_plugin plugin, void *reserved) {
    1346           8 :   grpc_plugin_credentials *c = gpr_malloc(sizeof(*c));
    1347           8 :   GPR_ASSERT(reserved == NULL);
    1348           8 :   memset(c, 0, sizeof(*c));
    1349           8 :   c->base.type = GRPC_CREDENTIALS_TYPE_METADATA_PLUGIN;
    1350           8 :   c->base.vtable = &plugin_vtable;
    1351           8 :   gpr_ref_init(&c->base.refcount, 1);
    1352           8 :   c->plugin = plugin;
    1353           8 :   return &c->base;
    1354             : }

Generated by: LCOV version 1.10