blob: d55d00b7b6638c25fff68cd406c3c56aa0312382 [file] [log] [blame]
Julien Boeuf8ca294e2016-05-02 14:56:30 -07001/*
2 *
David Garcia Quintas8bec6f62016-05-31 13:59:37 -07003 * Copyright 2015-2016, Google Inc.
Julien Boeuf8ca294e2016-05-02 14:56:30 -07004 * 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
David Garcia Quintas2a50dfe2016-05-31 15:09:12 -070038#include "src/core/lib/iomgr/polling_entity.h"
Julien Boeuf8ca294e2016-05-02 14:56:30 -070039#include "src/core/lib/surface/api_trace.h"
40
41#include <grpc/support/alloc.h>
42#include <grpc/support/log.h>
43#include <grpc/support/string_util.h>
44
45/* -- Composite call credentials. -- */
46
47typedef struct {
48 grpc_composite_call_credentials *composite_creds;
49 size_t creds_index;
50 grpc_credentials_md_store *md_elems;
51 grpc_auth_metadata_context auth_md_context;
52 void *user_data;
David Garcia Quintas2a50dfe2016-05-31 15:09:12 -070053 grpc_polling_entity *pollent;
Julien Boeuf8ca294e2016-05-02 14:56:30 -070054 grpc_credentials_metadata_cb cb;
55} grpc_composite_call_credentials_metadata_context;
56
57static void composite_call_destruct(grpc_call_credentials *creds) {
58 grpc_composite_call_credentials *c = (grpc_composite_call_credentials *)creds;
59 size_t i;
60 for (i = 0; i < c->inner.num_creds; i++) {
61 grpc_call_credentials_unref(c->inner.creds_array[i]);
62 }
63 gpr_free(c->inner.creds_array);
64}
65
66static void composite_call_md_context_destroy(
67 grpc_composite_call_credentials_metadata_context *ctx) {
68 grpc_credentials_md_store_unref(ctx->md_elems);
69 gpr_free(ctx);
70}
71
72static void composite_call_metadata_cb(grpc_exec_ctx *exec_ctx, void *user_data,
73 grpc_credentials_md *md_elems,
74 size_t num_md,
Julien Boeufbfc7ed62016-06-04 18:03:42 -070075 grpc_credentials_status status,
76 const char *error_details) {
Julien Boeuf8ca294e2016-05-02 14:56:30 -070077 grpc_composite_call_credentials_metadata_context *ctx =
78 (grpc_composite_call_credentials_metadata_context *)user_data;
79 if (status != GRPC_CREDENTIALS_OK) {
Julien Boeufbfc7ed62016-06-04 18:03:42 -070080 ctx->cb(exec_ctx, ctx->user_data, NULL, 0, status, error_details);
Julien Boeuf8ca294e2016-05-02 14:56:30 -070081 return;
82 }
83
84 /* Copy the metadata in the context. */
85 if (num_md > 0) {
86 size_t i;
87 for (i = 0; i < num_md; i++) {
88 grpc_credentials_md_store_add(ctx->md_elems, md_elems[i].key,
89 md_elems[i].value);
90 }
91 }
92
93 /* See if we need to get some more metadata. */
94 if (ctx->creds_index < ctx->composite_creds->inner.num_creds) {
95 grpc_call_credentials *inner_creds =
96 ctx->composite_creds->inner.creds_array[ctx->creds_index++];
David Garcia Quintas2a50dfe2016-05-31 15:09:12 -070097 grpc_call_credentials_get_request_metadata(
98 exec_ctx, inner_creds, ctx->pollent, ctx->auth_md_context,
99 composite_call_metadata_cb, ctx);
Julien Boeuf8ca294e2016-05-02 14:56:30 -0700100 return;
101 }
102
103 /* We're done!. */
104 ctx->cb(exec_ctx, ctx->user_data, ctx->md_elems->entries,
Julien Boeufbfc7ed62016-06-04 18:03:42 -0700105 ctx->md_elems->num_entries, GRPC_CREDENTIALS_OK, NULL);
Julien Boeuf8ca294e2016-05-02 14:56:30 -0700106 composite_call_md_context_destroy(ctx);
107}
108
109static void composite_call_get_request_metadata(
David Garcia Quintas2a50dfe2016-05-31 15:09:12 -0700110 grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds,
111 grpc_polling_entity *pollent, grpc_auth_metadata_context auth_md_context,
112 grpc_credentials_metadata_cb cb, void *user_data) {
Julien Boeuf8ca294e2016-05-02 14:56:30 -0700113 grpc_composite_call_credentials *c = (grpc_composite_call_credentials *)creds;
114 grpc_composite_call_credentials_metadata_context *ctx;
115
116 ctx = gpr_malloc(sizeof(grpc_composite_call_credentials_metadata_context));
117 memset(ctx, 0, sizeof(grpc_composite_call_credentials_metadata_context));
118 ctx->auth_md_context = auth_md_context;
119 ctx->user_data = user_data;
120 ctx->cb = cb;
121 ctx->composite_creds = c;
David Garcia Quintas2a50dfe2016-05-31 15:09:12 -0700122 ctx->pollent = pollent;
Julien Boeuf8ca294e2016-05-02 14:56:30 -0700123 ctx->md_elems = grpc_credentials_md_store_create(c->inner.num_creds);
124 grpc_call_credentials_get_request_metadata(
David Garcia Quintas2a50dfe2016-05-31 15:09:12 -0700125 exec_ctx, c->inner.creds_array[ctx->creds_index++], ctx->pollent,
Julien Boeuf8ca294e2016-05-02 14:56:30 -0700126 auth_md_context, composite_call_metadata_cb, ctx);
127}
128
129static grpc_call_credentials_vtable composite_call_credentials_vtable = {
130 composite_call_destruct, composite_call_get_request_metadata};
131
132static grpc_call_credentials_array get_creds_array(
133 grpc_call_credentials **creds_addr) {
134 grpc_call_credentials_array result;
135 grpc_call_credentials *creds = *creds_addr;
136 result.creds_array = creds_addr;
137 result.num_creds = 1;
138 if (strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0) {
139 result = *grpc_composite_call_credentials_get_credentials(creds);
140 }
141 return result;
142}
143
144grpc_call_credentials *grpc_composite_call_credentials_create(
145 grpc_call_credentials *creds1, grpc_call_credentials *creds2,
146 void *reserved) {
147 size_t i;
148 size_t creds_array_byte_size;
149 grpc_call_credentials_array creds1_array;
150 grpc_call_credentials_array creds2_array;
151 grpc_composite_call_credentials *c;
152 GRPC_API_TRACE(
153 "grpc_composite_call_credentials_create(creds1=%p, creds2=%p, "
154 "reserved=%p)",
155 3, (creds1, creds2, reserved));
156 GPR_ASSERT(reserved == NULL);
157 GPR_ASSERT(creds1 != NULL);
158 GPR_ASSERT(creds2 != NULL);
159 c = gpr_malloc(sizeof(grpc_composite_call_credentials));
160 memset(c, 0, sizeof(grpc_composite_call_credentials));
161 c->base.type = GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE;
162 c->base.vtable = &composite_call_credentials_vtable;
163 gpr_ref_init(&c->base.refcount, 1);
164 creds1_array = get_creds_array(&creds1);
165 creds2_array = get_creds_array(&creds2);
166 c->inner.num_creds = creds1_array.num_creds + creds2_array.num_creds;
167 creds_array_byte_size = c->inner.num_creds * sizeof(grpc_call_credentials *);
168 c->inner.creds_array = gpr_malloc(creds_array_byte_size);
169 memset(c->inner.creds_array, 0, creds_array_byte_size);
170 for (i = 0; i < creds1_array.num_creds; i++) {
171 grpc_call_credentials *cur_creds = creds1_array.creds_array[i];
172 c->inner.creds_array[i] = grpc_call_credentials_ref(cur_creds);
173 }
174 for (i = 0; i < creds2_array.num_creds; i++) {
175 grpc_call_credentials *cur_creds = creds2_array.creds_array[i];
176 c->inner.creds_array[i + creds1_array.num_creds] =
177 grpc_call_credentials_ref(cur_creds);
178 }
179 return &c->base;
180}
181
182const grpc_call_credentials_array *
183grpc_composite_call_credentials_get_credentials(grpc_call_credentials *creds) {
184 const grpc_composite_call_credentials *c =
185 (const grpc_composite_call_credentials *)creds;
186 GPR_ASSERT(strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0);
187 return &c->inner;
188}
189
190grpc_call_credentials *grpc_credentials_contains_type(
191 grpc_call_credentials *creds, const char *type,
192 grpc_call_credentials **composite_creds) {
193 size_t i;
194 if (strcmp(creds->type, type) == 0) {
195 if (composite_creds != NULL) *composite_creds = NULL;
196 return creds;
197 } else if (strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0) {
198 const grpc_call_credentials_array *inner_creds_array =
199 grpc_composite_call_credentials_get_credentials(creds);
200 for (i = 0; i < inner_creds_array->num_creds; i++) {
201 if (strcmp(type, inner_creds_array->creds_array[i]->type) == 0) {
202 if (composite_creds != NULL) *composite_creds = creds;
203 return inner_creds_array->creds_array[i];
204 }
205 }
206 }
207 return NULL;
208}
209
210/* -- Composite channel credentials. -- */
211
212static void composite_channel_destruct(grpc_channel_credentials *creds) {
213 grpc_composite_channel_credentials *c =
214 (grpc_composite_channel_credentials *)creds;
215 grpc_channel_credentials_unref(c->inner_creds);
216 grpc_call_credentials_unref(c->call_creds);
217}
218
219static grpc_security_status composite_channel_create_security_connector(
220 grpc_channel_credentials *creds, grpc_call_credentials *call_creds,
221 const char *target, const grpc_channel_args *args,
222 grpc_channel_security_connector **sc, grpc_channel_args **new_args) {
223 grpc_composite_channel_credentials *c =
224 (grpc_composite_channel_credentials *)creds;
225 grpc_security_status status = GRPC_SECURITY_ERROR;
226
227 GPR_ASSERT(c->inner_creds != NULL && c->call_creds != NULL &&
228 c->inner_creds->vtable != NULL &&
229 c->inner_creds->vtable->create_security_connector != NULL);
230 /* If we are passed a call_creds, create a call composite to pass it
231 downstream. */
232 if (call_creds != NULL) {
233 grpc_call_credentials *composite_call_creds =
234 grpc_composite_call_credentials_create(c->call_creds, call_creds, NULL);
235 status = c->inner_creds->vtable->create_security_connector(
236 c->inner_creds, composite_call_creds, target, args, sc, new_args);
237 grpc_call_credentials_unref(composite_call_creds);
238 } else {
239 status = c->inner_creds->vtable->create_security_connector(
240 c->inner_creds, c->call_creds, target, args, sc, new_args);
241 }
242 return status;
243}
244
Julien Boeufe26ab6c2016-09-22 15:13:07 -0700245static grpc_channel_credentials *
246composite_channel_duplicate_without_call_credentials(
247 grpc_channel_credentials *creds) {
248 grpc_composite_channel_credentials *c =
249 (grpc_composite_channel_credentials *)creds;
250 return grpc_channel_credentials_ref(c->inner_creds);
251}
252
Julien Boeuf8ca294e2016-05-02 14:56:30 -0700253static grpc_channel_credentials_vtable composite_channel_credentials_vtable = {
Julien Boeufe26ab6c2016-09-22 15:13:07 -0700254 composite_channel_destruct, composite_channel_create_security_connector,
255 composite_channel_duplicate_without_call_credentials};
Julien Boeuf8ca294e2016-05-02 14:56:30 -0700256
257grpc_channel_credentials *grpc_composite_channel_credentials_create(
258 grpc_channel_credentials *channel_creds, grpc_call_credentials *call_creds,
259 void *reserved) {
260 grpc_composite_channel_credentials *c = gpr_malloc(sizeof(*c));
261 memset(c, 0, sizeof(*c));
262 GPR_ASSERT(channel_creds != NULL && call_creds != NULL && reserved == NULL);
263 GRPC_API_TRACE(
264 "grpc_composite_channel_credentials_create(channel_creds=%p, "
265 "call_creds=%p, reserved=%p)",
266 3, (channel_creds, call_creds, reserved));
267 c->base.type = channel_creds->type;
268 c->base.vtable = &composite_channel_credentials_vtable;
269 gpr_ref_init(&c->base.refcount, 1);
270 c->inner_creds = grpc_channel_credentials_ref(channel_creds);
271 c->call_creds = grpc_call_credentials_ref(call_creds);
272 return &c->base;
273}