aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/lib/security/credentials/jwt/jwt_credentials.cc
diff options
context:
space:
mode:
authorGravatar Yash Tibrewal <yashkt@google.com>2017-09-21 18:56:08 -0700
committerGravatar Yash Tibrewal <yashkt@google.com>2017-10-02 16:29:41 -0700
commit83062842c3601faeddcae8f901c515e3c78f3661 (patch)
tree58536b25350a5f2b3123161ab4ca9b8ce01a43a5 /src/core/lib/security/credentials/jwt/jwt_credentials.cc
parent1c9b584a153ff592c92b6cf6baa620d8602a37cd (diff)
Changes for C to C++. Adding extern C to header files for compatibility.
Also converting to .cc
Diffstat (limited to 'src/core/lib/security/credentials/jwt/jwt_credentials.cc')
-rw-r--r--src/core/lib/security/credentials/jwt/jwt_credentials.cc193
1 files changed, 193 insertions, 0 deletions
diff --git a/src/core/lib/security/credentials/jwt/jwt_credentials.cc b/src/core/lib/security/credentials/jwt/jwt_credentials.cc
new file mode 100644
index 0000000000..b361265a7b
--- /dev/null
+++ b/src/core/lib/security/credentials/jwt/jwt_credentials.cc
@@ -0,0 +1,193 @@
+/*
+ *
+ * Copyright 2016 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "src/core/lib/security/credentials/jwt/jwt_credentials.h"
+
+#include <string.h>
+
+#include "src/core/lib/surface/api_trace.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/sync.h>
+
+static void jwt_reset_cache(grpc_exec_ctx *exec_ctx,
+ grpc_service_account_jwt_access_credentials *c) {
+ GRPC_MDELEM_UNREF(exec_ctx, c->cached.jwt_md);
+ c->cached.jwt_md = GRPC_MDNULL;
+ if (c->cached.service_url != NULL) {
+ gpr_free(c->cached.service_url);
+ c->cached.service_url = NULL;
+ }
+ c->cached.jwt_expiration = gpr_inf_past(GPR_CLOCK_REALTIME);
+}
+
+static void jwt_destruct(grpc_exec_ctx *exec_ctx,
+ grpc_call_credentials *creds) {
+ grpc_service_account_jwt_access_credentials *c =
+ (grpc_service_account_jwt_access_credentials *)creds;
+ grpc_auth_json_key_destruct(&c->key);
+ jwt_reset_cache(exec_ctx, c);
+ gpr_mu_destroy(&c->cache_mu);
+}
+
+static bool jwt_get_request_metadata(grpc_exec_ctx *exec_ctx,
+ grpc_call_credentials *creds,
+ grpc_polling_entity *pollent,
+ grpc_auth_metadata_context context,
+ grpc_credentials_mdelem_array *md_array,
+ grpc_closure *on_request_metadata,
+ grpc_error **error) {
+ grpc_service_account_jwt_access_credentials *c =
+ (grpc_service_account_jwt_access_credentials *)creds;
+ gpr_timespec refresh_threshold = gpr_time_from_seconds(
+ GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS, GPR_TIMESPAN);
+
+ /* See if we can return a cached jwt. */
+ grpc_mdelem jwt_md = GRPC_MDNULL;
+ {
+ gpr_mu_lock(&c->cache_mu);
+ if (c->cached.service_url != NULL &&
+ strcmp(c->cached.service_url, context.service_url) == 0 &&
+ !GRPC_MDISNULL(c->cached.jwt_md) &&
+ (gpr_time_cmp(gpr_time_sub(c->cached.jwt_expiration,
+ gpr_now(GPR_CLOCK_REALTIME)),
+ refresh_threshold) > 0)) {
+ jwt_md = GRPC_MDELEM_REF(c->cached.jwt_md);
+ }
+ gpr_mu_unlock(&c->cache_mu);
+ }
+
+ if (GRPC_MDISNULL(jwt_md)) {
+ char *jwt = NULL;
+ /* Generate a new jwt. */
+ gpr_mu_lock(&c->cache_mu);
+ jwt_reset_cache(exec_ctx, c);
+ jwt = grpc_jwt_encode_and_sign(&c->key, context.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(GPR_CLOCK_REALTIME), c->jwt_lifetime);
+ c->cached.service_url = gpr_strdup(context.service_url);
+ c->cached.jwt_md = grpc_mdelem_from_slices(
+ exec_ctx,
+ grpc_slice_from_static_string(GRPC_AUTHORIZATION_METADATA_KEY),
+ grpc_slice_from_copied_string(md_value));
+ gpr_free(md_value);
+ jwt_md = GRPC_MDELEM_REF(c->cached.jwt_md);
+ }
+ gpr_mu_unlock(&c->cache_mu);
+ }
+
+ if (!GRPC_MDISNULL(jwt_md)) {
+ grpc_credentials_mdelem_array_add(md_array, jwt_md);
+ GRPC_MDELEM_UNREF(exec_ctx, jwt_md);
+ } else {
+ *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Could not generate JWT.");
+ }
+ return true;
+}
+
+static void jwt_cancel_get_request_metadata(
+ grpc_exec_ctx *exec_ctx, grpc_call_credentials *c,
+ grpc_credentials_mdelem_array *md_array, grpc_error *error) {
+ GRPC_ERROR_UNREF(error);
+}
+
+static grpc_call_credentials_vtable jwt_vtable = {
+ jwt_destruct, jwt_get_request_metadata, jwt_cancel_get_request_metadata};
+
+grpc_call_credentials *
+grpc_service_account_jwt_access_credentials_create_from_auth_json_key(
+ grpc_exec_ctx *exec_ctx, grpc_auth_json_key key,
+ gpr_timespec token_lifetime) {
+ grpc_service_account_jwt_access_credentials *c;
+ if (!grpc_auth_json_key_is_valid(&key)) {
+ gpr_log(GPR_ERROR, "Invalid input for jwt credentials creation");
+ return NULL;
+ }
+ c = (grpc_service_account_jwt_access_credentials *)gpr_zalloc(
+ sizeof(grpc_service_account_jwt_access_credentials));
+ c->base.type = GRPC_CALL_CREDENTIALS_TYPE_JWT;
+ gpr_ref_init(&c->base.refcount, 1);
+ c->base.vtable = &jwt_vtable;
+ c->key = key;
+ gpr_timespec max_token_lifetime = grpc_max_auth_token_lifetime();
+ if (gpr_time_cmp(token_lifetime, max_token_lifetime) > 0) {
+ gpr_log(GPR_INFO,
+ "Cropping token lifetime to maximum allowed value (%d secs).",
+ (int)max_token_lifetime.tv_sec);
+ token_lifetime = grpc_max_auth_token_lifetime();
+ }
+ c->jwt_lifetime = token_lifetime;
+ gpr_mu_init(&c->cache_mu);
+ jwt_reset_cache(exec_ctx, c);
+ return &c->base;
+}
+
+static char *redact_private_key(const char *json_key) {
+ char *json_copy = gpr_strdup(json_key);
+ grpc_json *json = grpc_json_parse_string(json_copy);
+ if (!json) {
+ gpr_free(json_copy);
+ return gpr_strdup("<Json failed to parse.>");
+ }
+ const char *redacted = "<redacted>";
+ grpc_json *current = json->child;
+ while (current) {
+ if (current->type == GRPC_JSON_STRING &&
+ strcmp(current->key, "private_key") == 0) {
+ current->value = (char *)redacted;
+ break;
+ }
+ current = current->next;
+ }
+ char *clean_json = grpc_json_dump_to_string(json, 2);
+ gpr_free(json_copy);
+ grpc_json_destroy(json);
+ return clean_json;
+}
+
+grpc_call_credentials *grpc_service_account_jwt_access_credentials_create(
+ const char *json_key, gpr_timespec token_lifetime, void *reserved) {
+ if (GRPC_TRACER_ON(grpc_api_trace)) {
+ char *clean_json = redact_private_key(json_key);
+ gpr_log(GPR_INFO,
+ "grpc_service_account_jwt_access_credentials_create("
+ "json_key=%s, "
+ "token_lifetime="
+ "gpr_timespec { tv_sec: %" PRId64
+ ", tv_nsec: %d, clock_type: %d }, "
+ "reserved=%p)",
+ clean_json, token_lifetime.tv_sec, token_lifetime.tv_nsec,
+ (int)token_lifetime.clock_type, reserved);
+ gpr_free(clean_json);
+ }
+ GPR_ASSERT(reserved == NULL);
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_call_credentials *creds =
+ grpc_service_account_jwt_access_credentials_create_from_auth_json_key(
+ &exec_ctx, grpc_auth_json_key_create_from_string(json_key),
+ token_lifetime);
+ grpc_exec_ctx_finish(&exec_ctx);
+ return creds;
+}