blob: 6cf61c03a22384e86586b3c8a67ec4c670ddeadb [file] [log] [blame]
Julien Boeufc6f8d0a2015-05-11 22:40:02 -07001/*
2 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02003 * Copyright 2015 gRPC authors.
Julien Boeufc6f8d0a2015-05-11 22:40:02 -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 Boeufc6f8d0a2015-05-11 22:40:02 -07008 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02009 * http://www.apache.org/licenses/LICENSE-2.0
Julien Boeufc6f8d0a2015-05-11 22:40:02 -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 Boeufc6f8d0a2015-05-11 22:40:02 -070016 *
17 */
18
Julien Boeufea456fc2015-07-07 15:23:30 -070019#include <string.h>
20
Craig Tiller7c70b6c2017-01-23 07:48:42 -080021#include <grpc/support/alloc.h>
22#include <grpc/support/log.h>
23
Julien Boeuf8ca294e2016-05-02 14:56:30 -070024#include "src/core/lib/security/context/security_context.h"
25#include "src/core/lib/security/credentials/credentials.h"
26#include "src/core/lib/security/transport/auth_filters.h"
Craig Tiller7c70b6c2017-01-23 07:48:42 -080027#include "src/core/lib/slice/slice_internal.h"
Julien Boeufc6f8d0a2015-05-11 22:40:02 -070028
Mark D. Roth764cf042017-09-01 09:00:06 -070029typedef enum {
30 STATE_INIT = 0,
31 STATE_DONE,
32 STATE_CANCELLED,
33} async_state;
34
Craig Tillera82950e2015-09-22 12:33:20 -070035typedef struct call_data {
Mark D. Roth764cf042017-09-01 09:00:06 -070036 grpc_call_combiner *call_combiner;
37 grpc_call_stack *owning_call;
Mark D. Roth630e26b2017-07-10 07:31:29 -070038 grpc_transport_stream_op_batch *recv_initial_metadata_batch;
39 grpc_closure *original_recv_initial_metadata_ready;
40 grpc_closure recv_initial_metadata_ready;
Julien Boeufbf25bb02015-08-14 12:36:11 -070041 grpc_metadata_array md;
Julien Boeufea456fc2015-07-07 15:23:30 -070042 const grpc_metadata *consumed_md;
43 size_t num_consumed_md;
Julien Boeuf77a7b872015-08-05 20:11:02 -070044 grpc_auth_context *auth_context;
Mark D. Roth764cf042017-09-01 09:00:06 -070045 grpc_closure cancel_closure;
46 gpr_atm state; // async_state
Julien Boeufc6f8d0a2015-05-11 22:40:02 -070047} call_data;
48
Craig Tillera82950e2015-09-22 12:33:20 -070049typedef struct channel_data {
Julien Boeuf9a529082015-10-08 13:12:14 -070050 grpc_auth_context *auth_context;
51 grpc_server_credentials *creds;
Julien Boeufc6f8d0a2015-05-11 22:40:02 -070052} channel_data;
53
Craig Tillera82950e2015-09-22 12:33:20 -070054static grpc_metadata_array metadata_batch_to_md_array(
55 const grpc_metadata_batch *batch) {
Julien Boeufea456fc2015-07-07 15:23:30 -070056 grpc_linked_mdelem *l;
57 grpc_metadata_array result;
Craig Tillera82950e2015-09-22 12:33:20 -070058 grpc_metadata_array_init(&result);
59 for (l = batch->list.head; l != NULL; l = l->next) {
60 grpc_metadata *usr_md = NULL;
Craig Tiller7c70b6c2017-01-23 07:48:42 -080061 grpc_mdelem md = l->md;
62 grpc_slice key = GRPC_MDKEY(md);
63 grpc_slice value = GRPC_MDVALUE(md);
Craig Tillera82950e2015-09-22 12:33:20 -070064 if (result.count == result.capacity) {
65 result.capacity = GPR_MAX(result.capacity + 8, result.capacity * 2);
66 result.metadata =
67 gpr_realloc(result.metadata, result.capacity * sizeof(grpc_metadata));
Julien Boeufea456fc2015-07-07 15:23:30 -070068 }
Craig Tillera82950e2015-09-22 12:33:20 -070069 usr_md = &result.metadata[result.count++];
Craig Tiller7c70b6c2017-01-23 07:48:42 -080070 usr_md->key = grpc_slice_ref_internal(key);
71 usr_md->value = grpc_slice_ref_internal(value);
Craig Tillera82950e2015-09-22 12:33:20 -070072 }
Julien Boeufea456fc2015-07-07 15:23:30 -070073 return result;
74}
75
Craig Tiller7c70b6c2017-01-23 07:48:42 -080076static grpc_filtered_mdelem remove_consumed_md(grpc_exec_ctx *exec_ctx,
77 void *user_data,
78 grpc_mdelem md) {
Julien Boeufea456fc2015-07-07 15:23:30 -070079 grpc_call_element *elem = user_data;
80 call_data *calld = elem->call_data;
81 size_t i;
Craig Tillera82950e2015-09-22 12:33:20 -070082 for (i = 0; i < calld->num_consumed_md; i++) {
83 const grpc_metadata *consumed_md = &calld->consumed_md[i];
Craig Tiller7c70b6c2017-01-23 07:48:42 -080084 if (grpc_slice_eq(GRPC_MDKEY(md), consumed_md->key) &&
85 grpc_slice_eq(GRPC_MDVALUE(md), consumed_md->value))
86 return GRPC_FILTERED_REMOVE();
Craig Tillera82950e2015-09-22 12:33:20 -070087 }
Craig Tiller7c70b6c2017-01-23 07:48:42 -080088 return GRPC_FILTERED_MDELEM(md);
Julien Boeufea456fc2015-07-07 15:23:30 -070089}
90
Mark D. Roth764cf042017-09-01 09:00:06 -070091static void on_md_processing_done_inner(grpc_exec_ctx *exec_ctx,
92 grpc_call_element *elem,
93 const grpc_metadata *consumed_md,
94 size_t num_consumed_md,
95 const grpc_metadata *response_md,
96 size_t num_response_md,
97 grpc_error *error) {
Mark D. Roth76e264b2017-08-25 09:03:33 -070098 call_data *calld = elem->call_data;
Mark D. Rothbf199612017-08-29 16:59:07 -070099 grpc_transport_stream_op_batch *batch = calld->recv_initial_metadata_batch;
Mark D. Roth764cf042017-09-01 09:00:06 -0700100 grpc_call_combiner_set_notify_on_cancel(exec_ctx, calld->call_combiner, NULL);
Mark D. Rothbf199612017-08-29 16:59:07 -0700101 /* TODO(jboeuf): Implement support for response_md. */
102 if (response_md != NULL && num_response_md > 0) {
103 gpr_log(GPR_INFO,
104 "response_md in auth metadata processing not supported for now. "
105 "Ignoring...");
Mark D. Roth76e264b2017-08-25 09:03:33 -0700106 }
Mark D. Roth764cf042017-09-01 09:00:06 -0700107 if (error == GRPC_ERROR_NONE) {
Mark D. Rothbf199612017-08-29 16:59:07 -0700108 calld->consumed_md = consumed_md;
109 calld->num_consumed_md = num_consumed_md;
110 error = grpc_metadata_batch_filter(
Mark D. Roth764cf042017-09-01 09:00:06 -0700111 exec_ctx, batch->payload->recv_initial_metadata.recv_initial_metadata,
Mark D. Rothbf199612017-08-29 16:59:07 -0700112 remove_consumed_md, elem, "Response metadata filtering error");
Mark D. Rothbf199612017-08-29 16:59:07 -0700113 }
Mark D. Roth764cf042017-09-01 09:00:06 -0700114 GRPC_CLOSURE_SCHED(exec_ctx, calld->original_recv_initial_metadata_ready,
115 error);
116}
117
118// Called from application code.
119static void on_md_processing_done(
120 void *user_data, const grpc_metadata *consumed_md, size_t num_consumed_md,
121 const grpc_metadata *response_md, size_t num_response_md,
122 grpc_status_code status, const char *error_details) {
123 grpc_call_element *elem = user_data;
124 call_data *calld = elem->call_data;
125 grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
126 // If the call was not cancelled while we were in flight, process the result.
127 if (gpr_atm_full_cas(&calld->state, (gpr_atm)STATE_INIT,
128 (gpr_atm)STATE_DONE)) {
129 grpc_error *error = GRPC_ERROR_NONE;
130 if (status != GRPC_STATUS_OK) {
131 if (error_details == NULL) {
132 error_details = "Authentication metadata processing failed.";
133 }
134 error = grpc_error_set_int(
135 GRPC_ERROR_CREATE_FROM_COPIED_STRING(error_details),
136 GRPC_ERROR_INT_GRPC_STATUS, status);
137 }
138 on_md_processing_done_inner(&exec_ctx, elem, consumed_md, num_consumed_md,
139 response_md, num_response_md, error);
140 }
141 // Clean up.
Mark D. Roth630e26b2017-07-10 07:31:29 -0700142 for (size_t i = 0; i < calld->md.count; i++) {
143 grpc_slice_unref_internal(&exec_ctx, calld->md.metadata[i].key);
144 grpc_slice_unref_internal(&exec_ctx, calld->md.metadata[i].value);
145 }
146 grpc_metadata_array_destroy(&calld->md);
Mark D. Roth764cf042017-09-01 09:00:06 -0700147 GRPC_CALL_STACK_UNREF(&exec_ctx, calld->owning_call, "server_auth_metadata");
Craig Tillera82950e2015-09-22 12:33:20 -0700148 grpc_exec_ctx_finish(&exec_ctx);
Julien Boeufea456fc2015-07-07 15:23:30 -0700149}
150
Mark D. Roth764cf042017-09-01 09:00:06 -0700151static void cancel_call(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
152 grpc_call_element *elem = (grpc_call_element *)arg;
153 call_data *calld = elem->call_data;
154 // If the result was not already processed, invoke the callback now.
Mark D. Roth66f3d2b2017-09-01 09:02:17 -0700155 if (error != GRPC_ERROR_NONE &&
156 gpr_atm_full_cas(&calld->state, (gpr_atm)STATE_INIT,
Mark D. Roth764cf042017-09-01 09:00:06 -0700157 (gpr_atm)STATE_CANCELLED)) {
158 on_md_processing_done_inner(exec_ctx, elem, NULL, 0, NULL, 0,
159 GRPC_ERROR_REF(error));
160 }
Mark D. Roth66f3d2b2017-09-01 09:02:17 -0700161 GRPC_CALL_STACK_UNREF(exec_ctx, calld->owning_call, "cancel_call");
Mark D. Roth764cf042017-09-01 09:00:06 -0700162}
163
Mark D. Roth630e26b2017-07-10 07:31:29 -0700164static void recv_initial_metadata_ready(grpc_exec_ctx *exec_ctx, void *arg,
165 grpc_error *error) {
Mark D. Roth764cf042017-09-01 09:00:06 -0700166 grpc_call_element *elem = (grpc_call_element *)arg;
Julien Boeufea456fc2015-07-07 15:23:30 -0700167 channel_data *chand = elem->channel_data;
Mark D. Roth630e26b2017-07-10 07:31:29 -0700168 call_data *calld = elem->call_data;
169 grpc_transport_stream_op_batch *batch = calld->recv_initial_metadata_batch;
Craig Tiller804ff712016-05-05 16:25:40 -0700170 if (error == GRPC_ERROR_NONE) {
Julien Boeuf8f0fd822017-03-22 08:47:50 -0700171 if (chand->creds != NULL && chand->creds->processor.process != NULL) {
Mark D. Roth764cf042017-09-01 09:00:06 -0700172 // We're calling out to the application, so we need to make sure
173 // to drop the call combiner early if we get cancelled.
Mark D. Roth66f3d2b2017-09-01 09:02:17 -0700174 GRPC_CALL_STACK_REF(calld->owning_call, "cancel_call");
Mark D. Roth764cf042017-09-01 09:00:06 -0700175 GRPC_CLOSURE_INIT(&calld->cancel_closure, cancel_call, elem,
176 grpc_schedule_on_exec_ctx);
177 grpc_call_combiner_set_notify_on_cancel(exec_ctx, calld->call_combiner,
178 &calld->cancel_closure);
179 GRPC_CALL_STACK_REF(calld->owning_call, "server_auth_metadata");
Mark D. Roth630e26b2017-07-10 07:31:29 -0700180 calld->md = metadata_batch_to_md_array(
181 batch->payload->recv_initial_metadata.recv_initial_metadata);
Julien Boeuf9a529082015-10-08 13:12:14 -0700182 chand->creds->processor.process(
183 chand->creds->processor.state, calld->auth_context,
184 calld->md.metadata, calld->md.count, on_md_processing_done, elem);
Craig Tillera82950e2015-09-22 12:33:20 -0700185 return;
Julien Boeufea456fc2015-07-07 15:23:30 -0700186 }
Craig Tillera82950e2015-09-22 12:33:20 -0700187 }
Mark D. Roth630e26b2017-07-10 07:31:29 -0700188 GRPC_CLOSURE_RUN(exec_ctx, calld->original_recv_initial_metadata_ready,
189 GRPC_ERROR_REF(error));
Julien Boeufea456fc2015-07-07 15:23:30 -0700190}
191
Mark D. Roth630e26b2017-07-10 07:31:29 -0700192static void auth_start_transport_stream_op_batch(
193 grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
194 grpc_transport_stream_op_batch *batch) {
Julien Boeufea456fc2015-07-07 15:23:30 -0700195 call_data *calld = elem->call_data;
Mark D. Roth630e26b2017-07-10 07:31:29 -0700196 if (batch->recv_initial_metadata) {
197 // Inject our callback.
198 calld->recv_initial_metadata_batch = batch;
199 calld->original_recv_initial_metadata_ready =
200 batch->payload->recv_initial_metadata.recv_initial_metadata_ready;
201 batch->payload->recv_initial_metadata.recv_initial_metadata_ready =
202 &calld->recv_initial_metadata_ready;
Craig Tillera82950e2015-09-22 12:33:20 -0700203 }
Mark D. Roth630e26b2017-07-10 07:31:29 -0700204 grpc_call_next_op(exec_ctx, elem, batch);
Julien Boeufc6f8d0a2015-05-11 22:40:02 -0700205}
206
Julien Boeufc6f8d0a2015-05-11 22:40:02 -0700207/* Constructor for call_data */
Mark D. Roth76d24422016-06-23 13:22:10 -0700208static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
Mark D. Roth0badbe82016-06-23 10:15:12 -0700209 grpc_call_element *elem,
Craig Tillerc52ba3a2017-02-15 22:57:43 -0800210 const grpc_call_element_args *args) {
Julien Boeufc6f8d0a2015-05-11 22:40:02 -0700211 call_data *calld = elem->call_data;
Julien Boeuf84d964a2015-04-29 11:31:06 -0700212 channel_data *chand = elem->channel_data;
Mark D. Roth764cf042017-09-01 09:00:06 -0700213 calld->call_combiner = args->call_combiner;
214 calld->owning_call = args->call_stack;
Mark D. Roth630e26b2017-07-10 07:31:29 -0700215 GRPC_CLOSURE_INIT(&calld->recv_initial_metadata_ready,
216 recv_initial_metadata_ready, elem,
Craig Tiller91031da2016-12-28 15:44:25 -0800217 grpc_schedule_on_exec_ctx);
Mark D. Roth630e26b2017-07-10 07:31:29 -0700218 // Create server security context. Set its auth context from channel
219 // data and save it in the call context.
220 grpc_server_security_context *server_ctx =
221 grpc_server_security_context_create();
222 server_ctx->auth_context = grpc_auth_context_create(chand->auth_context);
223 calld->auth_context = server_ctx->auth_context;
Craig Tiller0581d122015-11-02 14:09:40 -0800224 if (args->context[GRPC_CONTEXT_SECURITY].value != NULL) {
225 args->context[GRPC_CONTEXT_SECURITY].destroy(
226 args->context[GRPC_CONTEXT_SECURITY].value);
Craig Tillera82950e2015-09-22 12:33:20 -0700227 }
Craig Tiller0581d122015-11-02 14:09:40 -0800228 args->context[GRPC_CONTEXT_SECURITY].value = server_ctx;
229 args->context[GRPC_CONTEXT_SECURITY].destroy =
230 grpc_server_security_context_destroy;
Mark D. Roth0badbe82016-06-23 10:15:12 -0700231 return GRPC_ERROR_NONE;
Julien Boeufc6f8d0a2015-05-11 22:40:02 -0700232}
233
234/* Destructor for call_data */
Craig Tiller2c8063c2016-03-22 22:12:15 -0700235static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
David Garcia Quintas5dde14c2016-07-28 17:29:27 -0700236 const grpc_call_final_info *final_info,
Craig Tillerd426cac2017-03-13 12:30:45 -0700237 grpc_closure *ignored) {}
Julien Boeufc6f8d0a2015-05-11 22:40:02 -0700238
239/* Constructor for channel_data */
Mark D. Rothc1087882016-11-18 10:54:45 -0800240static grpc_error *init_channel_elem(grpc_exec_ctx *exec_ctx,
Mark D. Roth5e2566e2016-11-18 10:53:13 -0800241 grpc_channel_element *elem,
242 grpc_channel_element_args *args) {
Mark D. Roth630e26b2017-07-10 07:31:29 -0700243 GPR_ASSERT(!args->is_last);
244 channel_data *chand = elem->channel_data;
Craig Tiller0581d122015-11-02 14:09:40 -0800245 grpc_auth_context *auth_context =
246 grpc_find_auth_context_in_args(args->channel_args);
Julien Boeuf9a529082015-10-08 13:12:14 -0700247 GPR_ASSERT(auth_context != NULL);
Julien Boeuf9a529082015-10-08 13:12:14 -0700248 chand->auth_context =
249 GRPC_AUTH_CONTEXT_REF(auth_context, "server_auth_filter");
Mark D. Roth630e26b2017-07-10 07:31:29 -0700250 grpc_server_credentials *creds =
251 grpc_find_server_credentials_in_args(args->channel_args);
Julien Boeuf9a529082015-10-08 13:12:14 -0700252 chand->creds = grpc_server_credentials_ref(creds);
Mark D. Roth5e2566e2016-11-18 10:53:13 -0800253 return GRPC_ERROR_NONE;
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 channel_data *chand = elem->channel_data;
Julien Boeuf9a529082015-10-08 13:12:14 -0700260 GRPC_AUTH_CONTEXT_UNREF(chand->auth_context, "server_auth_filter");
Craig Tillerbd1795c2016-10-31 15:30:00 -0700261 grpc_server_credentials_unref(exec_ctx, chand->creds);
Julien Boeufc6f8d0a2015-05-11 22:40:02 -0700262}
263
264const grpc_channel_filter grpc_server_auth_filter = {
Mark D. Roth630e26b2017-07-10 07:31:29 -0700265 auth_start_transport_stream_op_batch,
David Garcia Quintas4afce7e2016-04-18 16:25:17 -0700266 grpc_channel_next_op,
267 sizeof(call_data),
268 init_call_elem,
269 grpc_call_stack_ignore_set_pollset_or_pollset_set,
270 destroy_call_elem,
271 sizeof(channel_data),
272 init_channel_elem,
273 destroy_channel_elem,
Mark D. Rothb2d24882016-10-27 15:44:07 -0700274 grpc_channel_next_get_info,
David Garcia Quintas4afce7e2016-04-18 16:25:17 -0700275 "server-auth"};