aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar Yang Gao <yangg@google.com>2015-03-12 14:43:37 -0700
committerGravatar Yang Gao <yangg@google.com>2015-03-12 14:43:37 -0700
commitc3be769409757bd643ddbd079ea2ac509a5ba8fe (patch)
treeb2aa44bdeac10186504607a1717a7eeedaf93adb /src
parent5bdfe1a1894f45303ce58ea024f0cad077316c8f (diff)
parent9835cf02349840524491bd1684e5b7ea39b63ada (diff)
Merge pull request #983 from jboeuf/refresh_token_parsing
Adding refresh token credentials.
Diffstat (limited to 'src')
-rw-r--r--src/core/security/credentials.c79
-rw-r--r--src/core/security/credentials.h16
-rw-r--r--src/core/security/google_default_credentials.c19
-rw-r--r--src/core/security/json_token.c79
-rw-r--r--src/core/security/json_token.h23
5 files changed, 191 insertions, 25 deletions
diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c
index 3ad1e7edd7..698e099134 100644
--- a/src/core/security/credentials.c
+++ b/src/core/security/credentials.c
@@ -46,20 +46,6 @@
#include <grpc/support/sync.h>
#include <grpc/support/time.h>
-/* -- Constants. -- */
-
-#define GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS 60
-
-#define GRPC_COMPUTE_ENGINE_METADATA_HOST "metadata"
-#define GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH \
- "/computeMetadata/v1/instance/service-accounts/default/token"
-
-#define GRPC_SERVICE_ACCOUNT_HOST "www.googleapis.com"
-#define GRPC_SERVICE_ACCOUNT_TOKEN_PATH "/oauth2/v3/token"
-#define GRPC_SERVICE_ACCOUNT_POST_BODY_PREFIX \
- "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&" \
- "assertion="
-
/* -- Common. -- */
typedef struct {
@@ -671,8 +657,8 @@ static void service_account_fetch_oauth2(
}
gpr_asprintf(&body, "%s%s", GRPC_SERVICE_ACCOUNT_POST_BODY_PREFIX, jwt);
memset(&request, 0, sizeof(grpc_httpcli_request));
- request.host = GRPC_SERVICE_ACCOUNT_HOST;
- request.path = GRPC_SERVICE_ACCOUNT_TOKEN_PATH;
+ request.host = GRPC_GOOGLE_OAUTH2_SERVICE_HOST;
+ request.path = GRPC_GOOGLE_OAUTH2_SERVICE_TOKEN_PATH;
request.hdr_count = 1;
request.hdrs = &header;
request.use_ssl = 1;
@@ -703,6 +689,67 @@ grpc_credentials *grpc_service_account_credentials_create(
return &c->base.base;
}
+/* -- RefreshToken credentials. -- */
+
+typedef struct {
+ grpc_oauth2_token_fetcher_credentials base;
+ grpc_auth_refresh_token refresh_token;
+} grpc_refresh_token_credentials;
+
+static void refresh_token_destroy(grpc_credentials *creds) {
+ grpc_refresh_token_credentials *c =
+ (grpc_refresh_token_credentials *)creds;
+ grpc_auth_refresh_token_destruct(&c->refresh_token);
+ oauth2_token_fetcher_destroy(&c->base.base);
+}
+
+static grpc_credentials_vtable refresh_token_vtable = {
+ refresh_token_destroy, oauth2_token_fetcher_has_request_metadata,
+ oauth2_token_fetcher_has_request_metadata_only,
+ oauth2_token_fetcher_get_request_metadata};
+
+static void refresh_token_fetch_oauth2(
+ grpc_credentials_metadata_request *metadata_req,
+ grpc_httpcli_response_cb response_cb, gpr_timespec deadline) {
+ grpc_refresh_token_credentials *c =
+ (grpc_refresh_token_credentials *)metadata_req->creds;
+ grpc_httpcli_header header = {"Content-Type",
+ "application/x-www-form-urlencoded"};
+ grpc_httpcli_request request;
+ char *body = NULL;
+ gpr_asprintf(&body, GRPC_REFRESH_TOKEN_POST_BODY_FORMAT_STRING,
+ c->refresh_token.client_id, c->refresh_token.client_secret,
+ c->refresh_token.refresh_token);
+ memset(&request, 0, sizeof(grpc_httpcli_request));
+ request.host = GRPC_GOOGLE_OAUTH2_SERVICE_HOST;
+ request.path = GRPC_GOOGLE_OAUTH2_SERVICE_TOKEN_PATH;
+ request.hdr_count = 1;
+ request.hdrs = &header;
+ request.use_ssl = 1;
+ grpc_httpcli_post(&request, body, strlen(body), deadline, response_cb,
+ metadata_req);
+ gpr_free(body);
+}
+
+grpc_credentials *grpc_refresh_token_credentials_create(
+ const char *json_refresh_token) {
+ grpc_refresh_token_credentials *c;
+ grpc_auth_refresh_token refresh_token =
+ grpc_auth_refresh_token_create_from_string(json_refresh_token);
+
+ if (!grpc_auth_refresh_token_is_valid(&refresh_token)) {
+ gpr_log(GPR_ERROR,
+ "Invalid input for refresh token credentials creation");
+ return NULL;
+ }
+ c = gpr_malloc(sizeof(grpc_refresh_token_credentials));
+ memset(c, 0, sizeof(grpc_refresh_token_credentials));
+ init_oauth2_token_fetcher(&c->base, refresh_token_fetch_oauth2);
+ c->base.base.vtable = &refresh_token_vtable;
+ c->refresh_token = refresh_token;
+ return &c->base.base;
+}
+
/* -- Fake Oauth2 credentials. -- */
typedef struct {
diff --git a/src/core/security/credentials.h b/src/core/security/credentials.h
index 454e66845d..0f70670ced 100644
--- a/src/core/security/credentials.h
+++ b/src/core/security/credentials.h
@@ -64,6 +64,22 @@ typedef enum {
#define GRPC_GOOGLE_WELL_KNOWN_CREDENTIALS_FILE \
"application_default_credentials.json"
+#define GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS 60
+
+#define GRPC_COMPUTE_ENGINE_METADATA_HOST "metadata"
+#define GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH \
+ "/computeMetadata/v1/instance/service-accounts/default/token"
+
+#define GRPC_GOOGLE_OAUTH2_SERVICE_HOST "www.googleapis.com"
+#define GRPC_GOOGLE_OAUTH2_SERVICE_TOKEN_PATH "/oauth2/v3/token"
+
+#define GRPC_SERVICE_ACCOUNT_POST_BODY_PREFIX \
+ "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&" \
+ "assertion="
+
+#define GRPC_REFRESH_TOKEN_POST_BODY_FORMAT_STRING \
+ "client_id=%s&client_secret=%s&refresh_token=%s&grant_type=refresh_token"
+
/* --- grpc_credentials. --- */
/* It is the caller's responsibility to gpr_free the result if not NULL. */
diff --git a/src/core/security/google_default_credentials.c b/src/core/security/google_default_credentials.c
index bdc907e7b3..ebea70dad2 100644
--- a/src/core/security/google_default_credentials.c
+++ b/src/core/security/google_default_credentials.c
@@ -138,6 +138,23 @@ static grpc_credentials *create_jwt_creds_from_path(char *creds_path) {
return result;
}
+/* Takes ownership of creds_path if not NULL. */
+static grpc_credentials *create_refresh_token_creds_from_path(
+ char *creds_path) {
+ grpc_credentials *result = NULL;
+ gpr_slice creds_data;
+ int file_ok = 0;
+ if (creds_path == NULL) return NULL;
+ creds_data = gpr_load_file(creds_path, &file_ok);
+ gpr_free(creds_path);
+ if (file_ok) {
+ result = grpc_refresh_token_credentials_create(
+ (const char *)GPR_SLICE_START_PTR(creds_data));
+ gpr_slice_unref(creds_data);
+ }
+ return result;
+}
+
grpc_credentials *grpc_google_default_credentials_create(void) {
grpc_credentials *result = NULL;
int serving_cached_credentials = 0;
@@ -157,7 +174,7 @@ grpc_credentials *grpc_google_default_credentials_create(void) {
if (result != NULL) goto end;
/* Then the well-known file. */
- result = create_jwt_creds_from_path(
+ result = create_refresh_token_creds_from_path(
grpc_get_well_known_google_credentials_file_path());
if (result != NULL) goto end;
diff --git a/src/core/security/json_token.c b/src/core/security/json_token.c
index 40b612b206..eadae33609 100644
--- a/src/core/security/json_token.c
+++ b/src/core/security/json_token.c
@@ -52,8 +52,9 @@
/* 1 hour max. */
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_AUTH_JSON_TYPE_INVALID "invalid"
+#define GRPC_AUTH_JSON_TYPE_SERVICE_ACCOUNT "service_account"
+#define GRPC_AUTH_JSON_TYPE_AUTHORIZED_USER "authorized_user"
#define GRPC_JWT_RSA_SHA256_ALGORITHM "RS256"
#define GRPC_JWT_TYPE "JWT"
@@ -87,7 +88,7 @@ static int set_json_key_string_property(grpc_json *json, const char *prop_name,
int grpc_auth_json_key_is_valid(const grpc_auth_json_key *json_key) {
return (json_key != NULL) &&
- strcmp(json_key->type, GRPC_AUTH_JSON_KEY_TYPE_INVALID);
+ strcmp(json_key->type, GRPC_AUTH_JSON_TYPE_INVALID);
}
grpc_auth_json_key grpc_auth_json_key_create_from_string(
@@ -100,7 +101,7 @@ grpc_auth_json_key grpc_auth_json_key_create_from_string(
int success = 0;
memset(&result, 0, sizeof(grpc_auth_json_key));
- result.type = GRPC_AUTH_JSON_KEY_TYPE_INVALID;
+ result.type = GRPC_AUTH_JSON_TYPE_INVALID;
if (json == NULL) {
gpr_log(GPR_ERROR, "Invalid json string %s", json_string);
goto end;
@@ -108,10 +109,10 @@ grpc_auth_json_key grpc_auth_json_key_create_from_string(
prop_value = json_get_string_property(json, "type");
if (prop_value == NULL ||
- strcmp(prop_value, GRPC_AUTH_JSON_KEY_TYPE_SERVICE_ACCOUNT)) {
+ strcmp(prop_value, GRPC_AUTH_JSON_TYPE_SERVICE_ACCOUNT)) {
goto end;
}
- result.type = GRPC_AUTH_JSON_KEY_TYPE_SERVICE_ACCOUNT;
+ result.type = GRPC_AUTH_JSON_TYPE_SERVICE_ACCOUNT;
if (!set_json_key_string_property(json, "private_key_id",
&result.private_key_id) ||
@@ -148,7 +149,7 @@ end:
void grpc_auth_json_key_destruct(grpc_auth_json_key *json_key) {
if (json_key == NULL) return;
- json_key->type = GRPC_AUTH_JSON_KEY_TYPE_INVALID;
+ json_key->type = GRPC_AUTH_JSON_TYPE_INVALID;
if (json_key->client_id != NULL) {
gpr_free(json_key->client_id);
json_key->client_id = NULL;
@@ -331,3 +332,67 @@ void grpc_jwt_encode_and_sign_set_override(
grpc_jwt_encode_and_sign_override func) {
g_jwt_encode_and_sign_override = func;
}
+
+/* --- grpc_auth_refresh_token --- */
+
+int grpc_auth_refresh_token_is_valid(
+ const grpc_auth_refresh_token *refresh_token) {
+ return (refresh_token != NULL) &&
+ strcmp(refresh_token->type, GRPC_AUTH_JSON_TYPE_INVALID);
+}
+
+grpc_auth_refresh_token grpc_auth_refresh_token_create_from_string(
+ const char *json_string) {
+ grpc_auth_refresh_token result;
+ char *scratchpad = gpr_strdup(json_string);
+ grpc_json *json = grpc_json_parse_string(scratchpad);
+ const char *prop_value;
+ int success = 0;
+
+ memset(&result, 0, sizeof(grpc_auth_refresh_token));
+ result.type = GRPC_AUTH_JSON_TYPE_INVALID;
+ if (json == NULL) {
+ gpr_log(GPR_ERROR, "Invalid json string %s", json_string);
+ goto end;
+ }
+
+ prop_value = json_get_string_property(json, "type");
+ if (prop_value == NULL ||
+ strcmp(prop_value, GRPC_AUTH_JSON_TYPE_AUTHORIZED_USER)) {
+ goto end;
+ }
+ result.type = GRPC_AUTH_JSON_TYPE_AUTHORIZED_USER;
+
+ if (!set_json_key_string_property(json, "client_secret",
+ &result.client_secret) ||
+ !set_json_key_string_property(json, "client_id", &result.client_id) ||
+ !set_json_key_string_property(json, "refresh_token",
+ &result.refresh_token)) {
+ goto end;
+ }
+ success = 1;
+
+end:
+ if (json != NULL) grpc_json_destroy(json);
+ if (!success) grpc_auth_refresh_token_destruct(&result);
+ gpr_free(scratchpad);
+ return result;
+}
+
+void grpc_auth_refresh_token_destruct(grpc_auth_refresh_token *refresh_token) {
+ if (refresh_token == NULL) return;
+ refresh_token->type = GRPC_AUTH_JSON_TYPE_INVALID;
+ if (refresh_token->client_id != NULL) {
+ gpr_free(refresh_token->client_id);
+ refresh_token->client_id = NULL;
+ }
+ if (refresh_token->client_secret != NULL) {
+ gpr_free(refresh_token->client_secret);
+ refresh_token->client_secret = NULL;
+ }
+ if (refresh_token->refresh_token != NULL) {
+ gpr_free(refresh_token->refresh_token);
+ refresh_token->refresh_token = NULL;
+ }
+}
+
diff --git a/src/core/security/json_token.h b/src/core/security/json_token.h
index 029ede3955..197796ab4c 100644
--- a/src/core/security/json_token.h
+++ b/src/core/security/json_token.h
@@ -44,7 +44,7 @@
/* --- auth_json_key parsing. --- */
typedef struct {
- char *type;
+ const char *type;
char *private_key_id;
char *client_id;
char *client_email;
@@ -79,4 +79,25 @@ typedef char *(*grpc_jwt_encode_and_sign_override)(
void grpc_jwt_encode_and_sign_set_override(
grpc_jwt_encode_and_sign_override func);
+/* --- auth_refresh_token parsing. --- */
+
+typedef struct {
+ const char *type;
+ char *client_id;
+ char *client_secret;
+ char *refresh_token;
+} grpc_auth_refresh_token;
+
+/* Returns 1 if the object is valid, 0 otherwise. */
+int grpc_auth_refresh_token_is_valid(
+ const grpc_auth_refresh_token *refresh_token);
+
+/* Creates a refresh token object from string. Returns an invalid object if a
+ parsing error has been encountered. */
+grpc_auth_refresh_token grpc_auth_refresh_token_create_from_string(
+ const char *json_string);
+
+/* Destructs the object. */
+void grpc_auth_refresh_token_destruct(grpc_auth_refresh_token *refresh_token);
+
#endif /* GRPC_INTERNAL_CORE_SECURITY_JSON_TOKEN_H */