aboutsummaryrefslogtreecommitdiffhomepage
path: root/test/core/security
diff options
context:
space:
mode:
authorGravatar jboeuf <jboeuf@google.com>2014-12-19 15:44:30 -0800
committerGravatar Jan Tattermusch <jtattermusch@google.com>2014-12-29 17:03:04 -0800
commit1a809c0ebbf77aedf7f6322ef7d6373962c80264 (patch)
tree40ba18186cf5078fc36d8a5cb99b37e75015b3a1 /test/core/security
parent3f1af6ee2d5eb9898e9b21270f7fc1f5ee39b37a (diff)
Adding support for service account credentials.
- Tested end to end with a JSON key I generated for my account using the fetch_oauth2 binary. - The same fetch_oauth2 binary can get a token from the GCE metadata service on a VM in cloud. Change on 2014/12/19 by jboeuf <jboeuf@google.com> ------------- Created by MOE: http://code.google.com/p/moe-java MOE_MIGRATED_REVID=82548689
Diffstat (limited to 'test/core/security')
-rw-r--r--test/core/security/credentials_test.c392
-rw-r--r--test/core/security/fetch_oauth2.c177
2 files changed, 536 insertions, 33 deletions
diff --git a/test/core/security/credentials_test.c b/test/core/security/credentials_test.c
index 7eca8442b4..619f09308e 100644
--- a/test/core/security/credentials_test.c
+++ b/test/core/security/credentials_test.c
@@ -33,12 +33,16 @@
#include "src/core/security/credentials.h"
+#include <string.h>
+
#include "src/core/httpcli/httpcli.h"
+#include "src/core/security/json_token.h"
+#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+#include <grpc/support/string.h>
#include <grpc/support/time.h>
#include "test/core/util/test_config.h"
-
-#include <string.h>
+#include <openssl/rsa.h>
static const char test_iam_authorization_token[] = "blahblahblhahb";
static const char test_iam_authority_selector[] = "respectmyauthoritah";
@@ -46,30 +50,86 @@ static const char test_oauth2_bearer_token[] =
"Bearer blaaslkdjfaslkdfasdsfasf";
static const unsigned char test_root_cert[] = {0xDE, 0xAD, 0xBE, 0xEF};
+/* This JSON key was generated with the GCE console and revoked immediately.
+ The identifiers have been changed as well.
+ Maximum size for a string literal is 509 chars in C89, yay! */
+static const char test_json_key_str_part1[] =
+ "{ \"private_key\": \"-----BEGIN PRIVATE KEY-----"
+ "\nMIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAOEvJsnoHnyHkXcp\n7mJEqg"
+ "WGjiw71NfXByguekSKho65FxaGbsnSM9SMQAqVk7Q2rG+I0OpsT0LrWQtZ\nyjSeg/"
+ "rWBQvS4hle4LfijkP3J5BG+"
+ "IXDMP8RfziNRQsenAXDNPkY4kJCvKux2xdD\nOnVF6N7dL3nTYZg+"
+ "uQrNsMTz9UxVAgMBAAECgYEAzbLewe1xe9vy+2GoSsfib+28\nDZgSE6Bu/"
+ "zuFoPrRc6qL9p2SsnV7txrunTyJkkOnPLND9ABAXybRTlcVKP/sGgza\n/"
+ "8HpCqFYM9V8f34SBWfD4fRFT+n/"
+ "73cfRUtGXdXpseva2lh8RilIQfPhNZAncenU\ngqXjDvpkypEusgXAykECQQD+";
+static const char test_json_key_str_part2[] =
+ "53XxNVnxBHsYb+AYEfklR96yVi8HywjVHP34+OQZ\nCslxoHQM8s+"
+ "dBnjfScLu22JqkPv04xyxmt0QAKm9+vTdAkEA4ib7YvEAn2jXzcCI\nEkoy2L/"
+ "XydR1GCHoacdfdAwiL2npOdnbvi4ZmdYRPY1LSTO058tQHKVXV7NLeCa3\nAARh2QJBAMKeDAG"
+ "W303SQv2cZTdbeaLKJbB5drz3eo3j7dDKjrTD9JupixFbzcGw\n8FZi5c8idxiwC36kbAL6HzA"
+ "ZoX+ofI0CQE6KCzPJTtYNqyShgKAZdJ8hwOcvCZtf\n6z8RJm0+"
+ "6YBd38lfh5j8mZd7aHFf6I17j5AQY7oPEc47TjJj/"
+ "5nZ68ECQQDvYuI3\nLyK5fS8g0SYbmPOL9TlcHDOqwG0mrX9qpg5DC2fniXNSrrZ64GTDKdzZY"
+ "Ap6LI9W\nIqv4vr6y38N79TTC\n-----END PRIVATE KEY-----\n\", ";
+static const char test_json_key_str_part3[] =
+ "\"private_key_id\": \"e6b5137873db8d2ef81e06a47289e6434ec8a165\", "
+ "\"client_email\": "
+ "\"777-abaslkan11hlb6nmim3bpspl31ud@developer.gserviceaccount."
+ "com\", \"client_id\": "
+ "\"777-abaslkan11hlb6nmim3bpspl31ud.apps.googleusercontent."
+ "com\", \"type\": \"service_account\" }";
+
+static const char valid_oauth2_json_response[] =
+ "{\"access_token\":\"ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_\","
+ " \"expires_in\":3599, "
+ " \"token_type\":\"Bearer\"}";
+
+static const char test_user_data[] = "user data";
+
+static const char test_scope[] = "perm1 perm2";
+
+static const char test_signed_jwt[] = "signed jwt";
+
+static const char expected_service_account_http_body_prefix[] =
+ "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&"
+ "assertion=";
+
+static char *test_json_key_str(void) {
+ size_t result_len = strlen(test_json_key_str_part1) +
+ strlen(test_json_key_str_part2) +
+ strlen(test_json_key_str_part3);
+ char *result = gpr_malloc(result_len + 1);
+ char *current = result;
+ strcpy(result, test_json_key_str_part1);
+ current += strlen(test_json_key_str_part1);
+ strcpy(current, test_json_key_str_part2);
+ current += strlen(test_json_key_str_part2);
+ strcpy(current, test_json_key_str_part3);
+ return result;
+}
+
typedef struct {
const char *key;
const char *value;
} expected_md;
-static grpc_httpcli_response http_response(int status, char *body) {
+static grpc_httpcli_response http_response(int status, const char *body) {
grpc_httpcli_response response;
memset(&response, 0, sizeof(grpc_httpcli_response));
response.status = status;
- response.body = body;
+ response.body = (char *)body;
response.body_length = strlen(body);
return response;
}
-static void test_compute_engine_creds_parsing_ok(void) {
+static void test_oauth2_token_fetcher_creds_parsing_ok(void) {
grpc_mdctx *ctx = grpc_mdctx_create();
grpc_mdelem *token_elem = NULL;
gpr_timespec token_lifetime;
grpc_httpcli_response response =
- http_response(200,
- "{\"access_token\":\"ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_\","
- " \"expires_in\":3599, "
- " \"token_type\":\"Bearer\"}");
- GPR_ASSERT(grpc_compute_engine_credentials_parse_server_response(
+ http_response(200, valid_oauth2_json_response);
+ GPR_ASSERT(grpc_oauth2_token_fetcher_credentials_parse_server_response(
&response, ctx, &token_elem, &token_lifetime) ==
GRPC_CREDENTIALS_OK);
GPR_ASSERT(token_lifetime.tv_sec == 3599);
@@ -81,33 +141,30 @@ static void test_compute_engine_creds_parsing_ok(void) {
grpc_mdctx_orphan(ctx);
}
-static void test_compute_engine_creds_parsing_bad_http_status(void) {
+static void test_oauth2_token_fetcher_creds_parsing_bad_http_status(void) {
grpc_mdctx *ctx = grpc_mdctx_create();
grpc_mdelem *token_elem = NULL;
gpr_timespec token_lifetime;
grpc_httpcli_response response =
- http_response(401,
- "{\"access_token\":\"ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_\","
- " \"expires_in\":3599, "
- " \"token_type\":\"Bearer\"}");
- GPR_ASSERT(grpc_compute_engine_credentials_parse_server_response(
+ http_response(401, valid_oauth2_json_response);
+ GPR_ASSERT(grpc_oauth2_token_fetcher_credentials_parse_server_response(
&response, ctx, &token_elem, &token_lifetime) ==
GRPC_CREDENTIALS_ERROR);
grpc_mdctx_orphan(ctx);
}
-static void test_compute_engine_creds_parsing_empty_http_body(void) {
+static void test_oauth2_token_fetcher_creds_parsing_empty_http_body(void) {
grpc_mdctx *ctx = grpc_mdctx_create();
grpc_mdelem *token_elem = NULL;
gpr_timespec token_lifetime;
grpc_httpcli_response response = http_response(200, "");
- GPR_ASSERT(grpc_compute_engine_credentials_parse_server_response(
+ GPR_ASSERT(grpc_oauth2_token_fetcher_credentials_parse_server_response(
&response, ctx, &token_elem, &token_lifetime) ==
GRPC_CREDENTIALS_ERROR);
grpc_mdctx_orphan(ctx);
}
-static void test_compute_engine_creds_parsing_invalid_json(void) {
+static void test_oauth2_token_fetcher_creds_parsing_invalid_json(void) {
grpc_mdctx *ctx = grpc_mdctx_create();
grpc_mdelem *token_elem = NULL;
gpr_timespec token_lifetime;
@@ -116,13 +173,13 @@ static void test_compute_engine_creds_parsing_invalid_json(void) {
"{\"access_token\":\"ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_\","
" \"expires_in\":3599, "
" \"token_type\":\"Bearer\"");
- GPR_ASSERT(grpc_compute_engine_credentials_parse_server_response(
+ GPR_ASSERT(grpc_oauth2_token_fetcher_credentials_parse_server_response(
&response, ctx, &token_elem, &token_lifetime) ==
GRPC_CREDENTIALS_ERROR);
grpc_mdctx_orphan(ctx);
}
-static void test_compute_engine_creds_parsing_missing_token(void) {
+static void test_oauth2_token_fetcher_creds_parsing_missing_token(void) {
grpc_mdctx *ctx = grpc_mdctx_create();
grpc_mdelem *token_elem = NULL;
gpr_timespec token_lifetime;
@@ -130,13 +187,13 @@ static void test_compute_engine_creds_parsing_missing_token(void) {
"{"
" \"expires_in\":3599, "
" \"token_type\":\"Bearer\"}");
- GPR_ASSERT(grpc_compute_engine_credentials_parse_server_response(
+ GPR_ASSERT(grpc_oauth2_token_fetcher_credentials_parse_server_response(
&response, ctx, &token_elem, &token_lifetime) ==
GRPC_CREDENTIALS_ERROR);
grpc_mdctx_orphan(ctx);
}
-static void test_compute_engine_creds_parsing_missing_token_type(void) {
+static void test_oauth2_token_fetcher_creds_parsing_missing_token_type(void) {
grpc_mdctx *ctx = grpc_mdctx_create();
grpc_mdelem *token_elem = NULL;
gpr_timespec token_lifetime;
@@ -145,13 +202,14 @@ static void test_compute_engine_creds_parsing_missing_token_type(void) {
"{\"access_token\":\"ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_\","
" \"expires_in\":3599, "
"}");
- GPR_ASSERT(grpc_compute_engine_credentials_parse_server_response(
+ GPR_ASSERT(grpc_oauth2_token_fetcher_credentials_parse_server_response(
&response, ctx, &token_elem, &token_lifetime) ==
GRPC_CREDENTIALS_ERROR);
grpc_mdctx_orphan(ctx);
}
-static void test_compute_engine_creds_parsing_missing_token_lifetime(void) {
+static void test_oauth2_token_fetcher_creds_parsing_missing_token_lifetime(
+ void) {
grpc_mdctx *ctx = grpc_mdctx_create();
grpc_mdelem *token_elem = NULL;
gpr_timespec token_lifetime;
@@ -159,7 +217,7 @@ static void test_compute_engine_creds_parsing_missing_token_lifetime(void) {
http_response(200,
"{\"access_token\":\"ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_\","
" \"token_type\":\"Bearer\"}");
- GPR_ASSERT(grpc_compute_engine_credentials_parse_server_response(
+ GPR_ASSERT(grpc_oauth2_token_fetcher_credentials_parse_server_response(
&response, ctx, &token_elem, &token_lifetime) ==
GRPC_CREDENTIALS_ERROR);
grpc_mdctx_orphan(ctx);
@@ -285,17 +343,285 @@ static void test_ssl_oauth2_iam_composite_creds(void) {
composite_creds);
}
+static void on_oauth2_creds_get_metadata_success(
+ void *user_data, grpc_mdelem **md_elems, size_t num_md,
+ grpc_credentials_status status) {
+ GPR_ASSERT(status == GRPC_CREDENTIALS_OK);
+ GPR_ASSERT(num_md == 1);
+ GPR_ASSERT(
+ !strcmp(grpc_mdstr_as_c_string(md_elems[0]->key), "Authorization"));
+ GPR_ASSERT(!strcmp(grpc_mdstr_as_c_string(md_elems[0]->value),
+ "Bearer ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_"));
+ GPR_ASSERT(user_data != NULL);
+ GPR_ASSERT(!strcmp((const char *)user_data, test_user_data));
+}
+
+static void on_oauth2_creds_get_metadata_failure(
+ void *user_data, grpc_mdelem **md_elems, size_t num_md,
+ grpc_credentials_status status) {
+ GPR_ASSERT(status == GRPC_CREDENTIALS_ERROR);
+ GPR_ASSERT(num_md == 0);
+ GPR_ASSERT(user_data != NULL);
+ GPR_ASSERT(!strcmp((const char *)user_data, test_user_data));
+}
+
+static void validate_compute_engine_http_request(
+ const grpc_httpcli_request *request) {
+ GPR_ASSERT(!request->use_ssl);
+ GPR_ASSERT(!strcmp(request->host, "metadata"));
+ GPR_ASSERT(
+ !strcmp(request->path,
+ "/computeMetadata/v1/instance/service-accounts/default/token"));
+ GPR_ASSERT(request->hdr_count == 1);
+ GPR_ASSERT(!strcmp(request->hdrs[0].key, "Metadata-Flavor"));
+ GPR_ASSERT(!strcmp(request->hdrs[0].value, "Google"));
+}
+
+static int compute_engine_httpcli_get_success_override(
+ const grpc_httpcli_request *request, gpr_timespec deadline,
+ grpc_httpcli_response_cb on_response, void *user_data) {
+ grpc_httpcli_response response =
+ http_response(200, valid_oauth2_json_response);
+ validate_compute_engine_http_request(request);
+ on_response(user_data, &response);
+ return 1;
+}
+
+static int compute_engine_httpcli_get_failure_override(
+ const grpc_httpcli_request *request, gpr_timespec deadline,
+ grpc_httpcli_response_cb on_response, void *user_data) {
+ grpc_httpcli_response response = http_response(403, "Not Authorized.");
+ validate_compute_engine_http_request(request);
+ on_response(user_data, &response);
+ return 1;
+}
+
+static int httpcli_post_should_not_be_called(
+ const grpc_httpcli_request *request, const char *body_bytes,
+ size_t body_size, gpr_timespec deadline,
+ grpc_httpcli_response_cb on_response, void *user_data) {
+ GPR_ASSERT("HTTP POST should not be called" == NULL);
+ return 1;
+}
+
+static int httpcli_get_should_not_be_called(
+ const grpc_httpcli_request *request, gpr_timespec deadline,
+ grpc_httpcli_response_cb on_response, void *user_data) {
+ GPR_ASSERT("HTTP GET should not be called" == NULL);
+ return 1;
+}
+
+static void test_compute_engine_creds_success(void) {
+ grpc_credentials *compute_engine_creds =
+ grpc_compute_engine_credentials_create();
+ GPR_ASSERT(grpc_credentials_has_request_metadata(compute_engine_creds));
+ GPR_ASSERT(grpc_credentials_has_request_metadata_only(compute_engine_creds));
+
+ /* First request: http get should be called. */
+ grpc_httpcli_set_override(compute_engine_httpcli_get_success_override,
+ httpcli_post_should_not_be_called);
+ grpc_credentials_get_request_metadata(compute_engine_creds,
+ on_oauth2_creds_get_metadata_success,
+ (void *)test_user_data);
+
+ /* Second request: the cached token should be served directly. */
+ grpc_httpcli_set_override(httpcli_get_should_not_be_called,
+ httpcli_post_should_not_be_called);
+ grpc_credentials_get_request_metadata(compute_engine_creds,
+ on_oauth2_creds_get_metadata_success,
+ (void *)test_user_data);
+
+ grpc_credentials_unref(compute_engine_creds);
+ grpc_httpcli_set_override(NULL, NULL);
+}
+
+static void test_compute_engine_creds_failure(void) {
+ grpc_credentials *compute_engine_creds =
+ grpc_compute_engine_credentials_create();
+ grpc_httpcli_set_override(compute_engine_httpcli_get_failure_override,
+ httpcli_post_should_not_be_called);
+ GPR_ASSERT(grpc_credentials_has_request_metadata(compute_engine_creds));
+ GPR_ASSERT(grpc_credentials_has_request_metadata_only(compute_engine_creds));
+ grpc_credentials_get_request_metadata(compute_engine_creds,
+ on_oauth2_creds_get_metadata_failure,
+ (void *)test_user_data);
+ grpc_credentials_unref(compute_engine_creds);
+ grpc_httpcli_set_override(NULL, NULL);
+}
+
+static void validate_jwt_encode_and_sign_params(
+ const grpc_auth_json_key *json_key, const char *scope,
+ gpr_timespec token_lifetime) {
+ GPR_ASSERT(grpc_auth_json_key_is_valid(json_key));
+ GPR_ASSERT(json_key->private_key != NULL);
+ GPR_ASSERT(RSA_check_key(json_key->private_key));
+ GPR_ASSERT(json_key->type != NULL &&
+ !(strcmp(json_key->type, "service_account")));
+ GPR_ASSERT(json_key->private_key_id != NULL &&
+ !strcmp(json_key->private_key_id,
+ "e6b5137873db8d2ef81e06a47289e6434ec8a165"));
+ GPR_ASSERT(json_key->client_id != NULL &&
+ !strcmp(json_key->client_id,
+ "777-abaslkan11hlb6nmim3bpspl31ud.apps."
+ "googleusercontent.com"));
+ GPR_ASSERT(json_key->client_email != NULL &&
+ !strcmp(json_key->client_email,
+ "777-abaslkan11hlb6nmim3bpspl31ud@developer."
+ "gserviceaccount.com"));
+ GPR_ASSERT(!strcmp(scope, test_scope));
+ GPR_ASSERT(!gpr_time_cmp(token_lifetime, grpc_max_auth_token_lifetime));
+}
+
+static char *encode_and_sign_jwt_success(const grpc_auth_json_key *json_key,
+ const char *scope,
+ gpr_timespec token_lifetime) {
+ validate_jwt_encode_and_sign_params(json_key, scope, token_lifetime);
+ return gpr_strdup(test_signed_jwt);
+}
+
+static char *encode_and_sign_jwt_failure(const grpc_auth_json_key *json_key,
+ const char *scope,
+ gpr_timespec token_lifetime) {
+ validate_jwt_encode_and_sign_params(json_key, scope, token_lifetime);
+ return NULL;
+}
+
+static char *encode_and_sign_jwt_should_not_be_called(
+ const grpc_auth_json_key *json_key, const char *scope,
+ gpr_timespec token_lifetime) {
+ GPR_ASSERT("grpc_jwt_encode_and_sign should not be called" == NULL);
+}
+
+static void validate_service_account_http_request(
+ const grpc_httpcli_request *request, const char *body, size_t body_size) {
+ /* The content of the assertion is tested extensively in json_token_test. */
+ char *expected_body = NULL;
+ GPR_ASSERT(body != NULL);
+ GPR_ASSERT(body_size != 0);
+ expected_body = gpr_malloc(strlen(expected_service_account_http_body_prefix) +
+ strlen(test_signed_jwt) + 1);
+ sprintf(expected_body, "%s%s", expected_service_account_http_body_prefix,
+ test_signed_jwt);
+ GPR_ASSERT(strlen(expected_body) == body_size);
+ GPR_ASSERT(!memcmp(expected_body, body, body_size));
+ gpr_free(expected_body);
+ GPR_ASSERT(request->use_ssl);
+ GPR_ASSERT(!strcmp(request->host, "www.googleapis.com"));
+ GPR_ASSERT(!strcmp(request->path, "/oauth2/v3/token"));
+ GPR_ASSERT(request->hdr_count == 1);
+ GPR_ASSERT(!strcmp(request->hdrs[0].key, "Content-Type"));
+ GPR_ASSERT(
+ !strcmp(request->hdrs[0].value, "application/x-www-form-urlencoded"));
+}
+
+static int service_account_httpcli_post_success(
+ const grpc_httpcli_request *request, const char *body, size_t body_size,
+ gpr_timespec deadline, grpc_httpcli_response_cb on_response,
+ void *user_data) {
+ grpc_httpcli_response response =
+ http_response(200, valid_oauth2_json_response);
+ validate_service_account_http_request(request, body, body_size);
+ on_response(user_data, &response);
+ return 1;
+}
+
+static int service_account_httpcli_post_failure(
+ const grpc_httpcli_request *request, const char *body, size_t body_size,
+ gpr_timespec deadline, grpc_httpcli_response_cb on_response,
+ void *user_data) {
+ grpc_httpcli_response response = http_response(403, "Not Authorized.");
+ validate_service_account_http_request(request, body, body_size);
+ on_response(user_data, &response);
+ return 1;
+}
+
+static void test_service_accounts_creds_success(void) {
+ char *json_key_string = test_json_key_str();
+ grpc_credentials *service_account_creds =
+ grpc_service_account_credentials_create(json_key_string, test_scope,
+ grpc_max_auth_token_lifetime);
+ GPR_ASSERT(grpc_credentials_has_request_metadata(service_account_creds));
+ GPR_ASSERT(grpc_credentials_has_request_metadata_only(service_account_creds));
+
+ /* First request: http get should be called. */
+ grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_success);
+ grpc_httpcli_set_override(httpcli_get_should_not_be_called,
+ service_account_httpcli_post_success);
+ grpc_credentials_get_request_metadata(service_account_creds,
+ on_oauth2_creds_get_metadata_success,
+ (void *)test_user_data);
+
+ /* Second request: the cached token should be served directly. */
+ grpc_jwt_encode_and_sign_set_override(
+ encode_and_sign_jwt_should_not_be_called);
+ grpc_httpcli_set_override(httpcli_get_should_not_be_called,
+ httpcli_post_should_not_be_called);
+ grpc_credentials_get_request_metadata(service_account_creds,
+ on_oauth2_creds_get_metadata_success,
+ (void *)test_user_data);
+
+ gpr_free(json_key_string);
+ grpc_credentials_unref(service_account_creds);
+ grpc_jwt_encode_and_sign_set_override(NULL);
+ grpc_httpcli_set_override(NULL, NULL);
+}
+
+static void test_service_accounts_creds_http_failure(void) {
+ char *json_key_string = test_json_key_str();
+ grpc_credentials *service_account_creds =
+ grpc_service_account_credentials_create(json_key_string, test_scope,
+ grpc_max_auth_token_lifetime);
+ GPR_ASSERT(grpc_credentials_has_request_metadata(service_account_creds));
+ GPR_ASSERT(grpc_credentials_has_request_metadata_only(service_account_creds));
+
+ grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_success);
+ grpc_httpcli_set_override(httpcli_get_should_not_be_called,
+ service_account_httpcli_post_failure);
+ grpc_credentials_get_request_metadata(service_account_creds,
+ on_oauth2_creds_get_metadata_failure,
+ (void *)test_user_data);
+
+ gpr_free(json_key_string);
+ grpc_credentials_unref(service_account_creds);
+ grpc_httpcli_set_override(NULL, NULL);
+}
+
+static void test_service_accounts_creds_signing_failure(void) {
+ char *json_key_string = test_json_key_str();
+ grpc_credentials *service_account_creds =
+ grpc_service_account_credentials_create(json_key_string, test_scope,
+ grpc_max_auth_token_lifetime);
+ GPR_ASSERT(grpc_credentials_has_request_metadata(service_account_creds));
+ GPR_ASSERT(grpc_credentials_has_request_metadata_only(service_account_creds));
+
+ grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_failure);
+ grpc_httpcli_set_override(httpcli_get_should_not_be_called,
+ httpcli_post_should_not_be_called);
+ grpc_credentials_get_request_metadata(service_account_creds,
+ on_oauth2_creds_get_metadata_failure,
+ (void *)test_user_data);
+
+ gpr_free(json_key_string);
+ grpc_credentials_unref(service_account_creds);
+ grpc_httpcli_set_override(NULL, NULL);
+}
+
int main(int argc, char **argv) {
grpc_test_init(argc, argv);
- test_compute_engine_creds_parsing_ok();
- test_compute_engine_creds_parsing_bad_http_status();
- test_compute_engine_creds_parsing_empty_http_body();
- test_compute_engine_creds_parsing_invalid_json();
- test_compute_engine_creds_parsing_missing_token();
- test_compute_engine_creds_parsing_missing_token_type();
- test_compute_engine_creds_parsing_missing_token_lifetime();
+ test_oauth2_token_fetcher_creds_parsing_ok();
+ test_oauth2_token_fetcher_creds_parsing_bad_http_status();
+ test_oauth2_token_fetcher_creds_parsing_empty_http_body();
+ test_oauth2_token_fetcher_creds_parsing_invalid_json();
+ test_oauth2_token_fetcher_creds_parsing_missing_token();
+ test_oauth2_token_fetcher_creds_parsing_missing_token_type();
+ test_oauth2_token_fetcher_creds_parsing_missing_token_lifetime();
test_iam_creds();
test_ssl_oauth2_composite_creds();
test_ssl_oauth2_iam_composite_creds();
+ test_compute_engine_creds_success();
+ test_compute_engine_creds_failure();
+ test_service_accounts_creds_success();
+ test_service_accounts_creds_http_failure();
+ test_service_accounts_creds_signing_failure();
return 0;
}
diff --git a/test/core/security/fetch_oauth2.c b/test/core/security/fetch_oauth2.c
new file mode 100644
index 0000000000..c5cc3adfd6
--- /dev/null
+++ b/test/core/security/fetch_oauth2.c
@@ -0,0 +1,177 @@
+/*
+ *
+ * Copyright 2014, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "src/core/security/credentials.h"
+#include <grpc/grpc.h>
+#include <grpc/grpc_security.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/cmdline.h>
+#include <grpc/support/log.h>
+#include <grpc/support/slice.h>
+#include <grpc/support/sync.h>
+
+typedef struct {
+ gpr_cv cv;
+ gpr_mu mu;
+ int is_done;
+} synchronizer;
+
+static void on_oauth2_response(void *user_data, grpc_mdelem **md_elems,
+ size_t num_md, grpc_credentials_status status) {
+ synchronizer *sync = user_data;
+ char *token;
+ gpr_slice token_slice;
+ if (status == GRPC_CREDENTIALS_ERROR) {
+ gpr_log(GPR_ERROR, "Fetching token failed.");
+ } else {
+ GPR_ASSERT(num_md == 1);
+ token_slice = md_elems[0]->value->slice;
+ token = gpr_malloc(GPR_SLICE_LENGTH(token_slice) + 1);
+ memcpy(token, GPR_SLICE_START_PTR(token_slice),
+ GPR_SLICE_LENGTH(token_slice));
+ token[GPR_SLICE_LENGTH(token_slice)] = '\0';
+ printf("Got token: %s.\n", token);
+ gpr_free(token);
+ }
+ gpr_mu_lock(&sync->mu);
+ sync->is_done = 1;
+ gpr_mu_unlock(&sync->mu);
+ gpr_cv_signal(&sync->cv);
+}
+
+static grpc_credentials *create_service_account_creds(
+ const char *json_key_file_path, const char *scope) {
+ char json_key[8192]; /* Should be plenty. */
+ char *current = json_key;
+ FILE *json_key_file = fopen(json_key_file_path, "r");
+ if (json_key_file == NULL) {
+ gpr_log(GPR_ERROR, "Invalid path for json key file: %s.",
+ json_key_file_path);
+ exit(1);
+ }
+
+ do {
+ size_t bytes_read = fread(
+ current, 1, sizeof(json_key) - (current - json_key), json_key_file);
+ if (bytes_read == 0) {
+ if (!feof(json_key_file)) {
+ gpr_log(GPR_ERROR, "Error occured while reading %s.",
+ json_key_file_path);
+ exit(1);
+ }
+ break;
+ }
+ current += bytes_read;
+ } while (sizeof(json_key) > (current - json_key));
+
+ if ((current - json_key) == sizeof(json_key)) {
+ gpr_log(GPR_ERROR, "Json key file %s exceeds size limit (%d bytes).",
+ json_key_file_path, (int)sizeof(json_key));
+ exit(1);
+ }
+ fclose(json_key_file);
+
+ return grpc_service_account_credentials_create(json_key, scope,
+ grpc_max_auth_token_lifetime);
+}
+
+int main(int argc, char **argv) {
+ synchronizer sync;
+ grpc_credentials *creds = NULL;
+ char *json_key_file_path = NULL;
+ int use_gce = 0;
+ char *scope = NULL;
+ gpr_cmdline *cl = gpr_cmdline_create("fetch_oauth2");
+ gpr_cmdline_add_string(cl, "json_key", "File path of the json key.",
+ &json_key_file_path);
+ gpr_cmdline_add_string(cl, "scope", "Space delimited permissions.", &scope);
+ gpr_cmdline_add_flag(
+ cl, "gce",
+ "Get a token from the GCE metadata server (only works in GCE).",
+ &use_gce);
+ gpr_cmdline_parse(cl, argc, argv);
+
+ grpc_init();
+
+ if (use_gce) {
+ if (json_key_file_path != NULL || scope != NULL) {
+ gpr_log(GPR_INFO,
+ "Ignoring json key and scope to get a token from the GCE "
+ "metadata server.");
+ }
+ creds = grpc_compute_engine_credentials_create();
+ if (creds == NULL) {
+ gpr_log(GPR_ERROR, "Could not create gce credentials.");
+ exit(1);
+ }
+ } else {
+ if (json_key_file_path == NULL) {
+ gpr_log(GPR_ERROR, "missing --json_key option.");
+ exit(1);
+ }
+ if (scope == NULL) {
+ gpr_log(GPR_ERROR, "Missing --scope option.");
+ exit(1);
+ }
+
+ creds = create_service_account_creds(json_key_file_path, scope);
+ if (creds == NULL) {
+ gpr_log(GPR_ERROR,
+ "Could not create service account creds. %s does probably not "
+ "contain a valid json key.",
+ json_key_file_path);
+ exit(1);
+ }
+ }
+ GPR_ASSERT(creds != NULL);
+
+ gpr_mu_init(&sync.mu);
+ gpr_cv_init(&sync.cv);
+ sync.is_done = 0;
+
+ grpc_credentials_get_request_metadata(creds, on_oauth2_response, &sync);
+
+ gpr_mu_lock(&sync.mu);
+ while (!sync.is_done) gpr_cv_wait(&sync.cv, &sync.mu, gpr_inf_future);
+ gpr_mu_unlock(&sync.mu);
+
+ gpr_mu_destroy(&sync.mu);
+ gpr_cv_destroy(&sync.cv);
+ grpc_credentials_release(creds);
+ gpr_cmdline_destroy(cl);
+ grpc_shutdown();
+ return 0;
+}