blob: 09fd60a12c223f3071e983db5e9737a7f671410a [file] [log] [blame]
Julien Boeuf8ca294e2016-05-02 14:56:30 -07001/*
2 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02003 * Copyright 2015-2016 gRPC authors.
Julien Boeuf8ca294e2016-05-02 14:56:30 -07004 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02005 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
Julien Boeuf8ca294e2016-05-02 14:56:30 -07008 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02009 * http://www.apache.org/licenses/LICENSE-2.0
Julien Boeuf8ca294e2016-05-02 14:56:30 -070010 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +020011 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
Julien Boeuf8ca294e2016-05-02 14:56:30 -070016 *
17 */
18
19#include "src/core/lib/security/credentials/composite/composite_credentials.h"
20
21#include <string.h>
22
David Garcia Quintas2a50dfe2016-05-31 15:09:12 -070023#include "src/core/lib/iomgr/polling_entity.h"
Julien Boeuf8ca294e2016-05-02 14:56:30 -070024#include "src/core/lib/surface/api_trace.h"
25
26#include <grpc/support/alloc.h>
27#include <grpc/support/log.h>
28#include <grpc/support/string_util.h>
29
30/* -- Composite call credentials. -- */
31
32typedef struct {
33 grpc_composite_call_credentials *composite_creds;
34 size_t creds_index;
David Garcia Quintas2a50dfe2016-05-31 15:09:12 -070035 grpc_polling_entity *pollent;
Mark D. Rothe0778b22017-07-21 15:42:00 -070036 grpc_auth_metadata_context auth_md_context;
37 grpc_credentials_mdelem_array *md_array;
38 grpc_closure *on_request_metadata;
39 grpc_closure internal_on_request_metadata;
Julien Boeuf8ca294e2016-05-02 14:56:30 -070040} grpc_composite_call_credentials_metadata_context;
41
Craig Tillerbd1795c2016-10-31 15:30:00 -070042static void composite_call_destruct(grpc_exec_ctx *exec_ctx,
43 grpc_call_credentials *creds) {
Julien Boeuf8ca294e2016-05-02 14:56:30 -070044 grpc_composite_call_credentials *c = (grpc_composite_call_credentials *)creds;
Mark D. Rothe0778b22017-07-21 15:42:00 -070045 for (size_t i = 0; i < c->inner.num_creds; i++) {
Craig Tillerbd1795c2016-10-31 15:30:00 -070046 grpc_call_credentials_unref(exec_ctx, c->inner.creds_array[i]);
Julien Boeuf8ca294e2016-05-02 14:56:30 -070047 }
48 gpr_free(c->inner.creds_array);
49}
50
Mark D. Rothe0778b22017-07-21 15:42:00 -070051static void composite_call_metadata_cb(grpc_exec_ctx *exec_ctx, void *arg,
52 grpc_error *error) {
53 grpc_composite_call_credentials_metadata_context *ctx =
54 (grpc_composite_call_credentials_metadata_context *)arg;
55 if (error == GRPC_ERROR_NONE) {
56 /* See if we need to get some more metadata. */
57 if (ctx->creds_index < ctx->composite_creds->inner.num_creds) {
58 grpc_call_credentials *inner_creds =
59 ctx->composite_creds->inner.creds_array[ctx->creds_index++];
60 if (grpc_call_credentials_get_request_metadata(
61 exec_ctx, inner_creds, ctx->pollent, ctx->auth_md_context,
62 ctx->md_array, &ctx->internal_on_request_metadata, &error)) {
63 // Synchronous response, so call ourselves recursively.
64 composite_call_metadata_cb(exec_ctx, arg, error);
65 GRPC_ERROR_UNREF(error);
66 }
67 return;
68 }
69 // We're done!
70 }
71 GRPC_CLOSURE_SCHED(exec_ctx, ctx->on_request_metadata, GRPC_ERROR_REF(error));
Julien Boeuf8ca294e2016-05-02 14:56:30 -070072 gpr_free(ctx);
73}
74
Mark D. Rothe0778b22017-07-21 15:42:00 -070075static bool composite_call_get_request_metadata(
David Garcia Quintas2a50dfe2016-05-31 15:09:12 -070076 grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds,
77 grpc_polling_entity *pollent, grpc_auth_metadata_context auth_md_context,
Mark D. Rothe0778b22017-07-21 15:42:00 -070078 grpc_credentials_mdelem_array *md_array, grpc_closure *on_request_metadata,
79 grpc_error **error) {
Julien Boeuf8ca294e2016-05-02 14:56:30 -070080 grpc_composite_call_credentials *c = (grpc_composite_call_credentials *)creds;
81 grpc_composite_call_credentials_metadata_context *ctx;
Craig Tiller6f417882017-02-16 14:09:39 -080082 ctx = gpr_zalloc(sizeof(grpc_composite_call_credentials_metadata_context));
Julien Boeuf8ca294e2016-05-02 14:56:30 -070083 ctx->composite_creds = c;
David Garcia Quintas2a50dfe2016-05-31 15:09:12 -070084 ctx->pollent = pollent;
Mark D. Rothe0778b22017-07-21 15:42:00 -070085 ctx->auth_md_context = auth_md_context;
86 ctx->md_array = md_array;
87 ctx->on_request_metadata = on_request_metadata;
88 GRPC_CLOSURE_INIT(&ctx->internal_on_request_metadata,
89 composite_call_metadata_cb, ctx, grpc_schedule_on_exec_ctx);
90 while (ctx->creds_index < ctx->composite_creds->inner.num_creds) {
91 grpc_call_credentials *inner_creds =
92 ctx->composite_creds->inner.creds_array[ctx->creds_index++];
93 if (grpc_call_credentials_get_request_metadata(
94 exec_ctx, inner_creds, ctx->pollent, ctx->auth_md_context,
95 ctx->md_array, &ctx->internal_on_request_metadata, error)) {
96 if (*error != GRPC_ERROR_NONE) break;
97 } else {
98 break;
99 }
100 }
101 // If we got through all creds synchronously or we got a synchronous
102 // error on one of them, return synchronously.
103 if (ctx->creds_index == ctx->composite_creds->inner.num_creds ||
104 *error != GRPC_ERROR_NONE) {
105 gpr_free(ctx);
106 return true;
107 }
108 // At least one inner cred is returning asynchronously, so we'll
109 // return asynchronously as well.
110 return false;
111}
112
113static void composite_call_cancel_get_request_metadata(
114 grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds,
115 grpc_credentials_mdelem_array *md_array, grpc_error *error) {
116 grpc_composite_call_credentials *c = (grpc_composite_call_credentials *)creds;
117 for (size_t i = 0; i < c->inner.num_creds; ++i) {
118 grpc_call_credentials_cancel_get_request_metadata(
119 exec_ctx, c->inner.creds_array[i], md_array, GRPC_ERROR_REF(error));
120 }
121 GRPC_ERROR_UNREF(error);
Julien Boeuf8ca294e2016-05-02 14:56:30 -0700122}
123
124static grpc_call_credentials_vtable composite_call_credentials_vtable = {
Mark D. Rothe0778b22017-07-21 15:42:00 -0700125 composite_call_destruct, composite_call_get_request_metadata,
126 composite_call_cancel_get_request_metadata};
Julien Boeuf8ca294e2016-05-02 14:56:30 -0700127
128static grpc_call_credentials_array get_creds_array(
129 grpc_call_credentials **creds_addr) {
130 grpc_call_credentials_array result;
131 grpc_call_credentials *creds = *creds_addr;
132 result.creds_array = creds_addr;
133 result.num_creds = 1;
134 if (strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0) {
135 result = *grpc_composite_call_credentials_get_credentials(creds);
136 }
137 return result;
138}
139
140grpc_call_credentials *grpc_composite_call_credentials_create(
141 grpc_call_credentials *creds1, grpc_call_credentials *creds2,
142 void *reserved) {
143 size_t i;
144 size_t creds_array_byte_size;
145 grpc_call_credentials_array creds1_array;
146 grpc_call_credentials_array creds2_array;
147 grpc_composite_call_credentials *c;
148 GRPC_API_TRACE(
149 "grpc_composite_call_credentials_create(creds1=%p, creds2=%p, "
150 "reserved=%p)",
151 3, (creds1, creds2, reserved));
152 GPR_ASSERT(reserved == NULL);
153 GPR_ASSERT(creds1 != NULL);
154 GPR_ASSERT(creds2 != NULL);
Craig Tiller6f417882017-02-16 14:09:39 -0800155 c = gpr_zalloc(sizeof(grpc_composite_call_credentials));
Julien Boeuf8ca294e2016-05-02 14:56:30 -0700156 c->base.type = GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE;
157 c->base.vtable = &composite_call_credentials_vtable;
158 gpr_ref_init(&c->base.refcount, 1);
159 creds1_array = get_creds_array(&creds1);
160 creds2_array = get_creds_array(&creds2);
161 c->inner.num_creds = creds1_array.num_creds + creds2_array.num_creds;
162 creds_array_byte_size = c->inner.num_creds * sizeof(grpc_call_credentials *);
Craig Tiller6f417882017-02-16 14:09:39 -0800163 c->inner.creds_array = gpr_zalloc(creds_array_byte_size);
Julien Boeuf8ca294e2016-05-02 14:56:30 -0700164 for (i = 0; i < creds1_array.num_creds; i++) {
165 grpc_call_credentials *cur_creds = creds1_array.creds_array[i];
166 c->inner.creds_array[i] = grpc_call_credentials_ref(cur_creds);
167 }
168 for (i = 0; i < creds2_array.num_creds; i++) {
169 grpc_call_credentials *cur_creds = creds2_array.creds_array[i];
170 c->inner.creds_array[i + creds1_array.num_creds] =
171 grpc_call_credentials_ref(cur_creds);
172 }
173 return &c->base;
174}
175
176const grpc_call_credentials_array *
177grpc_composite_call_credentials_get_credentials(grpc_call_credentials *creds) {
178 const grpc_composite_call_credentials *c =
179 (const grpc_composite_call_credentials *)creds;
180 GPR_ASSERT(strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0);
181 return &c->inner;
182}
183
184grpc_call_credentials *grpc_credentials_contains_type(
185 grpc_call_credentials *creds, const char *type,
186 grpc_call_credentials **composite_creds) {
187 size_t i;
188 if (strcmp(creds->type, type) == 0) {
189 if (composite_creds != NULL) *composite_creds = NULL;
190 return creds;
191 } else if (strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0) {
192 const grpc_call_credentials_array *inner_creds_array =
193 grpc_composite_call_credentials_get_credentials(creds);
194 for (i = 0; i < inner_creds_array->num_creds; i++) {
195 if (strcmp(type, inner_creds_array->creds_array[i]->type) == 0) {
196 if (composite_creds != NULL) *composite_creds = creds;
197 return inner_creds_array->creds_array[i];
198 }
199 }
200 }
201 return NULL;
202}
203
204/* -- Composite channel credentials. -- */
205
Craig Tillerbd1795c2016-10-31 15:30:00 -0700206static void composite_channel_destruct(grpc_exec_ctx *exec_ctx,
207 grpc_channel_credentials *creds) {
Julien Boeuf8ca294e2016-05-02 14:56:30 -0700208 grpc_composite_channel_credentials *c =
209 (grpc_composite_channel_credentials *)creds;
Craig Tillerbd1795c2016-10-31 15:30:00 -0700210 grpc_channel_credentials_unref(exec_ctx, c->inner_creds);
211 grpc_call_credentials_unref(exec_ctx, c->call_creds);
Julien Boeuf8ca294e2016-05-02 14:56:30 -0700212}
213
214static grpc_security_status composite_channel_create_security_connector(
Craig Tillerbd1795c2016-10-31 15:30:00 -0700215 grpc_exec_ctx *exec_ctx, grpc_channel_credentials *creds,
216 grpc_call_credentials *call_creds, const char *target,
217 const grpc_channel_args *args, grpc_channel_security_connector **sc,
218 grpc_channel_args **new_args) {
Julien Boeuf8ca294e2016-05-02 14:56:30 -0700219 grpc_composite_channel_credentials *c =
220 (grpc_composite_channel_credentials *)creds;
221 grpc_security_status status = GRPC_SECURITY_ERROR;
222
223 GPR_ASSERT(c->inner_creds != NULL && c->call_creds != NULL &&
224 c->inner_creds->vtable != NULL &&
225 c->inner_creds->vtable->create_security_connector != NULL);
226 /* If we are passed a call_creds, create a call composite to pass it
227 downstream. */
228 if (call_creds != NULL) {
229 grpc_call_credentials *composite_call_creds =
230 grpc_composite_call_credentials_create(c->call_creds, call_creds, NULL);
231 status = c->inner_creds->vtable->create_security_connector(
Craig Tillerbd1795c2016-10-31 15:30:00 -0700232 exec_ctx, c->inner_creds, composite_call_creds, target, args, sc,
233 new_args);
234 grpc_call_credentials_unref(exec_ctx, composite_call_creds);
Julien Boeuf8ca294e2016-05-02 14:56:30 -0700235 } else {
236 status = c->inner_creds->vtable->create_security_connector(
Craig Tillerbd1795c2016-10-31 15:30:00 -0700237 exec_ctx, c->inner_creds, c->call_creds, target, args, sc, new_args);
Julien Boeuf8ca294e2016-05-02 14:56:30 -0700238 }
239 return status;
240}
241
Julien Boeufe26ab6c2016-09-22 15:13:07 -0700242static grpc_channel_credentials *
243composite_channel_duplicate_without_call_credentials(
244 grpc_channel_credentials *creds) {
245 grpc_composite_channel_credentials *c =
246 (grpc_composite_channel_credentials *)creds;
247 return grpc_channel_credentials_ref(c->inner_creds);
248}
249
Julien Boeuf8ca294e2016-05-02 14:56:30 -0700250static grpc_channel_credentials_vtable composite_channel_credentials_vtable = {
Julien Boeufe26ab6c2016-09-22 15:13:07 -0700251 composite_channel_destruct, composite_channel_create_security_connector,
252 composite_channel_duplicate_without_call_credentials};
Julien Boeuf8ca294e2016-05-02 14:56:30 -0700253
254grpc_channel_credentials *grpc_composite_channel_credentials_create(
255 grpc_channel_credentials *channel_creds, grpc_call_credentials *call_creds,
256 void *reserved) {
Craig Tiller6f417882017-02-16 14:09:39 -0800257 grpc_composite_channel_credentials *c = gpr_zalloc(sizeof(*c));
Julien Boeuf8ca294e2016-05-02 14:56:30 -0700258 GPR_ASSERT(channel_creds != NULL && call_creds != NULL && reserved == NULL);
259 GRPC_API_TRACE(
260 "grpc_composite_channel_credentials_create(channel_creds=%p, "
261 "call_creds=%p, reserved=%p)",
262 3, (channel_creds, call_creds, reserved));
263 c->base.type = channel_creds->type;
264 c->base.vtable = &composite_channel_credentials_vtable;
265 gpr_ref_init(&c->base.refcount, 1);
266 c->inner_creds = grpc_channel_credentials_ref(channel_creds);
267 c->call_creds = grpc_call_credentials_ref(call_creds);
268 return &c->base;
269}