aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/security/auth.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/security/auth.c')
-rw-r--r--src/core/security/auth.c130
1 files changed, 111 insertions, 19 deletions
diff --git a/src/core/security/auth.c b/src/core/security/auth.c
index 9d0c075bc3..18c32f90f4 100644
--- a/src/core/security/auth.c
+++ b/src/core/security/auth.c
@@ -35,22 +35,49 @@
#include <string.h>
-#include "src/core/security/security_context.h"
-#include "src/core/security/credentials.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+#include "src/core/support/string.h"
+#include "src/core/channel/channel_stack.h"
+#include "src/core/security/security_context.h"
+#include "src/core/security/credentials.h"
+#include "src/core/surface/call.h"
+
/* We can have a per-call credentials. */
typedef struct {
grpc_credentials *creds;
+ grpc_mdstr *host;
grpc_call_op op;
} call_data;
/* We can have a per-channel credentials. */
typedef struct {
grpc_channel_security_context *security_context;
+ grpc_mdctx *md_ctx;
+ grpc_mdstr *authority_string;
+ grpc_mdstr *error_msg_key;
} channel_data;
+static void do_nothing(void *ignored, grpc_op_error error) {}
+
+static void bubbleup_error(grpc_call_element *elem, const char *error_msg) {
+ grpc_call_op finish_op;
+ channel_data *channeld = elem->channel_data;
+
+ gpr_log(GPR_ERROR, "%s", error_msg);
+ finish_op.type = GRPC_RECV_METADATA;
+ finish_op.dir = GRPC_CALL_UP;
+ finish_op.flags = 0;
+ finish_op.data.metadata = grpc_mdelem_from_metadata_strings(
+ channeld->md_ctx, channeld->error_msg_key,
+ grpc_mdstr_from_string(channeld->md_ctx, error_msg));
+ finish_op.done_cb = do_nothing;
+ finish_op.user_data = NULL;
+ grpc_call_next_op(elem, &finish_op);
+ grpc_call_element_send_cancel(elem);
+}
+
static void on_credentials_metadata(void *user_data, grpc_mdelem **md_elems,
size_t num_md,
grpc_credentials_status status) {
@@ -62,6 +89,46 @@ static void on_credentials_metadata(void *user_data, grpc_mdelem **md_elems,
grpc_call_next_op(elem, &((call_data *)elem->call_data)->op);
}
+static void send_security_metadata(grpc_call_element *elem, grpc_call_op *op) {
+ /* grab pointers to our data from the call element */
+ call_data *calld = elem->call_data;
+ channel_data *channeld = elem->channel_data;
+
+ grpc_credentials *channel_creds =
+ channeld->security_context->request_metadata_creds;
+ /* TODO(jboeuf):
+ Decide on the policy in this case:
+ - populate both channel and call?
+ - the call takes precedence over the channel?
+ - leave this decision up to the channel credentials? */
+ if (calld->creds != NULL) {
+ gpr_log(GPR_ERROR, "Ignoring per call credentials for now.");
+ }
+ if (channel_creds != NULL &&
+ grpc_credentials_has_request_metadata(channel_creds)) {
+ calld->op = *op; /* Copy op (originates from the caller's stack). */
+ grpc_credentials_get_request_metadata(channel_creds,
+ on_credentials_metadata, elem);
+ } else {
+ grpc_call_next_op(elem, op);
+ }
+}
+
+static void on_host_checked(void *user_data, grpc_security_status status) {
+ grpc_call_element *elem = (grpc_call_element *)user_data;
+ call_data *calld = elem->call_data;
+
+ if (status == GRPC_SECURITY_OK) {
+ send_security_metadata(elem, &calld->op);
+ } else {
+ char *error_msg;
+ gpr_asprintf(&error_msg, "Invalid host %s set in :authority metadata.",
+ grpc_mdstr_as_c_string(calld->host));
+ bubbleup_error(elem, error_msg);
+ gpr_free(error_msg);
+ }
+}
+
/* Called either:
- in response to an API call (or similar) from above, to send something
- a network event (or similar) from below, to receive something
@@ -74,26 +141,36 @@ static void call_op(grpc_call_element *elem, grpc_call_element *from_elem,
channel_data *channeld = elem->channel_data;
switch (op->type) {
- case GRPC_SEND_START: {
- grpc_credentials *channel_creds =
- channeld->security_context->request_metadata_creds;
- /* TODO(jboeuf):
- Decide on the policy in this case:
- - populate both channel and call?
- - the call takes precedence over the channel?
- - leave this decision up to the channel credentials? */
- if (calld->creds != NULL) {
- gpr_log(GPR_ERROR, "Ignoring per call credentials for now.");
+ case GRPC_SEND_METADATA:
+ /* Pointer comparison is OK for md_elems created from the same context. */
+ if (op->data.metadata->key == channeld->authority_string) {
+ if (calld->host != NULL) grpc_mdstr_unref(calld->host);
+ calld->host = grpc_mdstr_ref(op->data.metadata->value);
}
- if (channel_creds != NULL &&
- grpc_credentials_has_request_metadata(channel_creds)) {
+ grpc_call_next_op(elem, op);
+ break;
+
+ case GRPC_SEND_START:
+ if (calld->host != NULL) {
+ grpc_security_status status;
+ const char *call_host = grpc_mdstr_as_c_string(calld->host);
calld->op = *op; /* Copy op (originates from the caller's stack). */
- grpc_credentials_get_request_metadata(channel_creds,
- on_credentials_metadata, elem);
- break;
+ status = grpc_channel_security_context_check_call_host(
+ channeld->security_context, call_host, on_host_checked, elem);
+ if (status != GRPC_SECURITY_OK) {
+ if (status == GRPC_SECURITY_ERROR) {
+ char *error_msg;
+ gpr_asprintf(&error_msg,
+ "Invalid host %s set in :authority metadata.",
+ call_host);
+ bubbleup_error(elem, error_msg);
+ gpr_free(error_msg);
+ }
+ break;
+ }
}
- /* FALLTHROUGH INTENDED. */
- }
+ send_security_metadata(elem, op);
+ break;
default:
/* pass control up or down the stack depending on op->dir */
@@ -116,6 +193,7 @@ static void init_call_elem(grpc_call_element *elem,
Find a way to pass-in the credentials from the caller here. */
call_data *calld = elem->call_data;
calld->creds = NULL;
+ calld->host = NULL;
}
/* Destructor for call_data */
@@ -124,6 +202,9 @@ static void destroy_call_elem(grpc_call_element *elem) {
if (calld->creds != NULL) {
grpc_credentials_unref(calld->creds);
}
+ if (calld->host != NULL) {
+ grpc_mdstr_unref(calld->host);
+ }
}
/* Constructor for channel_data */
@@ -146,6 +227,11 @@ static void init_channel_elem(grpc_channel_element *elem,
GPR_ASSERT(ctx->is_client_side);
channeld->security_context =
(grpc_channel_security_context *)grpc_security_context_ref(ctx);
+ channeld->md_ctx = metadata_context;
+ channeld->authority_string =
+ grpc_mdstr_from_string(channeld->md_ctx, ":authority");
+ channeld->error_msg_key =
+ grpc_mdstr_from_string(channeld->md_ctx, "grpc-message");
}
/* Destructor for channel data */
@@ -154,6 +240,12 @@ static void destroy_channel_elem(grpc_channel_element *elem) {
channel_data *channeld = elem->channel_data;
grpc_channel_security_context *ctx = channeld->security_context;
if (ctx != NULL) grpc_security_context_unref(&ctx->base);
+ if (channeld->authority_string != NULL) {
+ grpc_mdstr_unref(channeld->authority_string);
+ }
+ if (channeld->error_msg_key != NULL) {
+ grpc_mdstr_unref(channeld->error_msg_key);
+ }
}
const grpc_channel_filter grpc_client_auth_filter = {