aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/security/credentials.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/security/credentials.c')
-rw-r--r--src/core/security/credentials.c158
1 files changed, 144 insertions, 14 deletions
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;