blob: 442d2fa62490f3b1bf86a631984a5bcd178c6654 [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"
ctiller18b49ab2014-12-09 14:39:16 -080037#include "src/core/iomgr/iomgr.h"
jboeuf1a809c02014-12-19 15:44:30 -080038#include "src/core/security/json_token.h"
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080039#include <grpc/support/alloc.h>
40#include <grpc/support/log.h>
41#include <grpc/support/string.h>
42#include <grpc/support/sync.h>
43#include <grpc/support/time.h>
44
45#include "third_party/cJSON/cJSON.h"
46
47#include <string.h>
48#include <stdio.h>
49
50/* -- Constants. -- */
jboeuf1a809c02014-12-19 15:44:30 -080051
52#define GRPC_OAUTH2_TOKEN_REFRESH_THRESHOLD_SECS 60
53
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080054#define GRPC_COMPUTE_ENGINE_METADATA_HOST "metadata"
55#define GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH \
jboeuf1a809c02014-12-19 15:44:30 -080056 "/computeMetadata/v1/instance/service-accounts/default/token"
57
58#define GRPC_SERVICE_ACCOUNT_HOST "www.googleapis.com"
59#define GRPC_SERVICE_ACCOUNT_TOKEN_PATH "/oauth2/v3/token"
60#define GRPC_SERVICE_ACCOUNT_POST_BODY_PREFIX \
61 "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&" \
62 "assertion="
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080063
64/* -- Common. -- */
65
66typedef struct {
67 grpc_credentials *creds;
68 grpc_credentials_metadata_cb cb;
69 void *user_data;
70} grpc_credentials_metadata_request;
71
72static grpc_credentials_metadata_request *
73grpc_credentials_metadata_request_create(grpc_credentials *creds,
74 grpc_credentials_metadata_cb cb,
75 void *user_data) {
76 grpc_credentials_metadata_request *r =
77 gpr_malloc(sizeof(grpc_credentials_metadata_request));
78 r->creds = grpc_credentials_ref(creds);
79 r->cb = cb;
80 r->user_data = user_data;
81 return r;
82}
83
84static void grpc_credentials_metadata_request_destroy(
85 grpc_credentials_metadata_request *r) {
86 grpc_credentials_unref(r->creds);
87 gpr_free(r);
88}
89
90grpc_credentials *grpc_credentials_ref(grpc_credentials *creds) {
91 if (creds == NULL) return NULL;
92 gpr_ref(&creds->refcount);
93 return creds;
94}
95
96void grpc_credentials_unref(grpc_credentials *creds) {
97 if (creds == NULL) return;
98 if (gpr_unref(&creds->refcount)) creds->vtable->destroy(creds);
99}
100
101void grpc_credentials_release(grpc_credentials *creds) {
102 grpc_credentials_unref(creds);
103}
104
105int grpc_credentials_has_request_metadata(grpc_credentials *creds) {
106 if (creds == NULL) return 0;
107 return creds->vtable->has_request_metadata(creds);
108}
109
110int grpc_credentials_has_request_metadata_only(grpc_credentials *creds) {
111 if (creds == NULL) return 0;
112 return creds->vtable->has_request_metadata_only(creds);
113}
114
115void grpc_credentials_get_request_metadata(grpc_credentials *creds,
116 grpc_credentials_metadata_cb cb,
117 void *user_data) {
nnoble0c475f02014-12-05 15:37:39 -0800118 if (creds == NULL || !grpc_credentials_has_request_metadata(creds) ||
119 creds->vtable->get_request_metadata == NULL) {
120 if (cb != NULL) {
121 cb(user_data, NULL, 0, GRPC_CREDENTIALS_OK);
122 }
123 return;
124 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800125 creds->vtable->get_request_metadata(creds, cb, user_data);
126}
127
128void grpc_server_credentials_release(grpc_server_credentials *creds) {
129 if (creds == NULL) return;
130 creds->vtable->destroy(creds);
131}
132
133/* -- Ssl credentials. -- */
134
135typedef struct {
136 grpc_credentials base;
137 grpc_ssl_config config;
138} grpc_ssl_credentials;
139
140typedef struct {
141 grpc_server_credentials base;
142 grpc_ssl_config config;
143} grpc_ssl_server_credentials;
144
145static void ssl_destroy(grpc_credentials *creds) {
146 grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds;
147 if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs);
148 if (c->config.pem_private_key != NULL) gpr_free(c->config.pem_private_key);
149 if (c->config.pem_cert_chain != NULL) gpr_free(c->config.pem_cert_chain);
150 gpr_free(creds);
151}
152
153static void ssl_server_destroy(grpc_server_credentials *creds) {
154 grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds;
155 if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs);
156 if (c->config.pem_private_key != NULL) gpr_free(c->config.pem_private_key);
157 if (c->config.pem_cert_chain != NULL) gpr_free(c->config.pem_cert_chain);
158 gpr_free(creds);
159}
160
161static int ssl_has_request_metadata(const grpc_credentials *creds) { return 0; }
162
163static int ssl_has_request_metadata_only(const grpc_credentials *creds) {
164 return 0;
165}
166
167static grpc_credentials_vtable ssl_vtable = {
168 ssl_destroy, ssl_has_request_metadata, ssl_has_request_metadata_only, NULL};
169
170static grpc_server_credentials_vtable ssl_server_vtable = {ssl_server_destroy};
171
172const grpc_ssl_config *grpc_ssl_credentials_get_config(
173 const grpc_credentials *creds) {
174 if (creds == NULL || strcmp(creds->type, GRPC_CREDENTIALS_TYPE_SSL)) {
175 return NULL;
176 } else {
177 grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds;
178 return &c->config;
179 }
180}
181
182const grpc_ssl_config *grpc_ssl_server_credentials_get_config(
183 const grpc_server_credentials *creds) {
184 if (creds == NULL || strcmp(creds->type, GRPC_CREDENTIALS_TYPE_SSL)) {
185 return NULL;
186 } else {
187 grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds;
188 return &c->config;
189 }
190}
191
192static void ssl_build_config(const unsigned char *pem_root_certs,
193 size_t pem_root_certs_size,
194 const unsigned char *pem_private_key,
195 size_t pem_private_key_size,
196 const unsigned char *pem_cert_chain,
197 size_t pem_cert_chain_size,
198 grpc_ssl_config *config) {
199 if (pem_root_certs != NULL) {
200 config->pem_root_certs = gpr_malloc(pem_root_certs_size);
201 memcpy(config->pem_root_certs, pem_root_certs, pem_root_certs_size);
202 config->pem_root_certs_size = pem_root_certs_size;
203 }
204 if (pem_private_key != NULL) {
205 config->pem_private_key = gpr_malloc(pem_private_key_size);
206 memcpy(config->pem_private_key, pem_private_key, pem_private_key_size);
207 config->pem_private_key_size = pem_private_key_size;
208 }
209 if (pem_cert_chain != NULL) {
210 config->pem_cert_chain = gpr_malloc(pem_cert_chain_size);
211 memcpy(config->pem_cert_chain, pem_cert_chain, pem_cert_chain_size);
212 config->pem_cert_chain_size = pem_cert_chain_size;
213 }
214}
215
216grpc_credentials *grpc_ssl_credentials_create(
217 const unsigned char *pem_root_certs, size_t pem_root_certs_size,
218 const unsigned char *pem_private_key, size_t pem_private_key_size,
219 const unsigned char *pem_cert_chain, size_t pem_cert_chain_size) {
220 grpc_ssl_credentials *c = gpr_malloc(sizeof(grpc_ssl_credentials));
221 memset(c, 0, sizeof(grpc_ssl_credentials));
222 c->base.type = GRPC_CREDENTIALS_TYPE_SSL;
223 c->base.vtable = &ssl_vtable;
224 gpr_ref_init(&c->base.refcount, 1);
225 ssl_build_config(pem_root_certs, pem_root_certs_size, pem_private_key,
226 pem_private_key_size, pem_cert_chain, pem_cert_chain_size,
227 &c->config);
228 return &c->base;
229}
230
231grpc_server_credentials *grpc_ssl_server_credentials_create(
232 const unsigned char *pem_root_certs, size_t pem_root_certs_size,
233 const unsigned char *pem_private_key, size_t pem_private_key_size,
234 const unsigned char *pem_cert_chain, size_t pem_cert_chain_size) {
235 grpc_ssl_server_credentials *c =
236 gpr_malloc(sizeof(grpc_ssl_server_credentials));
237 memset(c, 0, sizeof(grpc_ssl_server_credentials));
238 c->base.type = GRPC_CREDENTIALS_TYPE_SSL;
239 c->base.vtable = &ssl_server_vtable;
240 ssl_build_config(pem_root_certs, pem_root_certs_size, pem_private_key,
241 pem_private_key_size, pem_cert_chain, pem_cert_chain_size,
242 &c->config);
243 return &c->base;
244}
245
jboeuf1a809c02014-12-19 15:44:30 -0800246/* -- Oauth2TokenFetcher credentials -- */
247
248/* This object is a base for credentials that need to acquire an oauth2 token
249 from an http service. */
250
251typedef void (*grpc_fetch_oauth2_func)(grpc_credentials_metadata_request *req,
252 grpc_httpcli_response_cb response_cb,
253 gpr_timespec deadline);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800254
255typedef struct {
256 grpc_credentials base;
257 gpr_mu mu;
258 grpc_mdctx *md_ctx;
259 grpc_mdelem *access_token_md;
260 gpr_timespec token_expiration;
jboeuf1a809c02014-12-19 15:44:30 -0800261 grpc_fetch_oauth2_func fetch_func;
262} grpc_oauth2_token_fetcher_credentials;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800263
jboeuf1a809c02014-12-19 15:44:30 -0800264static void oauth2_token_fetcher_destroy(grpc_credentials *creds) {
265 grpc_oauth2_token_fetcher_credentials *c =
266 (grpc_oauth2_token_fetcher_credentials *)creds;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800267 if (c->access_token_md != NULL) {
268 grpc_mdelem_unref(c->access_token_md);
269 }
270 gpr_mu_destroy(&c->mu);
271 grpc_mdctx_orphan(c->md_ctx);
272 gpr_free(c);
273}
274
jboeuf1a809c02014-12-19 15:44:30 -0800275static int oauth2_token_fetcher_has_request_metadata(
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800276 const grpc_credentials *creds) {
277 return 1;
278}
279
jboeuf1a809c02014-12-19 15:44:30 -0800280static int oauth2_token_fetcher_has_request_metadata_only(
281 const grpc_credentials *creds) {
282 return 1;
283}
284
285grpc_credentials_status
286grpc_oauth2_token_fetcher_credentials_parse_server_response(
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800287 const grpc_httpcli_response *response, grpc_mdctx *ctx,
288 grpc_mdelem **token_elem, gpr_timespec *token_lifetime) {
289 char *null_terminated_body = NULL;
290 char *new_access_token = NULL;
291 grpc_credentials_status status = GRPC_CREDENTIALS_OK;
292 cJSON *json = NULL;
293
jboeuf1a809c02014-12-19 15:44:30 -0800294 if (response->body_length > 0) {
295 null_terminated_body = gpr_malloc(response->body_length + 1);
296 null_terminated_body[response->body_length] = '\0';
297 memcpy(null_terminated_body, response->body, response->body_length);
298 }
299
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800300 if (response->status != 200) {
jboeuf1a809c02014-12-19 15:44:30 -0800301 gpr_log(GPR_ERROR, "Call to http server ended with error %d [%s].",
302 response->status,
303 null_terminated_body != NULL ? null_terminated_body : "");
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800304 status = GRPC_CREDENTIALS_ERROR;
305 goto end;
306 } else {
307 cJSON *access_token = NULL;
308 cJSON *token_type = NULL;
309 cJSON *expires_in = NULL;
310 size_t new_access_token_size = 0;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800311 json = cJSON_Parse(null_terminated_body);
312 if (json == NULL) {
313 gpr_log(GPR_ERROR, "Could not parse JSON from %s", null_terminated_body);
314 status = GRPC_CREDENTIALS_ERROR;
315 goto end;
316 }
317 if (json->type != cJSON_Object) {
318 gpr_log(GPR_ERROR, "Response should be a JSON object");
319 status = GRPC_CREDENTIALS_ERROR;
320 goto end;
321 }
322 access_token = cJSON_GetObjectItem(json, "access_token");
323 if (access_token == NULL || access_token->type != cJSON_String) {
324 gpr_log(GPR_ERROR, "Missing or invalid access_token in JSON.");
325 status = GRPC_CREDENTIALS_ERROR;
326 goto end;
327 }
328 token_type = cJSON_GetObjectItem(json, "token_type");
329 if (token_type == NULL || token_type->type != cJSON_String) {
330 gpr_log(GPR_ERROR, "Missing or invalid token_type in JSON.");
331 status = GRPC_CREDENTIALS_ERROR;
332 goto end;
333 }
334 expires_in = cJSON_GetObjectItem(json, "expires_in");
335 if (expires_in == NULL || expires_in->type != cJSON_Number) {
336 gpr_log(GPR_ERROR, "Missing or invalid expires_in in JSON.");
337 status = GRPC_CREDENTIALS_ERROR;
338 goto end;
339 }
340 new_access_token_size = strlen(token_type->valuestring) + 1 +
341 strlen(access_token->valuestring) + 1;
342 new_access_token = gpr_malloc(new_access_token_size);
343 /* C89 does not have snprintf :(. */
344 sprintf(new_access_token, "%s %s", token_type->valuestring,
345 access_token->valuestring);
346 token_lifetime->tv_sec = expires_in->valueint;
347 token_lifetime->tv_nsec = 0;
348 if (*token_elem != NULL) grpc_mdelem_unref(*token_elem);
349 *token_elem = grpc_mdelem_from_strings(ctx, GRPC_AUTHORIZATION_METADATA_KEY,
350 new_access_token);
351 status = GRPC_CREDENTIALS_OK;
352 }
353
354end:
355 if (status != GRPC_CREDENTIALS_OK && (*token_elem != NULL)) {
356 grpc_mdelem_unref(*token_elem);
357 *token_elem = NULL;
358 }
359 if (null_terminated_body != NULL) gpr_free(null_terminated_body);
360 if (new_access_token != NULL) gpr_free(new_access_token);
361 if (json != NULL) cJSON_Delete(json);
362 return status;
363}
364
jboeuf1a809c02014-12-19 15:44:30 -0800365static void on_oauth2_token_fetcher_http_response(
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800366 void *user_data, const grpc_httpcli_response *response) {
367 grpc_credentials_metadata_request *r =
368 (grpc_credentials_metadata_request *)user_data;
jboeuf1a809c02014-12-19 15:44:30 -0800369 grpc_oauth2_token_fetcher_credentials *c =
370 (grpc_oauth2_token_fetcher_credentials *)r->creds;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800371 gpr_timespec token_lifetime;
372 grpc_credentials_status status;
373
374 gpr_mu_lock(&c->mu);
jboeuf1a809c02014-12-19 15:44:30 -0800375 status = grpc_oauth2_token_fetcher_credentials_parse_server_response(
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800376 response, c->md_ctx, &c->access_token_md, &token_lifetime);
377 if (status == GRPC_CREDENTIALS_OK) {
378 c->token_expiration = gpr_time_add(gpr_now(), token_lifetime);
379 r->cb(r->user_data, &c->access_token_md, 1, status);
380 } else {
381 c->token_expiration = gpr_inf_past;
382 r->cb(r->user_data, NULL, 0, status);
383 }
384 gpr_mu_unlock(&c->mu);
385 grpc_credentials_metadata_request_destroy(r);
386}
387
jboeuf1a809c02014-12-19 15:44:30 -0800388static void oauth2_token_fetcher_get_request_metadata(
389 grpc_credentials *creds, grpc_credentials_metadata_cb cb, void *user_data) {
390 grpc_oauth2_token_fetcher_credentials *c =
391 (grpc_oauth2_token_fetcher_credentials *)creds;
392 gpr_timespec refresh_threshold = {GRPC_OAUTH2_TOKEN_REFRESH_THRESHOLD_SECS,
393 0};
394 grpc_mdelem *cached_access_token_md = NULL;
395 {
396 gpr_mu_lock(&c->mu);
397 if (c->access_token_md != NULL &&
398 (gpr_time_cmp(gpr_time_sub(c->token_expiration, gpr_now()),
399 refresh_threshold) > 0)) {
400 cached_access_token_md = grpc_mdelem_ref(c->access_token_md);
401 }
402 gpr_mu_unlock(&c->mu);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800403 }
jboeuf1a809c02014-12-19 15:44:30 -0800404 if (cached_access_token_md != NULL) {
405 cb(user_data, &cached_access_token_md, 1, GRPC_CREDENTIALS_OK);
406 grpc_mdelem_unref(cached_access_token_md);
407 } else {
408 c->fetch_func(
409 grpc_credentials_metadata_request_create(creds, cb, user_data),
410 on_oauth2_token_fetcher_http_response,
411 gpr_time_add(gpr_now(), refresh_threshold));
412 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800413}
414
jboeuf1a809c02014-12-19 15:44:30 -0800415static void init_oauth2_token_fetcher(grpc_oauth2_token_fetcher_credentials *c,
416 grpc_fetch_oauth2_func fetch_func) {
417 memset(c, 0, sizeof(grpc_oauth2_token_fetcher_credentials));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800418 c->base.type = GRPC_CREDENTIALS_TYPE_OAUTH2;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800419 gpr_ref_init(&c->base.refcount, 1);
420 gpr_mu_init(&c->mu);
421 c->md_ctx = grpc_mdctx_create();
422 c->token_expiration = gpr_inf_past;
jboeuf1a809c02014-12-19 15:44:30 -0800423 c->fetch_func = fetch_func;
424}
425
426/* -- ComputeEngine credentials. -- */
427
428static grpc_credentials_vtable compute_engine_vtable = {
429 oauth2_token_fetcher_destroy, oauth2_token_fetcher_has_request_metadata,
430 oauth2_token_fetcher_has_request_metadata_only,
431 oauth2_token_fetcher_get_request_metadata};
432
433static void compute_engine_fetch_oauth2(
434 grpc_credentials_metadata_request *metadata_req,
435 grpc_httpcli_response_cb response_cb, gpr_timespec deadline) {
436 grpc_httpcli_header header = {"Metadata-Flavor", "Google"};
437 grpc_httpcli_request request;
438 memset(&request, 0, sizeof(grpc_httpcli_request));
439 request.host = GRPC_COMPUTE_ENGINE_METADATA_HOST;
440 request.path = GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH;
441 request.hdr_count = 1;
442 request.hdrs = &header;
443 grpc_httpcli_get(&request, deadline, response_cb, metadata_req);
444}
445
446grpc_credentials *grpc_compute_engine_credentials_create(void) {
447 grpc_oauth2_token_fetcher_credentials *c =
448 gpr_malloc(sizeof(grpc_oauth2_token_fetcher_credentials));
449 init_oauth2_token_fetcher(c, compute_engine_fetch_oauth2);
450 c->base.vtable = &compute_engine_vtable;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800451 return &c->base;
452}
453
jboeuf1a809c02014-12-19 15:44:30 -0800454/* -- ServiceAccount credentials. -- */
455
456typedef struct {
457 grpc_oauth2_token_fetcher_credentials base;
458 grpc_auth_json_key key;
459 char *scope;
460 gpr_timespec token_lifetime;
461} grpc_service_account_credentials;
462
463static void service_account_destroy(grpc_credentials *creds) {
464 grpc_service_account_credentials *c =
465 (grpc_service_account_credentials *)creds;
466 if (c->scope != NULL) gpr_free(c->scope);
467 grpc_auth_json_key_destruct(&c->key);
468 oauth2_token_fetcher_destroy(&c->base.base);
469}
470
471static grpc_credentials_vtable service_account_vtable = {
472 service_account_destroy, oauth2_token_fetcher_has_request_metadata,
473 oauth2_token_fetcher_has_request_metadata_only,
474 oauth2_token_fetcher_get_request_metadata};
475
476static void service_account_fetch_oauth2(
477 grpc_credentials_metadata_request *metadata_req,
478 grpc_httpcli_response_cb response_cb, gpr_timespec deadline) {
479 grpc_service_account_credentials *c =
480 (grpc_service_account_credentials *)metadata_req->creds;
481 grpc_httpcli_header header = {"Content-Type",
482 "application/x-www-form-urlencoded"};
483 grpc_httpcli_request request;
484 char *body = NULL;
485 char *jwt = grpc_jwt_encode_and_sign(&c->key, c->scope, c->token_lifetime);
486 if (jwt == NULL) {
487 grpc_httpcli_response response;
488 memset(&response, 0, sizeof(grpc_httpcli_response));
489 response.status = 400; /* Invalid request. */
490 gpr_log(GPR_ERROR, "Could not create signed jwt.");
491 /* Do not even send the request, just call the response callback. */
492 response_cb(metadata_req, &response);
493 return;
494 }
495 body = gpr_malloc(strlen(GRPC_SERVICE_ACCOUNT_POST_BODY_PREFIX) +
496 strlen(jwt) + 1);
497 sprintf(body, "%s%s", GRPC_SERVICE_ACCOUNT_POST_BODY_PREFIX, jwt);
498 memset(&request, 0, sizeof(grpc_httpcli_request));
499 request.host = GRPC_SERVICE_ACCOUNT_HOST;
500 request.path = GRPC_SERVICE_ACCOUNT_TOKEN_PATH;
501 request.hdr_count = 1;
502 request.hdrs = &header;
503 request.use_ssl = 1;
504 grpc_httpcli_post(&request, body, strlen(body), deadline, response_cb,
505 metadata_req);
506 gpr_free(body);
507 gpr_free(jwt);
508}
509
510grpc_credentials *grpc_service_account_credentials_create(
511 const char *json_key, const char *scope, gpr_timespec token_lifetime) {
512 grpc_service_account_credentials *c;
513 grpc_auth_json_key key = grpc_auth_json_key_create_from_string(json_key);
514
515 if (scope == NULL || (strlen(scope) == 0) ||
516 !grpc_auth_json_key_is_valid(&key)) {
517 gpr_log(GPR_ERROR,
518 "Invalid input for service account credentials creation");
519 return NULL;
520 }
521 c = gpr_malloc(sizeof(grpc_service_account_credentials));
522 memset(c, 0, sizeof(grpc_service_account_credentials));
523 init_oauth2_token_fetcher(&c->base, service_account_fetch_oauth2);
524 c->base.base.vtable = &service_account_vtable;
525 c->scope = gpr_strdup(scope);
526 c->key = key;
527 c->token_lifetime = token_lifetime;
528 return &c->base.base;
529}
530
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800531/* -- Fake Oauth2 credentials. -- */
532
533typedef struct {
534 grpc_credentials base;
535 grpc_mdctx *md_ctx;
536 grpc_mdelem *access_token_md;
537 int is_async;
538} grpc_fake_oauth2_credentials;
539
540static void fake_oauth2_destroy(grpc_credentials *creds) {
541 grpc_fake_oauth2_credentials *c = (grpc_fake_oauth2_credentials *)creds;
542 if (c->access_token_md != NULL) {
543 grpc_mdelem_unref(c->access_token_md);
544 }
545 grpc_mdctx_orphan(c->md_ctx);
546 gpr_free(c);
547}
548
549static int fake_oauth2_has_request_metadata(const grpc_credentials *creds) {
550 return 1;
551}
552
553static int fake_oauth2_has_request_metadata_only(
554 const grpc_credentials *creds) {
555 return 1;
556}
557
ctiller18b49ab2014-12-09 14:39:16 -0800558void on_simulated_token_fetch_done(void *user_data,
559 grpc_iomgr_cb_status status) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800560 grpc_credentials_metadata_request *r =
561 (grpc_credentials_metadata_request *)user_data;
562 grpc_fake_oauth2_credentials *c = (grpc_fake_oauth2_credentials *)r->creds;
563 GPR_ASSERT(status == GRPC_CALLBACK_SUCCESS);
564 r->cb(r->user_data, &c->access_token_md, 1, GRPC_CREDENTIALS_OK);
565 grpc_credentials_metadata_request_destroy(r);
566}
567
568static void fake_oauth2_get_request_metadata(grpc_credentials *creds,
569 grpc_credentials_metadata_cb cb,
570 void *user_data) {
571 grpc_fake_oauth2_credentials *c = (grpc_fake_oauth2_credentials *)creds;
572
573 if (c->is_async) {
ctiller18b49ab2014-12-09 14:39:16 -0800574 grpc_iomgr_add_callback(
575 on_simulated_token_fetch_done,
576 grpc_credentials_metadata_request_create(creds, cb, user_data));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800577 } else {
578 cb(user_data, &c->access_token_md, 1, GRPC_CREDENTIALS_OK);
579 }
580}
581
582static grpc_credentials_vtable fake_oauth2_vtable = {
583 fake_oauth2_destroy, fake_oauth2_has_request_metadata,
584 fake_oauth2_has_request_metadata_only, fake_oauth2_get_request_metadata};
585
586grpc_credentials *grpc_fake_oauth2_credentials_create(
587 const char *token_md_value, int is_async) {
588 grpc_fake_oauth2_credentials *c =
589 gpr_malloc(sizeof(grpc_fake_oauth2_credentials));
590 memset(c, 0, sizeof(grpc_fake_oauth2_credentials));
591 c->base.type = GRPC_CREDENTIALS_TYPE_OAUTH2;
592 c->base.vtable = &fake_oauth2_vtable;
593 gpr_ref_init(&c->base.refcount, 1);
594 c->md_ctx = grpc_mdctx_create();
595 c->access_token_md = grpc_mdelem_from_strings(
596 c->md_ctx, GRPC_AUTHORIZATION_METADATA_KEY, token_md_value);
597 c->is_async = is_async;
598 return &c->base;
599}
600
601/* -- Fake transport security credentials. -- */
602
603static void fake_transport_security_credentials_destroy(
604 grpc_credentials *creds) {
605 gpr_free(creds);
606}
607
608static void fake_transport_security_server_credentials_destroy(
609 grpc_server_credentials *creds) {
610 gpr_free(creds);
611}
612
613static int fake_transport_security_has_request_metadata(
614 const grpc_credentials *creds) {
615 return 0;
616}
617
618static int fake_transport_security_has_request_metadata_only(
619 const grpc_credentials *creds) {
620 return 0;
621}
622
623static grpc_credentials_vtable fake_transport_security_credentials_vtable = {
624 fake_transport_security_credentials_destroy,
625 fake_transport_security_has_request_metadata,
626 fake_transport_security_has_request_metadata_only, NULL};
627
628static grpc_server_credentials_vtable
629 fake_transport_security_server_credentials_vtable = {
630 fake_transport_security_server_credentials_destroy};
631
632grpc_credentials *grpc_fake_transport_security_credentials_create(void) {
633 grpc_credentials *c = gpr_malloc(sizeof(grpc_credentials));
634 memset(c, 0, sizeof(grpc_credentials));
635 c->type = GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY;
636 c->vtable = &fake_transport_security_credentials_vtable;
637 gpr_ref_init(&c->refcount, 1);
638 return c;
639}
640
641grpc_server_credentials *
642grpc_fake_transport_security_server_credentials_create() {
643 grpc_server_credentials *c = gpr_malloc(sizeof(grpc_server_credentials));
644 memset(c, 0, sizeof(grpc_server_credentials));
645 c->type = GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY;
646 c->vtable = &fake_transport_security_server_credentials_vtable;
647 return c;
648}
649
nnoble0c475f02014-12-05 15:37:39 -0800650/* -- Composite credentials. -- */
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800651
nnoble0c475f02014-12-05 15:37:39 -0800652typedef struct {
653 grpc_credentials base;
654 grpc_credentials_array inner;
655} grpc_composite_credentials;
656
657typedef struct {
658 grpc_composite_credentials *composite_creds;
659 size_t creds_index;
660 grpc_mdelem **md_elems;
661 size_t num_md;
662 void *user_data;
663 grpc_credentials_metadata_cb cb;
664} grpc_composite_credentials_metadata_context;
665
666static void composite_destroy(grpc_credentials *creds) {
667 grpc_composite_credentials *c = (grpc_composite_credentials *)creds;
668 size_t i;
669 for (i = 0; i < c->inner.num_creds; i++) {
670 grpc_credentials_unref(c->inner.creds_array[i]);
671 }
672 gpr_free(c->inner.creds_array);
673 gpr_free(creds);
674}
675
676static int composite_has_request_metadata(const grpc_credentials *creds) {
677 const grpc_composite_credentials *c =
678 (const grpc_composite_credentials *)creds;
679 size_t i;
680 for (i = 0; i < c->inner.num_creds; i++) {
681 if (grpc_credentials_has_request_metadata(c->inner.creds_array[i])) {
682 return 1;
683 }
684 }
685 return 0;
686}
687
688static int composite_has_request_metadata_only(const grpc_credentials *creds) {
689 const grpc_composite_credentials *c =
690 (const grpc_composite_credentials *)creds;
691 size_t i;
692 for (i = 0; i < c->inner.num_creds; i++) {
693 if (!grpc_credentials_has_request_metadata_only(c->inner.creds_array[i])) {
694 return 0;
695 }
696 }
697 return 1;
698}
699
700static void composite_md_context_destroy(
701 grpc_composite_credentials_metadata_context *ctx) {
702 size_t i;
703 for (i = 0; i < ctx->num_md; i++) {
704 grpc_mdelem_unref(ctx->md_elems[i]);
705 }
706 gpr_free(ctx->md_elems);
707 gpr_free(ctx);
708}
709
710static void composite_metadata_cb(void *user_data, grpc_mdelem **md_elems,
711 size_t num_md,
712 grpc_credentials_status status) {
713 grpc_composite_credentials_metadata_context *ctx =
714 (grpc_composite_credentials_metadata_context *)user_data;
715 size_t i;
716 if (status != GRPC_CREDENTIALS_OK) {
717 ctx->cb(ctx->user_data, NULL, 0, status);
718 return;
719 }
720
721 /* Copy the metadata in the context. */
722 if (num_md > 0) {
723 ctx->md_elems = gpr_realloc(ctx->md_elems,
724 (ctx->num_md + num_md) * sizeof(grpc_mdelem *));
725 for (i = 0; i < num_md; i++) {
726 ctx->md_elems[i + ctx->num_md] = grpc_mdelem_ref(md_elems[i]);
727 }
728 ctx->num_md += num_md;
729 }
730
731 /* See if we need to get some more metadata. */
732 while (ctx->creds_index < ctx->composite_creds->inner.num_creds) {
733 grpc_credentials *inner_creds =
734 ctx->composite_creds->inner.creds_array[ctx->creds_index++];
735 if (grpc_credentials_has_request_metadata(inner_creds)) {
736 grpc_credentials_get_request_metadata(inner_creds, composite_metadata_cb,
737 ctx);
738 return;
739 }
740 }
741
742 /* We're done!. */
743 ctx->cb(ctx->user_data, ctx->md_elems, ctx->num_md, GRPC_CREDENTIALS_OK);
744 composite_md_context_destroy(ctx);
745}
746
747static void composite_get_request_metadata(grpc_credentials *creds,
748 grpc_credentials_metadata_cb cb,
749 void *user_data) {
750 grpc_composite_credentials *c = (grpc_composite_credentials *)creds;
751 grpc_composite_credentials_metadata_context *ctx;
752 if (!grpc_credentials_has_request_metadata(creds)) {
753 cb(user_data, NULL, 0, GRPC_CREDENTIALS_OK);
754 return;
755 }
756 ctx = gpr_malloc(sizeof(grpc_composite_credentials_metadata_context));
757 memset(ctx, 0, sizeof(grpc_composite_credentials_metadata_context));
758 ctx->user_data = user_data;
759 ctx->cb = cb;
760 ctx->composite_creds = c;
761 while (ctx->creds_index < c->inner.num_creds) {
762 grpc_credentials *inner_creds = c->inner.creds_array[ctx->creds_index++];
763 if (grpc_credentials_has_request_metadata(inner_creds)) {
764 grpc_credentials_get_request_metadata(inner_creds, composite_metadata_cb,
765 ctx);
766 return;
767 }
768 }
769 GPR_ASSERT(0); /* Should have exited before. */
770}
771
772static grpc_credentials_vtable composite_credentials_vtable = {
773 composite_destroy, composite_has_request_metadata,
774 composite_has_request_metadata_only, composite_get_request_metadata};
775
776static grpc_credentials_array get_creds_array(grpc_credentials **creds_addr) {
777 grpc_credentials_array result;
778 grpc_credentials *creds = *creds_addr;
779 result.creds_array = creds_addr;
780 result.num_creds = 1;
781 if (!strcmp(creds->type, GRPC_CREDENTIALS_TYPE_COMPOSITE)) {
782 result = *grpc_composite_credentials_get_credentials(creds);
783 }
784 return result;
785}
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800786
787grpc_credentials *grpc_composite_credentials_create(grpc_credentials *creds1,
788 grpc_credentials *creds2) {
nnoble0c475f02014-12-05 15:37:39 -0800789 size_t i;
790 grpc_credentials_array creds1_array;
791 grpc_credentials_array creds2_array;
792 grpc_composite_credentials *c;
793 GPR_ASSERT(creds1 != NULL);
794 GPR_ASSERT(creds2 != NULL);
795 c = gpr_malloc(sizeof(grpc_composite_credentials));
796 memset(c, 0, sizeof(grpc_composite_credentials));
797 c->base.type = GRPC_CREDENTIALS_TYPE_COMPOSITE;
798 c->base.vtable = &composite_credentials_vtable;
799 gpr_ref_init(&c->base.refcount, 1);
800 creds1_array = get_creds_array(&creds1);
801 creds2_array = get_creds_array(&creds2);
802 c->inner.num_creds = creds1_array.num_creds + creds2_array.num_creds;
803 c->inner.creds_array =
804 gpr_malloc(c->inner.num_creds * sizeof(grpc_credentials *));
805 for (i = 0; i < creds1_array.num_creds; i++) {
806 c->inner.creds_array[i] = grpc_credentials_ref(creds1_array.creds_array[i]);
807 }
808 for (i = 0; i < creds2_array.num_creds; i++) {
809 c->inner.creds_array[i + creds1_array.num_creds] =
810 grpc_credentials_ref(creds2_array.creds_array[i]);
811 }
812 return &c->base;
813}
814
815const grpc_credentials_array *grpc_composite_credentials_get_credentials(
816 grpc_credentials *creds) {
817 const grpc_composite_credentials *c =
818 (const grpc_composite_credentials *)creds;
819 GPR_ASSERT(!strcmp(creds->type, GRPC_CREDENTIALS_TYPE_COMPOSITE));
820 return &c->inner;
821}
822
823/* -- IAM credentials. -- */
824
825typedef struct {
826 grpc_credentials base;
827 grpc_mdctx *md_ctx;
828 grpc_mdelem *token_md;
829 grpc_mdelem *authority_selector_md;
830} grpc_iam_credentials;
831
832static void iam_destroy(grpc_credentials *creds) {
833 grpc_iam_credentials *c = (grpc_iam_credentials *)creds;
834 grpc_mdelem_unref(c->token_md);
835 grpc_mdelem_unref(c->authority_selector_md);
836 grpc_mdctx_orphan(c->md_ctx);
837 gpr_free(c);
838}
839
840static int iam_has_request_metadata(const grpc_credentials *creds) { return 1; }
841
842static int iam_has_request_metadata_only(const grpc_credentials *creds) {
843 return 1;
844}
845
846static void iam_get_request_metadata(grpc_credentials *creds,
847 grpc_credentials_metadata_cb cb,
848 void *user_data) {
849 grpc_iam_credentials *c = (grpc_iam_credentials *)creds;
850 grpc_mdelem *md_array[2];
851 md_array[0] = c->token_md;
852 md_array[1] = c->authority_selector_md;
853 cb(user_data, md_array, 2, GRPC_CREDENTIALS_OK);
854}
855
856static grpc_credentials_vtable iam_vtable = {
857 iam_destroy, iam_has_request_metadata, iam_has_request_metadata_only,
858 iam_get_request_metadata};
859
860grpc_credentials *grpc_iam_credentials_create(const char *token,
861 const char *authority_selector) {
862 grpc_iam_credentials *c;
863 GPR_ASSERT(token != NULL);
864 GPR_ASSERT(authority_selector != NULL);
865 c = gpr_malloc(sizeof(grpc_iam_credentials));
866 memset(c, 0, sizeof(grpc_iam_credentials));
867 c->base.type = GRPC_CREDENTIALS_TYPE_IAM;
868 c->base.vtable = &iam_vtable;
869 gpr_ref_init(&c->base.refcount, 1);
870 c->md_ctx = grpc_mdctx_create();
871 c->token_md = grpc_mdelem_from_strings(
872 c->md_ctx, GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY, token);
873 c->authority_selector_md = grpc_mdelem_from_strings(
874 c->md_ctx, GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY, authority_selector);
875 return &c->base;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800876}
877
878/* -- Default credentials TODO(jboeuf). -- */
879
880grpc_credentials *grpc_default_credentials_create(void) { return NULL; }
nnoble0c475f02014-12-05 15:37:39 -0800881