blob: 10efc6120870eb63e214c8de5d96981bd261a1cf [file] [log] [blame]
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001/*
2 *
Craig Tiller06059952015-02-18 08:34:56 -08003 * Copyright 2015, Google Inc.
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08004 * 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
Julien Boeuff47a5cb2015-02-18 12:24:08 -080036#include <string.h>
37#include <stdio.h>
38
Julien Boeuf7d1d9ca2015-04-17 14:38:48 -070039#include "src/core/channel/channel_args.h"
40#include "src/core/channel/http_client_filter.h"
Julien Boeuff47a5cb2015-02-18 12:24:08 -080041#include "src/core/json/json.h"
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080042#include "src/core/httpcli/httpcli.h"
ctiller18b49ab2014-12-09 14:39:16 -080043#include "src/core/iomgr/iomgr.h"
Craig Tiller485d7762015-01-23 12:54:05 -080044#include "src/core/support/string.h"
Julien Boeuf7d1d9ca2015-04-17 14:38:48 -070045
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080046#include <grpc/support/alloc.h>
47#include <grpc/support/log.h>
Masood Malekghassemi701af602015-06-03 15:01:17 -070048#include <grpc/support/string_util.h>
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080049#include <grpc/support/sync.h>
50#include <grpc/support/time.h>
51
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080052/* -- Common. -- */
53
54typedef struct {
55 grpc_credentials *creds;
56 grpc_credentials_metadata_cb cb;
David Garcia Quintas69ba8712015-06-01 11:29:42 -070057 grpc_iomgr_closure *on_simulated_token_fetch_done_closure;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080058 void *user_data;
59} grpc_credentials_metadata_request;
60
61static grpc_credentials_metadata_request *
62grpc_credentials_metadata_request_create(grpc_credentials *creds,
63 grpc_credentials_metadata_cb cb,
64 void *user_data) {
65 grpc_credentials_metadata_request *r =
66 gpr_malloc(sizeof(grpc_credentials_metadata_request));
67 r->creds = grpc_credentials_ref(creds);
68 r->cb = cb;
David Garcia Quintas69ba8712015-06-01 11:29:42 -070069 r->on_simulated_token_fetch_done_closure =
70 gpr_malloc(sizeof(grpc_iomgr_closure));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080071 r->user_data = user_data;
72 return r;
73}
74
75static void grpc_credentials_metadata_request_destroy(
76 grpc_credentials_metadata_request *r) {
77 grpc_credentials_unref(r->creds);
David Garcia Quintas69ba8712015-06-01 11:29:42 -070078 gpr_free(r->on_simulated_token_fetch_done_closure);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080079 gpr_free(r);
80}
81
82grpc_credentials *grpc_credentials_ref(grpc_credentials *creds) {
83 if (creds == NULL) return NULL;
84 gpr_ref(&creds->refcount);
85 return creds;
86}
87
88void grpc_credentials_unref(grpc_credentials *creds) {
89 if (creds == NULL) return;
90 if (gpr_unref(&creds->refcount)) creds->vtable->destroy(creds);
91}
92
93void grpc_credentials_release(grpc_credentials *creds) {
94 grpc_credentials_unref(creds);
95}
96
97int grpc_credentials_has_request_metadata(grpc_credentials *creds) {
98 if (creds == NULL) return 0;
99 return creds->vtable->has_request_metadata(creds);
100}
101
102int grpc_credentials_has_request_metadata_only(grpc_credentials *creds) {
103 if (creds == NULL) return 0;
104 return creds->vtable->has_request_metadata_only(creds);
105}
106
107void grpc_credentials_get_request_metadata(grpc_credentials *creds,
Craig Tiller06bac342015-06-01 12:55:57 -0700108 grpc_pollset *pollset,
Julien Boeuff47a5cb2015-02-18 12:24:08 -0800109 const char *service_url,
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800110 grpc_credentials_metadata_cb cb,
111 void *user_data) {
nnoble0c475f02014-12-05 15:37:39 -0800112 if (creds == NULL || !grpc_credentials_has_request_metadata(creds) ||
113 creds->vtable->get_request_metadata == NULL) {
114 if (cb != NULL) {
115 cb(user_data, NULL, 0, GRPC_CREDENTIALS_OK);
116 }
117 return;
118 }
Craig Tiller06bac342015-06-01 12:55:57 -0700119 creds->vtable->get_request_metadata(creds, pollset, service_url, cb,
120 user_data);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800121}
122
Julien Boeuf7d1d9ca2015-04-17 14:38:48 -0700123grpc_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 *new_args = NULL;
128 if (creds == NULL || creds->vtable->create_security_connector == NULL ||
129 grpc_credentials_has_request_metadata_only(creds)) {
130 gpr_log(GPR_ERROR,
131 "Invalid credentials for creating a security connector.");
132 return GRPC_SECURITY_ERROR;
133 }
134 return creds->vtable->create_security_connector(
135 creds, target, args, request_metadata_creds, sc, new_args);
Craig Tillerc4885ed2015-04-14 09:51:28 -0700136}
137
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800138void grpc_server_credentials_release(grpc_server_credentials *creds) {
139 if (creds == NULL) return;
140 creds->vtable->destroy(creds);
141}
142
Julien Boeuf7d1d9ca2015-04-17 14:38:48 -0700143grpc_security_status grpc_server_credentials_create_security_connector(
144 grpc_server_credentials *creds, grpc_security_connector **sc) {
145 if (creds == NULL || creds->vtable->create_security_connector == NULL) {
146 gpr_log(GPR_ERROR, "Server credentials cannot create security context.");
147 return GRPC_SECURITY_ERROR;
148 }
149 return creds->vtable->create_security_connector(creds, sc);
150}
151
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800152/* -- Ssl credentials. -- */
153
154typedef struct {
155 grpc_credentials base;
156 grpc_ssl_config config;
157} grpc_ssl_credentials;
158
159typedef struct {
160 grpc_server_credentials base;
Julien Boeuf8fbcc432015-01-15 16:44:13 -0800161 grpc_ssl_server_config config;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800162} grpc_ssl_server_credentials;
163
164static void ssl_destroy(grpc_credentials *creds) {
165 grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds;
166 if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs);
167 if (c->config.pem_private_key != NULL) gpr_free(c->config.pem_private_key);
168 if (c->config.pem_cert_chain != NULL) gpr_free(c->config.pem_cert_chain);
169 gpr_free(creds);
170}
171
172static void ssl_server_destroy(grpc_server_credentials *creds) {
173 grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds;
Julien Boeuf8fbcc432015-01-15 16:44:13 -0800174 size_t i;
175 for (i = 0; i < c->config.num_key_cert_pairs; i++) {
176 if (c->config.pem_private_keys[i] != NULL) {
177 gpr_free(c->config.pem_private_keys[i]);
178 }
Nicolas Noble614c2bf2015-01-21 15:48:36 -0800179 if (c->config.pem_cert_chains[i] != NULL) {
Julien Boeuf8fbcc432015-01-15 16:44:13 -0800180 gpr_free(c->config.pem_cert_chains[i]);
181 }
182 }
183 if (c->config.pem_private_keys != NULL) gpr_free(c->config.pem_private_keys);
184 if (c->config.pem_private_keys_sizes != NULL) {
185 gpr_free(c->config.pem_private_keys_sizes);
186 }
187 if (c->config.pem_cert_chains != NULL) gpr_free(c->config.pem_cert_chains);
188 if (c->config.pem_cert_chains_sizes != NULL) {
189 gpr_free(c->config.pem_cert_chains_sizes);
190 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800191 if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800192 gpr_free(creds);
193}
194
Craig Tiller83b826a2015-05-13 13:43:01 -0700195static int ssl_has_request_metadata(const grpc_credentials *creds) { return 0; }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800196
197static int ssl_has_request_metadata_only(const grpc_credentials *creds) {
198 return 0;
199}
200
Julien Boeuf7d1d9ca2015-04-17 14:38:48 -0700201static grpc_security_status ssl_create_security_connector(
202 grpc_credentials *creds, const char *target, const grpc_channel_args *args,
203 grpc_credentials *request_metadata_creds,
204 grpc_channel_security_connector **sc, grpc_channel_args **new_args) {
205 grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds;
206 grpc_security_status status = GRPC_SECURITY_OK;
207 size_t i = 0;
208 const char *overridden_target_name = NULL;
209 grpc_arg arg;
210
211 for (i = 0; args && i < args->num_args; i++) {
212 grpc_arg *arg = &args->args[i];
213 if (strcmp(arg->key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG) == 0 &&
214 arg->type == GRPC_ARG_STRING) {
215 overridden_target_name = arg->value.string;
216 break;
217 }
218 }
219 status = grpc_ssl_channel_security_connector_create(
220 request_metadata_creds, &c->config, target, overridden_target_name, sc);
221 if (status != GRPC_SECURITY_OK) {
222 return status;
223 }
224 arg.type = GRPC_ARG_STRING;
225 arg.key = GRPC_ARG_HTTP2_SCHEME;
226 arg.value.string = "https";
Craig Tillerd9a50882015-06-29 15:57:36 -0700227 *new_args = grpc_channel_args_copy_and_add(args, &arg, 1);
Julien Boeuf7d1d9ca2015-04-17 14:38:48 -0700228 return status;
229}
230
231static grpc_security_status ssl_server_create_security_connector(
232 grpc_server_credentials *creds, grpc_security_connector **sc) {
233 grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds;
234 return grpc_ssl_server_security_connector_create(&c->config, sc);
235}
236
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800237static grpc_credentials_vtable ssl_vtable = {
Julien Boeuf75c9b6f2015-05-29 13:12:12 -0700238 ssl_destroy, ssl_has_request_metadata, ssl_has_request_metadata_only, NULL,
239 ssl_create_security_connector};
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800240
Julien Boeuf7d1d9ca2015-04-17 14:38:48 -0700241static grpc_server_credentials_vtable ssl_server_vtable = {
242 ssl_server_destroy, ssl_server_create_security_connector};
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800243
Julien Boeuf8fbcc432015-01-15 16:44:13 -0800244static void ssl_copy_key_material(const char *input, unsigned char **output,
245 size_t *output_size) {
246 *output_size = strlen(input);
247 *output = gpr_malloc(*output_size);
248 memcpy(*output, input, *output_size);
249}
250
251static void ssl_build_config(const char *pem_root_certs,
252 grpc_ssl_pem_key_cert_pair *pem_key_cert_pair,
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800253 grpc_ssl_config *config) {
Julien Boeuf026a4172015-02-02 18:36:37 -0800254 if (pem_root_certs != NULL) {
Julien Boeuf8fbcc432015-01-15 16:44:13 -0800255 ssl_copy_key_material(pem_root_certs, &config->pem_root_certs,
256 &config->pem_root_certs_size);
257 }
Julien Boeuf8fbcc432015-01-15 16:44:13 -0800258 if (pem_key_cert_pair != NULL) {
259 GPR_ASSERT(pem_key_cert_pair->private_key != NULL);
260 GPR_ASSERT(pem_key_cert_pair->cert_chain != NULL);
261 ssl_copy_key_material(pem_key_cert_pair->private_key,
262 &config->pem_private_key,
263 &config->pem_private_key_size);
264 ssl_copy_key_material(pem_key_cert_pair->cert_chain,
265 &config->pem_cert_chain,
266 &config->pem_cert_chain_size);
267 }
268}
269
270static void ssl_build_server_config(
271 const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs,
272 size_t num_key_cert_pairs, grpc_ssl_server_config *config) {
273 size_t i;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800274 if (pem_root_certs != NULL) {
Julien Boeuf8fbcc432015-01-15 16:44:13 -0800275 ssl_copy_key_material(pem_root_certs, &config->pem_root_certs,
276 &config->pem_root_certs_size);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800277 }
Julien Boeuf8fbcc432015-01-15 16:44:13 -0800278 if (num_key_cert_pairs > 0) {
279 GPR_ASSERT(pem_key_cert_pairs != NULL);
280 config->pem_private_keys =
281 gpr_malloc(num_key_cert_pairs * sizeof(unsigned char *));
282 config->pem_cert_chains =
283 gpr_malloc(num_key_cert_pairs * sizeof(unsigned char *));
284 config->pem_private_keys_sizes =
285 gpr_malloc(num_key_cert_pairs * sizeof(size_t));
286 config->pem_cert_chains_sizes =
287 gpr_malloc(num_key_cert_pairs * sizeof(size_t));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800288 }
Julien Boeuf8fbcc432015-01-15 16:44:13 -0800289 config->num_key_cert_pairs = num_key_cert_pairs;
290 for (i = 0; i < num_key_cert_pairs; i++) {
291 GPR_ASSERT(pem_key_cert_pairs[i].private_key != NULL);
292 GPR_ASSERT(pem_key_cert_pairs[i].cert_chain != NULL);
293 ssl_copy_key_material(pem_key_cert_pairs[i].private_key,
294 &config->pem_private_keys[i],
295 &config->pem_private_keys_sizes[i]);
296 ssl_copy_key_material(pem_key_cert_pairs[i].cert_chain,
297 &config->pem_cert_chains[i],
298 &config->pem_cert_chains_sizes[i]);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800299 }
300}
301
302grpc_credentials *grpc_ssl_credentials_create(
Julien Boeuf8fbcc432015-01-15 16:44:13 -0800303 const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800304 grpc_ssl_credentials *c = gpr_malloc(sizeof(grpc_ssl_credentials));
305 memset(c, 0, sizeof(grpc_ssl_credentials));
306 c->base.type = GRPC_CREDENTIALS_TYPE_SSL;
307 c->base.vtable = &ssl_vtable;
308 gpr_ref_init(&c->base.refcount, 1);
Julien Boeuf8fbcc432015-01-15 16:44:13 -0800309 ssl_build_config(pem_root_certs, pem_key_cert_pair, &c->config);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800310 return &c->base;
311}
312
313grpc_server_credentials *grpc_ssl_server_credentials_create(
Julien Boeuf8fbcc432015-01-15 16:44:13 -0800314 const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs,
315 size_t num_key_cert_pairs) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800316 grpc_ssl_server_credentials *c =
317 gpr_malloc(sizeof(grpc_ssl_server_credentials));
318 memset(c, 0, sizeof(grpc_ssl_server_credentials));
319 c->base.type = GRPC_CREDENTIALS_TYPE_SSL;
320 c->base.vtable = &ssl_server_vtable;
Julien Boeuf8fbcc432015-01-15 16:44:13 -0800321 ssl_build_server_config(pem_root_certs, pem_key_cert_pairs,
322 num_key_cert_pairs, &c->config);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800323 return &c->base;
324}
325
Julien Boeuff47a5cb2015-02-18 12:24:08 -0800326/* -- Jwt credentials -- */
327
328typedef struct {
329 grpc_credentials base;
Julien Boeuff47a5cb2015-02-18 12:24:08 -0800330
331 /* Have a simple cache for now with just 1 entry. We could have a map based on
332 the service_url for a more sophisticated one. */
333 gpr_mu cache_mu;
334 struct {
Julien Boeuf75c9b6f2015-05-29 13:12:12 -0700335 grpc_credentials_md_store *jwt_md;
Julien Boeuff47a5cb2015-02-18 12:24:08 -0800336 char *service_url;
337 gpr_timespec jwt_expiration;
338 } cached;
339
340 grpc_auth_json_key key;
341 gpr_timespec jwt_lifetime;
342} grpc_jwt_credentials;
343
344static void jwt_reset_cache(grpc_jwt_credentials *c) {
345 if (c->cached.jwt_md != NULL) {
Julien Boeuf75c9b6f2015-05-29 13:12:12 -0700346 grpc_credentials_md_store_unref(c->cached.jwt_md);
Julien Boeuff47a5cb2015-02-18 12:24:08 -0800347 c->cached.jwt_md = NULL;
348 }
349 if (c->cached.service_url != NULL) {
350 gpr_free(c->cached.service_url);
351 c->cached.service_url = NULL;
352 }
353 c->cached.jwt_expiration = gpr_inf_past;
354}
355
356static void jwt_destroy(grpc_credentials *creds) {
357 grpc_jwt_credentials *c = (grpc_jwt_credentials *)creds;
358 grpc_auth_json_key_destruct(&c->key);
359 jwt_reset_cache(c);
360 gpr_mu_destroy(&c->cache_mu);
Julien Boeuff47a5cb2015-02-18 12:24:08 -0800361 gpr_free(c);
362}
363
364static int jwt_has_request_metadata(const grpc_credentials *creds) { return 1; }
365
366static int jwt_has_request_metadata_only(const grpc_credentials *creds) {
367 return 1;
368}
369
Julien Boeuff47a5cb2015-02-18 12:24:08 -0800370static void jwt_get_request_metadata(grpc_credentials *creds,
Craig Tiller06bac342015-06-01 12:55:57 -0700371 grpc_pollset *pollset,
Julien Boeuff47a5cb2015-02-18 12:24:08 -0800372 const char *service_url,
373 grpc_credentials_metadata_cb cb,
374 void *user_data) {
375 grpc_jwt_credentials *c = (grpc_jwt_credentials *)creds;
376 gpr_timespec refresh_threshold = {GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS,
377 0};
378
379 /* See if we can return a cached jwt. */
Julien Boeuf75c9b6f2015-05-29 13:12:12 -0700380 grpc_credentials_md_store *jwt_md = NULL;
Julien Boeuff47a5cb2015-02-18 12:24:08 -0800381 {
382 gpr_mu_lock(&c->cache_mu);
383 if (c->cached.service_url != NULL &&
Ronnie Sahlberg2ad8d212015-03-07 08:39:22 -0800384 strcmp(c->cached.service_url, service_url) == 0 &&
Julien Boeuff47a5cb2015-02-18 12:24:08 -0800385 c->cached.jwt_md != NULL &&
386 (gpr_time_cmp(gpr_time_sub(c->cached.jwt_expiration, gpr_now()),
387 refresh_threshold) > 0)) {
Julien Boeuf75c9b6f2015-05-29 13:12:12 -0700388 jwt_md = grpc_credentials_md_store_ref(c->cached.jwt_md);
Julien Boeuff47a5cb2015-02-18 12:24:08 -0800389 }
390 gpr_mu_unlock(&c->cache_mu);
391 }
392
393 if (jwt_md == NULL) {
394 char *jwt = NULL;
395 /* Generate a new jwt. */
396 gpr_mu_lock(&c->cache_mu);
397 jwt_reset_cache(c);
398 jwt = grpc_jwt_encode_and_sign(&c->key, service_url, c->jwt_lifetime, NULL);
399 if (jwt != NULL) {
400 char *md_value;
401 gpr_asprintf(&md_value, "Bearer %s", jwt);
402 gpr_free(jwt);
403 c->cached.jwt_expiration = gpr_time_add(gpr_now(), c->jwt_lifetime);
404 c->cached.service_url = gpr_strdup(service_url);
Julien Boeuf75c9b6f2015-05-29 13:12:12 -0700405 c->cached.jwt_md = grpc_credentials_md_store_create(1);
406 grpc_credentials_md_store_add_cstrings(
407 c->cached.jwt_md, GRPC_AUTHORIZATION_METADATA_KEY, md_value);
Julien Boeuff47a5cb2015-02-18 12:24:08 -0800408 gpr_free(md_value);
Julien Boeuf75c9b6f2015-05-29 13:12:12 -0700409 jwt_md = grpc_credentials_md_store_ref(c->cached.jwt_md);
Julien Boeuff47a5cb2015-02-18 12:24:08 -0800410 }
411 gpr_mu_unlock(&c->cache_mu);
412 }
413
414 if (jwt_md != NULL) {
Julien Boeuf75c9b6f2015-05-29 13:12:12 -0700415 cb(user_data, jwt_md->entries, jwt_md->num_entries, GRPC_CREDENTIALS_OK);
416 grpc_credentials_md_store_unref(jwt_md);
Julien Boeuff47a5cb2015-02-18 12:24:08 -0800417 } else {
418 cb(user_data, NULL, 0, GRPC_CREDENTIALS_ERROR);
419 }
420}
421
422static grpc_credentials_vtable jwt_vtable = {
423 jwt_destroy, jwt_has_request_metadata, jwt_has_request_metadata_only,
Julien Boeuf75c9b6f2015-05-29 13:12:12 -0700424 jwt_get_request_metadata, NULL};
Julien Boeuff47a5cb2015-02-18 12:24:08 -0800425
Julien Boeuf54006062015-07-07 19:13:04 -0700426grpc_credentials *grpc_jwt_credentials_create_from_auth_json_key(
427 grpc_auth_json_key key, gpr_timespec token_lifetime) {
Julien Boeuff47a5cb2015-02-18 12:24:08 -0800428 grpc_jwt_credentials *c;
Julien Boeuff47a5cb2015-02-18 12:24:08 -0800429 if (!grpc_auth_json_key_is_valid(&key)) {
430 gpr_log(GPR_ERROR, "Invalid input for jwt credentials creation");
431 return NULL;
432 }
433 c = gpr_malloc(sizeof(grpc_jwt_credentials));
434 memset(c, 0, sizeof(grpc_jwt_credentials));
435 c->base.type = GRPC_CREDENTIALS_TYPE_JWT;
436 gpr_ref_init(&c->base.refcount, 1);
437 c->base.vtable = &jwt_vtable;
Julien Boeuff47a5cb2015-02-18 12:24:08 -0800438 c->key = key;
439 c->jwt_lifetime = token_lifetime;
440 gpr_mu_init(&c->cache_mu);
441 jwt_reset_cache(c);
442 return &c->base;
443}
444
Julien Boeuf54006062015-07-07 19:13:04 -0700445grpc_credentials *grpc_jwt_credentials_create(const char *json_key,
446 gpr_timespec token_lifetime) {
447 return grpc_jwt_credentials_create_from_auth_json_key(
448 grpc_auth_json_key_create_from_string(json_key), token_lifetime);
449}
450
jboeuf1a809c02014-12-19 15:44:30 -0800451/* -- Oauth2TokenFetcher credentials -- */
452
453/* This object is a base for credentials that need to acquire an oauth2 token
454 from an http service. */
455
456typedef void (*grpc_fetch_oauth2_func)(grpc_credentials_metadata_request *req,
Craig Tillera0abe372015-06-01 11:31:08 -0700457 grpc_httpcli_context *http_context,
Craig Tiller06bac342015-06-01 12:55:57 -0700458 grpc_pollset *pollset,
jboeuf1a809c02014-12-19 15:44:30 -0800459 grpc_httpcli_response_cb response_cb,
460 gpr_timespec deadline);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800461
462typedef struct {
463 grpc_credentials base;
464 gpr_mu mu;
Julien Boeuf75c9b6f2015-05-29 13:12:12 -0700465 grpc_credentials_md_store *access_token_md;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800466 gpr_timespec token_expiration;
Craig Tillera0abe372015-06-01 11:31:08 -0700467 grpc_httpcli_context httpcli_context;
Craig Tillerca22c972015-05-11 10:09:09 -0700468 grpc_pollset_set pollset_set;
jboeuf1a809c02014-12-19 15:44:30 -0800469 grpc_fetch_oauth2_func fetch_func;
470} grpc_oauth2_token_fetcher_credentials;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800471
jboeuf1a809c02014-12-19 15:44:30 -0800472static void oauth2_token_fetcher_destroy(grpc_credentials *creds) {
473 grpc_oauth2_token_fetcher_credentials *c =
474 (grpc_oauth2_token_fetcher_credentials *)creds;
Julien Boeuf75c9b6f2015-05-29 13:12:12 -0700475 grpc_credentials_md_store_unref(c->access_token_md);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800476 gpr_mu_destroy(&c->mu);
Craig Tillera0abe372015-06-01 11:31:08 -0700477 grpc_httpcli_context_destroy(&c->httpcli_context);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800478 gpr_free(c);
479}
480
jboeuf1a809c02014-12-19 15:44:30 -0800481static int oauth2_token_fetcher_has_request_metadata(
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800482 const grpc_credentials *creds) {
483 return 1;
484}
485
jboeuf1a809c02014-12-19 15:44:30 -0800486static int oauth2_token_fetcher_has_request_metadata_only(
487 const grpc_credentials *creds) {
488 return 1;
489}
490
491grpc_credentials_status
492grpc_oauth2_token_fetcher_credentials_parse_server_response(
Craig Tiller8674cb12015-06-05 07:09:25 -0700493 const grpc_httpcli_response *response, grpc_credentials_md_store **token_md,
494 gpr_timespec *token_lifetime) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800495 char *null_terminated_body = NULL;
496 char *new_access_token = NULL;
497 grpc_credentials_status status = GRPC_CREDENTIALS_OK;
Nicolas Noble614c2bf2015-01-21 15:48:36 -0800498 grpc_json *json = NULL;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800499
Julien Boeuf90bd7c42015-02-18 18:51:16 -0800500 if (response == NULL) {
501 gpr_log(GPR_ERROR, "Received NULL response.");
502 status = GRPC_CREDENTIALS_ERROR;
503 goto end;
504 }
505
jboeuf1a809c02014-12-19 15:44:30 -0800506 if (response->body_length > 0) {
507 null_terminated_body = gpr_malloc(response->body_length + 1);
508 null_terminated_body[response->body_length] = '\0';
509 memcpy(null_terminated_body, response->body, response->body_length);
510 }
511
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800512 if (response->status != 200) {
jboeuf1a809c02014-12-19 15:44:30 -0800513 gpr_log(GPR_ERROR, "Call to http server ended with error %d [%s].",
514 response->status,
515 null_terminated_body != NULL ? null_terminated_body : "");
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800516 status = GRPC_CREDENTIALS_ERROR;
517 goto end;
518 } else {
Nicolas Noble614c2bf2015-01-21 15:48:36 -0800519 grpc_json *access_token = NULL;
520 grpc_json *token_type = NULL;
521 grpc_json *expires_in = NULL;
522 grpc_json *ptr;
Nicolas Noble614c2bf2015-01-21 15:48:36 -0800523 json = grpc_json_parse_string(null_terminated_body);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800524 if (json == NULL) {
525 gpr_log(GPR_ERROR, "Could not parse JSON from %s", null_terminated_body);
526 status = GRPC_CREDENTIALS_ERROR;
527 goto end;
528 }
Nicolas Noble614c2bf2015-01-21 15:48:36 -0800529 if (json->type != GRPC_JSON_OBJECT) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800530 gpr_log(GPR_ERROR, "Response should be a JSON object");
531 status = GRPC_CREDENTIALS_ERROR;
532 goto end;
533 }
Nicolas Noble614c2bf2015-01-21 15:48:36 -0800534 for (ptr = json->child; ptr; ptr = ptr->next) {
535 if (strcmp(ptr->key, "access_token") == 0) {
536 access_token = ptr;
537 } else if (strcmp(ptr->key, "token_type") == 0) {
538 token_type = ptr;
539 } else if (strcmp(ptr->key, "expires_in") == 0) {
540 expires_in = ptr;
541 }
542 }
543 if (access_token == NULL || access_token->type != GRPC_JSON_STRING) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800544 gpr_log(GPR_ERROR, "Missing or invalid access_token in JSON.");
545 status = GRPC_CREDENTIALS_ERROR;
546 goto end;
547 }
Nicolas Noble614c2bf2015-01-21 15:48:36 -0800548 if (token_type == NULL || token_type->type != GRPC_JSON_STRING) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800549 gpr_log(GPR_ERROR, "Missing or invalid token_type in JSON.");
550 status = GRPC_CREDENTIALS_ERROR;
551 goto end;
552 }
Nicolas Noble614c2bf2015-01-21 15:48:36 -0800553 if (expires_in == NULL || expires_in->type != GRPC_JSON_NUMBER) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800554 gpr_log(GPR_ERROR, "Missing or invalid expires_in in JSON.");
555 status = GRPC_CREDENTIALS_ERROR;
556 goto end;
557 }
Nicolas Noblefee065c2015-01-26 11:41:12 -0800558 gpr_asprintf(&new_access_token, "%s %s", token_type->value,
559 access_token->value);
Nicolas Noblee04455a2015-01-26 17:01:29 -0800560 token_lifetime->tv_sec = strtol(expires_in->value, NULL, 10);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800561 token_lifetime->tv_nsec = 0;
Julien Boeuf75c9b6f2015-05-29 13:12:12 -0700562 if (*token_md != NULL) grpc_credentials_md_store_unref(*token_md);
563 *token_md = grpc_credentials_md_store_create(1);
564 grpc_credentials_md_store_add_cstrings(
565 *token_md, GRPC_AUTHORIZATION_METADATA_KEY, new_access_token);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800566 status = GRPC_CREDENTIALS_OK;
567 }
568
569end:
Julien Boeuf75c9b6f2015-05-29 13:12:12 -0700570 if (status != GRPC_CREDENTIALS_OK && (*token_md != NULL)) {
571 grpc_credentials_md_store_unref(*token_md);
572 *token_md = NULL;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800573 }
574 if (null_terminated_body != NULL) gpr_free(null_terminated_body);
575 if (new_access_token != NULL) gpr_free(new_access_token);
Nicolas Noble8c2be9b2015-01-27 14:21:18 -0800576 if (json != NULL) grpc_json_destroy(json);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800577 return status;
578}
579
jboeuf1a809c02014-12-19 15:44:30 -0800580static void on_oauth2_token_fetcher_http_response(
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800581 void *user_data, const grpc_httpcli_response *response) {
582 grpc_credentials_metadata_request *r =
583 (grpc_credentials_metadata_request *)user_data;
jboeuf1a809c02014-12-19 15:44:30 -0800584 grpc_oauth2_token_fetcher_credentials *c =
585 (grpc_oauth2_token_fetcher_credentials *)r->creds;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800586 gpr_timespec token_lifetime;
587 grpc_credentials_status status;
588
589 gpr_mu_lock(&c->mu);
jboeuf1a809c02014-12-19 15:44:30 -0800590 status = grpc_oauth2_token_fetcher_credentials_parse_server_response(
Julien Boeuf75c9b6f2015-05-29 13:12:12 -0700591 response, &c->access_token_md, &token_lifetime);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800592 if (status == GRPC_CREDENTIALS_OK) {
593 c->token_expiration = gpr_time_add(gpr_now(), token_lifetime);
Julien Boeuf75c9b6f2015-05-29 13:12:12 -0700594 r->cb(r->user_data, c->access_token_md->entries,
595 c->access_token_md->num_entries, status);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800596 } else {
597 c->token_expiration = gpr_inf_past;
598 r->cb(r->user_data, NULL, 0, status);
599 }
600 gpr_mu_unlock(&c->mu);
601 grpc_credentials_metadata_request_destroy(r);
602}
603
jboeuf1a809c02014-12-19 15:44:30 -0800604static void oauth2_token_fetcher_get_request_metadata(
Craig Tiller06bac342015-06-01 12:55:57 -0700605 grpc_credentials *creds, grpc_pollset *pollset, const char *service_url,
Julien Boeuff47a5cb2015-02-18 12:24:08 -0800606 grpc_credentials_metadata_cb cb, void *user_data) {
jboeuf1a809c02014-12-19 15:44:30 -0800607 grpc_oauth2_token_fetcher_credentials *c =
608 (grpc_oauth2_token_fetcher_credentials *)creds;
Julien Boeuff47a5cb2015-02-18 12:24:08 -0800609 gpr_timespec refresh_threshold = {GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS,
jboeuf1a809c02014-12-19 15:44:30 -0800610 0};
Julien Boeuf75c9b6f2015-05-29 13:12:12 -0700611 grpc_credentials_md_store *cached_access_token_md = NULL;
jboeuf1a809c02014-12-19 15:44:30 -0800612 {
613 gpr_mu_lock(&c->mu);
614 if (c->access_token_md != NULL &&
615 (gpr_time_cmp(gpr_time_sub(c->token_expiration, gpr_now()),
616 refresh_threshold) > 0)) {
Craig Tiller8674cb12015-06-05 07:09:25 -0700617 cached_access_token_md =
618 grpc_credentials_md_store_ref(c->access_token_md);
jboeuf1a809c02014-12-19 15:44:30 -0800619 }
620 gpr_mu_unlock(&c->mu);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800621 }
jboeuf1a809c02014-12-19 15:44:30 -0800622 if (cached_access_token_md != NULL) {
Julien Boeuf75c9b6f2015-05-29 13:12:12 -0700623 cb(user_data, cached_access_token_md->entries,
624 cached_access_token_md->num_entries, GRPC_CREDENTIALS_OK);
625 grpc_credentials_md_store_unref(cached_access_token_md);
jboeuf1a809c02014-12-19 15:44:30 -0800626 } else {
627 c->fetch_func(
628 grpc_credentials_metadata_request_create(creds, cb, user_data),
Craig Tiller06bac342015-06-01 12:55:57 -0700629 &c->httpcli_context, pollset, on_oauth2_token_fetcher_http_response,
jboeuf1a809c02014-12-19 15:44:30 -0800630 gpr_time_add(gpr_now(), refresh_threshold));
631 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800632}
633
jboeuf1a809c02014-12-19 15:44:30 -0800634static void init_oauth2_token_fetcher(grpc_oauth2_token_fetcher_credentials *c,
635 grpc_fetch_oauth2_func fetch_func) {
636 memset(c, 0, sizeof(grpc_oauth2_token_fetcher_credentials));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800637 c->base.type = GRPC_CREDENTIALS_TYPE_OAUTH2;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800638 gpr_ref_init(&c->base.refcount, 1);
639 gpr_mu_init(&c->mu);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800640 c->token_expiration = gpr_inf_past;
jboeuf1a809c02014-12-19 15:44:30 -0800641 c->fetch_func = fetch_func;
Craig Tillerca22c972015-05-11 10:09:09 -0700642 grpc_pollset_set_init(&c->pollset_set);
jboeuf1a809c02014-12-19 15:44:30 -0800643}
644
645/* -- ComputeEngine credentials. -- */
646
647static grpc_credentials_vtable compute_engine_vtable = {
Craig Tiller8674cb12015-06-05 07:09:25 -0700648 oauth2_token_fetcher_destroy, oauth2_token_fetcher_has_request_metadata,
jboeuf1a809c02014-12-19 15:44:30 -0800649 oauth2_token_fetcher_has_request_metadata_only,
Julien Boeuf7d1d9ca2015-04-17 14:38:48 -0700650 oauth2_token_fetcher_get_request_metadata, NULL};
jboeuf1a809c02014-12-19 15:44:30 -0800651
652static void compute_engine_fetch_oauth2(
653 grpc_credentials_metadata_request *metadata_req,
Craig Tiller06bac342015-06-01 12:55:57 -0700654 grpc_httpcli_context *httpcli_context, grpc_pollset *pollset,
655 grpc_httpcli_response_cb response_cb, gpr_timespec deadline) {
jboeuf1a809c02014-12-19 15:44:30 -0800656 grpc_httpcli_header header = {"Metadata-Flavor", "Google"};
657 grpc_httpcli_request request;
658 memset(&request, 0, sizeof(grpc_httpcli_request));
659 request.host = GRPC_COMPUTE_ENGINE_METADATA_HOST;
660 request.path = GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH;
661 request.hdr_count = 1;
662 request.hdrs = &header;
Craig Tiller06bac342015-06-01 12:55:57 -0700663 grpc_httpcli_get(httpcli_context, pollset, &request, deadline, response_cb,
Craig Tiller83b826a2015-05-13 13:43:01 -0700664 metadata_req);
jboeuf1a809c02014-12-19 15:44:30 -0800665}
666
667grpc_credentials *grpc_compute_engine_credentials_create(void) {
668 grpc_oauth2_token_fetcher_credentials *c =
669 gpr_malloc(sizeof(grpc_oauth2_token_fetcher_credentials));
670 init_oauth2_token_fetcher(c, compute_engine_fetch_oauth2);
671 c->base.vtable = &compute_engine_vtable;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800672 return &c->base;
673}
674
jboeuf1a809c02014-12-19 15:44:30 -0800675/* -- ServiceAccount credentials. -- */
676
677typedef struct {
678 grpc_oauth2_token_fetcher_credentials base;
679 grpc_auth_json_key key;
680 char *scope;
681 gpr_timespec token_lifetime;
682} grpc_service_account_credentials;
683
684static void service_account_destroy(grpc_credentials *creds) {
685 grpc_service_account_credentials *c =
686 (grpc_service_account_credentials *)creds;
687 if (c->scope != NULL) gpr_free(c->scope);
688 grpc_auth_json_key_destruct(&c->key);
689 oauth2_token_fetcher_destroy(&c->base.base);
690}
691
692static grpc_credentials_vtable service_account_vtable = {
Craig Tiller8674cb12015-06-05 07:09:25 -0700693 service_account_destroy, oauth2_token_fetcher_has_request_metadata,
jboeuf1a809c02014-12-19 15:44:30 -0800694 oauth2_token_fetcher_has_request_metadata_only,
Julien Boeuf7d1d9ca2015-04-17 14:38:48 -0700695 oauth2_token_fetcher_get_request_metadata, NULL};
jboeuf1a809c02014-12-19 15:44:30 -0800696
697static void service_account_fetch_oauth2(
698 grpc_credentials_metadata_request *metadata_req,
Craig Tiller06bac342015-06-01 12:55:57 -0700699 grpc_httpcli_context *httpcli_context, grpc_pollset *pollset,
700 grpc_httpcli_response_cb response_cb, gpr_timespec deadline) {
jboeuf1a809c02014-12-19 15:44:30 -0800701 grpc_service_account_credentials *c =
702 (grpc_service_account_credentials *)metadata_req->creds;
703 grpc_httpcli_header header = {"Content-Type",
704 "application/x-www-form-urlencoded"};
705 grpc_httpcli_request request;
706 char *body = NULL;
Julien Boeuff47a5cb2015-02-18 12:24:08 -0800707 char *jwt = grpc_jwt_encode_and_sign(&c->key, GRPC_JWT_OAUTH2_AUDIENCE,
708 c->token_lifetime, c->scope);
jboeuf1a809c02014-12-19 15:44:30 -0800709 if (jwt == NULL) {
710 grpc_httpcli_response response;
711 memset(&response, 0, sizeof(grpc_httpcli_response));
712 response.status = 400; /* Invalid request. */
713 gpr_log(GPR_ERROR, "Could not create signed jwt.");
714 /* Do not even send the request, just call the response callback. */
715 response_cb(metadata_req, &response);
716 return;
717 }
Craig Tillerbe6a3552015-01-23 13:04:45 -0800718 gpr_asprintf(&body, "%s%s", GRPC_SERVICE_ACCOUNT_POST_BODY_PREFIX, jwt);
jboeuf1a809c02014-12-19 15:44:30 -0800719 memset(&request, 0, sizeof(grpc_httpcli_request));
Julien Boeuf9835cf02015-03-09 16:56:44 -0700720 request.host = GRPC_GOOGLE_OAUTH2_SERVICE_HOST;
721 request.path = GRPC_GOOGLE_OAUTH2_SERVICE_TOKEN_PATH;
jboeuf1a809c02014-12-19 15:44:30 -0800722 request.hdr_count = 1;
723 request.hdrs = &header;
724 request.use_ssl = 1;
Craig Tiller06bac342015-06-01 12:55:57 -0700725 grpc_httpcli_post(httpcli_context, pollset, &request, body, strlen(body),
726 deadline, response_cb, metadata_req);
jboeuf1a809c02014-12-19 15:44:30 -0800727 gpr_free(body);
728 gpr_free(jwt);
729}
730
731grpc_credentials *grpc_service_account_credentials_create(
732 const char *json_key, const char *scope, gpr_timespec token_lifetime) {
733 grpc_service_account_credentials *c;
734 grpc_auth_json_key key = grpc_auth_json_key_create_from_string(json_key);
735
736 if (scope == NULL || (strlen(scope) == 0) ||
737 !grpc_auth_json_key_is_valid(&key)) {
738 gpr_log(GPR_ERROR,
739 "Invalid input for service account credentials creation");
740 return NULL;
741 }
742 c = gpr_malloc(sizeof(grpc_service_account_credentials));
743 memset(c, 0, sizeof(grpc_service_account_credentials));
744 init_oauth2_token_fetcher(&c->base, service_account_fetch_oauth2);
745 c->base.base.vtable = &service_account_vtable;
746 c->scope = gpr_strdup(scope);
747 c->key = key;
748 c->token_lifetime = token_lifetime;
749 return &c->base.base;
750}
751
Julien Boeuf9835cf02015-03-09 16:56:44 -0700752/* -- RefreshToken credentials. -- */
753
754typedef struct {
755 grpc_oauth2_token_fetcher_credentials base;
756 grpc_auth_refresh_token refresh_token;
757} grpc_refresh_token_credentials;
758
759static void refresh_token_destroy(grpc_credentials *creds) {
Craig Tiller83b826a2015-05-13 13:43:01 -0700760 grpc_refresh_token_credentials *c = (grpc_refresh_token_credentials *)creds;
Julien Boeuf9835cf02015-03-09 16:56:44 -0700761 grpc_auth_refresh_token_destruct(&c->refresh_token);
762 oauth2_token_fetcher_destroy(&c->base.base);
763}
764
765static grpc_credentials_vtable refresh_token_vtable = {
Craig Tiller8674cb12015-06-05 07:09:25 -0700766 refresh_token_destroy, oauth2_token_fetcher_has_request_metadata,
Julien Boeuf9835cf02015-03-09 16:56:44 -0700767 oauth2_token_fetcher_has_request_metadata_only,
Julien Boeuf7d1d9ca2015-04-17 14:38:48 -0700768 oauth2_token_fetcher_get_request_metadata, NULL};
Julien Boeuf9835cf02015-03-09 16:56:44 -0700769
770static void refresh_token_fetch_oauth2(
771 grpc_credentials_metadata_request *metadata_req,
Craig Tiller06bac342015-06-01 12:55:57 -0700772 grpc_httpcli_context *httpcli_context, grpc_pollset *pollset,
773 grpc_httpcli_response_cb response_cb, gpr_timespec deadline) {
Julien Boeuf9835cf02015-03-09 16:56:44 -0700774 grpc_refresh_token_credentials *c =
775 (grpc_refresh_token_credentials *)metadata_req->creds;
776 grpc_httpcli_header header = {"Content-Type",
777 "application/x-www-form-urlencoded"};
778 grpc_httpcli_request request;
779 char *body = NULL;
780 gpr_asprintf(&body, GRPC_REFRESH_TOKEN_POST_BODY_FORMAT_STRING,
781 c->refresh_token.client_id, c->refresh_token.client_secret,
782 c->refresh_token.refresh_token);
783 memset(&request, 0, sizeof(grpc_httpcli_request));
784 request.host = GRPC_GOOGLE_OAUTH2_SERVICE_HOST;
785 request.path = GRPC_GOOGLE_OAUTH2_SERVICE_TOKEN_PATH;
786 request.hdr_count = 1;
787 request.hdrs = &header;
788 request.use_ssl = 1;
Craig Tiller06bac342015-06-01 12:55:57 -0700789 grpc_httpcli_post(httpcli_context, pollset, &request, body, strlen(body),
790 deadline, response_cb, metadata_req);
Julien Boeuf9835cf02015-03-09 16:56:44 -0700791 gpr_free(body);
792}
793
Julien Boeuf54006062015-07-07 19:13:04 -0700794grpc_credentials *grpc_refresh_token_credentials_create_from_auth_refresh_token(
795 grpc_auth_refresh_token refresh_token) {
Julien Boeuf9835cf02015-03-09 16:56:44 -0700796 grpc_refresh_token_credentials *c;
Julien Boeuf9835cf02015-03-09 16:56:44 -0700797 if (!grpc_auth_refresh_token_is_valid(&refresh_token)) {
Craig Tiller83b826a2015-05-13 13:43:01 -0700798 gpr_log(GPR_ERROR, "Invalid input for refresh token credentials creation");
Julien Boeuf9835cf02015-03-09 16:56:44 -0700799 return NULL;
800 }
801 c = gpr_malloc(sizeof(grpc_refresh_token_credentials));
802 memset(c, 0, sizeof(grpc_refresh_token_credentials));
803 init_oauth2_token_fetcher(&c->base, refresh_token_fetch_oauth2);
804 c->base.base.vtable = &refresh_token_vtable;
805 c->refresh_token = refresh_token;
806 return &c->base.base;
807}
808
Julien Boeuf54006062015-07-07 19:13:04 -0700809grpc_credentials *grpc_refresh_token_credentials_create(
810 const char *json_refresh_token) {
811 return grpc_refresh_token_credentials_create_from_auth_refresh_token(
812 grpc_auth_refresh_token_create_from_string(json_refresh_token));
813}
814
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800815/* -- Fake Oauth2 credentials. -- */
816
817typedef struct {
818 grpc_credentials base;
Julien Boeuf75c9b6f2015-05-29 13:12:12 -0700819 grpc_credentials_md_store *access_token_md;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800820 int is_async;
821} grpc_fake_oauth2_credentials;
822
823static void fake_oauth2_destroy(grpc_credentials *creds) {
824 grpc_fake_oauth2_credentials *c = (grpc_fake_oauth2_credentials *)creds;
Julien Boeuf75c9b6f2015-05-29 13:12:12 -0700825 grpc_credentials_md_store_unref(c->access_token_md);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800826 gpr_free(c);
827}
828
829static int fake_oauth2_has_request_metadata(const grpc_credentials *creds) {
830 return 1;
831}
832
833static int fake_oauth2_has_request_metadata_only(
834 const grpc_credentials *creds) {
835 return 1;
836}
837
ctiller58393c22015-01-07 14:03:30 -0800838void on_simulated_token_fetch_done(void *user_data, int success) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800839 grpc_credentials_metadata_request *r =
840 (grpc_credentials_metadata_request *)user_data;
841 grpc_fake_oauth2_credentials *c = (grpc_fake_oauth2_credentials *)r->creds;
ctiller58393c22015-01-07 14:03:30 -0800842 GPR_ASSERT(success);
Julien Boeuf75c9b6f2015-05-29 13:12:12 -0700843 r->cb(r->user_data, c->access_token_md->entries,
844 c->access_token_md->num_entries, GRPC_CREDENTIALS_OK);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800845 grpc_credentials_metadata_request_destroy(r);
846}
847
848static void fake_oauth2_get_request_metadata(grpc_credentials *creds,
Craig Tiller06bac342015-06-01 12:55:57 -0700849 grpc_pollset *pollset,
Julien Boeuff47a5cb2015-02-18 12:24:08 -0800850 const char *service_url,
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800851 grpc_credentials_metadata_cb cb,
852 void *user_data) {
853 grpc_fake_oauth2_credentials *c = (grpc_fake_oauth2_credentials *)creds;
854
855 if (c->is_async) {
David Garcia Quintas69ba8712015-06-01 11:29:42 -0700856 grpc_credentials_metadata_request *cb_arg =
David Garcia Quintas8b8cce02015-05-31 12:39:40 -0700857 grpc_credentials_metadata_request_create(creds, cb, user_data);
David Garcia Quintas69ba8712015-06-01 11:29:42 -0700858 grpc_iomgr_closure_init(cb_arg->on_simulated_token_fetch_done_closure,
859 on_simulated_token_fetch_done, cb_arg);
860 grpc_iomgr_add_callback(cb_arg->on_simulated_token_fetch_done_closure);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800861 } else {
Julien Boeuf75c9b6f2015-05-29 13:12:12 -0700862 cb(user_data, c->access_token_md->entries, 1, GRPC_CREDENTIALS_OK);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800863 }
864}
865
866static grpc_credentials_vtable fake_oauth2_vtable = {
867 fake_oauth2_destroy, fake_oauth2_has_request_metadata,
Julien Boeuf75c9b6f2015-05-29 13:12:12 -0700868 fake_oauth2_has_request_metadata_only, fake_oauth2_get_request_metadata,
Craig Tiller83b826a2015-05-13 13:43:01 -0700869 NULL};
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800870
871grpc_credentials *grpc_fake_oauth2_credentials_create(
872 const char *token_md_value, int is_async) {
873 grpc_fake_oauth2_credentials *c =
874 gpr_malloc(sizeof(grpc_fake_oauth2_credentials));
875 memset(c, 0, sizeof(grpc_fake_oauth2_credentials));
876 c->base.type = GRPC_CREDENTIALS_TYPE_OAUTH2;
877 c->base.vtable = &fake_oauth2_vtable;
878 gpr_ref_init(&c->base.refcount, 1);
Julien Boeuf75c9b6f2015-05-29 13:12:12 -0700879 c->access_token_md = grpc_credentials_md_store_create(1);
880 grpc_credentials_md_store_add_cstrings(
881 c->access_token_md, GRPC_AUTHORIZATION_METADATA_KEY, token_md_value);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800882 c->is_async = is_async;
883 return &c->base;
884}
885
886/* -- Fake transport security credentials. -- */
887
888static void fake_transport_security_credentials_destroy(
889 grpc_credentials *creds) {
890 gpr_free(creds);
891}
892
893static void fake_transport_security_server_credentials_destroy(
894 grpc_server_credentials *creds) {
895 gpr_free(creds);
896}
897
898static int fake_transport_security_has_request_metadata(
899 const grpc_credentials *creds) {
900 return 0;
901}
902
903static int fake_transport_security_has_request_metadata_only(
904 const grpc_credentials *creds) {
905 return 0;
906}
907
Craig Tiller8674cb12015-06-05 07:09:25 -0700908static grpc_security_status fake_transport_security_create_security_connector(
Julien Boeuf7d1d9ca2015-04-17 14:38:48 -0700909 grpc_credentials *c, const char *target, const grpc_channel_args *args,
910 grpc_credentials *request_metadata_creds,
911 grpc_channel_security_connector **sc, grpc_channel_args **new_args) {
912 *sc = grpc_fake_channel_security_connector_create(request_metadata_creds, 1);
913 return GRPC_SECURITY_OK;
914}
915
916static grpc_security_status
917fake_transport_security_server_create_security_connector(
918 grpc_server_credentials *c, grpc_security_connector **sc) {
919 *sc = grpc_fake_server_security_connector_create();
920 return GRPC_SECURITY_OK;
921}
922
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800923static grpc_credentials_vtable fake_transport_security_credentials_vtable = {
924 fake_transport_security_credentials_destroy,
925 fake_transport_security_has_request_metadata,
Julien Boeuf75c9b6f2015-05-29 13:12:12 -0700926 fake_transport_security_has_request_metadata_only, NULL,
Julien Boeuf7d1d9ca2015-04-17 14:38:48 -0700927 fake_transport_security_create_security_connector};
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800928
929static grpc_server_credentials_vtable
930 fake_transport_security_server_credentials_vtable = {
Julien Boeuf7d1d9ca2015-04-17 14:38:48 -0700931 fake_transport_security_server_credentials_destroy,
932 fake_transport_security_server_create_security_connector};
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800933
934grpc_credentials *grpc_fake_transport_security_credentials_create(void) {
935 grpc_credentials *c = gpr_malloc(sizeof(grpc_credentials));
936 memset(c, 0, sizeof(grpc_credentials));
937 c->type = GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY;
938 c->vtable = &fake_transport_security_credentials_vtable;
939 gpr_ref_init(&c->refcount, 1);
940 return c;
941}
942
Craig Tiller3eef2c42015-01-15 11:37:54 -0800943grpc_server_credentials *grpc_fake_transport_security_server_credentials_create(
944 void) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800945 grpc_server_credentials *c = gpr_malloc(sizeof(grpc_server_credentials));
946 memset(c, 0, sizeof(grpc_server_credentials));
947 c->type = GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY;
948 c->vtable = &fake_transport_security_server_credentials_vtable;
949 return c;
950}
951
nnoble0c475f02014-12-05 15:37:39 -0800952/* -- Composite credentials. -- */
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800953
nnoble0c475f02014-12-05 15:37:39 -0800954typedef struct {
955 grpc_credentials base;
956 grpc_credentials_array inner;
Julien Boeuf7d1d9ca2015-04-17 14:38:48 -0700957 grpc_credentials *connector_creds;
nnoble0c475f02014-12-05 15:37:39 -0800958} grpc_composite_credentials;
959
960typedef struct {
961 grpc_composite_credentials *composite_creds;
962 size_t creds_index;
Julien Boeuf75c9b6f2015-05-29 13:12:12 -0700963 grpc_credentials_md_store *md_elems;
Julien Boeuff47a5cb2015-02-18 12:24:08 -0800964 char *service_url;
nnoble0c475f02014-12-05 15:37:39 -0800965 void *user_data;
Craig Tiller06bac342015-06-01 12:55:57 -0700966 grpc_pollset *pollset;
nnoble0c475f02014-12-05 15:37:39 -0800967 grpc_credentials_metadata_cb cb;
968} grpc_composite_credentials_metadata_context;
969
970static void composite_destroy(grpc_credentials *creds) {
971 grpc_composite_credentials *c = (grpc_composite_credentials *)creds;
972 size_t i;
973 for (i = 0; i < c->inner.num_creds; i++) {
974 grpc_credentials_unref(c->inner.creds_array[i]);
975 }
976 gpr_free(c->inner.creds_array);
977 gpr_free(creds);
978}
979
980static int composite_has_request_metadata(const grpc_credentials *creds) {
981 const grpc_composite_credentials *c =
982 (const grpc_composite_credentials *)creds;
983 size_t i;
984 for (i = 0; i < c->inner.num_creds; i++) {
985 if (grpc_credentials_has_request_metadata(c->inner.creds_array[i])) {
986 return 1;
987 }
988 }
989 return 0;
990}
991
992static int composite_has_request_metadata_only(const grpc_credentials *creds) {
993 const grpc_composite_credentials *c =
994 (const grpc_composite_credentials *)creds;
995 size_t i;
996 for (i = 0; i < c->inner.num_creds; i++) {
997 if (!grpc_credentials_has_request_metadata_only(c->inner.creds_array[i])) {
998 return 0;
999 }
1000 }
1001 return 1;
1002}
1003
1004static void composite_md_context_destroy(
1005 grpc_composite_credentials_metadata_context *ctx) {
Julien Boeuf75c9b6f2015-05-29 13:12:12 -07001006 grpc_credentials_md_store_unref(ctx->md_elems);
Julien Boeuff47a5cb2015-02-18 12:24:08 -08001007 if (ctx->service_url != NULL) gpr_free(ctx->service_url);
nnoble0c475f02014-12-05 15:37:39 -08001008 gpr_free(ctx);
1009}
1010
Julien Boeuf75c9b6f2015-05-29 13:12:12 -07001011static void composite_metadata_cb(void *user_data,
1012 grpc_credentials_md *md_elems, size_t num_md,
nnoble0c475f02014-12-05 15:37:39 -08001013 grpc_credentials_status status) {
1014 grpc_composite_credentials_metadata_context *ctx =
1015 (grpc_composite_credentials_metadata_context *)user_data;
nnoble0c475f02014-12-05 15:37:39 -08001016 if (status != GRPC_CREDENTIALS_OK) {
1017 ctx->cb(ctx->user_data, NULL, 0, status);
1018 return;
1019 }
1020
1021 /* Copy the metadata in the context. */
1022 if (num_md > 0) {
Julien Boeuf75c9b6f2015-05-29 13:12:12 -07001023 size_t i;
nnoble0c475f02014-12-05 15:37:39 -08001024 for (i = 0; i < num_md; i++) {
Julien Boeuf75c9b6f2015-05-29 13:12:12 -07001025 grpc_credentials_md_store_add(ctx->md_elems, md_elems[i].key,
1026 md_elems[i].value);
nnoble0c475f02014-12-05 15:37:39 -08001027 }
nnoble0c475f02014-12-05 15:37:39 -08001028 }
1029
1030 /* See if we need to get some more metadata. */
1031 while (ctx->creds_index < ctx->composite_creds->inner.num_creds) {
1032 grpc_credentials *inner_creds =
1033 ctx->composite_creds->inner.creds_array[ctx->creds_index++];
1034 if (grpc_credentials_has_request_metadata(inner_creds)) {
Craig Tiller06bac342015-06-01 12:55:57 -07001035 grpc_credentials_get_request_metadata(inner_creds, ctx->pollset,
1036 ctx->service_url,
Julien Boeuff47a5cb2015-02-18 12:24:08 -08001037 composite_metadata_cb, ctx);
nnoble0c475f02014-12-05 15:37:39 -08001038 return;
1039 }
1040 }
1041
1042 /* We're done!. */
Julien Boeuf75c9b6f2015-05-29 13:12:12 -07001043 ctx->cb(ctx->user_data, ctx->md_elems->entries, ctx->md_elems->num_entries,
1044 GRPC_CREDENTIALS_OK);
nnoble0c475f02014-12-05 15:37:39 -08001045 composite_md_context_destroy(ctx);
1046}
1047
1048static void composite_get_request_metadata(grpc_credentials *creds,
Craig Tiller06bac342015-06-01 12:55:57 -07001049 grpc_pollset *pollset,
Julien Boeuff47a5cb2015-02-18 12:24:08 -08001050 const char *service_url,
nnoble0c475f02014-12-05 15:37:39 -08001051 grpc_credentials_metadata_cb cb,
1052 void *user_data) {
1053 grpc_composite_credentials *c = (grpc_composite_credentials *)creds;
1054 grpc_composite_credentials_metadata_context *ctx;
1055 if (!grpc_credentials_has_request_metadata(creds)) {
1056 cb(user_data, NULL, 0, GRPC_CREDENTIALS_OK);
1057 return;
1058 }
1059 ctx = gpr_malloc(sizeof(grpc_composite_credentials_metadata_context));
1060 memset(ctx, 0, sizeof(grpc_composite_credentials_metadata_context));
Julien Boeuff47a5cb2015-02-18 12:24:08 -08001061 ctx->service_url = gpr_strdup(service_url);
nnoble0c475f02014-12-05 15:37:39 -08001062 ctx->user_data = user_data;
1063 ctx->cb = cb;
1064 ctx->composite_creds = c;
Craig Tiller06bac342015-06-01 12:55:57 -07001065 ctx->pollset = pollset;
Julien Boeuf75c9b6f2015-05-29 13:12:12 -07001066 ctx->md_elems = grpc_credentials_md_store_create(c->inner.num_creds);
nnoble0c475f02014-12-05 15:37:39 -08001067 while (ctx->creds_index < c->inner.num_creds) {
1068 grpc_credentials *inner_creds = c->inner.creds_array[ctx->creds_index++];
1069 if (grpc_credentials_has_request_metadata(inner_creds)) {
Craig Tiller06bac342015-06-01 12:55:57 -07001070 grpc_credentials_get_request_metadata(inner_creds, pollset, service_url,
Julien Boeuff47a5cb2015-02-18 12:24:08 -08001071 composite_metadata_cb, ctx);
nnoble0c475f02014-12-05 15:37:39 -08001072 return;
1073 }
1074 }
1075 GPR_ASSERT(0); /* Should have exited before. */
1076}
1077
Julien Boeuf7d1d9ca2015-04-17 14:38:48 -07001078static grpc_security_status composite_create_security_connector(
1079 grpc_credentials *creds, const char *target, const grpc_channel_args *args,
1080 grpc_credentials *request_metadata_creds,
1081 grpc_channel_security_connector **sc, grpc_channel_args **new_args) {
1082 grpc_composite_credentials *c = (grpc_composite_credentials *)creds;
1083 if (c->connector_creds == NULL) {
1084 gpr_log(GPR_ERROR,
1085 "Cannot create security connector, missing connector credentials.");
1086 return GRPC_SECURITY_ERROR;
1087 }
1088 return grpc_credentials_create_security_connector(c->connector_creds, target,
1089 args, creds, sc, new_args);
1090}
1091
nnoble0c475f02014-12-05 15:37:39 -08001092static grpc_credentials_vtable composite_credentials_vtable = {
1093 composite_destroy, composite_has_request_metadata,
Julien Boeuf75c9b6f2015-05-29 13:12:12 -07001094 composite_has_request_metadata_only, composite_get_request_metadata,
Craig Tiller83b826a2015-05-13 13:43:01 -07001095 composite_create_security_connector};
nnoble0c475f02014-12-05 15:37:39 -08001096
1097static grpc_credentials_array get_creds_array(grpc_credentials **creds_addr) {
1098 grpc_credentials_array result;
1099 grpc_credentials *creds = *creds_addr;
1100 result.creds_array = creds_addr;
1101 result.num_creds = 1;
Ronnie Sahlberg2ad8d212015-03-07 08:39:22 -08001102 if (strcmp(creds->type, GRPC_CREDENTIALS_TYPE_COMPOSITE) == 0) {
nnoble0c475f02014-12-05 15:37:39 -08001103 result = *grpc_composite_credentials_get_credentials(creds);
1104 }
1105 return result;
1106}
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001107
1108grpc_credentials *grpc_composite_credentials_create(grpc_credentials *creds1,
1109 grpc_credentials *creds2) {
nnoble0c475f02014-12-05 15:37:39 -08001110 size_t i;
Julien Boeuf7d1d9ca2015-04-17 14:38:48 -07001111 size_t creds_array_byte_size;
nnoble0c475f02014-12-05 15:37:39 -08001112 grpc_credentials_array creds1_array;
1113 grpc_credentials_array creds2_array;
1114 grpc_composite_credentials *c;
1115 GPR_ASSERT(creds1 != NULL);
1116 GPR_ASSERT(creds2 != NULL);
1117 c = gpr_malloc(sizeof(grpc_composite_credentials));
1118 memset(c, 0, sizeof(grpc_composite_credentials));
1119 c->base.type = GRPC_CREDENTIALS_TYPE_COMPOSITE;
1120 c->base.vtable = &composite_credentials_vtable;
1121 gpr_ref_init(&c->base.refcount, 1);
1122 creds1_array = get_creds_array(&creds1);
1123 creds2_array = get_creds_array(&creds2);
1124 c->inner.num_creds = creds1_array.num_creds + creds2_array.num_creds;
Julien Boeuf7d1d9ca2015-04-17 14:38:48 -07001125 creds_array_byte_size = c->inner.num_creds * sizeof(grpc_credentials *);
1126 c->inner.creds_array = gpr_malloc(creds_array_byte_size);
1127 memset(c->inner.creds_array, 0, creds_array_byte_size);
nnoble0c475f02014-12-05 15:37:39 -08001128 for (i = 0; i < creds1_array.num_creds; i++) {
Julien Boeuf7d1d9ca2015-04-17 14:38:48 -07001129 grpc_credentials *cur_creds = creds1_array.creds_array[i];
1130 if (!grpc_credentials_has_request_metadata_only(cur_creds)) {
1131 if (c->connector_creds == NULL) {
1132 c->connector_creds = cur_creds;
1133 } else {
1134 gpr_log(GPR_ERROR, "Cannot compose multiple connector credentials.");
1135 goto fail;
1136 }
1137 }
1138 c->inner.creds_array[i] = grpc_credentials_ref(cur_creds);
nnoble0c475f02014-12-05 15:37:39 -08001139 }
1140 for (i = 0; i < creds2_array.num_creds; i++) {
Julien Boeuf7d1d9ca2015-04-17 14:38:48 -07001141 grpc_credentials *cur_creds = creds2_array.creds_array[i];
1142 if (!grpc_credentials_has_request_metadata_only(cur_creds)) {
1143 if (c->connector_creds == NULL) {
1144 c->connector_creds = cur_creds;
1145 } else {
1146 gpr_log(GPR_ERROR, "Cannot compose multiple connector credentials.");
1147 goto fail;
1148 }
1149 }
nnoble0c475f02014-12-05 15:37:39 -08001150 c->inner.creds_array[i + creds1_array.num_creds] =
Julien Boeuf7d1d9ca2015-04-17 14:38:48 -07001151 grpc_credentials_ref(cur_creds);
nnoble0c475f02014-12-05 15:37:39 -08001152 }
1153 return &c->base;
Julien Boeuf7d1d9ca2015-04-17 14:38:48 -07001154
1155fail:
1156 grpc_credentials_unref(&c->base);
1157 return NULL;
nnoble0c475f02014-12-05 15:37:39 -08001158}
1159
1160const grpc_credentials_array *grpc_composite_credentials_get_credentials(
1161 grpc_credentials *creds) {
1162 const grpc_composite_credentials *c =
1163 (const grpc_composite_credentials *)creds;
Ronnie Sahlberg2ad8d212015-03-07 08:39:22 -08001164 GPR_ASSERT(strcmp(creds->type, GRPC_CREDENTIALS_TYPE_COMPOSITE) == 0);
nnoble0c475f02014-12-05 15:37:39 -08001165 return &c->inner;
1166}
1167
jboeuf6ad120e2015-01-12 17:08:15 -08001168grpc_credentials *grpc_credentials_contains_type(
1169 grpc_credentials *creds, const char *type,
1170 grpc_credentials **composite_creds) {
1171 size_t i;
Ronnie Sahlberg2ad8d212015-03-07 08:39:22 -08001172 if (strcmp(creds->type, type) == 0) {
jboeuf6ad120e2015-01-12 17:08:15 -08001173 if (composite_creds != NULL) *composite_creds = NULL;
1174 return creds;
Ronnie Sahlberg2ad8d212015-03-07 08:39:22 -08001175 } else if (strcmp(creds->type, GRPC_CREDENTIALS_TYPE_COMPOSITE) == 0) {
jboeuf6ad120e2015-01-12 17:08:15 -08001176 const grpc_credentials_array *inner_creds_array =
1177 grpc_composite_credentials_get_credentials(creds);
1178 for (i = 0; i < inner_creds_array->num_creds; i++) {
Ronnie Sahlberg2ad8d212015-03-07 08:39:22 -08001179 if (strcmp(type, inner_creds_array->creds_array[i]->type) == 0) {
jboeuf6ad120e2015-01-12 17:08:15 -08001180 if (composite_creds != NULL) *composite_creds = creds;
1181 return inner_creds_array->creds_array[i];
1182 }
1183 }
1184 }
1185 return NULL;
1186}
1187
nnoble0c475f02014-12-05 15:37:39 -08001188/* -- IAM credentials. -- */
1189
1190typedef struct {
1191 grpc_credentials base;
Julien Boeuf75c9b6f2015-05-29 13:12:12 -07001192 grpc_credentials_md_store *iam_md;
nnoble0c475f02014-12-05 15:37:39 -08001193} grpc_iam_credentials;
1194
1195static void iam_destroy(grpc_credentials *creds) {
1196 grpc_iam_credentials *c = (grpc_iam_credentials *)creds;
Julien Boeuf75c9b6f2015-05-29 13:12:12 -07001197 grpc_credentials_md_store_unref(c->iam_md);
nnoble0c475f02014-12-05 15:37:39 -08001198 gpr_free(c);
1199}
1200
Craig Tiller83b826a2015-05-13 13:43:01 -07001201static int iam_has_request_metadata(const grpc_credentials *creds) { return 1; }
nnoble0c475f02014-12-05 15:37:39 -08001202
1203static int iam_has_request_metadata_only(const grpc_credentials *creds) {
1204 return 1;
1205}
1206
1207static void iam_get_request_metadata(grpc_credentials *creds,
Craig Tiller06bac342015-06-01 12:55:57 -07001208 grpc_pollset *pollset,
Julien Boeuff47a5cb2015-02-18 12:24:08 -08001209 const char *service_url,
nnoble0c475f02014-12-05 15:37:39 -08001210 grpc_credentials_metadata_cb cb,
1211 void *user_data) {
1212 grpc_iam_credentials *c = (grpc_iam_credentials *)creds;
Julien Boeuf75c9b6f2015-05-29 13:12:12 -07001213 cb(user_data, c->iam_md->entries, c->iam_md->num_entries,
1214 GRPC_CREDENTIALS_OK);
nnoble0c475f02014-12-05 15:37:39 -08001215}
1216
1217static grpc_credentials_vtable iam_vtable = {
1218 iam_destroy, iam_has_request_metadata, iam_has_request_metadata_only,
Julien Boeuf75c9b6f2015-05-29 13:12:12 -07001219 iam_get_request_metadata, NULL};
nnoble0c475f02014-12-05 15:37:39 -08001220
1221grpc_credentials *grpc_iam_credentials_create(const char *token,
1222 const char *authority_selector) {
1223 grpc_iam_credentials *c;
1224 GPR_ASSERT(token != NULL);
1225 GPR_ASSERT(authority_selector != NULL);
1226 c = gpr_malloc(sizeof(grpc_iam_credentials));
1227 memset(c, 0, sizeof(grpc_iam_credentials));
1228 c->base.type = GRPC_CREDENTIALS_TYPE_IAM;
1229 c->base.vtable = &iam_vtable;
1230 gpr_ref_init(&c->base.refcount, 1);
Julien Boeuf75c9b6f2015-05-29 13:12:12 -07001231 c->iam_md = grpc_credentials_md_store_create(2);
1232 grpc_credentials_md_store_add_cstrings(
1233 c->iam_md, GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY, token);
1234 grpc_credentials_md_store_add_cstrings(
1235 c->iam_md, GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY, authority_selector);
nnoble0c475f02014-12-05 15:37:39 -08001236 return &c->base;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001237}