blob: 7ff48f91232ec3fbbf3f215344202225886336ff [file] [log] [blame]
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001/*
2 *
3 * Copyright 2014, 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 "src/core/httpcli/httpcli.h"
37#include "src/core/surface/surface_em.h"
38#include <grpc/support/alloc.h>
39#include <grpc/support/log.h>
40#include <grpc/support/string.h>
41#include <grpc/support/sync.h>
42#include <grpc/support/time.h>
43
44#include "third_party/cJSON/cJSON.h"
45
46#include <string.h>
47#include <stdio.h>
48
49/* -- Constants. -- */
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080050#define GRPC_COMPUTE_ENGINE_TOKEN_REFRESH_THRESHOLD_SECS 60
51#define GRPC_COMPUTE_ENGINE_METADATA_HOST "metadata"
52#define GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH \
53 "computeMetadata/v1/instance/service-accounts/default/token"
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080054
55/* -- Common. -- */
56
57typedef struct {
58 grpc_credentials *creds;
59 grpc_credentials_metadata_cb cb;
60 void *user_data;
61} grpc_credentials_metadata_request;
62
63static grpc_credentials_metadata_request *
64grpc_credentials_metadata_request_create(grpc_credentials *creds,
65 grpc_credentials_metadata_cb cb,
66 void *user_data) {
67 grpc_credentials_metadata_request *r =
68 gpr_malloc(sizeof(grpc_credentials_metadata_request));
69 r->creds = grpc_credentials_ref(creds);
70 r->cb = cb;
71 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);
78 gpr_free(r);
79}
80
81grpc_credentials *grpc_credentials_ref(grpc_credentials *creds) {
82 if (creds == NULL) return NULL;
83 gpr_ref(&creds->refcount);
84 return creds;
85}
86
87void grpc_credentials_unref(grpc_credentials *creds) {
88 if (creds == NULL) return;
89 if (gpr_unref(&creds->refcount)) creds->vtable->destroy(creds);
90}
91
92void grpc_credentials_release(grpc_credentials *creds) {
93 grpc_credentials_unref(creds);
94}
95
96int grpc_credentials_has_request_metadata(grpc_credentials *creds) {
97 if (creds == NULL) return 0;
98 return creds->vtable->has_request_metadata(creds);
99}
100
101int grpc_credentials_has_request_metadata_only(grpc_credentials *creds) {
102 if (creds == NULL) return 0;
103 return creds->vtable->has_request_metadata_only(creds);
104}
105
106void grpc_credentials_get_request_metadata(grpc_credentials *creds,
107 grpc_credentials_metadata_cb cb,
108 void *user_data) {
nnoble0c475f02014-12-05 15:37:39 -0800109 if (creds == NULL || !grpc_credentials_has_request_metadata(creds) ||
110 creds->vtable->get_request_metadata == NULL) {
111 if (cb != NULL) {
112 cb(user_data, NULL, 0, GRPC_CREDENTIALS_OK);
113 }
114 return;
115 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800116 creds->vtable->get_request_metadata(creds, cb, user_data);
117}
118
119void grpc_server_credentials_release(grpc_server_credentials *creds) {
120 if (creds == NULL) return;
121 creds->vtable->destroy(creds);
122}
123
124/* -- Ssl credentials. -- */
125
126typedef struct {
127 grpc_credentials base;
128 grpc_ssl_config config;
129} grpc_ssl_credentials;
130
131typedef struct {
132 grpc_server_credentials base;
133 grpc_ssl_config config;
134} grpc_ssl_server_credentials;
135
136static void ssl_destroy(grpc_credentials *creds) {
137 grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds;
138 if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs);
139 if (c->config.pem_private_key != NULL) gpr_free(c->config.pem_private_key);
140 if (c->config.pem_cert_chain != NULL) gpr_free(c->config.pem_cert_chain);
141 gpr_free(creds);
142}
143
144static void ssl_server_destroy(grpc_server_credentials *creds) {
145 grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds;
146 if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs);
147 if (c->config.pem_private_key != NULL) gpr_free(c->config.pem_private_key);
148 if (c->config.pem_cert_chain != NULL) gpr_free(c->config.pem_cert_chain);
149 gpr_free(creds);
150}
151
152static int ssl_has_request_metadata(const grpc_credentials *creds) { return 0; }
153
154static int ssl_has_request_metadata_only(const grpc_credentials *creds) {
155 return 0;
156}
157
158static grpc_credentials_vtable ssl_vtable = {
159 ssl_destroy, ssl_has_request_metadata, ssl_has_request_metadata_only, NULL};
160
161static grpc_server_credentials_vtable ssl_server_vtable = {ssl_server_destroy};
162
163const grpc_ssl_config *grpc_ssl_credentials_get_config(
164 const grpc_credentials *creds) {
165 if (creds == NULL || strcmp(creds->type, GRPC_CREDENTIALS_TYPE_SSL)) {
166 return NULL;
167 } else {
168 grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds;
169 return &c->config;
170 }
171}
172
173const grpc_ssl_config *grpc_ssl_server_credentials_get_config(
174 const grpc_server_credentials *creds) {
175 if (creds == NULL || strcmp(creds->type, GRPC_CREDENTIALS_TYPE_SSL)) {
176 return NULL;
177 } else {
178 grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds;
179 return &c->config;
180 }
181}
182
183static void ssl_build_config(const unsigned char *pem_root_certs,
184 size_t pem_root_certs_size,
185 const unsigned char *pem_private_key,
186 size_t pem_private_key_size,
187 const unsigned char *pem_cert_chain,
188 size_t pem_cert_chain_size,
189 grpc_ssl_config *config) {
190 if (pem_root_certs != NULL) {
191 config->pem_root_certs = gpr_malloc(pem_root_certs_size);
192 memcpy(config->pem_root_certs, pem_root_certs, pem_root_certs_size);
193 config->pem_root_certs_size = pem_root_certs_size;
194 }
195 if (pem_private_key != NULL) {
196 config->pem_private_key = gpr_malloc(pem_private_key_size);
197 memcpy(config->pem_private_key, pem_private_key, pem_private_key_size);
198 config->pem_private_key_size = pem_private_key_size;
199 }
200 if (pem_cert_chain != NULL) {
201 config->pem_cert_chain = gpr_malloc(pem_cert_chain_size);
202 memcpy(config->pem_cert_chain, pem_cert_chain, pem_cert_chain_size);
203 config->pem_cert_chain_size = pem_cert_chain_size;
204 }
205}
206
207grpc_credentials *grpc_ssl_credentials_create(
208 const unsigned char *pem_root_certs, size_t pem_root_certs_size,
209 const unsigned char *pem_private_key, size_t pem_private_key_size,
210 const unsigned char *pem_cert_chain, size_t pem_cert_chain_size) {
211 grpc_ssl_credentials *c = gpr_malloc(sizeof(grpc_ssl_credentials));
212 memset(c, 0, sizeof(grpc_ssl_credentials));
213 c->base.type = GRPC_CREDENTIALS_TYPE_SSL;
214 c->base.vtable = &ssl_vtable;
215 gpr_ref_init(&c->base.refcount, 1);
216 ssl_build_config(pem_root_certs, pem_root_certs_size, pem_private_key,
217 pem_private_key_size, pem_cert_chain, pem_cert_chain_size,
218 &c->config);
219 return &c->base;
220}
221
222grpc_server_credentials *grpc_ssl_server_credentials_create(
223 const unsigned char *pem_root_certs, size_t pem_root_certs_size,
224 const unsigned char *pem_private_key, size_t pem_private_key_size,
225 const unsigned char *pem_cert_chain, size_t pem_cert_chain_size) {
226 grpc_ssl_server_credentials *c =
227 gpr_malloc(sizeof(grpc_ssl_server_credentials));
228 memset(c, 0, sizeof(grpc_ssl_server_credentials));
229 c->base.type = GRPC_CREDENTIALS_TYPE_SSL;
230 c->base.vtable = &ssl_server_vtable;
231 ssl_build_config(pem_root_certs, pem_root_certs_size, pem_private_key,
232 pem_private_key_size, pem_cert_chain, pem_cert_chain_size,
233 &c->config);
234 return &c->base;
235}
236
237/* -- ComputeEngine credentials. -- */
238
239typedef struct {
240 grpc_credentials base;
241 gpr_mu mu;
242 grpc_mdctx *md_ctx;
243 grpc_mdelem *access_token_md;
244 gpr_timespec token_expiration;
245} grpc_compute_engine_credentials;
246
247static void compute_engine_destroy(grpc_credentials *creds) {
248 grpc_compute_engine_credentials *c = (grpc_compute_engine_credentials *)creds;
249 if (c->access_token_md != NULL) {
250 grpc_mdelem_unref(c->access_token_md);
251 }
252 gpr_mu_destroy(&c->mu);
253 grpc_mdctx_orphan(c->md_ctx);
254 gpr_free(c);
255}
256
257static int compute_engine_has_request_metadata(const grpc_credentials *creds) {
258 return 1;
259}
260
261static int compute_engine_has_request_metadata_only(
262 const grpc_credentials *creds) {
263 return 1;
264}
265
266grpc_credentials_status grpc_compute_engine_credentials_parse_server_response(
267 const grpc_httpcli_response *response, grpc_mdctx *ctx,
268 grpc_mdelem **token_elem, gpr_timespec *token_lifetime) {
269 char *null_terminated_body = NULL;
270 char *new_access_token = NULL;
271 grpc_credentials_status status = GRPC_CREDENTIALS_OK;
272 cJSON *json = NULL;
273
274 if (response->status != 200) {
275 gpr_log(GPR_ERROR, "Call to metadata server ended with error %d",
276 response->status);
277 status = GRPC_CREDENTIALS_ERROR;
278 goto end;
279 } else {
280 cJSON *access_token = NULL;
281 cJSON *token_type = NULL;
282 cJSON *expires_in = NULL;
283 size_t new_access_token_size = 0;
284 null_terminated_body = gpr_malloc(response->body_length + 1);
285 null_terminated_body[response->body_length] = '\0';
286 memcpy(null_terminated_body, response->body, response->body_length);
287 json = cJSON_Parse(null_terminated_body);
288 if (json == NULL) {
289 gpr_log(GPR_ERROR, "Could not parse JSON from %s", null_terminated_body);
290 status = GRPC_CREDENTIALS_ERROR;
291 goto end;
292 }
293 if (json->type != cJSON_Object) {
294 gpr_log(GPR_ERROR, "Response should be a JSON object");
295 status = GRPC_CREDENTIALS_ERROR;
296 goto end;
297 }
298 access_token = cJSON_GetObjectItem(json, "access_token");
299 if (access_token == NULL || access_token->type != cJSON_String) {
300 gpr_log(GPR_ERROR, "Missing or invalid access_token in JSON.");
301 status = GRPC_CREDENTIALS_ERROR;
302 goto end;
303 }
304 token_type = cJSON_GetObjectItem(json, "token_type");
305 if (token_type == NULL || token_type->type != cJSON_String) {
306 gpr_log(GPR_ERROR, "Missing or invalid token_type in JSON.");
307 status = GRPC_CREDENTIALS_ERROR;
308 goto end;
309 }
310 expires_in = cJSON_GetObjectItem(json, "expires_in");
311 if (expires_in == NULL || expires_in->type != cJSON_Number) {
312 gpr_log(GPR_ERROR, "Missing or invalid expires_in in JSON.");
313 status = GRPC_CREDENTIALS_ERROR;
314 goto end;
315 }
316 new_access_token_size = strlen(token_type->valuestring) + 1 +
317 strlen(access_token->valuestring) + 1;
318 new_access_token = gpr_malloc(new_access_token_size);
319 /* C89 does not have snprintf :(. */
320 sprintf(new_access_token, "%s %s", token_type->valuestring,
321 access_token->valuestring);
322 token_lifetime->tv_sec = expires_in->valueint;
323 token_lifetime->tv_nsec = 0;
324 if (*token_elem != NULL) grpc_mdelem_unref(*token_elem);
325 *token_elem = grpc_mdelem_from_strings(ctx, GRPC_AUTHORIZATION_METADATA_KEY,
326 new_access_token);
327 status = GRPC_CREDENTIALS_OK;
328 }
329
330end:
331 if (status != GRPC_CREDENTIALS_OK && (*token_elem != NULL)) {
332 grpc_mdelem_unref(*token_elem);
333 *token_elem = NULL;
334 }
335 if (null_terminated_body != NULL) gpr_free(null_terminated_body);
336 if (new_access_token != NULL) gpr_free(new_access_token);
337 if (json != NULL) cJSON_Delete(json);
338 return status;
339}
340
341static void on_compute_engine_token_response(
342 void *user_data, const grpc_httpcli_response *response) {
343 grpc_credentials_metadata_request *r =
344 (grpc_credentials_metadata_request *)user_data;
345 grpc_compute_engine_credentials *c =
346 (grpc_compute_engine_credentials *)r->creds;
347 gpr_timespec token_lifetime;
348 grpc_credentials_status status;
349
350 gpr_mu_lock(&c->mu);
351 status = grpc_compute_engine_credentials_parse_server_response(
352 response, c->md_ctx, &c->access_token_md, &token_lifetime);
353 if (status == GRPC_CREDENTIALS_OK) {
354 c->token_expiration = gpr_time_add(gpr_now(), token_lifetime);
355 r->cb(r->user_data, &c->access_token_md, 1, status);
356 } else {
357 c->token_expiration = gpr_inf_past;
358 r->cb(r->user_data, NULL, 0, status);
359 }
360 gpr_mu_unlock(&c->mu);
361 grpc_credentials_metadata_request_destroy(r);
362}
363
364static void compute_engine_get_request_metadata(grpc_credentials *creds,
365 grpc_credentials_metadata_cb cb,
366 void *user_data) {
367 grpc_compute_engine_credentials *c = (grpc_compute_engine_credentials *)creds;
368 gpr_timespec refresh_threshold = {
369 GRPC_COMPUTE_ENGINE_TOKEN_REFRESH_THRESHOLD_SECS, 0};
370
371 gpr_mu_lock(&c->mu);
372 if (c->access_token_md == NULL ||
373 (gpr_time_cmp(gpr_time_sub(gpr_now(), c->token_expiration),
374 refresh_threshold) < 0)) {
375 grpc_httpcli_header header = {"Metadata-Flavor", "Google"};
376 grpc_httpcli_request request;
377 request.host = GRPC_COMPUTE_ENGINE_METADATA_HOST;
378 request.path = GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH;
379 request.hdr_count = 1;
380 request.hdrs = &header;
381 grpc_httpcli_get(
382 &request, gpr_time_add(gpr_now(), refresh_threshold), grpc_surface_em(),
383 on_compute_engine_token_response,
384 grpc_credentials_metadata_request_create(creds, cb, user_data));
385 } else {
386 cb(user_data, &c->access_token_md, 1, GRPC_CREDENTIALS_OK);
387 }
388 gpr_mu_unlock(&c->mu);
389}
390
391static grpc_credentials_vtable compute_engine_vtable = {
392 compute_engine_destroy, compute_engine_has_request_metadata,
393 compute_engine_has_request_metadata_only,
394 compute_engine_get_request_metadata};
395
396grpc_credentials *grpc_compute_engine_credentials_create(void) {
397 grpc_compute_engine_credentials *c =
398 gpr_malloc(sizeof(grpc_compute_engine_credentials));
399 memset(c, 0, sizeof(grpc_compute_engine_credentials));
400 c->base.type = GRPC_CREDENTIALS_TYPE_OAUTH2;
401 c->base.vtable = &compute_engine_vtable;
402 gpr_ref_init(&c->base.refcount, 1);
403 gpr_mu_init(&c->mu);
404 c->md_ctx = grpc_mdctx_create();
405 c->token_expiration = gpr_inf_past;
406 return &c->base;
407}
408
409/* -- Fake Oauth2 credentials. -- */
410
411typedef struct {
412 grpc_credentials base;
413 grpc_mdctx *md_ctx;
414 grpc_mdelem *access_token_md;
415 int is_async;
416} grpc_fake_oauth2_credentials;
417
418static void fake_oauth2_destroy(grpc_credentials *creds) {
419 grpc_fake_oauth2_credentials *c = (grpc_fake_oauth2_credentials *)creds;
420 if (c->access_token_md != NULL) {
421 grpc_mdelem_unref(c->access_token_md);
422 }
423 grpc_mdctx_orphan(c->md_ctx);
424 gpr_free(c);
425}
426
427static int fake_oauth2_has_request_metadata(const grpc_credentials *creds) {
428 return 1;
429}
430
431static int fake_oauth2_has_request_metadata_only(
432 const grpc_credentials *creds) {
433 return 1;
434}
435
436void on_simulated_token_fetch_done(void *user_data, grpc_em_cb_status status) {
437 grpc_credentials_metadata_request *r =
438 (grpc_credentials_metadata_request *)user_data;
439 grpc_fake_oauth2_credentials *c = (grpc_fake_oauth2_credentials *)r->creds;
440 GPR_ASSERT(status == GRPC_CALLBACK_SUCCESS);
441 r->cb(r->user_data, &c->access_token_md, 1, GRPC_CREDENTIALS_OK);
442 grpc_credentials_metadata_request_destroy(r);
443}
444
445static void fake_oauth2_get_request_metadata(grpc_credentials *creds,
446 grpc_credentials_metadata_cb cb,
447 void *user_data) {
448 grpc_fake_oauth2_credentials *c = (grpc_fake_oauth2_credentials *)creds;
449
450 if (c->is_async) {
451 GPR_ASSERT(grpc_em_add_callback(grpc_surface_em(),
452 on_simulated_token_fetch_done,
453 grpc_credentials_metadata_request_create(
454 creds, cb, user_data)) == GRPC_EM_OK);
455 } else {
456 cb(user_data, &c->access_token_md, 1, GRPC_CREDENTIALS_OK);
457 }
458}
459
460static grpc_credentials_vtable fake_oauth2_vtable = {
461 fake_oauth2_destroy, fake_oauth2_has_request_metadata,
462 fake_oauth2_has_request_metadata_only, fake_oauth2_get_request_metadata};
463
464grpc_credentials *grpc_fake_oauth2_credentials_create(
465 const char *token_md_value, int is_async) {
466 grpc_fake_oauth2_credentials *c =
467 gpr_malloc(sizeof(grpc_fake_oauth2_credentials));
468 memset(c, 0, sizeof(grpc_fake_oauth2_credentials));
469 c->base.type = GRPC_CREDENTIALS_TYPE_OAUTH2;
470 c->base.vtable = &fake_oauth2_vtable;
471 gpr_ref_init(&c->base.refcount, 1);
472 c->md_ctx = grpc_mdctx_create();
473 c->access_token_md = grpc_mdelem_from_strings(
474 c->md_ctx, GRPC_AUTHORIZATION_METADATA_KEY, token_md_value);
475 c->is_async = is_async;
476 return &c->base;
477}
478
479/* -- Fake transport security credentials. -- */
480
481static void fake_transport_security_credentials_destroy(
482 grpc_credentials *creds) {
483 gpr_free(creds);
484}
485
486static void fake_transport_security_server_credentials_destroy(
487 grpc_server_credentials *creds) {
488 gpr_free(creds);
489}
490
491static int fake_transport_security_has_request_metadata(
492 const grpc_credentials *creds) {
493 return 0;
494}
495
496static int fake_transport_security_has_request_metadata_only(
497 const grpc_credentials *creds) {
498 return 0;
499}
500
501static grpc_credentials_vtable fake_transport_security_credentials_vtable = {
502 fake_transport_security_credentials_destroy,
503 fake_transport_security_has_request_metadata,
504 fake_transport_security_has_request_metadata_only, NULL};
505
506static grpc_server_credentials_vtable
507 fake_transport_security_server_credentials_vtable = {
508 fake_transport_security_server_credentials_destroy};
509
510grpc_credentials *grpc_fake_transport_security_credentials_create(void) {
511 grpc_credentials *c = gpr_malloc(sizeof(grpc_credentials));
512 memset(c, 0, sizeof(grpc_credentials));
513 c->type = GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY;
514 c->vtable = &fake_transport_security_credentials_vtable;
515 gpr_ref_init(&c->refcount, 1);
516 return c;
517}
518
519grpc_server_credentials *
520grpc_fake_transport_security_server_credentials_create() {
521 grpc_server_credentials *c = gpr_malloc(sizeof(grpc_server_credentials));
522 memset(c, 0, sizeof(grpc_server_credentials));
523 c->type = GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY;
524 c->vtable = &fake_transport_security_server_credentials_vtable;
525 return c;
526}
527
nnoble0c475f02014-12-05 15:37:39 -0800528/* -- Composite credentials. -- */
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800529
nnoble0c475f02014-12-05 15:37:39 -0800530typedef struct {
531 grpc_credentials base;
532 grpc_credentials_array inner;
533} grpc_composite_credentials;
534
535typedef struct {
536 grpc_composite_credentials *composite_creds;
537 size_t creds_index;
538 grpc_mdelem **md_elems;
539 size_t num_md;
540 void *user_data;
541 grpc_credentials_metadata_cb cb;
542} grpc_composite_credentials_metadata_context;
543
544static void composite_destroy(grpc_credentials *creds) {
545 grpc_composite_credentials *c = (grpc_composite_credentials *)creds;
546 size_t i;
547 for (i = 0; i < c->inner.num_creds; i++) {
548 grpc_credentials_unref(c->inner.creds_array[i]);
549 }
550 gpr_free(c->inner.creds_array);
551 gpr_free(creds);
552}
553
554static int composite_has_request_metadata(const grpc_credentials *creds) {
555 const grpc_composite_credentials *c =
556 (const grpc_composite_credentials *)creds;
557 size_t i;
558 for (i = 0; i < c->inner.num_creds; i++) {
559 if (grpc_credentials_has_request_metadata(c->inner.creds_array[i])) {
560 return 1;
561 }
562 }
563 return 0;
564}
565
566static int composite_has_request_metadata_only(const grpc_credentials *creds) {
567 const grpc_composite_credentials *c =
568 (const grpc_composite_credentials *)creds;
569 size_t i;
570 for (i = 0; i < c->inner.num_creds; i++) {
571 if (!grpc_credentials_has_request_metadata_only(c->inner.creds_array[i])) {
572 return 0;
573 }
574 }
575 return 1;
576}
577
578static void composite_md_context_destroy(
579 grpc_composite_credentials_metadata_context *ctx) {
580 size_t i;
581 for (i = 0; i < ctx->num_md; i++) {
582 grpc_mdelem_unref(ctx->md_elems[i]);
583 }
584 gpr_free(ctx->md_elems);
585 gpr_free(ctx);
586}
587
588static void composite_metadata_cb(void *user_data, grpc_mdelem **md_elems,
589 size_t num_md,
590 grpc_credentials_status status) {
591 grpc_composite_credentials_metadata_context *ctx =
592 (grpc_composite_credentials_metadata_context *)user_data;
593 size_t i;
594 if (status != GRPC_CREDENTIALS_OK) {
595 ctx->cb(ctx->user_data, NULL, 0, status);
596 return;
597 }
598
599 /* Copy the metadata in the context. */
600 if (num_md > 0) {
601 ctx->md_elems = gpr_realloc(ctx->md_elems,
602 (ctx->num_md + num_md) * sizeof(grpc_mdelem *));
603 for (i = 0; i < num_md; i++) {
604 ctx->md_elems[i + ctx->num_md] = grpc_mdelem_ref(md_elems[i]);
605 }
606 ctx->num_md += num_md;
607 }
608
609 /* See if we need to get some more metadata. */
610 while (ctx->creds_index < ctx->composite_creds->inner.num_creds) {
611 grpc_credentials *inner_creds =
612 ctx->composite_creds->inner.creds_array[ctx->creds_index++];
613 if (grpc_credentials_has_request_metadata(inner_creds)) {
614 grpc_credentials_get_request_metadata(inner_creds, composite_metadata_cb,
615 ctx);
616 return;
617 }
618 }
619
620 /* We're done!. */
621 ctx->cb(ctx->user_data, ctx->md_elems, ctx->num_md, GRPC_CREDENTIALS_OK);
622 composite_md_context_destroy(ctx);
623}
624
625static void composite_get_request_metadata(grpc_credentials *creds,
626 grpc_credentials_metadata_cb cb,
627 void *user_data) {
628 grpc_composite_credentials *c = (grpc_composite_credentials *)creds;
629 grpc_composite_credentials_metadata_context *ctx;
630 if (!grpc_credentials_has_request_metadata(creds)) {
631 cb(user_data, NULL, 0, GRPC_CREDENTIALS_OK);
632 return;
633 }
634 ctx = gpr_malloc(sizeof(grpc_composite_credentials_metadata_context));
635 memset(ctx, 0, sizeof(grpc_composite_credentials_metadata_context));
636 ctx->user_data = user_data;
637 ctx->cb = cb;
638 ctx->composite_creds = c;
639 while (ctx->creds_index < c->inner.num_creds) {
640 grpc_credentials *inner_creds = c->inner.creds_array[ctx->creds_index++];
641 if (grpc_credentials_has_request_metadata(inner_creds)) {
642 grpc_credentials_get_request_metadata(inner_creds, composite_metadata_cb,
643 ctx);
644 return;
645 }
646 }
647 GPR_ASSERT(0); /* Should have exited before. */
648}
649
650static grpc_credentials_vtable composite_credentials_vtable = {
651 composite_destroy, composite_has_request_metadata,
652 composite_has_request_metadata_only, composite_get_request_metadata};
653
654static grpc_credentials_array get_creds_array(grpc_credentials **creds_addr) {
655 grpc_credentials_array result;
656 grpc_credentials *creds = *creds_addr;
657 result.creds_array = creds_addr;
658 result.num_creds = 1;
659 if (!strcmp(creds->type, GRPC_CREDENTIALS_TYPE_COMPOSITE)) {
660 result = *grpc_composite_credentials_get_credentials(creds);
661 }
662 return result;
663}
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800664
665grpc_credentials *grpc_composite_credentials_create(grpc_credentials *creds1,
666 grpc_credentials *creds2) {
nnoble0c475f02014-12-05 15:37:39 -0800667 size_t i;
668 grpc_credentials_array creds1_array;
669 grpc_credentials_array creds2_array;
670 grpc_composite_credentials *c;
671 GPR_ASSERT(creds1 != NULL);
672 GPR_ASSERT(creds2 != NULL);
673 c = gpr_malloc(sizeof(grpc_composite_credentials));
674 memset(c, 0, sizeof(grpc_composite_credentials));
675 c->base.type = GRPC_CREDENTIALS_TYPE_COMPOSITE;
676 c->base.vtable = &composite_credentials_vtable;
677 gpr_ref_init(&c->base.refcount, 1);
678 creds1_array = get_creds_array(&creds1);
679 creds2_array = get_creds_array(&creds2);
680 c->inner.num_creds = creds1_array.num_creds + creds2_array.num_creds;
681 c->inner.creds_array =
682 gpr_malloc(c->inner.num_creds * sizeof(grpc_credentials *));
683 for (i = 0; i < creds1_array.num_creds; i++) {
684 c->inner.creds_array[i] = grpc_credentials_ref(creds1_array.creds_array[i]);
685 }
686 for (i = 0; i < creds2_array.num_creds; i++) {
687 c->inner.creds_array[i + creds1_array.num_creds] =
688 grpc_credentials_ref(creds2_array.creds_array[i]);
689 }
690 return &c->base;
691}
692
693const grpc_credentials_array *grpc_composite_credentials_get_credentials(
694 grpc_credentials *creds) {
695 const grpc_composite_credentials *c =
696 (const grpc_composite_credentials *)creds;
697 GPR_ASSERT(!strcmp(creds->type, GRPC_CREDENTIALS_TYPE_COMPOSITE));
698 return &c->inner;
699}
700
701/* -- IAM credentials. -- */
702
703typedef struct {
704 grpc_credentials base;
705 grpc_mdctx *md_ctx;
706 grpc_mdelem *token_md;
707 grpc_mdelem *authority_selector_md;
708} grpc_iam_credentials;
709
710static void iam_destroy(grpc_credentials *creds) {
711 grpc_iam_credentials *c = (grpc_iam_credentials *)creds;
712 grpc_mdelem_unref(c->token_md);
713 grpc_mdelem_unref(c->authority_selector_md);
714 grpc_mdctx_orphan(c->md_ctx);
715 gpr_free(c);
716}
717
718static int iam_has_request_metadata(const grpc_credentials *creds) { return 1; }
719
720static int iam_has_request_metadata_only(const grpc_credentials *creds) {
721 return 1;
722}
723
724static void iam_get_request_metadata(grpc_credentials *creds,
725 grpc_credentials_metadata_cb cb,
726 void *user_data) {
727 grpc_iam_credentials *c = (grpc_iam_credentials *)creds;
728 grpc_mdelem *md_array[2];
729 md_array[0] = c->token_md;
730 md_array[1] = c->authority_selector_md;
731 cb(user_data, md_array, 2, GRPC_CREDENTIALS_OK);
732}
733
734static grpc_credentials_vtable iam_vtable = {
735 iam_destroy, iam_has_request_metadata, iam_has_request_metadata_only,
736 iam_get_request_metadata};
737
738grpc_credentials *grpc_iam_credentials_create(const char *token,
739 const char *authority_selector) {
740 grpc_iam_credentials *c;
741 GPR_ASSERT(token != NULL);
742 GPR_ASSERT(authority_selector != NULL);
743 c = gpr_malloc(sizeof(grpc_iam_credentials));
744 memset(c, 0, sizeof(grpc_iam_credentials));
745 c->base.type = GRPC_CREDENTIALS_TYPE_IAM;
746 c->base.vtable = &iam_vtable;
747 gpr_ref_init(&c->base.refcount, 1);
748 c->md_ctx = grpc_mdctx_create();
749 c->token_md = grpc_mdelem_from_strings(
750 c->md_ctx, GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY, token);
751 c->authority_selector_md = grpc_mdelem_from_strings(
752 c->md_ctx, GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY, authority_selector);
753 return &c->base;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800754}
755
756/* -- Default credentials TODO(jboeuf). -- */
757
758grpc_credentials *grpc_default_credentials_create(void) { return NULL; }
nnoble0c475f02014-12-05 15:37:39 -0800759