blob: def16c822991967b7a1e2541dcf7d1a885e607b5 [file] [log] [blame]
Julien Boeufc6f8d0a2015-05-11 22:40:02 -07001/*
2 *
Craig Tiller6169d5f2016-03-31 07:46:18 -07003 * Copyright 2015, Google Inc.
Julien Boeufc6f8d0a2015-05-11 22:40:02 -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
Julien Boeufea456fc2015-07-07 15:23:30 -070034#include <string.h>
35
Julien Boeuf8ca294e2016-05-02 14:56:30 -070036#include "src/core/lib/security/context/security_context.h"
37#include "src/core/lib/security/credentials/credentials.h"
38#include "src/core/lib/security/transport/auth_filters.h"
Julien Boeufc6f8d0a2015-05-11 22:40:02 -070039
Julien Boeufea456fc2015-07-07 15:23:30 -070040#include <grpc/support/alloc.h>
Julien Boeufc6f8d0a2015-05-11 22:40:02 -070041#include <grpc/support/log.h>
42
Craig Tillera82950e2015-09-22 12:33:20 -070043typedef struct call_data {
Craig Tiller0581d122015-11-02 14:09:40 -080044 grpc_metadata_batch *recv_initial_metadata;
Julien Boeufa87d6c22015-07-17 15:51:46 -070045 /* Closure to call when finished with the auth_on_recv hook. */
Craig Tiller33825112015-09-18 07:44:19 -070046 grpc_closure *on_done_recv;
Julien Boeufea456fc2015-07-07 15:23:30 -070047 /* Receive closures are chained: we inject this closure as the on_done_recv
48 up-call on transport_op, and remember to call our on_done_recv member after
49 handling it. */
Craig Tiller33825112015-09-18 07:44:19 -070050 grpc_closure auth_on_recv;
Julien Boeufa87d6c22015-07-17 15:51:46 -070051 grpc_transport_stream_op transport_op;
Julien Boeufbf25bb02015-08-14 12:36:11 -070052 grpc_metadata_array md;
Julien Boeufea456fc2015-07-07 15:23:30 -070053 const grpc_metadata *consumed_md;
54 size_t num_consumed_md;
Julien Boeuf77a7b872015-08-05 20:11:02 -070055 grpc_auth_context *auth_context;
Julien Boeufc6f8d0a2015-05-11 22:40:02 -070056} call_data;
57
Craig Tillera82950e2015-09-22 12:33:20 -070058typedef struct channel_data {
Julien Boeuf9a529082015-10-08 13:12:14 -070059 grpc_auth_context *auth_context;
60 grpc_server_credentials *creds;
Julien Boeufc6f8d0a2015-05-11 22:40:02 -070061} channel_data;
62
Craig Tillera82950e2015-09-22 12:33:20 -070063static grpc_metadata_array metadata_batch_to_md_array(
64 const grpc_metadata_batch *batch) {
Julien Boeufea456fc2015-07-07 15:23:30 -070065 grpc_linked_mdelem *l;
66 grpc_metadata_array result;
Craig Tillera82950e2015-09-22 12:33:20 -070067 grpc_metadata_array_init(&result);
68 for (l = batch->list.head; l != NULL; l = l->next) {
69 grpc_metadata *usr_md = NULL;
70 grpc_mdelem *md = l->md;
71 grpc_mdstr *key = md->key;
72 grpc_mdstr *value = md->value;
73 if (result.count == result.capacity) {
74 result.capacity = GPR_MAX(result.capacity + 8, result.capacity * 2);
75 result.metadata =
76 gpr_realloc(result.metadata, result.capacity * sizeof(grpc_metadata));
Julien Boeufea456fc2015-07-07 15:23:30 -070077 }
Craig Tillera82950e2015-09-22 12:33:20 -070078 usr_md = &result.metadata[result.count++];
79 usr_md->key = grpc_mdstr_as_c_string(key);
80 usr_md->value = grpc_mdstr_as_c_string(value);
81 usr_md->value_length = GPR_SLICE_LENGTH(value->slice);
82 }
Julien Boeufea456fc2015-07-07 15:23:30 -070083 return result;
84}
85
Craig Tillera82950e2015-09-22 12:33:20 -070086static grpc_mdelem *remove_consumed_md(void *user_data, grpc_mdelem *md) {
Julien Boeufea456fc2015-07-07 15:23:30 -070087 grpc_call_element *elem = user_data;
88 call_data *calld = elem->call_data;
89 size_t i;
Craig Tillera82950e2015-09-22 12:33:20 -070090 for (i = 0; i < calld->num_consumed_md; i++) {
91 const grpc_metadata *consumed_md = &calld->consumed_md[i];
92 /* Maybe we could do a pointer comparison but we do not have any guarantee
93 that the metadata processor used the same pointers for consumed_md in the
94 callback. */
95 if (GPR_SLICE_LENGTH(md->key->slice) != strlen(consumed_md->key) ||
96 GPR_SLICE_LENGTH(md->value->slice) != consumed_md->value_length) {
97 continue;
Julien Boeuf0c711ad2015-08-28 14:10:58 -070098 }
Craig Tillera82950e2015-09-22 12:33:20 -070099 if (memcmp(GPR_SLICE_START_PTR(md->key->slice), consumed_md->key,
100 GPR_SLICE_LENGTH(md->key->slice)) == 0 &&
101 memcmp(GPR_SLICE_START_PTR(md->value->slice), consumed_md->value,
102 GPR_SLICE_LENGTH(md->value->slice)) == 0) {
103 return NULL; /* Delete. */
104 }
105 }
Julien Boeufea456fc2015-07-07 15:23:30 -0700106 return md;
107}
108
Craig Tillerd1bec032015-09-18 17:29:00 -0700109/* called from application code */
Craig Tillera82950e2015-09-22 12:33:20 -0700110static void on_md_processing_done(
111 void *user_data, const grpc_metadata *consumed_md, size_t num_consumed_md,
112 const grpc_metadata *response_md, size_t num_response_md,
113 grpc_status_code status, const char *error_details) {
Julien Boeufea456fc2015-07-07 15:23:30 -0700114 grpc_call_element *elem = user_data;
115 call_data *calld = elem->call_data;
Craig Tillerf5768a62015-09-22 10:54:34 -0700116 grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
Julien Boeufea456fc2015-07-07 15:23:30 -0700117
Julien Boeufee3dbb02015-08-19 22:17:03 -0700118 /* TODO(jboeuf): Implement support for response_md. */
Craig Tillera82950e2015-09-22 12:33:20 -0700119 if (response_md != NULL && num_response_md > 0) {
120 gpr_log(GPR_INFO,
121 "response_md in auth metadata processing not supported for now. "
122 "Ignoring...");
123 }
Julien Boeufee3dbb02015-08-19 22:17:03 -0700124
Craig Tillera82950e2015-09-22 12:33:20 -0700125 if (status == GRPC_STATUS_OK) {
126 calld->consumed_md = consumed_md;
127 calld->num_consumed_md = num_consumed_md;
Craig Tiller0581d122015-11-02 14:09:40 -0800128 grpc_metadata_batch_filter(calld->recv_initial_metadata, remove_consumed_md,
Craig Tillera82950e2015-09-22 12:33:20 -0700129 elem);
130 grpc_metadata_array_destroy(&calld->md);
Craig Tiller332f1b32016-05-24 13:21:21 -0700131 grpc_exec_ctx_sched(&exec_ctx, calld->on_done_recv, GRPC_ERROR_NONE, NULL);
Craig Tillera82950e2015-09-22 12:33:20 -0700132 } else {
133 gpr_slice message;
Craig Tiller0581d122015-11-02 14:09:40 -0800134 grpc_transport_stream_op close_op;
135 memset(&close_op, 0, sizeof(close_op));
Craig Tillera82950e2015-09-22 12:33:20 -0700136 grpc_metadata_array_destroy(&calld->md);
137 error_details = error_details != NULL
138 ? error_details
139 : "Authentication metadata processing failed.";
140 message = gpr_slice_from_copied_string(error_details);
Craig Tiller0581d122015-11-02 14:09:40 -0800141 calld->transport_op.send_initial_metadata = NULL;
142 if (calld->transport_op.send_message != NULL) {
Craig Tillerc8b70132015-12-09 20:49:09 -0800143 grpc_byte_stream_destroy(&exec_ctx, calld->transport_op.send_message);
Craig Tiller0581d122015-11-02 14:09:40 -0800144 calld->transport_op.send_message = NULL;
145 }
146 calld->transport_op.send_trailing_metadata = NULL;
147 grpc_transport_stream_op_add_close(&close_op, status, &message);
148 grpc_call_next_op(&exec_ctx, elem, &close_op);
Craig Tiller332f1b32016-05-24 13:21:21 -0700149 grpc_exec_ctx_sched(&exec_ctx, calld->on_done_recv,
Craig Tiller77c983d2016-05-24 13:23:14 -0700150 grpc_error_set_int(GRPC_ERROR_CREATE(error_details),
151 GRPC_ERROR_INT_GRPC_STATUS, status),
152 NULL);
Craig Tillera82950e2015-09-22 12:33:20 -0700153 }
Craig Tillerd1bec032015-09-18 17:29:00 -0700154
Craig Tillera82950e2015-09-22 12:33:20 -0700155 grpc_exec_ctx_finish(&exec_ctx);
Julien Boeufea456fc2015-07-07 15:23:30 -0700156}
157
Craig Tillera82950e2015-09-22 12:33:20 -0700158static void auth_on_recv(grpc_exec_ctx *exec_ctx, void *user_data,
Craig Tiller804ff712016-05-05 16:25:40 -0700159 grpc_error *error) {
Julien Boeufea456fc2015-07-07 15:23:30 -0700160 grpc_call_element *elem = user_data;
161 call_data *calld = elem->call_data;
162 channel_data *chand = elem->channel_data;
Craig Tiller804ff712016-05-05 16:25:40 -0700163 if (error == GRPC_ERROR_NONE) {
Craig Tiller0581d122015-11-02 14:09:40 -0800164 if (chand->creds->processor.process != NULL) {
165 calld->md = metadata_batch_to_md_array(calld->recv_initial_metadata);
Julien Boeuf9a529082015-10-08 13:12:14 -0700166 chand->creds->processor.process(
167 chand->creds->processor.state, calld->auth_context,
168 calld->md.metadata, calld->md.count, on_md_processing_done, elem);
Craig Tillera82950e2015-09-22 12:33:20 -0700169 return;
Julien Boeufea456fc2015-07-07 15:23:30 -0700170 }
Craig Tillera82950e2015-09-22 12:33:20 -0700171 }
Craig Tiller332f1b32016-05-24 13:21:21 -0700172 grpc_exec_ctx_sched(exec_ctx, calld->on_done_recv, GRPC_ERROR_REF(error),
Craig Tiller77c983d2016-05-24 13:23:14 -0700173 NULL);
Julien Boeufea456fc2015-07-07 15:23:30 -0700174}
175
Craig Tillera82950e2015-09-22 12:33:20 -0700176static void set_recv_ops_md_callbacks(grpc_call_element *elem,
177 grpc_transport_stream_op *op) {
Julien Boeufea456fc2015-07-07 15:23:30 -0700178 call_data *calld = elem->call_data;
Julien Boeufea456fc2015-07-07 15:23:30 -0700179
Craig Tiller0581d122015-11-02 14:09:40 -0800180 if (op->recv_initial_metadata != NULL) {
Craig Tillera82950e2015-09-22 12:33:20 -0700181 /* substitute our callback for the higher callback */
Craig Tiller0581d122015-11-02 14:09:40 -0800182 calld->recv_initial_metadata = op->recv_initial_metadata;
Craig Tillera44cbfc2016-02-03 16:02:49 -0800183 calld->on_done_recv = op->recv_initial_metadata_ready;
184 op->recv_initial_metadata_ready = &calld->auth_on_recv;
Craig Tillera82950e2015-09-22 12:33:20 -0700185 calld->transport_op = *op;
186 }
Julien Boeufea456fc2015-07-07 15:23:30 -0700187}
188
Julien Boeufc6f8d0a2015-05-11 22:40:02 -0700189/* Called either:
190 - in response to an API call (or similar) from above, to send something
191 - a network event (or similar) from below, to receive something
192 op contains type and call direction information, in addition to the data
193 that is being sent or received. */
Craig Tillera82950e2015-09-22 12:33:20 -0700194static void auth_start_transport_op(grpc_exec_ctx *exec_ctx,
195 grpc_call_element *elem,
196 grpc_transport_stream_op *op) {
197 set_recv_ops_md_callbacks(elem, op);
198 grpc_call_next_op(exec_ctx, elem, op);
Julien Boeufc6f8d0a2015-05-11 22:40:02 -0700199}
200
Julien Boeufc6f8d0a2015-05-11 22:40:02 -0700201/* Constructor for call_data */
Mark D. Roth76d24422016-06-23 13:22:10 -0700202static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
Mark D. Roth0badbe82016-06-23 10:15:12 -0700203 grpc_call_element *elem,
204 grpc_call_element_args *args) {
Julien Boeufc6f8d0a2015-05-11 22:40:02 -0700205 /* grab pointers to our data from the call element */
206 call_data *calld = elem->call_data;
Julien Boeuf84d964a2015-04-29 11:31:06 -0700207 channel_data *chand = elem->channel_data;
208 grpc_server_security_context *server_ctx = NULL;
Julien Boeufc6f8d0a2015-05-11 22:40:02 -0700209
210 /* initialize members */
Craig Tillera82950e2015-09-22 12:33:20 -0700211 memset(calld, 0, sizeof(*calld));
212 grpc_closure_init(&calld->auth_on_recv, auth_on_recv, elem);
Julien Boeufc6f8d0a2015-05-11 22:40:02 -0700213
Craig Tiller0581d122015-11-02 14:09:40 -0800214 if (args->context[GRPC_CONTEXT_SECURITY].value != NULL) {
215 args->context[GRPC_CONTEXT_SECURITY].destroy(
216 args->context[GRPC_CONTEXT_SECURITY].value);
Craig Tillera82950e2015-09-22 12:33:20 -0700217 }
Craig Tiller0581d122015-11-02 14:09:40 -0800218
Craig Tillera82950e2015-09-22 12:33:20 -0700219 server_ctx = grpc_server_security_context_create();
Craig Tiller0581d122015-11-02 14:09:40 -0800220 server_ctx->auth_context = grpc_auth_context_create(chand->auth_context);
Julien Boeuf77a7b872015-08-05 20:11:02 -0700221 calld->auth_context = server_ctx->auth_context;
Julien Boeufea456fc2015-07-07 15:23:30 -0700222
Craig Tiller0581d122015-11-02 14:09:40 -0800223 args->context[GRPC_CONTEXT_SECURITY].value = server_ctx;
224 args->context[GRPC_CONTEXT_SECURITY].destroy =
225 grpc_server_security_context_destroy;
Mark D. Roth0badbe82016-06-23 10:15:12 -0700226
227 return GRPC_ERROR_NONE;
Julien Boeufc6f8d0a2015-05-11 22:40:02 -0700228}
229
230/* Destructor for call_data */
Craig Tiller2c8063c2016-03-22 22:12:15 -0700231static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
David Garcia Quintas5dde14c2016-07-28 17:29:27 -0700232 const grpc_call_final_info *final_info,
233 void *ignored) {}
Julien Boeufc6f8d0a2015-05-11 22:40:02 -0700234
235/* Constructor for channel_data */
Craig Tillera82950e2015-09-22 12:33:20 -0700236static void init_channel_elem(grpc_exec_ctx *exec_ctx,
Craig Tiller0581d122015-11-02 14:09:40 -0800237 grpc_channel_element *elem,
238 grpc_channel_element_args *args) {
239 grpc_auth_context *auth_context =
240 grpc_find_auth_context_in_args(args->channel_args);
241 grpc_server_credentials *creds =
242 grpc_find_server_credentials_in_args(args->channel_args);
Julien Boeufc6f8d0a2015-05-11 22:40:02 -0700243 /* grab pointers to our data from the channel element */
244 channel_data *chand = elem->channel_data;
245
Craig Tiller0581d122015-11-02 14:09:40 -0800246 GPR_ASSERT(!args->is_last);
Julien Boeuf9a529082015-10-08 13:12:14 -0700247 GPR_ASSERT(auth_context != NULL);
248 GPR_ASSERT(creds != NULL);
Julien Boeufc6f8d0a2015-05-11 22:40:02 -0700249
250 /* initialize members */
Julien Boeuf9a529082015-10-08 13:12:14 -0700251 chand->auth_context =
252 GRPC_AUTH_CONTEXT_REF(auth_context, "server_auth_filter");
253 chand->creds = grpc_server_credentials_ref(creds);
Julien Boeufc6f8d0a2015-05-11 22:40:02 -0700254}
255
256/* Destructor for channel data */
Craig Tillera82950e2015-09-22 12:33:20 -0700257static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
258 grpc_channel_element *elem) {
Julien Boeufc6f8d0a2015-05-11 22:40:02 -0700259 /* grab pointers to our data from the channel element */
260 channel_data *chand = elem->channel_data;
Julien Boeuf9a529082015-10-08 13:12:14 -0700261 GRPC_AUTH_CONTEXT_UNREF(chand->auth_context, "server_auth_filter");
262 grpc_server_credentials_unref(chand->creds);
Julien Boeufc6f8d0a2015-05-11 22:40:02 -0700263}
264
265const grpc_channel_filter grpc_server_auth_filter = {
David Garcia Quintas4afce7e2016-04-18 16:25:17 -0700266 auth_start_transport_op,
267 grpc_channel_next_op,
268 sizeof(call_data),
269 init_call_elem,
270 grpc_call_stack_ignore_set_pollset_or_pollset_set,
271 destroy_call_elem,
272 sizeof(channel_data),
273 init_channel_elem,
274 destroy_channel_elem,
275 grpc_call_next_get_peer,
276 "server-auth"};