blob: 4a17f7c1b984dc524b1081e89e8ae9c534c4275a [file] [log] [blame]
Julien Boeuf8ca294e2016-05-02 14:56:30 -07001/*
2 *
3 * Copyright 2015, Google Inc.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
34#include "src/core/lib/security/credentials/composite/composite_credentials.h"
35
36#include <string.h>
37
38#include "src/core/lib/surface/api_trace.h"
39
40#include <grpc/support/alloc.h>
41#include <grpc/support/log.h>
42#include <grpc/support/string_util.h>
43
44/* -- Composite call credentials. -- */
45
46typedef struct {
47 grpc_composite_call_credentials *composite_creds;
48 size_t creds_index;
49 grpc_credentials_md_store *md_elems;
50 grpc_auth_metadata_context auth_md_context;
51 void *user_data;
52 grpc_pollset *pollset;
53 grpc_credentials_metadata_cb cb;
54} grpc_composite_call_credentials_metadata_context;
55
56static void composite_call_destruct(grpc_call_credentials *creds) {
57 grpc_composite_call_credentials *c = (grpc_composite_call_credentials *)creds;
58 size_t i;
59 for (i = 0; i < c->inner.num_creds; i++) {
60 grpc_call_credentials_unref(c->inner.creds_array[i]);
61 }
62 gpr_free(c->inner.creds_array);
63}
64
65static void composite_call_md_context_destroy(
66 grpc_composite_call_credentials_metadata_context *ctx) {
67 grpc_credentials_md_store_unref(ctx->md_elems);
68 gpr_free(ctx);
69}
70
71static void composite_call_metadata_cb(grpc_exec_ctx *exec_ctx, void *user_data,
72 grpc_credentials_md *md_elems,
73 size_t num_md,
74 grpc_credentials_status status) {
75 grpc_composite_call_credentials_metadata_context *ctx =
76 (grpc_composite_call_credentials_metadata_context *)user_data;
77 if (status != GRPC_CREDENTIALS_OK) {
78 ctx->cb(exec_ctx, ctx->user_data, NULL, 0, status);
79 return;
80 }
81
82 /* Copy the metadata in the context. */
83 if (num_md > 0) {
84 size_t i;
85 for (i = 0; i < num_md; i++) {
86 grpc_credentials_md_store_add(ctx->md_elems, md_elems[i].key,
87 md_elems[i].value);
88 }
89 }
90
91 /* See if we need to get some more metadata. */
92 if (ctx->creds_index < ctx->composite_creds->inner.num_creds) {
93 grpc_call_credentials *inner_creds =
94 ctx->composite_creds->inner.creds_array[ctx->creds_index++];
95 grpc_call_credentials_get_request_metadata(
96 exec_ctx, inner_creds, ctx->pollset, ctx->auth_md_context,
97 composite_call_metadata_cb, ctx);
98 return;
99 }
100
101 /* We're done!. */
102 ctx->cb(exec_ctx, ctx->user_data, ctx->md_elems->entries,
103 ctx->md_elems->num_entries, GRPC_CREDENTIALS_OK);
104 composite_call_md_context_destroy(ctx);
105}
106
107static void composite_call_get_request_metadata(
108 grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds,
109 grpc_pollset *pollset, grpc_auth_metadata_context auth_md_context,
110 grpc_credentials_metadata_cb cb, void *user_data) {
111 grpc_composite_call_credentials *c = (grpc_composite_call_credentials *)creds;
112 grpc_composite_call_credentials_metadata_context *ctx;
113
114 ctx = gpr_malloc(sizeof(grpc_composite_call_credentials_metadata_context));
115 memset(ctx, 0, sizeof(grpc_composite_call_credentials_metadata_context));
116 ctx->auth_md_context = auth_md_context;
117 ctx->user_data = user_data;
118 ctx->cb = cb;
119 ctx->composite_creds = c;
120 ctx->pollset = pollset;
121 ctx->md_elems = grpc_credentials_md_store_create(c->inner.num_creds);
122 grpc_call_credentials_get_request_metadata(
123 exec_ctx, c->inner.creds_array[ctx->creds_index++], pollset,
124 auth_md_context, composite_call_metadata_cb, ctx);
125}
126
127static grpc_call_credentials_vtable composite_call_credentials_vtable = {
128 composite_call_destruct, composite_call_get_request_metadata};
129
130static grpc_call_credentials_array get_creds_array(
131 grpc_call_credentials **creds_addr) {
132 grpc_call_credentials_array result;
133 grpc_call_credentials *creds = *creds_addr;
134 result.creds_array = creds_addr;
135 result.num_creds = 1;
136 if (strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0) {
137 result = *grpc_composite_call_credentials_get_credentials(creds);
138 }
139 return result;
140}
141
142grpc_call_credentials *grpc_composite_call_credentials_create(
143 grpc_call_credentials *creds1, grpc_call_credentials *creds2,
144 void *reserved) {
145 size_t i;
146 size_t creds_array_byte_size;
147 grpc_call_credentials_array creds1_array;
148 grpc_call_credentials_array creds2_array;
149 grpc_composite_call_credentials *c;
150 GRPC_API_TRACE(
151 "grpc_composite_call_credentials_create(creds1=%p, creds2=%p, "
152 "reserved=%p)",
153 3, (creds1, creds2, reserved));
154 GPR_ASSERT(reserved == NULL);
155 GPR_ASSERT(creds1 != NULL);
156 GPR_ASSERT(creds2 != NULL);
157 c = gpr_malloc(sizeof(grpc_composite_call_credentials));
158 memset(c, 0, sizeof(grpc_composite_call_credentials));
159 c->base.type = GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE;
160 c->base.vtable = &composite_call_credentials_vtable;
161 gpr_ref_init(&c->base.refcount, 1);
162 creds1_array = get_creds_array(&creds1);
163 creds2_array = get_creds_array(&creds2);
164 c->inner.num_creds = creds1_array.num_creds + creds2_array.num_creds;
165 creds_array_byte_size = c->inner.num_creds * sizeof(grpc_call_credentials *);
166 c->inner.creds_array = gpr_malloc(creds_array_byte_size);
167 memset(c->inner.creds_array, 0, creds_array_byte_size);
168 for (i = 0; i < creds1_array.num_creds; i++) {
169 grpc_call_credentials *cur_creds = creds1_array.creds_array[i];
170 c->inner.creds_array[i] = grpc_call_credentials_ref(cur_creds);
171 }
172 for (i = 0; i < creds2_array.num_creds; i++) {
173 grpc_call_credentials *cur_creds = creds2_array.creds_array[i];
174 c->inner.creds_array[i + creds1_array.num_creds] =
175 grpc_call_credentials_ref(cur_creds);
176 }
177 return &c->base;
178}
179
180const grpc_call_credentials_array *
181grpc_composite_call_credentials_get_credentials(grpc_call_credentials *creds) {
182 const grpc_composite_call_credentials *c =
183 (const grpc_composite_call_credentials *)creds;
184 GPR_ASSERT(strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0);
185 return &c->inner;
186}
187
188grpc_call_credentials *grpc_credentials_contains_type(
189 grpc_call_credentials *creds, const char *type,
190 grpc_call_credentials **composite_creds) {
191 size_t i;
192 if (strcmp(creds->type, type) == 0) {
193 if (composite_creds != NULL) *composite_creds = NULL;
194 return creds;
195 } else if (strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0) {
196 const grpc_call_credentials_array *inner_creds_array =
197 grpc_composite_call_credentials_get_credentials(creds);
198 for (i = 0; i < inner_creds_array->num_creds; i++) {
199 if (strcmp(type, inner_creds_array->creds_array[i]->type) == 0) {
200 if (composite_creds != NULL) *composite_creds = creds;
201 return inner_creds_array->creds_array[i];
202 }
203 }
204 }
205 return NULL;
206}
207
208/* -- Composite channel credentials. -- */
209
210static void composite_channel_destruct(grpc_channel_credentials *creds) {
211 grpc_composite_channel_credentials *c =
212 (grpc_composite_channel_credentials *)creds;
213 grpc_channel_credentials_unref(c->inner_creds);
214 grpc_call_credentials_unref(c->call_creds);
215}
216
217static grpc_security_status composite_channel_create_security_connector(
218 grpc_channel_credentials *creds, grpc_call_credentials *call_creds,
219 const char *target, const grpc_channel_args *args,
220 grpc_channel_security_connector **sc, grpc_channel_args **new_args) {
221 grpc_composite_channel_credentials *c =
222 (grpc_composite_channel_credentials *)creds;
223 grpc_security_status status = GRPC_SECURITY_ERROR;
224
225 GPR_ASSERT(c->inner_creds != NULL && c->call_creds != NULL &&
226 c->inner_creds->vtable != NULL &&
227 c->inner_creds->vtable->create_security_connector != NULL);
228 /* If we are passed a call_creds, create a call composite to pass it
229 downstream. */
230 if (call_creds != NULL) {
231 grpc_call_credentials *composite_call_creds =
232 grpc_composite_call_credentials_create(c->call_creds, call_creds, NULL);
233 status = c->inner_creds->vtable->create_security_connector(
234 c->inner_creds, composite_call_creds, target, args, sc, new_args);
235 grpc_call_credentials_unref(composite_call_creds);
236 } else {
237 status = c->inner_creds->vtable->create_security_connector(
238 c->inner_creds, c->call_creds, target, args, sc, new_args);
239 }
240 return status;
241}
242
243static grpc_channel_credentials_vtable composite_channel_credentials_vtable = {
244 composite_channel_destruct, composite_channel_create_security_connector};
245
246grpc_channel_credentials *grpc_composite_channel_credentials_create(
247 grpc_channel_credentials *channel_creds, grpc_call_credentials *call_creds,
248 void *reserved) {
249 grpc_composite_channel_credentials *c = gpr_malloc(sizeof(*c));
250 memset(c, 0, sizeof(*c));
251 GPR_ASSERT(channel_creds != NULL && call_creds != NULL && reserved == NULL);
252 GRPC_API_TRACE(
253 "grpc_composite_channel_credentials_create(channel_creds=%p, "
254 "call_creds=%p, reserved=%p)",
255 3, (channel_creds, call_creds, reserved));
256 c->base.type = channel_creds->type;
257 c->base.vtable = &composite_channel_credentials_vtable;
258 gpr_ref_init(&c->base.refcount, 1);
259 c->inner_creds = grpc_channel_credentials_ref(channel_creds);
260 c->call_creds = grpc_call_credentials_ref(call_creds);
261 return &c->base;
262}
263