blob: 77d7b04627b60fa93849c042bbc903e3dcc47fd7 [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;
35 grpc_credentials_md_store *md_elems;
36 grpc_auth_metadata_context auth_md_context;
37 void *user_data;
David Garcia Quintas2a50dfe2016-05-31 15:09:12 -070038 grpc_polling_entity *pollent;
Julien Boeuf8ca294e2016-05-02 14:56:30 -070039 grpc_credentials_metadata_cb cb;
40} 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;
45 size_t i;
46 for (i = 0; i < c->inner.num_creds; i++) {
Craig Tillerbd1795c2016-10-31 15:30:00 -070047 grpc_call_credentials_unref(exec_ctx, c->inner.creds_array[i]);
Julien Boeuf8ca294e2016-05-02 14:56:30 -070048 }
49 gpr_free(c->inner.creds_array);
50}
51
52static void composite_call_md_context_destroy(
Craig Tillerbd1795c2016-10-31 15:30:00 -070053 grpc_exec_ctx *exec_ctx,
Julien Boeuf8ca294e2016-05-02 14:56:30 -070054 grpc_composite_call_credentials_metadata_context *ctx) {
Craig Tillerbd1795c2016-10-31 15:30:00 -070055 grpc_credentials_md_store_unref(exec_ctx, ctx->md_elems);
Julien Boeuf8ca294e2016-05-02 14:56:30 -070056 gpr_free(ctx);
57}
58
59static void composite_call_metadata_cb(grpc_exec_ctx *exec_ctx, void *user_data,
60 grpc_credentials_md *md_elems,
61 size_t num_md,
Julien Boeufbfc7ed62016-06-04 18:03:42 -070062 grpc_credentials_status status,
63 const char *error_details) {
Julien Boeuf8ca294e2016-05-02 14:56:30 -070064 grpc_composite_call_credentials_metadata_context *ctx =
65 (grpc_composite_call_credentials_metadata_context *)user_data;
66 if (status != GRPC_CREDENTIALS_OK) {
Julien Boeufbfc7ed62016-06-04 18:03:42 -070067 ctx->cb(exec_ctx, ctx->user_data, NULL, 0, status, error_details);
Julien Boeuf8ca294e2016-05-02 14:56:30 -070068 return;
69 }
70
71 /* Copy the metadata in the context. */
72 if (num_md > 0) {
73 size_t i;
74 for (i = 0; i < num_md; i++) {
75 grpc_credentials_md_store_add(ctx->md_elems, md_elems[i].key,
76 md_elems[i].value);
77 }
78 }
79
80 /* See if we need to get some more metadata. */
81 if (ctx->creds_index < ctx->composite_creds->inner.num_creds) {
82 grpc_call_credentials *inner_creds =
83 ctx->composite_creds->inner.creds_array[ctx->creds_index++];
David Garcia Quintas2a50dfe2016-05-31 15:09:12 -070084 grpc_call_credentials_get_request_metadata(
85 exec_ctx, inner_creds, ctx->pollent, ctx->auth_md_context,
86 composite_call_metadata_cb, ctx);
Julien Boeuf8ca294e2016-05-02 14:56:30 -070087 return;
88 }
89
90 /* We're done!. */
91 ctx->cb(exec_ctx, ctx->user_data, ctx->md_elems->entries,
Julien Boeufbfc7ed62016-06-04 18:03:42 -070092 ctx->md_elems->num_entries, GRPC_CREDENTIALS_OK, NULL);
Craig Tillerbd1795c2016-10-31 15:30:00 -070093 composite_call_md_context_destroy(exec_ctx, ctx);
Julien Boeuf8ca294e2016-05-02 14:56:30 -070094}
95
96static void composite_call_get_request_metadata(
David Garcia Quintas2a50dfe2016-05-31 15:09:12 -070097 grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds,
98 grpc_polling_entity *pollent, grpc_auth_metadata_context auth_md_context,
99 grpc_credentials_metadata_cb cb, void *user_data) {
Julien Boeuf8ca294e2016-05-02 14:56:30 -0700100 grpc_composite_call_credentials *c = (grpc_composite_call_credentials *)creds;
101 grpc_composite_call_credentials_metadata_context *ctx;
102
Craig Tiller6f417882017-02-16 14:09:39 -0800103 ctx = gpr_zalloc(sizeof(grpc_composite_call_credentials_metadata_context));
Julien Boeuf8ca294e2016-05-02 14:56:30 -0700104 ctx->auth_md_context = auth_md_context;
105 ctx->user_data = user_data;
106 ctx->cb = cb;
107 ctx->composite_creds = c;
David Garcia Quintas2a50dfe2016-05-31 15:09:12 -0700108 ctx->pollent = pollent;
Julien Boeuf8ca294e2016-05-02 14:56:30 -0700109 ctx->md_elems = grpc_credentials_md_store_create(c->inner.num_creds);
110 grpc_call_credentials_get_request_metadata(
David Garcia Quintas2a50dfe2016-05-31 15:09:12 -0700111 exec_ctx, c->inner.creds_array[ctx->creds_index++], ctx->pollent,
Julien Boeuf8ca294e2016-05-02 14:56:30 -0700112 auth_md_context, composite_call_metadata_cb, ctx);
113}
114
115static grpc_call_credentials_vtable composite_call_credentials_vtable = {
116 composite_call_destruct, composite_call_get_request_metadata};
117
118static grpc_call_credentials_array get_creds_array(
119 grpc_call_credentials **creds_addr) {
120 grpc_call_credentials_array result;
121 grpc_call_credentials *creds = *creds_addr;
122 result.creds_array = creds_addr;
123 result.num_creds = 1;
124 if (strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0) {
125 result = *grpc_composite_call_credentials_get_credentials(creds);
126 }
127 return result;
128}
129
130grpc_call_credentials *grpc_composite_call_credentials_create(
131 grpc_call_credentials *creds1, grpc_call_credentials *creds2,
132 void *reserved) {
133 size_t i;
134 size_t creds_array_byte_size;
135 grpc_call_credentials_array creds1_array;
136 grpc_call_credentials_array creds2_array;
137 grpc_composite_call_credentials *c;
138 GRPC_API_TRACE(
139 "grpc_composite_call_credentials_create(creds1=%p, creds2=%p, "
140 "reserved=%p)",
141 3, (creds1, creds2, reserved));
142 GPR_ASSERT(reserved == NULL);
143 GPR_ASSERT(creds1 != NULL);
144 GPR_ASSERT(creds2 != NULL);
Craig Tiller6f417882017-02-16 14:09:39 -0800145 c = gpr_zalloc(sizeof(grpc_composite_call_credentials));
Julien Boeuf8ca294e2016-05-02 14:56:30 -0700146 c->base.type = GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE;
147 c->base.vtable = &composite_call_credentials_vtable;
148 gpr_ref_init(&c->base.refcount, 1);
149 creds1_array = get_creds_array(&creds1);
150 creds2_array = get_creds_array(&creds2);
151 c->inner.num_creds = creds1_array.num_creds + creds2_array.num_creds;
152 creds_array_byte_size = c->inner.num_creds * sizeof(grpc_call_credentials *);
Craig Tiller6f417882017-02-16 14:09:39 -0800153 c->inner.creds_array = gpr_zalloc(creds_array_byte_size);
Julien Boeuf8ca294e2016-05-02 14:56:30 -0700154 for (i = 0; i < creds1_array.num_creds; i++) {
155 grpc_call_credentials *cur_creds = creds1_array.creds_array[i];
156 c->inner.creds_array[i] = grpc_call_credentials_ref(cur_creds);
157 }
158 for (i = 0; i < creds2_array.num_creds; i++) {
159 grpc_call_credentials *cur_creds = creds2_array.creds_array[i];
160 c->inner.creds_array[i + creds1_array.num_creds] =
161 grpc_call_credentials_ref(cur_creds);
162 }
163 return &c->base;
164}
165
166const grpc_call_credentials_array *
167grpc_composite_call_credentials_get_credentials(grpc_call_credentials *creds) {
168 const grpc_composite_call_credentials *c =
169 (const grpc_composite_call_credentials *)creds;
170 GPR_ASSERT(strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0);
171 return &c->inner;
172}
173
174grpc_call_credentials *grpc_credentials_contains_type(
175 grpc_call_credentials *creds, const char *type,
176 grpc_call_credentials **composite_creds) {
177 size_t i;
178 if (strcmp(creds->type, type) == 0) {
179 if (composite_creds != NULL) *composite_creds = NULL;
180 return creds;
181 } else if (strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0) {
182 const grpc_call_credentials_array *inner_creds_array =
183 grpc_composite_call_credentials_get_credentials(creds);
184 for (i = 0; i < inner_creds_array->num_creds; i++) {
185 if (strcmp(type, inner_creds_array->creds_array[i]->type) == 0) {
186 if (composite_creds != NULL) *composite_creds = creds;
187 return inner_creds_array->creds_array[i];
188 }
189 }
190 }
191 return NULL;
192}
193
194/* -- Composite channel credentials. -- */
195
Craig Tillerbd1795c2016-10-31 15:30:00 -0700196static void composite_channel_destruct(grpc_exec_ctx *exec_ctx,
197 grpc_channel_credentials *creds) {
Julien Boeuf8ca294e2016-05-02 14:56:30 -0700198 grpc_composite_channel_credentials *c =
199 (grpc_composite_channel_credentials *)creds;
Craig Tillerbd1795c2016-10-31 15:30:00 -0700200 grpc_channel_credentials_unref(exec_ctx, c->inner_creds);
201 grpc_call_credentials_unref(exec_ctx, c->call_creds);
Julien Boeuf8ca294e2016-05-02 14:56:30 -0700202}
203
204static grpc_security_status composite_channel_create_security_connector(
Craig Tillerbd1795c2016-10-31 15:30:00 -0700205 grpc_exec_ctx *exec_ctx, grpc_channel_credentials *creds,
206 grpc_call_credentials *call_creds, const char *target,
207 const grpc_channel_args *args, grpc_channel_security_connector **sc,
208 grpc_channel_args **new_args) {
Julien Boeuf8ca294e2016-05-02 14:56:30 -0700209 grpc_composite_channel_credentials *c =
210 (grpc_composite_channel_credentials *)creds;
211 grpc_security_status status = GRPC_SECURITY_ERROR;
212
213 GPR_ASSERT(c->inner_creds != NULL && c->call_creds != NULL &&
214 c->inner_creds->vtable != NULL &&
215 c->inner_creds->vtable->create_security_connector != NULL);
216 /* If we are passed a call_creds, create a call composite to pass it
217 downstream. */
218 if (call_creds != NULL) {
219 grpc_call_credentials *composite_call_creds =
220 grpc_composite_call_credentials_create(c->call_creds, call_creds, NULL);
221 status = c->inner_creds->vtable->create_security_connector(
Craig Tillerbd1795c2016-10-31 15:30:00 -0700222 exec_ctx, c->inner_creds, composite_call_creds, target, args, sc,
223 new_args);
224 grpc_call_credentials_unref(exec_ctx, composite_call_creds);
Julien Boeuf8ca294e2016-05-02 14:56:30 -0700225 } else {
226 status = c->inner_creds->vtable->create_security_connector(
Craig Tillerbd1795c2016-10-31 15:30:00 -0700227 exec_ctx, c->inner_creds, c->call_creds, target, args, sc, new_args);
Julien Boeuf8ca294e2016-05-02 14:56:30 -0700228 }
229 return status;
230}
231
Julien Boeufe26ab6c2016-09-22 15:13:07 -0700232static grpc_channel_credentials *
233composite_channel_duplicate_without_call_credentials(
234 grpc_channel_credentials *creds) {
235 grpc_composite_channel_credentials *c =
236 (grpc_composite_channel_credentials *)creds;
237 return grpc_channel_credentials_ref(c->inner_creds);
238}
239
Julien Boeuf8ca294e2016-05-02 14:56:30 -0700240static grpc_channel_credentials_vtable composite_channel_credentials_vtable = {
Julien Boeufe26ab6c2016-09-22 15:13:07 -0700241 composite_channel_destruct, composite_channel_create_security_connector,
242 composite_channel_duplicate_without_call_credentials};
Julien Boeuf8ca294e2016-05-02 14:56:30 -0700243
244grpc_channel_credentials *grpc_composite_channel_credentials_create(
245 grpc_channel_credentials *channel_creds, grpc_call_credentials *call_creds,
246 void *reserved) {
Craig Tiller6f417882017-02-16 14:09:39 -0800247 grpc_composite_channel_credentials *c = gpr_zalloc(sizeof(*c));
Julien Boeuf8ca294e2016-05-02 14:56:30 -0700248 GPR_ASSERT(channel_creds != NULL && call_creds != NULL && reserved == NULL);
249 GRPC_API_TRACE(
250 "grpc_composite_channel_credentials_create(channel_creds=%p, "
251 "call_creds=%p, reserved=%p)",
252 3, (channel_creds, call_creds, reserved));
253 c->base.type = channel_creds->type;
254 c->base.vtable = &composite_channel_credentials_vtable;
255 gpr_ref_init(&c->base.refcount, 1);
256 c->inner_creds = grpc_channel_credentials_ref(channel_creds);
257 c->call_creds = grpc_call_credentials_ref(call_creds);
258 return &c->base;
259}