diff options
author | Donna Dionne <donnadionne@google.com> | 2015-02-21 10:29:06 -0800 |
---|---|---|
committer | Donna Dionne <donnadionne@google.com> | 2015-02-21 10:29:06 -0800 |
commit | 2c77f75b74f266da0970f30333a290f2eb38cdfd (patch) | |
tree | cd818aba0dde90b3060c221916caf8a98f5cb3f4 /src/core/security | |
parent | b5795aa24d1605b04c9f61b87adf6f7b26af23e1 (diff) | |
parent | f3599aed6cb48bc4f132546e7f4e5747914ca291 (diff) |
Merge branch 'master' of github.com:google/grpc into docker_python
Diffstat (limited to 'src/core/security')
-rw-r--r-- | src/core/security/auth.c | 32 | ||||
-rw-r--r-- | src/core/security/credentials.c | 158 | ||||
-rw-r--r-- | src/core/security/credentials.h | 3 | ||||
-rw-r--r-- | src/core/security/json_token.c | 34 | ||||
-rw-r--r-- | src/core/security/json_token.h | 13 | ||||
-rw-r--r-- | src/core/security/security_context.c | 4 | ||||
-rw-r--r-- | src/core/security/security_context.h | 6 |
7 files changed, 219 insertions, 31 deletions
diff --git a/src/core/security/auth.c b/src/core/security/auth.c index 58679a87aa..92878e3b7e 100644 --- a/src/core/security/auth.c +++ b/src/core/security/auth.c @@ -48,6 +48,7 @@ typedef struct { grpc_credentials *creds; grpc_mdstr *host; + grpc_mdstr *method; grpc_call_op op; } call_data; @@ -56,6 +57,7 @@ typedef struct { grpc_channel_security_context *security_context; grpc_mdctx *md_ctx; grpc_mdstr *authority_string; + grpc_mdstr *path_string; grpc_mdstr *error_msg_key; } channel_data; @@ -89,6 +91,26 @@ static void on_credentials_metadata(void *user_data, grpc_mdelem **md_elems, grpc_call_next_op(elem, &((call_data *)elem->call_data)->op); } +static char *build_service_url(const char *url_scheme, call_data *calld) { + char *service_url; + char *service = gpr_strdup(grpc_mdstr_as_c_string(calld->method)); + char *last_slash = strrchr(service, '/'); + if (last_slash == NULL) { + gpr_log(GPR_ERROR, "No '/' found in fully qualified method name"); + service[0] = '\0'; + } else if (last_slash == service) { + /* No service part in fully qualified method name: will just be "/". */ + service[1] = '\0'; + } else { + *last_slash = '\0'; + } + if (url_scheme == NULL) url_scheme = ""; + gpr_asprintf(&service_url, "%s://%s%s", url_scheme, + grpc_mdstr_as_c_string(calld->host), service); + gpr_free(service); + return service_url; +} + static void send_security_metadata(grpc_call_element *elem, grpc_call_op *op) { /* grab pointers to our data from the call element */ call_data *calld = elem->call_data; @@ -106,9 +128,12 @@ static void send_security_metadata(grpc_call_element *elem, grpc_call_op *op) { } if (channel_creds != NULL && grpc_credentials_has_request_metadata(channel_creds)) { + char *service_url = + build_service_url(channeld->security_context->base.url_scheme, calld); calld->op = *op; /* Copy op (originates from the caller's stack). */ - grpc_credentials_get_request_metadata(channel_creds, + grpc_credentials_get_request_metadata(channel_creds, service_url, on_credentials_metadata, elem); + gpr_free(service_url); } else { grpc_call_next_op(elem, op); } @@ -146,6 +171,9 @@ static void call_op(grpc_call_element *elem, grpc_call_element *from_elem, if (op->data.metadata->key == channeld->authority_string) { if (calld->host != NULL) grpc_mdstr_unref(calld->host); calld->host = grpc_mdstr_ref(op->data.metadata->value); + } else if (op->data.metadata->key == channeld->path_string) { + if (calld->method != NULL) grpc_mdstr_unref(calld->method); + calld->method = grpc_mdstr_ref(op->data.metadata->value); } grpc_call_next_op(elem, op); break; @@ -194,6 +222,7 @@ static void init_call_elem(grpc_call_element *elem, call_data *calld = elem->call_data; calld->creds = NULL; calld->host = NULL; + calld->method = NULL; } /* Destructor for call_data */ @@ -230,6 +259,7 @@ static void init_channel_elem(grpc_channel_element *elem, channeld->md_ctx = metadata_context; channeld->authority_string = grpc_mdstr_from_string(channeld->md_ctx, ":authority"); + channeld->path_string = grpc_mdstr_from_string(channeld->md_ctx, ":path"); channeld->error_msg_key = grpc_mdstr_from_string(channeld->md_ctx, "grpc-message"); } diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c index a21c27bff9..42d1a900fc 100644 --- a/src/core/security/credentials.c +++ b/src/core/security/credentials.c @@ -33,6 +33,10 @@ #include "src/core/security/credentials.h" +#include <string.h> +#include <stdio.h> + +#include "src/core/json/json.h" #include "src/core/httpcli/httpcli.h" #include "src/core/iomgr/iomgr.h" #include "src/core/security/json_token.h" @@ -42,14 +46,9 @@ #include <grpc/support/sync.h> #include <grpc/support/time.h> -#include "src/core/json/json.h" - -#include <string.h> -#include <stdio.h> - /* -- Constants. -- */ -#define GRPC_OAUTH2_TOKEN_REFRESH_THRESHOLD_SECS 60 +#define GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS 60 #define GRPC_COMPUTE_ENGINE_METADATA_HOST "metadata" #define GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH \ @@ -113,6 +112,7 @@ int grpc_credentials_has_request_metadata_only(grpc_credentials *creds) { } void grpc_credentials_get_request_metadata(grpc_credentials *creds, + const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) { if (creds == NULL || !grpc_credentials_has_request_metadata(creds) || @@ -122,7 +122,7 @@ void grpc_credentials_get_request_metadata(grpc_credentials *creds, } return; } - creds->vtable->get_request_metadata(creds, cb, user_data); + creds->vtable->get_request_metadata(creds, service_url, cb, user_data); } void grpc_server_credentials_release(grpc_server_credentials *creds) { @@ -288,6 +288,128 @@ grpc_server_credentials *grpc_ssl_server_credentials_create( return &c->base; } +/* -- Jwt credentials -- */ + +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; + char *service_url; + gpr_timespec jwt_expiration; + } cached; + + grpc_auth_json_key key; + gpr_timespec jwt_lifetime; +} grpc_jwt_credentials; + +static void jwt_reset_cache(grpc_jwt_credentials *c) { + if (c->cached.jwt_md != NULL) { + grpc_mdelem_unref(c->cached.jwt_md); + c->cached.jwt_md = NULL; + } + if (c->cached.service_url != NULL) { + gpr_free(c->cached.service_url); + c->cached.service_url = NULL; + } + c->cached.jwt_expiration = gpr_inf_past; +} + +static void jwt_destroy(grpc_credentials *creds) { + grpc_jwt_credentials *c = (grpc_jwt_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); +} + +static int jwt_has_request_metadata(const grpc_credentials *creds) { return 1; } + +static int jwt_has_request_metadata_only(const grpc_credentials *creds) { + return 1; +} + + +static void jwt_get_request_metadata(grpc_credentials *creds, + const char *service_url, + grpc_credentials_metadata_cb cb, + void *user_data) { + grpc_jwt_credentials *c = (grpc_jwt_credentials *)creds; + gpr_timespec refresh_threshold = {GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS, + 0}; + + /* See if we can return a cached jwt. */ + grpc_mdelem *jwt_md = NULL; + { + gpr_mu_lock(&c->cache_mu); + if (c->cached.service_url != NULL && + !strcmp(c->cached.service_url, service_url) && + 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); + } + gpr_mu_unlock(&c->cache_mu); + } + + if (jwt_md == NULL) { + char *jwt = NULL; + /* Generate a new jwt. */ + gpr_mu_lock(&c->cache_mu); + jwt_reset_cache(c); + jwt = grpc_jwt_encode_and_sign(&c->key, service_url, c->jwt_lifetime, NULL); + if (jwt != NULL) { + char *md_value; + gpr_asprintf(&md_value, "Bearer %s", jwt); + 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); + gpr_free(md_value); + jwt_md = grpc_mdelem_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); + } else { + cb(user_data, NULL, 0, GRPC_CREDENTIALS_ERROR); + } +} + +static grpc_credentials_vtable jwt_vtable = { + jwt_destroy, jwt_has_request_metadata, jwt_has_request_metadata_only, + jwt_get_request_metadata}; + +grpc_credentials *grpc_jwt_credentials_create(const char *json_key, + gpr_timespec token_lifetime) { + grpc_jwt_credentials *c; + grpc_auth_json_key key = grpc_auth_json_key_create_from_string(json_key); + if (!grpc_auth_json_key_is_valid(&key)) { + gpr_log(GPR_ERROR, "Invalid input for jwt credentials creation"); + return NULL; + } + c = gpr_malloc(sizeof(grpc_jwt_credentials)); + memset(c, 0, sizeof(grpc_jwt_credentials)); + 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); + jwt_reset_cache(c); + return &c->base; +} + /* -- Oauth2TokenFetcher credentials -- */ /* This object is a base for credentials that need to acquire an oauth2 token @@ -439,10 +561,11 @@ static void on_oauth2_token_fetcher_http_response( } static void oauth2_token_fetcher_get_request_metadata( - grpc_credentials *creds, grpc_credentials_metadata_cb cb, void *user_data) { + grpc_credentials *creds, const char *service_url, + grpc_credentials_metadata_cb cb, void *user_data) { grpc_oauth2_token_fetcher_credentials *c = (grpc_oauth2_token_fetcher_credentials *)creds; - gpr_timespec refresh_threshold = {GRPC_OAUTH2_TOKEN_REFRESH_THRESHOLD_SECS, + gpr_timespec refresh_threshold = {GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS, 0}; grpc_mdelem *cached_access_token_md = NULL; { @@ -535,7 +658,8 @@ static void service_account_fetch_oauth2( "application/x-www-form-urlencoded"}; grpc_httpcli_request request; char *body = NULL; - char *jwt = grpc_jwt_encode_and_sign(&c->key, c->scope, c->token_lifetime); + char *jwt = grpc_jwt_encode_and_sign(&c->key, GRPC_JWT_OAUTH2_AUDIENCE, + c->token_lifetime, c->scope); if (jwt == NULL) { grpc_httpcli_response response; memset(&response, 0, sizeof(grpc_httpcli_response)); @@ -616,6 +740,7 @@ void on_simulated_token_fetch_done(void *user_data, int success) { } static void fake_oauth2_get_request_metadata(grpc_credentials *creds, + const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) { grpc_fake_oauth2_credentials *c = (grpc_fake_oauth2_credentials *)creds; @@ -709,6 +834,7 @@ typedef struct { size_t creds_index; grpc_mdelem **md_elems; size_t num_md; + char *service_url; void *user_data; grpc_credentials_metadata_cb cb; } grpc_composite_credentials_metadata_context; @@ -754,6 +880,7 @@ static void composite_md_context_destroy( grpc_mdelem_unref(ctx->md_elems[i]); } gpr_free(ctx->md_elems); + if (ctx->service_url != NULL) gpr_free(ctx->service_url); gpr_free(ctx); } @@ -783,8 +910,8 @@ static void composite_metadata_cb(void *user_data, grpc_mdelem **md_elems, grpc_credentials *inner_creds = ctx->composite_creds->inner.creds_array[ctx->creds_index++]; if (grpc_credentials_has_request_metadata(inner_creds)) { - grpc_credentials_get_request_metadata(inner_creds, composite_metadata_cb, - ctx); + grpc_credentials_get_request_metadata(inner_creds, ctx->service_url, + composite_metadata_cb, ctx); return; } } @@ -795,6 +922,7 @@ static void composite_metadata_cb(void *user_data, grpc_mdelem **md_elems, } static void composite_get_request_metadata(grpc_credentials *creds, + const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) { grpc_composite_credentials *c = (grpc_composite_credentials *)creds; @@ -805,14 +933,15 @@ static void composite_get_request_metadata(grpc_credentials *creds, } ctx = gpr_malloc(sizeof(grpc_composite_credentials_metadata_context)); memset(ctx, 0, sizeof(grpc_composite_credentials_metadata_context)); + ctx->service_url = gpr_strdup(service_url); ctx->user_data = user_data; ctx->cb = cb; ctx->composite_creds = c; 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)) { - grpc_credentials_get_request_metadata(inner_creds, composite_metadata_cb, - ctx); + grpc_credentials_get_request_metadata(inner_creds, service_url, + composite_metadata_cb, ctx); return; } } @@ -916,6 +1045,7 @@ static int iam_has_request_metadata_only(const grpc_credentials *creds) { } static void iam_get_request_metadata(grpc_credentials *creds, + const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) { grpc_iam_credentials *c = (grpc_iam_credentials *)creds; diff --git a/src/core/security/credentials.h b/src/core/security/credentials.h index 614db96ad7..7b8929492b 100644 --- a/src/core/security/credentials.h +++ b/src/core/security/credentials.h @@ -50,6 +50,7 @@ typedef enum { #define GRPC_CREDENTIALS_TYPE_SSL "Ssl" #define GRPC_CREDENTIALS_TYPE_OAUTH2 "Oauth2" +#define GRPC_CREDENTIALS_TYPE_JWT "Jwt" #define GRPC_CREDENTIALS_TYPE_IAM "Iam" #define GRPC_CREDENTIALS_TYPE_COMPOSITE "Composite" #define GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY "FakeTransportSecurity" @@ -71,6 +72,7 @@ typedef struct { int (*has_request_metadata)(const grpc_credentials *c); int (*has_request_metadata_only)(const grpc_credentials *c); void (*get_request_metadata)(grpc_credentials *c, + const char *service_url, grpc_credentials_metadata_cb cb, void *user_data); } grpc_credentials_vtable; @@ -86,6 +88,7 @@ void grpc_credentials_unref(grpc_credentials *creds); int grpc_credentials_has_request_metadata(grpc_credentials *creds); int grpc_credentials_has_request_metadata_only(grpc_credentials *creds); void grpc_credentials_get_request_metadata(grpc_credentials *creds, + const char *service_url, grpc_credentials_metadata_cb cb, void *user_data); typedef struct { diff --git a/src/core/security/json_token.c b/src/core/security/json_token.c index 20d62e2b43..26d57036a6 100644 --- a/src/core/security/json_token.c +++ b/src/core/security/json_token.c @@ -55,7 +55,6 @@ const gpr_timespec grpc_max_auth_token_lifetime = {3600, 0}; #define GRPC_AUTH_JSON_KEY_TYPE_INVALID "invalid" #define GRPC_AUTH_JSON_KEY_TYPE_SERVICE_ACCOUNT "service_account" -#define GRPC_JWT_AUDIENCE "https://www.googleapis.com/oauth2/v3/token" #define GRPC_JWT_RSA_SHA256_ALGORITHM "RS256" #define GRPC_JWT_TYPE "JWT" @@ -171,8 +170,8 @@ void grpc_auth_json_key_destruct(grpc_auth_json_key *json_key) { /* --- jwt encoding and signature. --- */ static grpc_json *create_child(grpc_json *brother, grpc_json *parent, - const char *key, const char *value, - grpc_json_type type) { + const char *key, const char *value, + grpc_json_type type) { grpc_json *child = grpc_json_create(type); if (brother) brother->next = child; if (!parent->child) parent->child = child; @@ -182,14 +181,15 @@ static grpc_json *create_child(grpc_json *brother, grpc_json *parent, return child; } -static char *encoded_jwt_header(const char *algorithm) { +static char *encoded_jwt_header(const char *key_id, const char *algorithm) { grpc_json *json = grpc_json_create(GRPC_JSON_OBJECT); grpc_json *child = NULL; char *json_str = NULL; char *result = NULL; child = create_child(NULL, json, "alg", algorithm, GRPC_JSON_STRING); - create_child(child, json, "typ", GRPC_JWT_TYPE, GRPC_JSON_STRING); + child = create_child(child, json, "typ", GRPC_JWT_TYPE, GRPC_JSON_STRING); + create_child(child, json, "kid", key_id, GRPC_JSON_STRING); json_str = grpc_json_dump_to_string(json, 0); result = grpc_base64_encode(json_str, strlen(json_str), 1, 0); @@ -199,7 +199,8 @@ static char *encoded_jwt_header(const char *algorithm) { } static char *encoded_jwt_claim(const grpc_auth_json_key *json_key, - const char *scope, gpr_timespec token_lifetime) { + const char *audience, + gpr_timespec token_lifetime, const char *scope) { grpc_json *json = grpc_json_create(GRPC_JSON_OBJECT); grpc_json *child = NULL; char *json_str = NULL; @@ -217,8 +218,15 @@ static char *encoded_jwt_claim(const grpc_auth_json_key *json_key, child = create_child(NULL, json, "iss", json_key->client_email, GRPC_JSON_STRING); - child = create_child(child, json, "scope", scope, GRPC_JSON_STRING); - child = create_child(child, json, "aud", GRPC_JWT_AUDIENCE, GRPC_JSON_STRING); + if (scope != NULL) { + child = create_child(child, json, "scope", scope, GRPC_JSON_STRING); + } else { + /* Unscoped JWTs need a sub field. */ + child = create_child(child, json, "sub", json_key->client_email, + GRPC_JSON_STRING); + } + + child = create_child(child, json, "aud", audience, GRPC_JSON_STRING); child = create_child(child, json, "iat", now_str, GRPC_JSON_NUMBER); create_child(child, json, "exp", expiration_str, GRPC_JSON_NUMBER); @@ -300,14 +308,16 @@ end: } char *grpc_jwt_encode_and_sign(const grpc_auth_json_key *json_key, - const char *scope, gpr_timespec token_lifetime) { + const char *audience, + gpr_timespec token_lifetime, const char *scope) { if (g_jwt_encode_and_sign_override != NULL) { - return g_jwt_encode_and_sign_override(json_key, scope, token_lifetime); + return g_jwt_encode_and_sign_override(json_key, audience, token_lifetime, + scope); } else { const char *sig_algo = GRPC_JWT_RSA_SHA256_ALGORITHM; char *to_sign = dot_concat_and_free_strings( - encoded_jwt_header(sig_algo), - encoded_jwt_claim(json_key, scope, token_lifetime)); + encoded_jwt_header(json_key->private_key_id, sig_algo), + encoded_jwt_claim(json_key, audience, token_lifetime, scope)); char *sig = compute_and_encode_signature(json_key, sig_algo, to_sign); if (sig == NULL) { gpr_free(to_sign); diff --git a/src/core/security/json_token.h b/src/core/security/json_token.h index 5a9b2dab4b..1ef9682f52 100644 --- a/src/core/security/json_token.h +++ b/src/core/security/json_token.h @@ -37,6 +37,10 @@ #include <grpc/support/slice.h> #include <openssl/rsa.h> +/* --- Constants. --- */ + +#define GRPC_JWT_OAUTH2_AUDIENCE "https://www.googleapis.com/oauth2/v3/token" + /* --- auth_json_key parsing. --- */ typedef struct { @@ -61,14 +65,15 @@ void grpc_auth_json_key_destruct(grpc_auth_json_key *json_key); /* --- json token encoding and signing. --- */ /* Caller is responsible for calling gpr_free on the returned value. May return - NULL on invalid input. */ + NULL on invalid input. The scope parameter may be NULL. */ char *grpc_jwt_encode_and_sign(const grpc_auth_json_key *json_key, - const char *scope, gpr_timespec token_lifetime); + const char *audience, + gpr_timespec token_lifetime, const char *scope); /* Override encode_and_sign function for testing. */ typedef char *(*grpc_jwt_encode_and_sign_override)( - const grpc_auth_json_key *json_key, const char *scope, - gpr_timespec token_lifetime); + const grpc_auth_json_key *json_key, const char *audience, + gpr_timespec token_lifetime, const char *scope); /* Set a custom encode_and_sign override for testing. */ void grpc_jwt_encode_and_sign_set_override( diff --git a/src/core/security/security_context.c b/src/core/security/security_context.c index 37a312bc81..71bd06b271 100644 --- a/src/core/security/security_context.c +++ b/src/core/security/security_context.c @@ -238,6 +238,7 @@ grpc_channel_security_context *grpc_fake_channel_security_context_create( gpr_malloc(sizeof(grpc_fake_channel_security_context)); 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; c->base.base.vtable = &fake_channel_vtable; GPR_ASSERT(check_request_metadata_creds(request_metadata_creds)); c->base.request_metadata_creds = grpc_credentials_ref(request_metadata_creds); @@ -250,6 +251,7 @@ grpc_security_context *grpc_fake_server_security_context_create(void) { grpc_security_context *c = gpr_malloc(sizeof(grpc_security_context)); gpr_ref_init(&c->refcount, 1); c->vtable = &fake_server_vtable; + c->url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME; return c; } @@ -458,6 +460,7 @@ grpc_security_status grpc_ssl_channel_security_context_create( gpr_ref_init(&c->base.base.refcount, 1); c->base.base.vtable = &ssl_channel_vtable; c->base.base.is_client_side = 1; + c->base.base.url_scheme = GRPC_SSL_URL_SCHEME; c->base.request_metadata_creds = grpc_credentials_ref(request_metadata_creds); c->base.check_call_host = ssl_channel_check_call_host; if (target_name != NULL) { @@ -525,6 +528,7 @@ grpc_security_status grpc_ssl_server_security_context_create( memset(c, 0, sizeof(grpc_ssl_server_security_context)); gpr_ref_init(&c->base.refcount, 1); + c->base.url_scheme = GRPC_SSL_URL_SCHEME; c->base.vtable = &ssl_server_vtable; result = tsi_create_ssl_server_handshaker_factory( (const unsigned char **)config->pem_private_keys, diff --git a/src/core/security/security_context.h b/src/core/security/security_context.h index 2b9610fac3..40e2daceb8 100644 --- a/src/core/security/security_context.h +++ b/src/core/security/security_context.h @@ -47,6 +47,11 @@ typedef enum { GRPC_SECURITY_ERROR } grpc_security_status; +/* --- URL schemes. --- */ + +#define GRPC_SSL_URL_SCHEME "https" +#define GRPC_FAKE_SECURITY_URL_SCHEME "http+fake_security" + /* --- security_context object. --- A security context object represents away to configure the underlying @@ -72,6 +77,7 @@ struct grpc_security_context { const grpc_security_context_vtable *vtable; gpr_refcount refcount; int is_client_side; + const char *url_scheme; }; /* Increments the refcount. */ |