diff options
author | Yang Gao <yangg@google.com> | 2015-03-12 14:43:37 -0700 |
---|---|---|
committer | Yang Gao <yangg@google.com> | 2015-03-12 14:43:37 -0700 |
commit | c3be769409757bd643ddbd079ea2ac509a5ba8fe (patch) | |
tree | b2aa44bdeac10186504607a1717a7eeedaf93adb /src | |
parent | 5bdfe1a1894f45303ce58ea024f0cad077316c8f (diff) | |
parent | 9835cf02349840524491bd1684e5b7ea39b63ada (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.c | 79 | ||||
-rw-r--r-- | src/core/security/credentials.h | 16 | ||||
-rw-r--r-- | src/core/security/google_default_credentials.c | 19 | ||||
-rw-r--r-- | src/core/security/json_token.c | 79 | ||||
-rw-r--r-- | src/core/security/json_token.h | 23 |
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 */ |