diff options
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/channel/context.h | 7 | ||||
-rw-r--r-- | src/core/security/auth_filters.h (renamed from src/core/security/auth.h) | 7 | ||||
-rw-r--r-- | src/core/security/client_auth_filter.c (renamed from src/core/security/auth.c) | 26 | ||||
-rw-r--r-- | src/core/security/credentials.c | 235 | ||||
-rw-r--r-- | src/core/security/credentials.h | 44 | ||||
-rw-r--r-- | src/core/security/credentials_metadata.c | 101 | ||||
-rw-r--r-- | src/core/security/security_connector.c | 75 | ||||
-rw-r--r-- | src/core/security/security_connector.h | 1 | ||||
-rw-r--r-- | src/core/security/security_context.c | 150 | ||||
-rw-r--r-- | src/core/security/security_context.h | 48 | ||||
-rw-r--r-- | src/core/security/server_auth_filter.c | 128 | ||||
-rw-r--r-- | src/core/security/server_secure_chttp2.c | 25 | ||||
-rw-r--r-- | src/core/surface/call.c | 22 | ||||
-rw-r--r-- | src/core/surface/secure_channel_create.c | 4 | ||||
-rw-r--r-- | src/core/surface/server.c | 6 | ||||
-rw-r--r-- | src/core/surface/server.h | 2 | ||||
-rw-r--r-- | src/core/surface/server_chttp2.c | 3 | ||||
-rw-r--r-- | src/core/transport/metadata.h | 2 | ||||
-rw-r--r-- | src/core/transport/transport.h | 3 |
19 files changed, 706 insertions, 183 deletions
diff --git a/src/core/channel/context.h b/src/core/channel/context.h index e2e5e80513..ac5796b9ef 100644 --- a/src/core/channel/context.h +++ b/src/core/channel/context.h @@ -41,4 +41,9 @@ typedef enum { GRPC_CONTEXT_COUNT } grpc_context_index; -#endif +typedef struct { + void *value; + void (*destroy)(void *); +} grpc_call_context_element; + +#endif /* GRPC_INTERNAL_CORE_CHANNEL_CONTEXT_H */ diff --git a/src/core/security/auth.h b/src/core/security/auth_filters.h index 08dc4152ba..ff921690e0 100644 --- a/src/core/security/auth.h +++ b/src/core/security/auth_filters.h @@ -31,11 +31,12 @@ * */ -#ifndef GRPC_INTERNAL_CORE_SECURITY_AUTH_H -#define GRPC_INTERNAL_CORE_SECURITY_AUTH_H +#ifndef GRPC_INTERNAL_CORE_SECURITY_AUTH_FILTERS_H +#define GRPC_INTERNAL_CORE_SECURITY_AUTH_FILTERS_H #include "src/core/channel/channel_stack.h" extern const grpc_channel_filter grpc_client_auth_filter; +extern const grpc_channel_filter grpc_server_auth_filter; -#endif /* GRPC_INTERNAL_CORE_SECURITY_AUTH_H */ +#endif /* GRPC_INTERNAL_CORE_SECURITY_AUTH_FILTERS_H */ diff --git a/src/core/security/auth.c b/src/core/security/client_auth_filter.c index faf12d8f14..b2bce1fd32 100644 --- a/src/core/security/auth.c +++ b/src/core/security/client_auth_filter.c @@ -31,7 +31,7 @@ * */ -#include "src/core/security/auth.h" +#include "src/core/security/auth_filters.h" #include <string.h> @@ -77,11 +77,13 @@ static void bubble_up_error(grpc_call_element *elem, const char *error_msg) { grpc_call_next_op(elem, &calld->op); } -static void on_credentials_metadata(void *user_data, grpc_mdelem **md_elems, +static void on_credentials_metadata(void *user_data, + grpc_credentials_md *md_elems, size_t num_md, grpc_credentials_status status) { grpc_call_element *elem = (grpc_call_element *)user_data; call_data *calld = elem->call_data; + channel_data *chand = elem->channel_data; grpc_transport_op *op = &calld->op; grpc_metadata_batch *mdb; size_t i; @@ -94,8 +96,10 @@ static void on_credentials_metadata(void *user_data, grpc_mdelem **md_elems, op->send_ops->ops[calld->op_md_idx].type == GRPC_OP_METADATA); mdb = &op->send_ops->ops[calld->op_md_idx].data.metadata; for (i = 0; i < num_md; i++) { - grpc_metadata_batch_add_tail(mdb, &calld->md_links[i], - grpc_mdelem_ref(md_elems[i])); + grpc_metadata_batch_add_tail( + mdb, &calld->md_links[i], + grpc_mdelem_from_slices(chand->md_ctx, gpr_slice_ref(md_elems[i].key), + gpr_slice_ref(md_elems[i].value))); } grpc_call_next_op(elem, op); } @@ -125,7 +129,7 @@ static void send_security_metadata(grpc_call_element *elem, call_data *calld = elem->call_data; channel_data *chand = elem->channel_data; grpc_client_security_context *ctx = - (grpc_client_security_context *)op->context[GRPC_CONTEXT_SECURITY]; + (grpc_client_security_context *)op->context[GRPC_CONTEXT_SECURITY].value; char *service_url = NULL; grpc_credentials *channel_creds = chand->security_connector->request_metadata_creds; @@ -189,6 +193,8 @@ static void auth_start_transport_op(grpc_call_element *elem, grpc_linked_mdelem *l; size_t i; + /* TODO(jboeuf): write the call auth context. */ + if (op->send_ops && !calld->sent_initial_metadata) { size_t nops = op->send_ops->nops; grpc_stream_op *ops = op->send_ops->ops; @@ -273,7 +279,7 @@ static void init_channel_elem(grpc_channel_element *elem, const grpc_channel_args *args, grpc_mdctx *metadata_context, int is_first, int is_last) { - grpc_security_connector *ctx = grpc_find_security_connector_in_args(args); + grpc_security_connector *sc = grpc_find_security_connector_in_args(args); /* grab pointers to our data from the channel element */ channel_data *chand = elem->channel_data; @@ -282,12 +288,12 @@ static void init_channel_elem(grpc_channel_element *elem, path */ GPR_ASSERT(!is_first); GPR_ASSERT(!is_last); - GPR_ASSERT(ctx != NULL); + GPR_ASSERT(sc != NULL); /* initialize members */ - GPR_ASSERT(ctx->is_client_side); + GPR_ASSERT(sc->is_client_side); chand->security_connector = - (grpc_channel_security_connector *)grpc_security_connector_ref(ctx); + (grpc_channel_security_connector *)grpc_security_connector_ref(sc); chand->md_ctx = metadata_context; chand->authority_string = grpc_mdstr_from_string(chand->md_ctx, ":authority"); @@ -321,4 +327,4 @@ static void destroy_channel_elem(grpc_channel_element *elem) { const grpc_channel_filter grpc_client_auth_filter = { auth_start_transport_op, channel_op, sizeof(call_data), init_call_elem, destroy_call_elem, sizeof(channel_data), init_channel_elem, - destroy_channel_elem, "auth"}; + destroy_channel_elem, "client-auth"}; diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c index 0305726663..ae02949670 100644 --- a/src/core/security/credentials.c +++ b/src/core/security/credentials.c @@ -114,20 +114,6 @@ void grpc_credentials_get_request_metadata(grpc_credentials *creds, creds->vtable->get_request_metadata(creds, service_url, cb, user_data); } -grpc_mdctx *grpc_credentials_get_or_create_metadata_context( - grpc_credentials *creds) { - grpc_mdctx *mdctx = NULL; - if (creds != NULL && creds->vtable->get_metadata_context != NULL) { - mdctx = creds->vtable->get_metadata_context(creds); - } - if (mdctx == NULL) { - return grpc_mdctx_create(); - } else { - grpc_mdctx_ref(mdctx); - return mdctx; - } -} - grpc_security_status grpc_credentials_create_security_connector( grpc_credentials *creds, const char *target, const grpc_channel_args *args, grpc_credentials *request_metadata_creds, @@ -206,10 +192,6 @@ static int ssl_has_request_metadata_only(const grpc_credentials *creds) { return 0; } -static grpc_mdctx *ssl_get_metadata_context(grpc_credentials *creds) { - return NULL; -} - static grpc_security_status ssl_create_security_connector( grpc_credentials *creds, const char *target, const grpc_channel_args *args, grpc_credentials *request_metadata_creds, @@ -246,12 +228,18 @@ static grpc_security_status ssl_server_create_security_connector( return grpc_ssl_server_security_connector_create(&c->config, sc); } +<<<<<<< HEAD static grpc_credentials_vtable ssl_vtable = {ssl_destroy, ssl_has_request_metadata, ssl_has_request_metadata_only, ssl_get_metadata_context, NULL, ssl_create_security_connector}; +======= +static grpc_credentials_vtable ssl_vtable = { + ssl_destroy, ssl_has_request_metadata, ssl_has_request_metadata_only, NULL, + ssl_create_security_connector}; +>>>>>>> a2779c122ec3b2c3b6a475afa2ed18145d1f1b61 static grpc_server_credentials_vtable ssl_server_vtable = { ssl_server_destroy, ssl_server_create_security_connector}; @@ -342,13 +330,12 @@ grpc_server_credentials *grpc_ssl_server_credentials_create( typedef struct { grpc_credentials base; - grpc_mdctx *md_ctx; /* Have a simple cache for now with just 1 entry. We could have a map based on the service_url for a more sophisticated one. */ gpr_mu cache_mu; struct { - grpc_mdelem *jwt_md; + grpc_credentials_md_store *jwt_md; char *service_url; gpr_timespec jwt_expiration; } cached; @@ -359,7 +346,7 @@ typedef struct { static void jwt_reset_cache(grpc_jwt_credentials *c) { if (c->cached.jwt_md != NULL) { - grpc_mdelem_unref(c->cached.jwt_md); + grpc_credentials_md_store_unref(c->cached.jwt_md); c->cached.jwt_md = NULL; } if (c->cached.service_url != NULL) { @@ -374,7 +361,6 @@ static void jwt_destroy(grpc_credentials *creds) { grpc_auth_json_key_destruct(&c->key); jwt_reset_cache(c); gpr_mu_destroy(&c->cache_mu); - grpc_mdctx_unref(c->md_ctx); gpr_free(c); } @@ -393,7 +379,7 @@ static void jwt_get_request_metadata(grpc_credentials *creds, 0}; /* See if we can return a cached jwt. */ - grpc_mdelem *jwt_md = NULL; + grpc_credentials_md_store *jwt_md = NULL; { gpr_mu_lock(&c->cache_mu); if (c->cached.service_url != NULL && @@ -401,7 +387,7 @@ static void jwt_get_request_metadata(grpc_credentials *creds, c->cached.jwt_md != NULL && (gpr_time_cmp(gpr_time_sub(c->cached.jwt_expiration, gpr_now()), refresh_threshold) > 0)) { - jwt_md = grpc_mdelem_ref(c->cached.jwt_md); + jwt_md = grpc_credentials_md_store_ref(c->cached.jwt_md); } gpr_mu_unlock(&c->cache_mu); } @@ -418,22 +404,24 @@ static void jwt_get_request_metadata(grpc_credentials *creds, gpr_free(jwt); c->cached.jwt_expiration = gpr_time_add(gpr_now(), c->jwt_lifetime); c->cached.service_url = gpr_strdup(service_url); - c->cached.jwt_md = grpc_mdelem_from_strings( - c->md_ctx, GRPC_AUTHORIZATION_METADATA_KEY, md_value); + c->cached.jwt_md = grpc_credentials_md_store_create(1); + grpc_credentials_md_store_add_cstrings( + c->cached.jwt_md, GRPC_AUTHORIZATION_METADATA_KEY, md_value); gpr_free(md_value); - jwt_md = grpc_mdelem_ref(c->cached.jwt_md); + jwt_md = grpc_credentials_md_store_ref(c->cached.jwt_md); } gpr_mu_unlock(&c->cache_mu); } if (jwt_md != NULL) { - cb(user_data, &jwt_md, 1, GRPC_CREDENTIALS_OK); - grpc_mdelem_unref(jwt_md); + cb(user_data, jwt_md->entries, jwt_md->num_entries, GRPC_CREDENTIALS_OK); + grpc_credentials_md_store_unref(jwt_md); } else { cb(user_data, NULL, 0, GRPC_CREDENTIALS_ERROR); } } +<<<<<<< HEAD static grpc_mdctx *jwt_get_metadata_context(grpc_credentials *creds) { grpc_jwt_credentials *c = (grpc_jwt_credentials *)creds; return c->md_ctx; @@ -445,6 +433,11 @@ static grpc_credentials_vtable jwt_vtable = {jwt_destroy, jwt_get_metadata_context, jwt_get_request_metadata, NULL}; +======= +static grpc_credentials_vtable jwt_vtable = { + jwt_destroy, jwt_has_request_metadata, jwt_has_request_metadata_only, + jwt_get_request_metadata, NULL}; +>>>>>>> a2779c122ec3b2c3b6a475afa2ed18145d1f1b61 grpc_credentials *grpc_jwt_credentials_create(const char *json_key, gpr_timespec token_lifetime) { @@ -459,7 +452,6 @@ grpc_credentials *grpc_jwt_credentials_create(const char *json_key, c->base.type = GRPC_CREDENTIALS_TYPE_JWT; gpr_ref_init(&c->base.refcount, 1); c->base.vtable = &jwt_vtable; - c->md_ctx = grpc_mdctx_create(); c->key = key; c->jwt_lifetime = token_lifetime; gpr_mu_init(&c->cache_mu); @@ -480,8 +472,7 @@ typedef void (*grpc_fetch_oauth2_func)(grpc_credentials_metadata_request *req, typedef struct { grpc_credentials base; gpr_mu mu; - grpc_mdctx *md_ctx; - grpc_mdelem *access_token_md; + grpc_credentials_md_store *access_token_md; gpr_timespec token_expiration; grpc_pollset_set pollset_set; grpc_fetch_oauth2_func fetch_func; @@ -490,12 +481,13 @@ typedef struct { static void oauth2_token_fetcher_destroy(grpc_credentials *creds) { grpc_oauth2_token_fetcher_credentials *c = (grpc_oauth2_token_fetcher_credentials *)creds; - if (c->access_token_md != NULL) { - grpc_mdelem_unref(c->access_token_md); - } + grpc_credentials_md_store_unref(c->access_token_md); gpr_mu_destroy(&c->mu); +<<<<<<< HEAD grpc_mdctx_unref(c->md_ctx); grpc_pollset_set_destroy(&c->pollset_set); +======= +>>>>>>> a2779c122ec3b2c3b6a475afa2ed18145d1f1b61 gpr_free(c); } @@ -511,8 +503,8 @@ static int oauth2_token_fetcher_has_request_metadata_only( grpc_credentials_status grpc_oauth2_token_fetcher_credentials_parse_server_response( - const grpc_httpcli_response *response, grpc_mdctx *ctx, - grpc_mdelem **token_elem, gpr_timespec *token_lifetime) { + const grpc_httpcli_response *response, + grpc_credentials_md_store **token_md, gpr_timespec *token_lifetime) { char *null_terminated_body = NULL; char *new_access_token = NULL; grpc_credentials_status status = GRPC_CREDENTIALS_OK; @@ -580,16 +572,17 @@ grpc_oauth2_token_fetcher_credentials_parse_server_response( access_token->value); token_lifetime->tv_sec = strtol(expires_in->value, NULL, 10); token_lifetime->tv_nsec = 0; - if (*token_elem != NULL) grpc_mdelem_unref(*token_elem); - *token_elem = grpc_mdelem_from_strings(ctx, GRPC_AUTHORIZATION_METADATA_KEY, - new_access_token); + if (*token_md != NULL) grpc_credentials_md_store_unref(*token_md); + *token_md = grpc_credentials_md_store_create(1); + grpc_credentials_md_store_add_cstrings( + *token_md, GRPC_AUTHORIZATION_METADATA_KEY, new_access_token); status = GRPC_CREDENTIALS_OK; } end: - if (status != GRPC_CREDENTIALS_OK && (*token_elem != NULL)) { - grpc_mdelem_unref(*token_elem); - *token_elem = NULL; + if (status != GRPC_CREDENTIALS_OK && (*token_md != NULL)) { + grpc_credentials_md_store_unref(*token_md); + *token_md = NULL; } if (null_terminated_body != NULL) gpr_free(null_terminated_body); if (new_access_token != NULL) gpr_free(new_access_token); @@ -608,10 +601,11 @@ static void on_oauth2_token_fetcher_http_response( gpr_mu_lock(&c->mu); status = grpc_oauth2_token_fetcher_credentials_parse_server_response( - response, c->md_ctx, &c->access_token_md, &token_lifetime); + response, &c->access_token_md, &token_lifetime); if (status == GRPC_CREDENTIALS_OK) { c->token_expiration = gpr_time_add(gpr_now(), token_lifetime); - r->cb(r->user_data, &c->access_token_md, 1, status); + r->cb(r->user_data, c->access_token_md->entries, + c->access_token_md->num_entries, status); } else { c->token_expiration = gpr_inf_past; r->cb(r->user_data, NULL, 0, status); @@ -627,19 +621,20 @@ static void oauth2_token_fetcher_get_request_metadata( (grpc_oauth2_token_fetcher_credentials *)creds; gpr_timespec refresh_threshold = {GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS, 0}; - grpc_mdelem *cached_access_token_md = NULL; + grpc_credentials_md_store *cached_access_token_md = NULL; { gpr_mu_lock(&c->mu); if (c->access_token_md != NULL && (gpr_time_cmp(gpr_time_sub(c->token_expiration, gpr_now()), refresh_threshold) > 0)) { - cached_access_token_md = grpc_mdelem_ref(c->access_token_md); + cached_access_token_md = grpc_credentials_md_store_ref(c->access_token_md); } gpr_mu_unlock(&c->mu); } if (cached_access_token_md != NULL) { - cb(user_data, &cached_access_token_md, 1, GRPC_CREDENTIALS_OK); - grpc_mdelem_unref(cached_access_token_md); + cb(user_data, cached_access_token_md->entries, + cached_access_token_md->num_entries, GRPC_CREDENTIALS_OK); + grpc_credentials_md_store_unref(cached_access_token_md); } else { c->fetch_func( grpc_credentials_metadata_request_create(creds, cb, user_data), @@ -654,28 +649,24 @@ static void init_oauth2_token_fetcher(grpc_oauth2_token_fetcher_credentials *c, c->base.type = GRPC_CREDENTIALS_TYPE_OAUTH2; gpr_ref_init(&c->base.refcount, 1); gpr_mu_init(&c->mu); - c->md_ctx = grpc_mdctx_create(); c->token_expiration = gpr_inf_past; c->fetch_func = fetch_func; grpc_pollset_set_init(&c->pollset_set); } -static grpc_mdctx *oauth2_token_fetcher_get_metadata_context( - grpc_credentials *creds) { - grpc_oauth2_token_fetcher_credentials *c = - (grpc_oauth2_token_fetcher_credentials *)creds; - return c->md_ctx; -} - /* -- ComputeEngine credentials. -- */ static grpc_credentials_vtable compute_engine_vtable = { oauth2_token_fetcher_destroy, oauth2_token_fetcher_has_request_metadata, oauth2_token_fetcher_has_request_metadata_only, +<<<<<<< HEAD oauth2_token_fetcher_get_metadata_context, oauth2_token_fetcher_get_request_metadata, NULL}; +======= + oauth2_token_fetcher_get_request_metadata, NULL}; +>>>>>>> a2779c122ec3b2c3b6a475afa2ed18145d1f1b61 static void compute_engine_fetch_oauth2( grpc_credentials_metadata_request *metadata_req, @@ -721,9 +712,13 @@ static grpc_credentials_vtable service_account_vtable = { service_account_destroy, oauth2_token_fetcher_has_request_metadata, oauth2_token_fetcher_has_request_metadata_only, +<<<<<<< HEAD oauth2_token_fetcher_get_metadata_context, oauth2_token_fetcher_get_request_metadata, NULL}; +======= + oauth2_token_fetcher_get_request_metadata, NULL}; +>>>>>>> a2779c122ec3b2c3b6a475afa2ed18145d1f1b61 static void service_account_fetch_oauth2( grpc_credentials_metadata_request *metadata_req, @@ -797,9 +792,13 @@ static grpc_credentials_vtable refresh_token_vtable = { refresh_token_destroy, oauth2_token_fetcher_has_request_metadata, oauth2_token_fetcher_has_request_metadata_only, +<<<<<<< HEAD oauth2_token_fetcher_get_metadata_context, oauth2_token_fetcher_get_request_metadata, NULL}; +======= + oauth2_token_fetcher_get_request_metadata, NULL}; +>>>>>>> a2779c122ec3b2c3b6a475afa2ed18145d1f1b61 static void refresh_token_fetch_oauth2( grpc_credentials_metadata_request *metadata_req, @@ -847,17 +846,13 @@ grpc_credentials *grpc_refresh_token_credentials_create( typedef struct { grpc_credentials base; - grpc_mdctx *md_ctx; - grpc_mdelem *access_token_md; + grpc_credentials_md_store *access_token_md; int is_async; } grpc_fake_oauth2_credentials; static void fake_oauth2_destroy(grpc_credentials *creds) { grpc_fake_oauth2_credentials *c = (grpc_fake_oauth2_credentials *)creds; - if (c->access_token_md != NULL) { - grpc_mdelem_unref(c->access_token_md); - } - grpc_mdctx_unref(c->md_ctx); + grpc_credentials_md_store_unref(c->access_token_md); gpr_free(c); } @@ -875,7 +870,8 @@ void on_simulated_token_fetch_done(void *user_data, int success) { (grpc_credentials_metadata_request *)user_data; grpc_fake_oauth2_credentials *c = (grpc_fake_oauth2_credentials *)r->creds; GPR_ASSERT(success); - r->cb(r->user_data, &c->access_token_md, 1, GRPC_CREDENTIALS_OK); + r->cb(r->user_data, c->access_token_md->entries, + c->access_token_md->num_entries, GRPC_CREDENTIALS_OK); grpc_credentials_metadata_request_destroy(r); } @@ -890,21 +886,21 @@ static void fake_oauth2_get_request_metadata(grpc_credentials *creds, on_simulated_token_fetch_done, grpc_credentials_metadata_request_create(creds, cb, user_data)); } else { - cb(user_data, &c->access_token_md, 1, GRPC_CREDENTIALS_OK); + cb(user_data, c->access_token_md->entries, 1, GRPC_CREDENTIALS_OK); } } -static grpc_mdctx *fake_oauth2_get_metadata_context(grpc_credentials *creds) { - grpc_fake_oauth2_credentials *c = (grpc_fake_oauth2_credentials *)creds; - return c->md_ctx; -} - static grpc_credentials_vtable fake_oauth2_vtable = { +<<<<<<< HEAD fake_oauth2_destroy, fake_oauth2_has_request_metadata, fake_oauth2_has_request_metadata_only, fake_oauth2_get_metadata_context, fake_oauth2_get_request_metadata, +======= + fake_oauth2_destroy, fake_oauth2_has_request_metadata, + fake_oauth2_has_request_metadata_only, fake_oauth2_get_request_metadata, +>>>>>>> a2779c122ec3b2c3b6a475afa2ed18145d1f1b61 NULL}; grpc_credentials *grpc_fake_oauth2_credentials_create( @@ -915,9 +911,9 @@ grpc_credentials *grpc_fake_oauth2_credentials_create( c->base.type = GRPC_CREDENTIALS_TYPE_OAUTH2; c->base.vtable = &fake_oauth2_vtable; gpr_ref_init(&c->base.refcount, 1); - c->md_ctx = grpc_mdctx_create(); - c->access_token_md = grpc_mdelem_from_strings( - c->md_ctx, GRPC_AUTHORIZATION_METADATA_KEY, token_md_value); + 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->is_async = is_async; return &c->base; } @@ -944,12 +940,17 @@ static int fake_transport_security_has_request_metadata_only( return 0; } +<<<<<<< HEAD static grpc_mdctx *fake_transport_security_get_metadata_context( grpc_credentials *c) { return NULL; } static grpc_security_status fake_transport_security_create_security_connector( +======= +static grpc_security_status +fake_transport_security_create_security_connector( +>>>>>>> a2779c122ec3b2c3b6a475afa2ed18145d1f1b61 grpc_credentials *c, const char *target, const grpc_channel_args *args, grpc_credentials *request_metadata_creds, grpc_channel_security_connector **sc, grpc_channel_args **new_args) { @@ -967,9 +968,13 @@ fake_transport_security_server_create_security_connector( static grpc_credentials_vtable fake_transport_security_credentials_vtable = { fake_transport_security_credentials_destroy, fake_transport_security_has_request_metadata, +<<<<<<< HEAD fake_transport_security_has_request_metadata_only, fake_transport_security_get_metadata_context, NULL, +======= + fake_transport_security_has_request_metadata_only, NULL, +>>>>>>> a2779c122ec3b2c3b6a475afa2ed18145d1f1b61 fake_transport_security_create_security_connector}; static grpc_server_credentials_vtable @@ -1006,8 +1011,7 @@ typedef struct { typedef struct { grpc_composite_credentials *composite_creds; size_t creds_index; - grpc_mdelem **md_elems; - size_t num_md; + grpc_credentials_md_store *md_elems; char *service_url; void *user_data; grpc_credentials_metadata_cb cb; @@ -1049,21 +1053,16 @@ static int composite_has_request_metadata_only(const grpc_credentials *creds) { static void composite_md_context_destroy( grpc_composite_credentials_metadata_context *ctx) { - size_t i; - for (i = 0; i < ctx->num_md; i++) { - grpc_mdelem_unref(ctx->md_elems[i]); - } - gpr_free(ctx->md_elems); + grpc_credentials_md_store_unref(ctx->md_elems); if (ctx->service_url != NULL) gpr_free(ctx->service_url); gpr_free(ctx); } -static void composite_metadata_cb(void *user_data, grpc_mdelem **md_elems, - size_t num_md, +static void composite_metadata_cb(void *user_data, + grpc_credentials_md *md_elems, size_t num_md, grpc_credentials_status status) { grpc_composite_credentials_metadata_context *ctx = (grpc_composite_credentials_metadata_context *)user_data; - size_t i; if (status != GRPC_CREDENTIALS_OK) { ctx->cb(ctx->user_data, NULL, 0, status); return; @@ -1071,12 +1070,11 @@ static void composite_metadata_cb(void *user_data, grpc_mdelem **md_elems, /* Copy the metadata in the context. */ if (num_md > 0) { - ctx->md_elems = gpr_realloc(ctx->md_elems, - (ctx->num_md + num_md) * sizeof(grpc_mdelem *)); + size_t i; for (i = 0; i < num_md; i++) { - ctx->md_elems[i + ctx->num_md] = grpc_mdelem_ref(md_elems[i]); + grpc_credentials_md_store_add(ctx->md_elems, md_elems[i].key, + md_elems[i].value); } - ctx->num_md += num_md; } /* See if we need to get some more metadata. */ @@ -1091,7 +1089,8 @@ static void composite_metadata_cb(void *user_data, grpc_mdelem **md_elems, } /* We're done!. */ - ctx->cb(ctx->user_data, ctx->md_elems, ctx->num_md, GRPC_CREDENTIALS_OK); + ctx->cb(ctx->user_data, ctx->md_elems->entries, ctx->md_elems->num_entries, + GRPC_CREDENTIALS_OK); composite_md_context_destroy(ctx); } @@ -1111,6 +1110,7 @@ static void composite_get_request_metadata(grpc_credentials *creds, ctx->user_data = user_data; ctx->cb = cb; ctx->composite_creds = c; + ctx->md_elems = grpc_credentials_md_store_create(c->inner.num_creds); while (ctx->creds_index < c->inner.num_creds) { grpc_credentials *inner_creds = c->inner.creds_array[ctx->creds_index++]; if (grpc_credentials_has_request_metadata(inner_creds)) { @@ -1122,25 +1122,6 @@ static void composite_get_request_metadata(grpc_credentials *creds, GPR_ASSERT(0); /* Should have exited before. */ } -static grpc_mdctx *composite_get_metadata_context(grpc_credentials *creds) { - grpc_composite_credentials *c = (grpc_composite_credentials *)creds; - grpc_mdctx *ctx = NULL; - size_t i; - for (i = 0; i < c->inner.num_creds; i++) { - grpc_credentials *inner_creds = c->inner.creds_array[i]; - grpc_mdctx *inner_ctx = NULL; - if (inner_creds->vtable->get_metadata_context != NULL) { - inner_ctx = inner_creds->vtable->get_metadata_context(inner_creds); - } - if (inner_ctx) { - GPR_ASSERT(ctx == NULL && - "can only have one metadata context per composite credential"); - ctx = inner_ctx; - } - } - return ctx; -} - static grpc_security_status composite_create_security_connector( grpc_credentials *creds, const char *target, const grpc_channel_args *args, grpc_credentials *request_metadata_creds, @@ -1156,11 +1137,16 @@ static grpc_security_status composite_create_security_connector( } static grpc_credentials_vtable composite_credentials_vtable = { +<<<<<<< HEAD composite_destroy, composite_has_request_metadata, composite_has_request_metadata_only, composite_get_metadata_context, composite_get_request_metadata, +======= + composite_destroy, composite_has_request_metadata, + composite_has_request_metadata_only, composite_get_request_metadata, +>>>>>>> a2779c122ec3b2c3b6a475afa2ed18145d1f1b61 composite_create_security_connector}; static grpc_credentials_array get_creds_array(grpc_credentials **creds_addr) { @@ -1258,16 +1244,12 @@ grpc_credentials *grpc_credentials_contains_type( typedef struct { grpc_credentials base; - grpc_mdctx *md_ctx; - grpc_mdelem *token_md; - grpc_mdelem *authority_selector_md; + grpc_credentials_md_store *iam_md; } grpc_iam_credentials; static void iam_destroy(grpc_credentials *creds) { grpc_iam_credentials *c = (grpc_iam_credentials *)creds; - grpc_mdelem_unref(c->token_md); - grpc_mdelem_unref(c->authority_selector_md); - grpc_mdctx_unref(c->md_ctx); + grpc_credentials_md_store_unref(c->iam_md); gpr_free(c); } @@ -1282,23 +1264,22 @@ static void iam_get_request_metadata(grpc_credentials *creds, grpc_credentials_metadata_cb cb, void *user_data) { grpc_iam_credentials *c = (grpc_iam_credentials *)creds; - grpc_mdelem *md_array[2]; - md_array[0] = c->token_md; - md_array[1] = c->authority_selector_md; - cb(user_data, md_array, 2, GRPC_CREDENTIALS_OK); -} - -static grpc_mdctx *iam_get_metadata_context(grpc_credentials *creds) { - grpc_iam_credentials *c = (grpc_iam_credentials *)creds; - return c->md_ctx; + cb(user_data, c->iam_md->entries, c->iam_md->num_entries, + GRPC_CREDENTIALS_OK); } +<<<<<<< HEAD static grpc_credentials_vtable iam_vtable = {iam_destroy, iam_has_request_metadata, iam_has_request_metadata_only, iam_get_metadata_context, iam_get_request_metadata, NULL}; +======= +static grpc_credentials_vtable iam_vtable = { + iam_destroy, iam_has_request_metadata, iam_has_request_metadata_only, + iam_get_request_metadata, NULL}; +>>>>>>> a2779c122ec3b2c3b6a475afa2ed18145d1f1b61 grpc_credentials *grpc_iam_credentials_create(const char *token, const char *authority_selector) { @@ -1310,10 +1291,10 @@ grpc_credentials *grpc_iam_credentials_create(const char *token, c->base.type = GRPC_CREDENTIALS_TYPE_IAM; c->base.vtable = &iam_vtable; gpr_ref_init(&c->base.refcount, 1); - c->md_ctx = grpc_mdctx_create(); - c->token_md = grpc_mdelem_from_strings( - c->md_ctx, GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY, token); - c->authority_selector_md = grpc_mdelem_from_strings( - c->md_ctx, GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY, authority_selector); + c->iam_md = grpc_credentials_md_store_create(2); + grpc_credentials_md_store_add_cstrings( + c->iam_md, GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY, token); + grpc_credentials_md_store_add_cstrings( + c->iam_md, GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY, authority_selector); return &c->base; } diff --git a/src/core/security/credentials.h b/src/core/security/credentials.h index 9233f31418..059a723afb 100644 --- a/src/core/security/credentials.h +++ b/src/core/security/credentials.h @@ -82,13 +82,40 @@ typedef enum { #define GRPC_REFRESH_TOKEN_POST_BODY_FORMAT_STRING \ "client_id=%s&client_secret=%s&refresh_token=%s&grant_type=refresh_token" +/* --- grpc_credentials_md. --- */ + +typedef struct { + gpr_slice key; + gpr_slice value; +} grpc_credentials_md; + +typedef struct { + grpc_credentials_md *entries; + size_t num_entries; + size_t allocated; + gpr_refcount refcount; +} grpc_credentials_md_store; + +grpc_credentials_md_store *grpc_credentials_md_store_create( + size_t initial_capacity); + +/* Will ref key and value. */ +void grpc_credentials_md_store_add(grpc_credentials_md_store *store, + gpr_slice key, gpr_slice value); +void grpc_credentials_md_store_add_cstrings(grpc_credentials_md_store *store, + const char *key, const char *value); +grpc_credentials_md_store *grpc_credentials_md_store_ref( + grpc_credentials_md_store *store); +void grpc_credentials_md_store_unref(grpc_credentials_md_store *store); + + /* --- grpc_credentials. --- */ /* It is the caller's responsibility to gpr_free the result if not NULL. */ char *grpc_get_well_known_google_credentials_file_path(void); typedef void (*grpc_credentials_metadata_cb)(void *user_data, - grpc_mdelem **md_elems, + grpc_credentials_md *md_elems, size_t num_md, grpc_credentials_status status); @@ -96,8 +123,13 @@ typedef struct { void (*destroy)(grpc_credentials *c); int (*has_request_metadata)(const grpc_credentials *c); int (*has_request_metadata_only)(const grpc_credentials *c); +<<<<<<< HEAD grpc_mdctx *(*get_metadata_context)(grpc_credentials *c); void (*get_request_metadata)(grpc_credentials *c, const char *service_url, +======= + void (*get_request_metadata)(grpc_credentials *c, + const char *service_url, +>>>>>>> a2779c122ec3b2c3b6a475afa2ed18145d1f1b61 grpc_credentials_metadata_cb cb, void *user_data); grpc_security_status (*create_security_connector)( @@ -121,11 +153,6 @@ void grpc_credentials_get_request_metadata(grpc_credentials *creds, grpc_credentials_metadata_cb cb, void *user_data); -/* Gets the mdctx from the credentials and increase the refcount if it exists, - otherwise, create a new one. */ -grpc_mdctx *grpc_credentials_get_or_create_metadata_context( - grpc_credentials *creds); - /* Creates a security connector for the channel. May also create new channel args for the channel to be used in place of the passed in const args if returned non NULL. In that case the caller is responsible for destroying @@ -154,8 +181,13 @@ grpc_credentials *grpc_credentials_contains_type( /* Exposed for testing only. */ grpc_credentials_status grpc_oauth2_token_fetcher_credentials_parse_server_response( +<<<<<<< HEAD const struct grpc_httpcli_response *response, grpc_mdctx *ctx, grpc_mdelem **token_elem, gpr_timespec *token_lifetime); +======= + const struct grpc_httpcli_response *response, grpc_credentials_md_store **token_md, + gpr_timespec *token_lifetime); +>>>>>>> a2779c122ec3b2c3b6a475afa2ed18145d1f1b61 /* Simulates an oauth2 token fetch with the specified value for testing. */ grpc_credentials *grpc_fake_oauth2_credentials_create( diff --git a/src/core/security/credentials_metadata.c b/src/core/security/credentials_metadata.c new file mode 100644 index 0000000000..22c786be56 --- /dev/null +++ b/src/core/security/credentials_metadata.c @@ -0,0 +1,101 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/security/credentials.h" + +#include <grpc/support/alloc.h> + +#include <string.h> + +static void store_ensure_capacity(grpc_credentials_md_store *store) { + if (store->num_entries == store->allocated) { + store->allocated = (store->allocated == 0) ? 1 : store->allocated * 2; + store->entries = gpr_realloc( + store->entries, store->allocated * sizeof(grpc_credentials_md)); + } +} + +grpc_credentials_md_store *grpc_credentials_md_store_create( + size_t initial_capacity) { + grpc_credentials_md_store *store = gpr_malloc(sizeof(grpc_credentials_md_store)); + memset(store, 0, sizeof(grpc_credentials_md_store)); + if (initial_capacity > 0) { + store->entries = gpr_malloc(initial_capacity * sizeof(grpc_credentials_md)); + store->allocated = initial_capacity; + } + gpr_ref_init(&store->refcount, 1); + return store; +} + +void grpc_credentials_md_store_add(grpc_credentials_md_store *store, + gpr_slice key, gpr_slice value) { + if (store == NULL) return; + store_ensure_capacity(store); + store->entries[store->num_entries].key = gpr_slice_ref(key); + store->entries[store->num_entries].value = gpr_slice_ref(value); + store->num_entries++; +} + +void grpc_credentials_md_store_add_cstrings(grpc_credentials_md_store *store, + const char *key, + const char *value) { + if (store == NULL) return; + store_ensure_capacity(store); + store->entries[store->num_entries].key = gpr_slice_from_copied_string(key); + store->entries[store->num_entries].value = + gpr_slice_from_copied_string(value); + store->num_entries++; +} + +grpc_credentials_md_store *grpc_credentials_md_store_ref( + grpc_credentials_md_store *store) { + if (store == NULL) return NULL; + gpr_ref(&store->refcount); + return store; +} + +void grpc_credentials_md_store_unref(grpc_credentials_md_store *store) { + if (store == NULL) return; + if (gpr_unref(&store->refcount)) { + if (store->entries != NULL) { + size_t i; + for (i = 0; i < store->num_entries; i++) { + gpr_slice_unref(store->entries[i].key); + gpr_slice_unref(store->entries[i].value); + } + gpr_free(store->entries); + } + gpr_free(store); + } +} + diff --git a/src/core/security/security_connector.c b/src/core/security/security_connector.c index b17e0e0dfa..11505f8cb0 100644 --- a/src/core/security/security_connector.c +++ b/src/core/security/security_connector.c @@ -37,6 +37,7 @@ #include "src/core/security/credentials.h" #include "src/core/security/secure_endpoint.h" +#include "src/core/security/security_context.h" #include "src/core/support/env.h" #include "src/core/support/file.h" #include "src/core/support/string.h" @@ -194,10 +195,14 @@ typedef struct { static void fake_channel_destroy(grpc_security_connector *sc) { grpc_channel_security_connector *c = (grpc_channel_security_connector *)sc; grpc_credentials_unref(c->request_metadata_creds); + grpc_auth_context_unref(sc->auth_context); gpr_free(sc); } -static void fake_server_destroy(grpc_security_connector *sc) { gpr_free(sc); } +static void fake_server_destroy(grpc_security_connector *sc) { + grpc_auth_context_unref(sc->auth_context); + gpr_free(sc); +} static grpc_security_status fake_channel_create_handshaker( grpc_security_connector *sc, tsi_handshaker **handshaker) { @@ -236,6 +241,12 @@ static grpc_security_status fake_check_peer(grpc_security_connector *sc, status = GRPC_SECURITY_ERROR; goto end; } + grpc_auth_context_unref(sc->auth_context); + 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, + GRPC_FAKE_TRANSPORT_SECURITY_TYPE); + end: tsi_peer_destruct(&peer); return status; @@ -264,6 +275,7 @@ grpc_channel_security_connector *grpc_fake_channel_security_connector_create( grpc_credentials *request_metadata_creds, int call_host_check_is_async) { grpc_fake_channel_security_connector *c = gpr_malloc(sizeof(grpc_fake_channel_security_connector)); + memset(c, 0, sizeof(grpc_fake_channel_security_connector)); gpr_ref_init(&c->base.base.refcount, 1); c->base.base.is_client_side = 1; c->base.base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME; @@ -277,7 +289,9 @@ grpc_channel_security_connector *grpc_fake_channel_security_connector_create( grpc_security_connector *grpc_fake_server_security_connector_create(void) { grpc_security_connector *c = gpr_malloc(sizeof(grpc_security_connector)); + memset(c, 0, sizeof(grpc_security_connector)); gpr_ref_init(&c->refcount, 1); + c->is_client_side = 0; c->vtable = &fake_server_vtable; c->url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME; return c; @@ -308,6 +322,7 @@ static void ssl_channel_destroy(grpc_security_connector *sc) { if (c->target_name != NULL) gpr_free(c->target_name); if (c->overridden_target_name != NULL) gpr_free(c->overridden_target_name); tsi_peer_destruct(&c->peer); + grpc_auth_context_unref(sc->auth_context); gpr_free(sc); } @@ -317,6 +332,7 @@ static void ssl_server_destroy(grpc_security_connector *sc) { if (c->handshaker_factory != NULL) { tsi_ssl_handshaker_factory_destroy(c->handshaker_factory); } + grpc_auth_context_unref(sc->auth_context); gpr_free(sc); } @@ -369,7 +385,51 @@ static int ssl_host_matches_name(const tsi_peer *peer, const char *peer_name) { return r; } -static grpc_security_status ssl_check_peer(const char *peer_name, +static grpc_auth_context *tsi_ssl_peer_to_auth_context(const tsi_peer *peer) { + /* We bet that iterating over a handful of properties twice will be faster + than having to realloc on average . */ + size_t auth_prop_count = 1; /* for transport_security_type. */ + size_t i; + const char *peer_identity_property_name = NULL; + grpc_auth_context *ctx = NULL; + 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) { + auth_prop_count++; + /* If there is no subject alt name, have the CN as the identity. */ + if (peer_identity_property_name == NULL) { + peer_identity_property_name = prop->name; + } + } else if (strcmp(prop->name, + TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == 0) { + auth_prop_count++; + peer_identity_property_name = prop->name; + } + } + ctx = grpc_auth_context_create(NULL, auth_prop_count); + ctx->properties[0] = grpc_auth_property_init_from_cstring( + 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) { + ctx->properties[ctx->property_count++] = grpc_auth_property_init( + 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->properties[ctx->property_count++] = grpc_auth_property_init( + GRPC_X509_SAN_PROPERTY_NAME, prop->value.data, prop->value.length); + } + } + GPR_ASSERT(auth_prop_count == ctx->property_count); + return ctx; +} + +static grpc_security_status ssl_check_peer(grpc_security_connector *sc, + const char *peer_name, const tsi_peer *peer) { /* Check the ALPN. */ const tsi_peer_property *p = @@ -388,7 +448,7 @@ static grpc_security_status ssl_check_peer(const char *peer_name, gpr_log(GPR_ERROR, "Peer name %s is not in peer certificate", peer_name); return GRPC_SECURITY_ERROR; } - + sc->auth_context = tsi_ssl_peer_to_auth_context(peer); return GRPC_SECURITY_OK; } @@ -401,9 +461,9 @@ static grpc_security_status ssl_channel_check_peer(grpc_security_connector *sc, grpc_security_status status; tsi_peer_destruct(&c->peer); c->peer = peer; - status = ssl_check_peer(c->overridden_target_name != NULL - ? c->overridden_target_name - : c->target_name, + status = ssl_check_peer(sc, c->overridden_target_name != NULL + ? c->overridden_target_name + : c->target_name, &peer); return status; } @@ -412,8 +472,7 @@ static grpc_security_status ssl_server_check_peer(grpc_security_connector *sc, tsi_peer peer, grpc_security_check_cb cb, void *user_data) { - /* TODO(jboeuf): Find a way to expose the peer to the authorization layer. */ - grpc_security_status status = ssl_check_peer(NULL, &peer); + grpc_security_status status = ssl_check_peer(sc, NULL, &peer); tsi_peer_destruct(&peer); return status; } diff --git a/src/core/security/security_connector.h b/src/core/security/security_connector.h index 87b7ca9b8b..0617041448 100644 --- a/src/core/security/security_connector.h +++ b/src/core/security/security_connector.h @@ -77,6 +77,7 @@ struct grpc_security_connector { gpr_refcount refcount; int is_client_side; const char *url_scheme; + grpc_auth_context *auth_context; /* Populated after the peer is checked. */ }; /* Increments the refcount. */ diff --git a/src/core/security/security_context.c b/src/core/security/security_context.c index b90dc5097a..14c194c8f6 100644 --- a/src/core/security/security_context.c +++ b/src/core/security/security_context.c @@ -35,11 +35,14 @@ #include "src/core/security/security_context.h" #include "src/core/surface/call.h" +#include "src/core/support/string.h" #include <grpc/grpc_security.h> #include <grpc/support/alloc.h> #include <grpc/support/log.h> +/* --- grpc_call --- */ + grpc_call_error grpc_call_set_credentials(grpc_call *call, grpc_credentials *creds) { grpc_client_security_context *ctx = NULL; @@ -65,6 +68,16 @@ grpc_call_error grpc_call_set_credentials(grpc_call *call, return GRPC_CALL_OK; } +const grpc_auth_context *grpc_call_auth_context(grpc_call *call) { + void *sec_ctx = grpc_call_context_get(call, GRPC_CONTEXT_SECURITY); + if (sec_ctx == NULL) return NULL; + return grpc_call_is_client(call) + ? ((grpc_client_security_context *)sec_ctx)->auth_context + : ((grpc_server_security_context *)sec_ctx)->auth_context; +} + +/* --- grpc_client_security_context --- */ + grpc_client_security_context *grpc_client_security_context_create(void) { grpc_client_security_context *ctx = gpr_malloc(sizeof(grpc_client_security_context)); @@ -75,5 +88,142 @@ grpc_client_security_context *grpc_client_security_context_create(void) { void grpc_client_security_context_destroy(void *ctx) { grpc_client_security_context *c = (grpc_client_security_context *)ctx; grpc_credentials_unref(c->creds); + grpc_auth_context_unref(c->auth_context); + gpr_free(ctx); +} + +/* --- grpc_server_security_context --- */ + +grpc_server_security_context *grpc_server_security_context_create(void) { + grpc_server_security_context *ctx = + gpr_malloc(sizeof(grpc_server_security_context)); + memset(ctx, 0, sizeof(grpc_server_security_context)); + return ctx; +} + +void grpc_server_security_context_destroy(void *ctx) { + grpc_server_security_context *c = (grpc_server_security_context *)ctx; + grpc_auth_context_unref(c->auth_context); gpr_free(ctx); } + +/* --- grpc_auth_context --- */ + +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 *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); + return ctx; +} + +grpc_auth_context *grpc_auth_context_ref(grpc_auth_context *ctx) { + if (ctx == NULL) return NULL; + gpr_ref(&ctx->refcount); + return ctx; +} + +void grpc_auth_context_unref(grpc_auth_context *ctx) { + if (ctx == NULL) return; + if (gpr_unref(&ctx->refcount)) { + size_t i; + grpc_auth_context_unref(ctx->chained); + if (ctx->properties != NULL) { + for (i = 0; i < ctx->property_count; i++) { + grpc_auth_property_reset(&ctx->properties[i]); + } + gpr_free(ctx->properties); + } + gpr_free(ctx); + } +} + +const char *grpc_auth_context_peer_identity_property_name( + const grpc_auth_context *ctx) { + return ctx->peer_identity_property_name; +} + +int grpc_auth_context_peer_is_authenticated( + const grpc_auth_context *ctx) { + return ctx->peer_identity_property_name == NULL ? 0 : 1; +} + +grpc_auth_property_iterator grpc_auth_context_property_iterator( + const grpc_auth_context *ctx) { + grpc_auth_property_iterator it = empty_iterator; + if (ctx == NULL) return it; + it.ctx = ctx; + return it; +} + +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) { + 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++]; + } else { + while (it->index < it->ctx->property_count) { + const grpc_auth_property *prop = &it->ctx->properties[it->index++]; + GPR_ASSERT(prop->name != NULL); + if (strcmp(it->name, prop->name) == 0) { + return prop; + } + } + /* We could not find the name, try another round. */ + return grpc_auth_property_iterator_next(it); + } +} + +grpc_auth_property_iterator grpc_auth_context_find_properties_by_name( + const grpc_auth_context *ctx, const char *name) { + grpc_auth_property_iterator it = empty_iterator; + if (ctx == NULL || name == NULL) return empty_iterator; + it.ctx = ctx; + it.name = name; + return it; +} + +grpc_auth_property_iterator grpc_auth_context_peer_identity( + const grpc_auth_context *ctx) { + if (ctx == NULL) return empty_iterator; + return grpc_auth_context_find_properties_by_name( + 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; +} + +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_property_reset(grpc_auth_property *property) { + if (property->name != NULL) gpr_free(property->name); + if (property->value != NULL) gpr_free(property->value); + memset(property, 0, sizeof(grpc_auth_property)); +} + diff --git a/src/core/security/security_context.h b/src/core/security/security_context.h index 561633b452..d8909cd6f1 100644 --- a/src/core/security/security_context.h +++ b/src/core/security/security_context.h @@ -36,13 +36,59 @@ #include "src/core/security/credentials.h" -/* Security context attached to a client-side call. */ +/* --- grpc_auth_context --- + + High level authentication context object. Can optionally be chained. */ + +/* Property names are always NULL terminated. */ + +struct grpc_auth_context { + struct grpc_auth_context *chained; + grpc_auth_property *properties; + size_t property_count; + gpr_refcount refcount; + const char *peer_identity_property_name; +}; + +/* Constructor. */ +grpc_auth_context *grpc_auth_context_create(grpc_auth_context *chained, + size_t property_count); + +/* Refcounting. */ +grpc_auth_context *grpc_auth_context_ref( + grpc_auth_context *ctx); +void grpc_auth_context_unref(grpc_auth_context *ctx); + +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 --- + + Internal client-side security context. */ + typedef struct { grpc_credentials *creds; + grpc_auth_context *auth_context; } grpc_client_security_context; grpc_client_security_context *grpc_client_security_context_create(void); void grpc_client_security_context_destroy(void *ctx); +/* --- grpc_server_security_context --- + + Internal server-side security context. */ + +typedef struct { + grpc_auth_context *auth_context; +} grpc_server_security_context; + +grpc_server_security_context *grpc_server_security_context_create(void); +void grpc_server_security_context_destroy(void *ctx); + #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 new file mode 100644 index 0000000000..1823f75808 --- /dev/null +++ b/src/core/security/server_auth_filter.c @@ -0,0 +1,128 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/security/auth_filters.h" +#include "src/core/security/security_connector.h" +#include "src/core/security/security_context.h" + +#include <grpc/support/log.h> + +typedef struct call_data { + int unused; /* C89 requires at least one struct element */ +} call_data; + +typedef struct channel_data { + grpc_security_connector *security_connector; +} channel_data; + +/* 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 + op contains type and call direction information, in addition to the data + that is being sent or received. */ +static void auth_start_transport_op(grpc_call_element *elem, + grpc_transport_op *op) { + /* TODO(jboeuf): Get the metadata and get a new context from it. */ + + /* pass control down the stack */ + grpc_call_next_op(elem, op); +} + +/* Called on special channel events, such as disconnection or new incoming + calls on the server */ +static void channel_op(grpc_channel_element *elem, + grpc_channel_element *from_elem, grpc_channel_op *op) { + grpc_channel_next_op(elem, op); +} + +/* Constructor for call_data */ +static void init_call_elem(grpc_call_element *elem, + const void *server_transport_data, + grpc_transport_op *initial_op) { + /* grab pointers to our data from the call element */ + call_data *calld = elem->call_data; + channel_data *chand = elem->channel_data; + grpc_server_security_context *server_ctx = NULL; + + /* initialize members */ + calld->unused = 0; + + GPR_ASSERT(initial_op && initial_op->context != NULL && + chand->security_connector->auth_context != NULL && + initial_op->context[GRPC_CONTEXT_SECURITY].value == NULL); + + /* Create a security context for the call and reference the auth context from + the channel. */ + server_ctx = grpc_server_security_context_create(); + server_ctx->auth_context = + grpc_auth_context_ref(chand->security_connector->auth_context); + initial_op->context[GRPC_CONTEXT_SECURITY].value = server_ctx; + initial_op->context[GRPC_CONTEXT_SECURITY].destroy = + grpc_server_security_context_destroy; +} + +/* Destructor for call_data */ +static void destroy_call_elem(grpc_call_element *elem) { +} + +/* Constructor for channel_data */ +static void init_channel_elem(grpc_channel_element *elem, + 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); + /* grab pointers to our data from the channel element */ + channel_data *chand = elem->channel_data; + + /* The first and the last filters tend to be implemented differently to + handle the case that there's no 'next' filter to call on the up or down + path */ + GPR_ASSERT(!is_first); + GPR_ASSERT(!is_last); + GPR_ASSERT(sc != NULL); + + /* initialize members */ + GPR_ASSERT(!sc->is_client_side); + chand->security_connector = grpc_security_connector_ref(sc); +} + +/* Destructor for channel data */ +static void destroy_channel_elem(grpc_channel_element *elem) { + /* grab pointers to our data from the channel element */ + channel_data *chand = elem->channel_data; + grpc_security_connector_unref(chand->security_connector); +} + +const grpc_channel_filter grpc_server_auth_filter = { + auth_start_transport_op, channel_op, sizeof(call_data), init_call_elem, + destroy_call_elem, sizeof(channel_data), init_channel_elem, + destroy_channel_elem, "server-auth"}; diff --git a/src/core/security/server_secure_chttp2.c b/src/core/security/server_secure_chttp2.c index db9d545c0e..3519930f38 100644 --- a/src/core/security/server_secure_chttp2.c +++ b/src/core/security/server_secure_chttp2.c @@ -35,10 +35,12 @@ #include <string.h> +#include "src/core/channel/channel_args.h" #include "src/core/channel/http_server_filter.h" #include "src/core/iomgr/endpoint.h" #include "src/core/iomgr/resolve_address.h" #include "src/core/iomgr/tcp_server.h" +#include "src/core/security/auth_filters.h" #include "src/core/security/credentials.h" #include "src/core/security/security_connector.h" #include "src/core/security/secure_transport_setup.h" @@ -69,13 +71,21 @@ static void state_unref(grpc_server_secure_state *state) { } } -static grpc_transport_setup_result setup_transport(void *server, +static grpc_transport_setup_result setup_transport(void *statep, grpc_transport *transport, grpc_mdctx *mdctx) { static grpc_channel_filter const *extra_filters[] = { - &grpc_http_server_filter}; - return grpc_server_setup_transport(server, transport, extra_filters, - GPR_ARRAY_SIZE(extra_filters), mdctx); + &grpc_server_auth_filter, &grpc_http_server_filter}; + grpc_server_secure_state *state = statep; + grpc_transport_setup_result result; + 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); + result = grpc_server_setup_transport(state->server, transport, extra_filters, + GPR_ARRAY_SIZE(extra_filters), mdctx, + args_copy); + grpc_channel_args_destroy(args_copy); + return result; } static void on_secure_transport_setup_done(void *statep, @@ -85,10 +95,9 @@ static void on_secure_transport_setup_done(void *statep, if (status == GRPC_SECURITY_OK) { gpr_mu_lock(&state->mu); if (!state->is_shutdown) { - grpc_create_chttp2_transport(setup_transport, state->server, - grpc_server_get_channel_args(state->server), - secure_endpoint, NULL, 0, - grpc_mdctx_create(), 0); + grpc_create_chttp2_transport( + setup_transport, state, grpc_server_get_channel_args(state->server), + secure_endpoint, NULL, 0, grpc_mdctx_create(), 0); } else { /* We need to consume this here, because the server may already have gone * away. */ diff --git a/src/core/surface/call.c b/src/core/surface/call.c index 31c304e556..138cd084c5 100644 --- a/src/core/surface/call.c +++ b/src/core/surface/call.c @@ -207,8 +207,8 @@ struct grpc_call { /* Received call statuses from various sources */ received_status status[STATUS_SOURCE_COUNT]; - void *context[GRPC_CONTEXT_COUNT]; - void (*destroy_context[GRPC_CONTEXT_COUNT])(void *); + /* Contexts for various subsystems (security, tracing, ...). */ + grpc_call_context_element context[GRPC_CONTEXT_COUNT]; /* Deadline alarm - if have_alarm is non-zero */ grpc_alarm alarm; @@ -351,8 +351,8 @@ static void destroy_call(void *call, int ignored_success) { grpc_mdelem_unref(c->send_initial_metadata[i].md); } for (i = 0; i < GRPC_CONTEXT_COUNT; i++) { - if (c->destroy_context[i]) { - c->destroy_context[i](c->context[i]); + if (c->context[i].destroy) { + c->context[i].destroy(c->context[i].value); } } grpc_sopb_destroy(&c->send_ops); @@ -1309,17 +1309,17 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops, return grpc_call_start_ioreq_and_call_back(call, reqs, out, finish_func, tag); } -void grpc_call_context_set(grpc_call *call, grpc_context_index elem, - void *value, void (*destroy)(void *value)) { - if (call->destroy_context[elem]) { - call->destroy_context[elem](value); +void grpc_call_context_set(grpc_call *call, grpc_context_index elem, void *value, + void (*destroy)(void *value)) { + if (call->context[elem].destroy) { + call->context[elem].destroy(call->context[elem].value); } - call->context[elem] = value; - call->destroy_context[elem] = destroy; + call->context[elem].value = value; + call->context[elem].destroy = destroy; } void *grpc_call_context_get(grpc_call *call, grpc_context_index elem) { - return call->context[elem]; + return call->context[elem].value; } gpr_uint8 grpc_call_is_client(grpc_call *call) { return call->is_client; } diff --git a/src/core/surface/secure_channel_create.c b/src/core/surface/secure_channel_create.c index dfc4a1920a..b9c6d5f760 100644 --- a/src/core/surface/secure_channel_create.c +++ b/src/core/surface/secure_channel_create.c @@ -46,7 +46,7 @@ #include "src/core/channel/http_client_filter.h" #include "src/core/iomgr/resolve_address.h" #include "src/core/iomgr/tcp_client.h" -#include "src/core/security/auth.h" +#include "src/core/security/auth_filters.h" #include "src/core/security/credentials.h" #include "src/core/security/secure_transport_setup.h" #include "src/core/support/string.h" @@ -227,7 +227,7 @@ grpc_channel *grpc_secure_channel_create(grpc_credentials *creds, GRPC_SECURITY_OK) { return grpc_lame_client_channel_create(); } - mdctx = grpc_credentials_get_or_create_metadata_context(creds); + mdctx = grpc_mdctx_create(); s = gpr_malloc(sizeof(setup)); connector_arg = grpc_security_connector_to_arg(&connector->base); diff --git a/src/core/surface/server.c b/src/core/surface/server.c index 6118e43620..f173e7da4a 100644 --- a/src/core/surface/server.c +++ b/src/core/surface/server.c @@ -791,7 +791,7 @@ void grpc_server_start(grpc_server *server) { grpc_transport_setup_result grpc_server_setup_transport( grpc_server *s, grpc_transport *transport, grpc_channel_filter const **extra_filters, size_t num_extra_filters, - grpc_mdctx *mdctx) { + grpc_mdctx *mdctx, const grpc_channel_args *args) { size_t num_filters = s->channel_filter_count + num_extra_filters + 1; grpc_channel_filter const **filters = gpr_malloc(sizeof(grpc_channel_filter *) * num_filters); @@ -822,8 +822,8 @@ grpc_transport_setup_result grpc_server_setup_transport( grpc_transport_add_to_pollset(transport, grpc_cq_pollset(s->cqs[i])); } - channel = grpc_channel_create_from_filters(filters, num_filters, - s->channel_args, mdctx, 0); + channel = + grpc_channel_create_from_filters(filters, num_filters, args, mdctx, 0); chand = (channel_data *)grpc_channel_stack_element( grpc_channel_get_channel_stack(channel), 0) ->channel_data; diff --git a/src/core/surface/server.h b/src/core/surface/server.h index 58f17272a4..91a1a2a7f6 100644 --- a/src/core/surface/server.h +++ b/src/core/surface/server.h @@ -58,7 +58,7 @@ void grpc_server_listener_destroy_done(void *server); grpc_transport_setup_result grpc_server_setup_transport( grpc_server *server, grpc_transport *transport, grpc_channel_filter const **extra_filters, size_t num_extra_filters, - grpc_mdctx *mdctx); + grpc_mdctx *mdctx, const grpc_channel_args *args); const grpc_channel_args *grpc_server_get_channel_args(grpc_server *server); diff --git a/src/core/surface/server_chttp2.c b/src/core/surface/server_chttp2.c index 7b5c2f227b..7e49a531df 100644 --- a/src/core/surface/server_chttp2.c +++ b/src/core/surface/server_chttp2.c @@ -48,7 +48,8 @@ static grpc_transport_setup_result setup_transport(void *server, static grpc_channel_filter const *extra_filters[] = { &grpc_http_server_filter}; return grpc_server_setup_transport(server, transport, extra_filters, - GPR_ARRAY_SIZE(extra_filters), mdctx); + GPR_ARRAY_SIZE(extra_filters), mdctx, + grpc_server_get_channel_args(server)); } static void new_transport(void *server, grpc_endpoint *tcp) { diff --git a/src/core/transport/metadata.h b/src/core/transport/metadata.h index e7508718f5..76e3f3c1f8 100644 --- a/src/core/transport/metadata.h +++ b/src/core/transport/metadata.h @@ -96,6 +96,7 @@ size_t grpc_mdctx_get_mdtab_free_test_only(grpc_mdctx *mdctx); /* Constructors for grpc_mdstr instances; take a variety of data types that clients may have handy */ grpc_mdstr *grpc_mdstr_from_string(grpc_mdctx *ctx, const char *str); +/* Unrefs the slice. */ grpc_mdstr *grpc_mdstr_from_slice(grpc_mdctx *ctx, gpr_slice slice); grpc_mdstr *grpc_mdstr_from_buffer(grpc_mdctx *ctx, const gpr_uint8 *str, size_t length); @@ -110,6 +111,7 @@ grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdctx *ctx, grpc_mdstr *key, grpc_mdstr *value); grpc_mdelem *grpc_mdelem_from_strings(grpc_mdctx *ctx, const char *key, const char *value); +/* Unrefs the slices. */ grpc_mdelem *grpc_mdelem_from_slices(grpc_mdctx *ctx, gpr_slice key, gpr_slice value); grpc_mdelem *grpc_mdelem_from_string_and_buffer(grpc_mdctx *ctx, diff --git a/src/core/transport/transport.h b/src/core/transport/transport.h index 738c3536e4..521d74c4c4 100644 --- a/src/core/transport/transport.h +++ b/src/core/transport/transport.h @@ -39,6 +39,7 @@ #include "src/core/iomgr/pollset.h" #include "src/core/iomgr/pollset_set.h" #include "src/core/transport/stream_op.h" +#include "src/core/channel/context.h" /* forward declarations */ typedef struct grpc_transport grpc_transport; @@ -79,7 +80,7 @@ typedef struct grpc_transport_op { grpc_mdstr *cancel_message; /* Indexes correspond to grpc_context_index enum values */ - void *const *context; + grpc_call_context_element *context; } grpc_transport_op; /* Callbacks made from the transport to the upper layers of grpc. */ |