diff options
Diffstat (limited to 'src/core/security')
-rw-r--r-- | src/core/security/client_auth_filter.c | 7 | ||||
-rw-r--r-- | src/core/security/credentials.c | 58 | ||||
-rw-r--r-- | src/core/security/credentials.h | 14 | ||||
-rw-r--r-- | src/core/security/google_default_credentials.c | 10 | ||||
-rw-r--r-- | src/core/security/jwt_verifier.c | 4 | ||||
-rw-r--r-- | src/core/security/security_connector.c | 32 | ||||
-rw-r--r-- | src/core/security/security_context.c | 132 | ||||
-rw-r--r-- | src/core/security/security_context.h | 37 | ||||
-rw-r--r-- | src/core/security/server_auth_filter.c | 146 | ||||
-rw-r--r-- | src/core/security/server_secure_chttp2.c | 14 |
10 files changed, 340 insertions, 114 deletions
diff --git a/src/core/security/client_auth_filter.c b/src/core/security/client_auth_filter.c index e86b5430b2..0e699874bc 100644 --- a/src/core/security/client_auth_filter.c +++ b/src/core/security/client_auth_filter.c @@ -77,10 +77,9 @@ typedef struct { static void bubble_up_error(grpc_call_element *elem, const char *error_msg) { call_data *calld = elem->call_data; - channel_data *chand = elem->channel_data; - grpc_transport_stream_op_add_cancellation( - &calld->op, GRPC_STATUS_UNAUTHENTICATED, - grpc_mdstr_from_string(chand->md_ctx, error_msg, 0)); + gpr_log(GPR_ERROR, "Client side authentication failure: %s", error_msg); + grpc_transport_stream_op_add_cancellation(&calld->op, + GRPC_STATUS_UNAUTHENTICATED); grpc_call_next_op(elem, &calld->op); } diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c index 15268cefbe..6421ce673d 100644 --- a/src/core/security/credentials.c +++ b/src/core/security/credentials.c @@ -149,6 +149,12 @@ grpc_security_status grpc_server_credentials_create_security_connector( return creds->vtable->create_security_connector(creds, sc); } +void grpc_server_credentials_set_auth_metadata_processor( + grpc_server_credentials *creds, grpc_auth_metadata_processor processor) { + if (creds == NULL) return; + creds->processor = processor; +} + /* -- Ssl credentials. -- */ static void ssl_destroy(grpc_credentials *creds) { @@ -679,7 +685,7 @@ static void service_account_fetch_oauth2( request.path = GRPC_GOOGLE_OAUTH2_SERVICE_TOKEN_PATH; request.hdr_count = 1; request.hdrs = &header; - request.use_ssl = 1; + request.handshaker = &grpc_httpcli_ssl; grpc_httpcli_post(httpcli_context, pollset, &request, body, strlen(body), deadline, response_cb, metadata_req); gpr_free(body); @@ -738,7 +744,7 @@ static void refresh_token_fetch_oauth2( request.path = GRPC_GOOGLE_OAUTH2_SERVICE_TOKEN_PATH; request.hdr_count = 1; request.hdrs = &header; - request.use_ssl = 1; + request.handshaker = &grpc_httpcli_ssl; grpc_httpcli_post(httpcli_context, pollset, &request, body, strlen(body), deadline, response_cb, metadata_req); gpr_free(body); @@ -765,19 +771,19 @@ grpc_credentials *grpc_refresh_token_credentials_create( grpc_auth_refresh_token_create_from_string(json_refresh_token)); } -/* -- Fake Oauth2 credentials. -- */ +/* -- Metadata-only credentials. -- */ -static void fake_oauth2_destroy(grpc_credentials *creds) { - grpc_fake_oauth2_credentials *c = (grpc_fake_oauth2_credentials *)creds; - grpc_credentials_md_store_unref(c->access_token_md); +static void md_only_test_destroy(grpc_credentials *creds) { + grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)creds; + grpc_credentials_md_store_unref(c->md_store); gpr_free(c); } -static int fake_oauth2_has_request_metadata(const grpc_credentials *creds) { +static int md_only_test_has_request_metadata(const grpc_credentials *creds) { return 1; } -static int fake_oauth2_has_request_metadata_only( +static int md_only_test_has_request_metadata_only( const grpc_credentials *creds) { return 1; } @@ -785,19 +791,19 @@ static int fake_oauth2_has_request_metadata_only( void on_simulated_token_fetch_done(void *user_data, int success) { grpc_credentials_metadata_request *r = (grpc_credentials_metadata_request *)user_data; - grpc_fake_oauth2_credentials *c = (grpc_fake_oauth2_credentials *)r->creds; + grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)r->creds; GPR_ASSERT(success); - r->cb(r->user_data, c->access_token_md->entries, - c->access_token_md->num_entries, GRPC_CREDENTIALS_OK); + r->cb(r->user_data, c->md_store->entries, + c->md_store->num_entries, GRPC_CREDENTIALS_OK); grpc_credentials_metadata_request_destroy(r); } -static void fake_oauth2_get_request_metadata(grpc_credentials *creds, +static void md_only_test_get_request_metadata(grpc_credentials *creds, grpc_pollset *pollset, const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) { - grpc_fake_oauth2_credentials *c = (grpc_fake_oauth2_credentials *)creds; + grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)creds; if (c->is_async) { grpc_credentials_metadata_request *cb_arg = @@ -806,26 +812,26 @@ static void fake_oauth2_get_request_metadata(grpc_credentials *creds, on_simulated_token_fetch_done, cb_arg); grpc_iomgr_add_callback(cb_arg->on_simulated_token_fetch_done_closure); } else { - cb(user_data, c->access_token_md->entries, 1, GRPC_CREDENTIALS_OK); + cb(user_data, c->md_store->entries, 1, GRPC_CREDENTIALS_OK); } } -static grpc_credentials_vtable fake_oauth2_vtable = { - fake_oauth2_destroy, fake_oauth2_has_request_metadata, - fake_oauth2_has_request_metadata_only, fake_oauth2_get_request_metadata, +static grpc_credentials_vtable md_only_test_vtable = { + md_only_test_destroy, md_only_test_has_request_metadata, + md_only_test_has_request_metadata_only, md_only_test_get_request_metadata, NULL}; -grpc_credentials *grpc_fake_oauth2_credentials_create( - const char *token_md_value, int is_async) { - grpc_fake_oauth2_credentials *c = - gpr_malloc(sizeof(grpc_fake_oauth2_credentials)); - memset(c, 0, sizeof(grpc_fake_oauth2_credentials)); +grpc_credentials *grpc_md_only_test_credentials_create(const char *md_key, + const char *md_value, + int is_async) { + grpc_md_only_test_credentials *c = + gpr_malloc(sizeof(grpc_md_only_test_credentials)); + memset(c, 0, sizeof(grpc_md_only_test_credentials)); c->base.type = GRPC_CREDENTIALS_TYPE_OAUTH2; - c->base.vtable = &fake_oauth2_vtable; + c->base.vtable = &md_only_test_vtable; gpr_ref_init(&c->base.refcount, 1); - c->access_token_md = grpc_credentials_md_store_create(1); - grpc_credentials_md_store_add_cstrings( - c->access_token_md, GRPC_AUTHORIZATION_METADATA_KEY, token_md_value); + c->md_store = grpc_credentials_md_store_create(1); + grpc_credentials_md_store_add_cstrings(c->md_store, md_key, md_value); c->is_async = is_async; return &c->base; } diff --git a/src/core/security/credentials.h b/src/core/security/credentials.h index 8d40da47c1..04736525dc 100644 --- a/src/core/security/credentials.h +++ b/src/core/security/credentials.h @@ -190,9 +190,10 @@ grpc_oauth2_token_fetcher_credentials_parse_server_response( grpc_credentials_md_store **token_md, gpr_timespec *token_lifetime); void grpc_flush_cached_google_default_credentials(void); -/* Simulates an oauth2 token fetch with the specified value for testing. */ -grpc_credentials *grpc_fake_oauth2_credentials_create( - const char *token_md_value, int is_async); +/* Metadata-only credentials with the specified key and value where + asynchronicity can be simulated for testing. */ +grpc_credentials *grpc_md_only_test_credentials_create( + const char *md_key, const char *md_value, int is_async); /* Private constructor for jwt credentials from an already parsed json key. Takes ownership of the key. */ @@ -216,6 +217,7 @@ typedef struct { struct grpc_server_credentials { const grpc_server_credentials_vtable *vtable; const char *type; + grpc_auth_metadata_processor processor; }; grpc_security_status grpc_server_credentials_create_security_connector( @@ -297,13 +299,13 @@ typedef struct { grpc_credentials_md_store *access_token_md; } grpc_access_token_credentials; -/* -- Fake Oauth2 credentials. -- */ +/* -- Metadata-only Test credentials. -- */ typedef struct { grpc_credentials base; - grpc_credentials_md_store *access_token_md; + grpc_credentials_md_store *md_store; int is_async; -} grpc_fake_oauth2_credentials; +} grpc_md_only_test_credentials; /* -- IAM credentials. -- */ diff --git a/src/core/security/google_default_credentials.c b/src/core/security/google_default_credentials.c index de1929fe76..d1f228665f 100644 --- a/src/core/security/google_default_credentials.c +++ b/src/core/security/google_default_credentials.c @@ -80,10 +80,12 @@ static void on_compute_engine_detection_http_response( } gpr_mu_lock(GRPC_POLLSET_MU(&detector->pollset)); detector->is_done = 1; - grpc_pollset_kick(&detector->pollset); + grpc_pollset_kick(&detector->pollset, NULL); gpr_mu_unlock(GRPC_POLLSET_MU(&detector->pollset)); } +static void destroy_pollset(void *p) { grpc_pollset_destroy(p); } + static int is_stack_running_on_compute_engine(void) { compute_engine_detector detector; grpc_httpcli_request request; @@ -112,12 +114,14 @@ static int is_stack_running_on_compute_engine(void) { called once for the lifetime of the process by the default credentials. */ gpr_mu_lock(GRPC_POLLSET_MU(&detector.pollset)); while (!detector.is_done) { - grpc_pollset_work(&detector.pollset, gpr_inf_future(GPR_CLOCK_REALTIME)); + grpc_pollset_worker worker; + grpc_pollset_work(&detector.pollset, &worker, + gpr_inf_future(GPR_CLOCK_MONOTONIC)); } gpr_mu_unlock(GRPC_POLLSET_MU(&detector.pollset)); grpc_httpcli_context_destroy(&context); - grpc_pollset_destroy(&detector.pollset); + grpc_pollset_shutdown(&detector.pollset, destroy_pollset, &detector.pollset); return detector.success; } diff --git a/src/core/security/jwt_verifier.c b/src/core/security/jwt_verifier.c index 1276693da7..38ad134a6a 100644 --- a/src/core/security/jwt_verifier.c +++ b/src/core/security/jwt_verifier.c @@ -628,7 +628,7 @@ static void on_openid_config_retrieved(void *user_data, goto error; } jwks_uri += 8; - req.use_ssl = 1; + req.handshaker = &grpc_httpcli_ssl; req.host = gpr_strdup(jwks_uri); req.path = strchr(jwks_uri, '/'); if (req.path == NULL) { @@ -685,7 +685,7 @@ static void retrieve_key_and_verify(verifier_cb_ctx *ctx) { const char *iss; grpc_httpcli_request req; memset(&req, 0, sizeof(grpc_httpcli_request)); - req.use_ssl = 1; + req.handshaker = &grpc_httpcli_ssl; GPR_ASSERT(ctx != NULL && ctx->header != NULL && ctx->claims != NULL); iss = ctx->claims->iss; diff --git a/src/core/security/security_connector.c b/src/core/security/security_connector.c index 726b4c1e12..a354536dcd 100644 --- a/src/core/security/security_connector.c +++ b/src/core/security/security_connector.c @@ -263,9 +263,9 @@ static grpc_security_status fake_check_peer(grpc_security_connector *sc, goto end; } GRPC_AUTH_CONTEXT_UNREF(sc->auth_context, "connector"); - sc->auth_context = grpc_auth_context_create(NULL, 1); - sc->auth_context->properties[0] = grpc_auth_property_init_from_cstring( - GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME, + sc->auth_context = grpc_auth_context_create(NULL); + grpc_auth_context_add_cstring_property( + sc->auth_context, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME, GRPC_FAKE_TRANSPORT_SECURITY_TYPE); end: @@ -409,31 +409,35 @@ static int ssl_host_matches_name(const tsi_peer *peer, const char *peer_name) { grpc_auth_context *tsi_ssl_peer_to_auth_context(const tsi_peer *peer) { size_t i; grpc_auth_context *ctx = NULL; + const char *peer_identity_property_name = NULL; /* The caller has checked the certificate type property. */ GPR_ASSERT(peer->property_count >= 1); - ctx = grpc_auth_context_create(NULL, peer->property_count); - ctx->properties[0] = grpc_auth_property_init_from_cstring( - GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME, + ctx = grpc_auth_context_create(NULL); + grpc_auth_context_add_cstring_property( + ctx, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME, GRPC_SSL_TRANSPORT_SECURITY_TYPE); - ctx->property_count = 1; for (i = 0; i < peer->property_count; i++) { const tsi_peer_property *prop = &peer->properties[i]; if (prop->name == NULL) continue; if (strcmp(prop->name, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY) == 0) { /* If there is no subject alt name, have the CN as the identity. */ - if (ctx->peer_identity_property_name == NULL) { - ctx->peer_identity_property_name = GRPC_X509_CN_PROPERTY_NAME; + if (peer_identity_property_name == NULL) { + peer_identity_property_name = GRPC_X509_CN_PROPERTY_NAME; } - ctx->properties[ctx->property_count++] = grpc_auth_property_init( - GRPC_X509_CN_PROPERTY_NAME, prop->value.data, prop->value.length); + grpc_auth_context_add_property(ctx, GRPC_X509_CN_PROPERTY_NAME, + prop->value.data, prop->value.length); } else if (strcmp(prop->name, TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == 0) { - ctx->peer_identity_property_name = GRPC_X509_SAN_PROPERTY_NAME; - ctx->properties[ctx->property_count++] = grpc_auth_property_init( - GRPC_X509_SAN_PROPERTY_NAME, prop->value.data, prop->value.length); + peer_identity_property_name = GRPC_X509_SAN_PROPERTY_NAME; + grpc_auth_context_add_property(ctx, GRPC_X509_SAN_PROPERTY_NAME, + prop->value.data, prop->value.length); } } + if (peer_identity_property_name != NULL) { + GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name( + ctx, peer_identity_property_name) == 1); + } return ctx; } diff --git a/src/core/security/security_context.c b/src/core/security/security_context.c index 8ce7876bd8..1ef0fc9255 100644 --- a/src/core/security/security_context.c +++ b/src/core/security/security_context.c @@ -42,6 +42,19 @@ #include <grpc/support/log.h> #include <grpc/support/string_util.h> +/* --- grpc_process_auth_metadata_func --- */ + +static grpc_auth_metadata_processor server_processor = {NULL, NULL}; + +grpc_auth_metadata_processor grpc_server_get_auth_metadata_processor(void) { + return server_processor; +} + +void grpc_server_register_auth_metadata_processor( + grpc_auth_metadata_processor processor) { + server_processor = processor; +} + /* --- grpc_call --- */ grpc_call_error grpc_call_set_credentials(grpc_call *call, @@ -120,15 +133,15 @@ void grpc_server_security_context_destroy(void *ctx) { static grpc_auth_property_iterator empty_iterator = {NULL, 0, NULL}; -grpc_auth_context *grpc_auth_context_create(grpc_auth_context *chained, - size_t property_count) { +grpc_auth_context *grpc_auth_context_create(grpc_auth_context *chained) { grpc_auth_context *ctx = gpr_malloc(sizeof(grpc_auth_context)); memset(ctx, 0, sizeof(grpc_auth_context)); - ctx->properties = gpr_malloc(property_count * sizeof(grpc_auth_property)); - memset(ctx->properties, 0, property_count * sizeof(grpc_auth_property)); - ctx->property_count = property_count; gpr_ref_init(&ctx->refcount, 1); - if (chained != NULL) ctx->chained = GRPC_AUTH_CONTEXT_REF(chained, "chained"); + if (chained != NULL) { + ctx->chained = GRPC_AUTH_CONTEXT_REF(chained, "chained"); + ctx->peer_identity_property_name = + ctx->chained->peer_identity_property_name; + } return ctx; } @@ -162,11 +175,11 @@ void grpc_auth_context_unref(grpc_auth_context *ctx) { if (gpr_unref(&ctx->refcount)) { size_t i; GRPC_AUTH_CONTEXT_UNREF(ctx->chained, "chained"); - if (ctx->properties != NULL) { - for (i = 0; i < ctx->property_count; i++) { - grpc_auth_property_reset(&ctx->properties[i]); + if (ctx->properties.array != NULL) { + for (i = 0; i < ctx->properties.count; i++) { + grpc_auth_property_reset(&ctx->properties.array[i]); } - gpr_free(ctx->properties); + gpr_free(ctx->properties.array); } gpr_free(ctx); } @@ -177,6 +190,20 @@ const char *grpc_auth_context_peer_identity_property_name( return ctx->peer_identity_property_name; } +int grpc_auth_context_set_peer_identity_property_name(grpc_auth_context *ctx, + const char *name) { + grpc_auth_property_iterator it = + grpc_auth_context_find_properties_by_name(ctx, name); + const grpc_auth_property *prop = grpc_auth_property_iterator_next(&it); + if (prop == NULL) { + gpr_log(GPR_ERROR, "Property name %s not found in auth context.", + name != NULL ? name : "NULL"); + return 0; + } + ctx->peer_identity_property_name = prop->name; + return 1; +} + int grpc_auth_context_peer_is_authenticated( const grpc_auth_context *ctx) { return ctx->peer_identity_property_name == NULL ? 0 : 1; @@ -193,16 +220,16 @@ grpc_auth_property_iterator grpc_auth_context_property_iterator( const grpc_auth_property *grpc_auth_property_iterator_next( grpc_auth_property_iterator *it) { if (it == NULL || it->ctx == NULL) return NULL; - while (it->index == it->ctx->property_count) { + while (it->index == it->ctx->properties.count) { if (it->ctx->chained == NULL) return NULL; it->ctx = it->ctx->chained; it->index = 0; } if (it->name == NULL) { - return &it->ctx->properties[it->index++]; + return &it->ctx->properties.array[it->index++]; } else { - while (it->index < it->ctx->property_count) { - const grpc_auth_property *prop = &it->ctx->properties[it->index++]; + while (it->index < it->ctx->properties.count) { + const grpc_auth_property *prop = &it->ctx->properties.array[it->index++]; GPR_ASSERT(prop->name != NULL); if (strcmp(it->name, prop->name) == 0) { return prop; @@ -229,24 +256,37 @@ grpc_auth_property_iterator grpc_auth_context_peer_identity( ctx, ctx->peer_identity_property_name); } -grpc_auth_property grpc_auth_property_init_from_cstring(const char *name, - const char *value) { - grpc_auth_property prop; - prop.name = gpr_strdup(name); - prop.value = gpr_strdup(value); - prop.value_length = strlen(value); - return prop; +static void ensure_auth_context_capacity(grpc_auth_context *ctx) { + if (ctx->properties.count == ctx->properties.capacity) { + ctx->properties.capacity = + GPR_MAX(ctx->properties.capacity + 8, ctx->properties.capacity * 2); + ctx->properties.array = + gpr_realloc(ctx->properties.array, + ctx->properties.capacity * sizeof(grpc_auth_property)); + } } -grpc_auth_property grpc_auth_property_init(const char *name, const char *value, - size_t value_length) { - grpc_auth_property prop; - prop.name = gpr_strdup(name); - prop.value = gpr_malloc(value_length + 1); - memcpy(prop.value, value, value_length); - prop.value[value_length] = '\0'; - prop.value_length = value_length; - return prop; +void grpc_auth_context_add_property(grpc_auth_context *ctx, const char *name, + const char *value, size_t value_length) { + grpc_auth_property *prop; + ensure_auth_context_capacity(ctx); + prop = &ctx->properties.array[ctx->properties.count++]; + prop->name = gpr_strdup(name); + prop->value = gpr_malloc(value_length + 1); + memcpy(prop->value, value, value_length); + prop->value[value_length] = '\0'; + prop->value_length = value_length; +} + +void grpc_auth_context_add_cstring_property(grpc_auth_context *ctx, + const char *name, + const char *value) { + grpc_auth_property *prop; + ensure_auth_context_capacity(ctx); + prop = &ctx->properties.array[ctx->properties.count++]; + prop->name = gpr_strdup(name); + prop->value = gpr_strdup(value); + prop->value_length = strlen(value); } void grpc_auth_property_reset(grpc_auth_property *property) { @@ -255,3 +295,35 @@ void grpc_auth_property_reset(grpc_auth_property *property) { memset(property, 0, sizeof(grpc_auth_property)); } +grpc_arg grpc_auth_metadata_processor_to_arg(grpc_auth_metadata_processor *p) { + grpc_arg arg; + memset(&arg, 0, sizeof(grpc_arg)); + arg.type = GRPC_ARG_POINTER; + arg.key = GRPC_AUTH_METADATA_PROCESSOR_ARG; + arg.value.pointer.p = p; + return arg; +} + +grpc_auth_metadata_processor *grpc_auth_metadata_processor_from_arg( + const grpc_arg *arg) { + if (strcmp(arg->key, GRPC_AUTH_METADATA_PROCESSOR_ARG) != 0) return NULL; + if (arg->type != GRPC_ARG_POINTER) { + gpr_log(GPR_ERROR, "Invalid type %d for arg %s", arg->type, + GRPC_AUTH_METADATA_PROCESSOR_ARG); + return NULL; + } + return arg->value.pointer.p; +} + +grpc_auth_metadata_processor *grpc_find_auth_metadata_processor_in_args( + const grpc_channel_args *args) { + size_t i; + if (args == NULL) return NULL; + for (i = 0; i < args->num_args; i++) { + grpc_auth_metadata_processor *p = + grpc_auth_metadata_processor_from_arg(&args->args[i]); + if (p != NULL) return p; + } + return NULL; +} + diff --git a/src/core/security/security_context.h b/src/core/security/security_context.h index 76a45910bb..7fcd438cf6 100644 --- a/src/core/security/security_context.h +++ b/src/core/security/security_context.h @@ -34,29 +34,31 @@ #ifndef GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONTEXT_H #define GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONTEXT_H +#include "src/core/iomgr/pollset.h" #include "src/core/security/credentials.h" -#ifdef __cplusplus -extern "C" { -#endif - /* --- grpc_auth_context --- High level authentication context object. Can optionally be chained. */ /* Property names are always NULL terminated. */ +typedef struct { + grpc_auth_property *array; + size_t count; + size_t capacity; +} grpc_auth_property_array; + struct grpc_auth_context { struct grpc_auth_context *chained; - grpc_auth_property *properties; - size_t property_count; + grpc_auth_property_array properties; gpr_refcount refcount; const char *peer_identity_property_name; + grpc_pollset *pollset; }; -/* Constructor. */ -grpc_auth_context *grpc_auth_context_create(grpc_auth_context *chained, - size_t property_count); +/* Creation. */ +grpc_auth_context *grpc_auth_context_create(grpc_auth_context *chained); /* Refcounting. */ #ifdef GRPC_AUTH_CONTEXT_REFCOUNT_DEBUG @@ -76,12 +78,6 @@ grpc_auth_context *grpc_auth_context_ref(grpc_auth_context *policy); void grpc_auth_context_unref(grpc_auth_context *policy); #endif -grpc_auth_property grpc_auth_property_init_from_cstring(const char *name, - const char *value); - -grpc_auth_property grpc_auth_property_init(const char *name, const char *value, - size_t value_length); - void grpc_auth_property_reset(grpc_auth_property *property); /* --- grpc_client_security_context --- @@ -107,9 +103,14 @@ typedef struct { grpc_server_security_context *grpc_server_security_context_create(void); void grpc_server_security_context_destroy(void *ctx); -#ifdef __cplusplus -} -#endif +/* --- Auth metadata processing. --- */ +#define GRPC_AUTH_METADATA_PROCESSOR_ARG "grpc.auth_metadata_processor" + +grpc_arg grpc_auth_metadata_processor_to_arg(grpc_auth_metadata_processor *p); +grpc_auth_metadata_processor *grpc_auth_metadata_processor_from_arg( + const grpc_arg *arg); +grpc_auth_metadata_processor *grpc_find_auth_metadata_processor_in_args( + const grpc_channel_args *args); #endif /* GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONTEXT_H */ diff --git a/src/core/security/server_auth_filter.c b/src/core/security/server_auth_filter.c index 69789c2f0d..2fc689caec 100644 --- a/src/core/security/server_auth_filter.c +++ b/src/core/security/server_auth_filter.c @@ -31,20 +31,140 @@ * */ +#include <string.h> + #include "src/core/security/auth_filters.h" #include "src/core/security/security_connector.h" #include "src/core/security/security_context.h" +#include <grpc/support/alloc.h> #include <grpc/support/log.h> typedef struct call_data { - int unused; /* C89 requires at least one struct element */ + gpr_uint8 got_client_metadata; + grpc_stream_op_buffer *recv_ops; + /* Closure to call when finished with the auth_on_recv hook. */ + grpc_iomgr_closure *on_done_recv; + /* Receive closures are chained: we inject this closure as the on_done_recv + up-call on transport_op, and remember to call our on_done_recv member after + handling it. */ + grpc_iomgr_closure auth_on_recv; + grpc_transport_stream_op transport_op; + const grpc_metadata *consumed_md; + size_t num_consumed_md; + grpc_stream_op *md_op; + grpc_auth_context *auth_context; } call_data; typedef struct channel_data { grpc_security_connector *security_connector; + grpc_auth_metadata_processor processor; + grpc_mdctx *mdctx; } channel_data; +static grpc_metadata_array metadata_batch_to_md_array( + const grpc_metadata_batch *batch) { + grpc_linked_mdelem *l; + grpc_metadata_array result; + grpc_metadata_array_init(&result); + for (l = batch->list.head; l != NULL; l = l->next) { + grpc_metadata *usr_md = NULL; + grpc_mdelem *md = l->md; + grpc_mdstr *key = md->key; + grpc_mdstr *value = md->value; + if (result.count == result.capacity) { + result.capacity = GPR_MAX(result.capacity + 8, result.capacity * 2); + result.metadata = + gpr_realloc(result.metadata, result.capacity * sizeof(grpc_metadata)); + } + usr_md = &result.metadata[result.count++]; + usr_md->key = grpc_mdstr_as_c_string(key); + usr_md->value = grpc_mdstr_as_c_string(value); + usr_md->value_length = GPR_SLICE_LENGTH(value->slice); + } + return result; +} + +static grpc_mdelem *remove_consumed_md(void *user_data, grpc_mdelem *md) { + grpc_call_element *elem = user_data; + call_data *calld = elem->call_data; + size_t i; + for (i = 0; i < calld->num_consumed_md; i++) { + /* Maybe we could do a pointer comparison but we do not have any guarantee + that the metadata processor used the same pointers for consumed_md in the + callback. */ + if (memcmp(GPR_SLICE_START_PTR(md->key->slice), calld->consumed_md[i].key, + GPR_SLICE_LENGTH(md->key->slice)) == 0 && + memcmp(GPR_SLICE_START_PTR(md->value->slice), + calld->consumed_md[i].value, + GPR_SLICE_LENGTH(md->value->slice)) == 0) { + return NULL; /* Delete. */ + } + } + return md; +} + +static void on_md_processing_done(void *user_data, + const grpc_metadata *consumed_md, + size_t num_consumed_md, int success) { + grpc_call_element *elem = user_data; + call_data *calld = elem->call_data; + + if (success) { + calld->consumed_md = consumed_md; + calld->num_consumed_md = num_consumed_md; + grpc_metadata_batch_filter(&calld->md_op->data.metadata, remove_consumed_md, + elem); + calld->on_done_recv->cb(calld->on_done_recv->cb_arg, success); + } else { + gpr_slice message = gpr_slice_from_copied_string( + "Authentication metadata processing failed."); + grpc_sopb_reset(calld->recv_ops); + grpc_transport_stream_op_add_close(&calld->transport_op, + GRPC_STATUS_UNAUTHENTICATED, &message); + grpc_call_next_op(elem, &calld->transport_op); + } +} + +static void auth_on_recv(void *user_data, int success) { + grpc_call_element *elem = user_data; + call_data *calld = elem->call_data; + channel_data *chand = elem->channel_data; + if (success) { + size_t i; + size_t nops = calld->recv_ops->nops; + grpc_stream_op *ops = calld->recv_ops->ops; + for (i = 0; i < nops; i++) { + grpc_metadata_array md_array; + grpc_stream_op *op = &ops[i]; + if (op->type != GRPC_OP_METADATA || calld->got_client_metadata) continue; + calld->got_client_metadata = 1; + if (chand->processor.process == NULL) continue; + calld->md_op = op; + md_array = metadata_batch_to_md_array(&op->data.metadata); + chand->processor.process(chand->processor.state, calld->auth_context, + md_array.metadata, md_array.count, + on_md_processing_done, elem); + grpc_metadata_array_destroy(&md_array); + return; + } + } + calld->on_done_recv->cb(calld->on_done_recv->cb_arg, success); +} + +static void set_recv_ops_md_callbacks(grpc_call_element *elem, + grpc_transport_stream_op *op) { + call_data *calld = elem->call_data; + + if (op->recv_ops && !calld->got_client_metadata) { + /* substitute our callback for the higher callback */ + calld->recv_ops = op->recv_ops; + calld->on_done_recv = op->on_done_recv; + op->on_done_recv = &calld->auth_on_recv; + calld->transport_op = *op; + } +} + /* 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 @@ -52,9 +172,7 @@ typedef struct channel_data { that is being sent or received. */ static void auth_start_transport_op(grpc_call_element *elem, grpc_transport_stream_op *op) { - /* TODO(jboeuf): Get the metadata and get a new context from it. */ - - /* pass control down the stack */ + set_recv_ops_md_callbacks(elem, op); grpc_call_next_op(elem, op); } @@ -68,7 +186,8 @@ static void init_call_elem(grpc_call_element *elem, grpc_server_security_context *server_ctx = NULL; /* initialize members */ - calld->unused = 0; + memset(calld, 0, sizeof(*calld)); + grpc_iomgr_closure_init(&calld->auth_on_recv, auth_on_recv, elem); GPR_ASSERT(initial_op && initial_op->context != NULL && initial_op->context[GRPC_CONTEXT_SECURITY].value == NULL); @@ -80,21 +199,29 @@ static void init_call_elem(grpc_call_element *elem, initial_op->context[GRPC_CONTEXT_SECURITY].value); } server_ctx = grpc_server_security_context_create(); - server_ctx->auth_context = GRPC_AUTH_CONTEXT_REF( - chand->security_connector->auth_context, "server_security_context"); + server_ctx->auth_context = + grpc_auth_context_create(chand->security_connector->auth_context); + server_ctx->auth_context->pollset = initial_op->bind_pollset; initial_op->context[GRPC_CONTEXT_SECURITY].value = server_ctx; initial_op->context[GRPC_CONTEXT_SECURITY].destroy = grpc_server_security_context_destroy; + calld->auth_context = server_ctx->auth_context; + + /* Set the metadata callbacks. */ + set_recv_ops_md_callbacks(elem, initial_op); } /* Destructor for call_data */ -static void destroy_call_elem(grpc_call_element *elem) {} +static void destroy_call_elem(grpc_call_element *elem) { +} /* Constructor for channel_data */ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master, const grpc_channel_args *args, grpc_mdctx *mdctx, int is_first, int is_last) { grpc_security_connector *sc = grpc_find_security_connector_in_args(args); + grpc_auth_metadata_processor *processor = + grpc_find_auth_metadata_processor_in_args(args); /* grab pointers to our data from the channel element */ channel_data *chand = elem->channel_data; @@ -104,11 +231,14 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master, GPR_ASSERT(!is_first); GPR_ASSERT(!is_last); GPR_ASSERT(sc != NULL); + GPR_ASSERT(processor != NULL); /* initialize members */ GPR_ASSERT(!sc->is_client_side); chand->security_connector = GRPC_SECURITY_CONNECTOR_REF(sc, "server_auth_filter"); + chand->mdctx = mdctx; + chand->processor = *processor; } /* Destructor for channel data */ diff --git a/src/core/security/server_secure_chttp2.c b/src/core/security/server_secure_chttp2.c index 3717b8989f..8d9d036d80 100644 --- a/src/core/security/server_secure_chttp2.c +++ b/src/core/security/server_secure_chttp2.c @@ -43,6 +43,7 @@ #include "src/core/security/auth_filters.h" #include "src/core/security/credentials.h" #include "src/core/security/security_connector.h" +#include "src/core/security/security_context.h" #include "src/core/security/secure_transport_setup.h" #include "src/core/surface/server.h" #include "src/core/transport/chttp2_transport.h" @@ -60,6 +61,7 @@ typedef struct grpc_server_secure_state { grpc_server *server; grpc_tcp_server *tcp; grpc_security_connector *sc; + grpc_auth_metadata_processor processor; tcp_endpoint_list *handshaking_tcp_endpoints; int is_shutdown; gpr_mu mu; @@ -86,9 +88,13 @@ static void setup_transport(void *statep, grpc_transport *transport, static grpc_channel_filter const *extra_filters[] = { &grpc_server_auth_filter, &grpc_http_server_filter}; grpc_server_secure_state *state = statep; - grpc_arg connector_arg = grpc_security_connector_to_arg(state->sc); - grpc_channel_args *args_copy = grpc_channel_args_copy_and_add( - grpc_server_get_channel_args(state->server), &connector_arg, 1); + grpc_channel_args *args_copy; + grpc_arg args_to_add[2]; + args_to_add[0] = grpc_security_connector_to_arg(state->sc); + args_to_add[1] = grpc_auth_metadata_processor_to_arg(&state->processor); + args_copy = grpc_channel_args_copy_and_add( + grpc_server_get_channel_args(state->server), args_to_add, + GPR_ARRAY_SIZE(args_to_add)); grpc_server_setup_transport(state->server, transport, extra_filters, GPR_ARRAY_SIZE(extra_filters), mdctx, args_copy); grpc_channel_args_destroy(args_copy); @@ -252,9 +258,11 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr, grpc_resolved_addresses_destroy(resolved); state = gpr_malloc(sizeof(*state)); + memset(state, 0, sizeof(*state)); state->server = server; state->tcp = tcp; state->sc = sc; + state->processor = creds->processor; state->handshaking_tcp_endpoints = NULL; state->is_shutdown = 0; gpr_mu_init(&state->mu); |