Adding tests and fixing mem leak in default creds.

pull/2323/head
Julien Boeuf 10 years ago
parent 5400606d21
commit b037bb6488
  1. 5
      include/grpc/grpc_security.h
  2. 78
      src/core/security/credentials.c
  3. 95
      src/core/security/credentials.h
  4. 41
      src/core/security/google_default_credentials.c
  5. 71
      test/core/security/credentials_test.c

@ -51,6 +51,11 @@ typedef struct grpc_credentials grpc_credentials;
The creator of the credentials object is responsible for its release. */
void grpc_credentials_release(grpc_credentials *creds);
/* Environment variable that points to the google default application
credentials json key or refresh token. Used in the
grpc_google_default_credentials_create function. */
#define GRPC_GOOGLE_CREDENTIALS_ENV_VAR "GOOGLE_APPLICATION_CREDENTIALS"
/* Creates default credentials to connect to a google gRPC service.
WARNING: Do NOT use this credentials to connect to a non-google service as
this could result in an oauth2 token leak. */

@ -51,12 +51,12 @@
/* -- Common. -- */
typedef struct {
struct grpc_credentials_metadata_request {
grpc_credentials *creds;
grpc_credentials_metadata_cb cb;
grpc_iomgr_closure *on_simulated_token_fetch_done_closure;
void *user_data;
} grpc_credentials_metadata_request;
};
static grpc_credentials_metadata_request *
grpc_credentials_metadata_request_create(grpc_credentials *creds,
@ -151,16 +151,6 @@ grpc_security_status grpc_server_credentials_create_security_connector(
/* -- Ssl credentials. -- */
typedef struct {
grpc_credentials base;
grpc_ssl_config config;
} grpc_ssl_credentials;
typedef struct {
grpc_server_credentials base;
grpc_ssl_server_config config;
} grpc_ssl_server_credentials;
static void ssl_destroy(grpc_credentials *creds) {
grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds;
if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs);
@ -325,22 +315,6 @@ grpc_server_credentials *grpc_ssl_server_credentials_create(
/* -- Jwt credentials -- */
typedef struct {
grpc_credentials base;
/* 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_credentials_md_store *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_credentials_md_store_unref(c->cached.jwt_md);
@ -450,25 +424,6 @@ grpc_credentials *grpc_jwt_credentials_create(const char *json_key,
/* -- Oauth2TokenFetcher credentials -- */
/* This object is a base for credentials that need to acquire an oauth2 token
from an http service. */
typedef void (*grpc_fetch_oauth2_func)(grpc_credentials_metadata_request *req,
grpc_httpcli_context *http_context,
grpc_pollset *pollset,
grpc_httpcli_response_cb response_cb,
gpr_timespec deadline);
typedef struct {
grpc_credentials base;
gpr_mu mu;
grpc_credentials_md_store *access_token_md;
gpr_timespec token_expiration;
grpc_httpcli_context httpcli_context;
grpc_pollset_set pollset_set;
grpc_fetch_oauth2_func fetch_func;
} grpc_oauth2_token_fetcher_credentials;
static void oauth2_token_fetcher_destroy(grpc_credentials *creds) {
grpc_oauth2_token_fetcher_credentials *c =
(grpc_oauth2_token_fetcher_credentials *)creds;
@ -674,13 +629,6 @@ grpc_credentials *grpc_compute_engine_credentials_create(void) {
/* -- ServiceAccount credentials. -- */
typedef struct {
grpc_oauth2_token_fetcher_credentials base;
grpc_auth_json_key key;
char *scope;
gpr_timespec token_lifetime;
} grpc_service_account_credentials;
static void service_account_destroy(grpc_credentials *creds) {
grpc_service_account_credentials *c =
(grpc_service_account_credentials *)creds;
@ -751,11 +699,6 @@ grpc_credentials *grpc_service_account_credentials_create(
/* -- 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);
@ -814,12 +757,6 @@ grpc_credentials *grpc_refresh_token_credentials_create(
/* -- Fake Oauth2 credentials. -- */
typedef struct {
grpc_credentials base;
grpc_credentials_md_store *access_token_md;
int is_async;
} grpc_fake_oauth2_credentials;
static void fake_oauth2_destroy(grpc_credentials *creds) {
grpc_fake_oauth2_credentials *c = (grpc_fake_oauth2_credentials *)creds;
grpc_credentials_md_store_unref(c->access_token_md);
@ -951,12 +888,6 @@ grpc_server_credentials *grpc_fake_transport_security_server_credentials_create(
/* -- Composite credentials. -- */
typedef struct {
grpc_credentials base;
grpc_credentials_array inner;
grpc_credentials *connector_creds;
} grpc_composite_credentials;
typedef struct {
grpc_composite_credentials *composite_creds;
size_t creds_index;
@ -1187,11 +1118,6 @@ grpc_credentials *grpc_credentials_contains_type(
/* -- IAM credentials. -- */
typedef struct {
grpc_credentials base;
grpc_credentials_md_store *iam_md;
} grpc_iam_credentials;
static void iam_destroy(grpc_credentials *creds) {
grpc_iam_credentials *c = (grpc_iam_credentials *)creds;
grpc_credentials_md_store_unref(c->iam_md);

@ -39,6 +39,7 @@
#include <grpc/grpc_security.h>
#include <grpc/support/sync.h>
#include "src/core/httpcli/httpcli.h"
#include "src/core/security/json_token.h"
#include "src/core/security/security_connector.h"
@ -179,6 +180,7 @@ grpc_credentials_status
grpc_oauth2_token_fetcher_credentials_parse_server_response(
const struct grpc_httpcli_response *response,
grpc_credentials_md_store **token_md, gpr_timespec *token_lifetime);
void grpc_flush_cached_google_default_credentials(void);
/* Simulates an oauth2 token fetch with the specified value for testing. */
grpc_credentials *grpc_fake_oauth2_credentials_create(
@ -210,4 +212,97 @@ struct grpc_server_credentials {
grpc_security_status grpc_server_credentials_create_security_connector(
grpc_server_credentials *creds, grpc_security_connector **sc);
/* -- Ssl credentials. -- */
typedef struct {
grpc_credentials base;
grpc_ssl_config config;
} grpc_ssl_credentials;
typedef struct {
grpc_server_credentials base;
grpc_ssl_server_config config;
} grpc_ssl_server_credentials;
/* -- Jwt credentials -- */
typedef struct {
grpc_credentials base;
/* 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_credentials_md_store *jwt_md;
char *service_url;
gpr_timespec jwt_expiration;
} cached;
grpc_auth_json_key key;
gpr_timespec jwt_lifetime;
} grpc_jwt_credentials;
/* -- Oauth2TokenFetcher credentials --
This object is a base for credentials that need to acquire an oauth2 token
from an http service. */
typedef struct grpc_credentials_metadata_request
grpc_credentials_metadata_request;
typedef void (*grpc_fetch_oauth2_func)(grpc_credentials_metadata_request *req,
grpc_httpcli_context *http_context,
grpc_pollset *pollset,
grpc_httpcli_response_cb response_cb,
gpr_timespec deadline);
typedef struct {
grpc_credentials base;
gpr_mu mu;
grpc_credentials_md_store *access_token_md;
gpr_timespec token_expiration;
grpc_httpcli_context httpcli_context;
grpc_pollset_set pollset_set;
grpc_fetch_oauth2_func fetch_func;
} grpc_oauth2_token_fetcher_credentials;
/* -- ServiceAccount credentials. -- */
typedef struct {
grpc_oauth2_token_fetcher_credentials base;
grpc_auth_json_key key;
char *scope;
gpr_timespec token_lifetime;
} grpc_service_account_credentials;
/* -- RefreshToken credentials. -- */
typedef struct {
grpc_oauth2_token_fetcher_credentials base;
grpc_auth_refresh_token refresh_token;
} grpc_refresh_token_credentials;
/* -- Fake Oauth2 credentials. -- */
typedef struct {
grpc_credentials base;
grpc_credentials_md_store *access_token_md;
int is_async;
} grpc_fake_oauth2_credentials;
/* -- IAM credentials. -- */
typedef struct {
grpc_credentials base;
grpc_credentials_md_store *iam_md;
} grpc_iam_credentials;
/* -- Composite credentials. -- */
typedef struct {
grpc_credentials base;
grpc_credentials_array inner;
grpc_credentials *connector_creds;
} grpc_composite_credentials;
#endif /* GRPC_INTERNAL_CORE_SECURITY_CREDENTIALS_H */

@ -46,7 +46,6 @@
/* -- Constants. -- */
#define GRPC_COMPUTE_ENGINE_DETECTION_HOST "metadata.google.internal"
#define GRPC_GOOGLE_CREDENTIALS_ENV_VAR "GOOGLE_APPLICATION_CREDENTIALS"
/* -- Default credentials. -- */
@ -160,23 +159,6 @@ end:
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, 1, &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;
@ -196,7 +178,7 @@ grpc_credentials *grpc_google_default_credentials_create(void) {
if (result != NULL) goto end;
/* Then the well-known file. */
result = create_refresh_token_creds_from_path(
result = create_default_creds_from_path(
grpc_get_well_known_google_credentials_file_path());
if (result != NULL) goto end;
@ -214,11 +196,24 @@ end:
if (!serving_cached_credentials && result != NULL) {
/* Blend with default ssl credentials and add a global reference so that it
can be cached and re-served. */
result = grpc_composite_credentials_create(
grpc_ssl_credentials_create(NULL, NULL), result);
GPR_ASSERT(result != NULL);
default_credentials = grpc_credentials_ref(result);
grpc_credentials *ssl_creds = grpc_ssl_credentials_create(NULL, NULL);
default_credentials = grpc_credentials_ref(grpc_composite_credentials_create(
ssl_creds, result));
GPR_ASSERT(default_credentials != NULL);
grpc_credentials_unref(ssl_creds);
grpc_credentials_unref(result);
result = default_credentials;
}
gpr_mu_unlock(&g_mu);
return result;
}
void grpc_flush_cached_google_default_credentials(void) {
gpr_once_init(&g_once, init_default_credentials);
gpr_mu_lock(&g_mu);
if (default_credentials != NULL) {
grpc_credentials_unref(default_credentials);
default_credentials = NULL;
}
gpr_mu_unlock(&g_mu);
}

@ -37,12 +37,17 @@
#include "src/core/httpcli/httpcli.h"
#include "src/core/security/json_token.h"
#include "src/core/support/env.h"
#include "src/core/support/file.h"
#include "src/core/support/string.h"
#include "test/core/util/test_config.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/time.h>
#include "test/core/util/test_config.h"
#include <openssl/rsa.h>
static const char test_iam_authorization_token[] = "blahblahblhahb";
@ -847,6 +852,68 @@ static void test_jwt_creds_signing_failure(void) {
grpc_jwt_encode_and_sign_set_override(NULL);
}
static void set_google_default_creds_env_var_with_file_contents(
const char *file_prefix, const char *contents) {
size_t contents_len = strlen(contents);
char *creds_file_name;
FILE *creds_file = gpr_tmpfile(file_prefix, &creds_file_name);
GPR_ASSERT(creds_file_name != NULL);
GPR_ASSERT(creds_file != NULL);
GPR_ASSERT(fwrite(contents, 1, contents_len, creds_file) == contents_len);
fclose(creds_file);
gpr_setenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, creds_file_name);
gpr_free(creds_file_name);
}
static grpc_credentials *composite_inner_creds(grpc_credentials *creds,
const char *inner_creds_type) {
size_t i;
grpc_composite_credentials *composite;
GPR_ASSERT(strcmp(creds->type, GRPC_CREDENTIALS_TYPE_COMPOSITE) == 0);
composite = (grpc_composite_credentials *)creds;
for (i = 0; i < composite->inner.num_creds; i++) {
grpc_credentials *c = composite->inner.creds_array[i];
if (strcmp(c->type, inner_creds_type) == 0) return c;
}
GPR_ASSERT(0); /* Not found. */
}
static void test_google_default_creds_auth_key(void) {
grpc_jwt_credentials *jwt;
grpc_credentials *creds;
char *json_key = test_json_key_str();
grpc_flush_cached_google_default_credentials();
set_google_default_creds_env_var_with_file_contents(
"json_key_google_default_creds", json_key);
gpr_free(json_key);
creds = grpc_google_default_credentials_create();
GPR_ASSERT(creds != NULL);
jwt = (grpc_jwt_credentials *)composite_inner_creds(
creds, GRPC_CREDENTIALS_TYPE_JWT);
GPR_ASSERT(
strcmp(jwt->key.client_id,
"777-abaslkan11hlb6nmim3bpspl31ud.apps.googleusercontent.com") ==
0);
grpc_credentials_unref(creds);
gpr_setenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, ""); /* Reset. */
}
static void test_google_default_creds_access_token(void) {
grpc_refresh_token_credentials *refresh;
grpc_credentials *creds;
grpc_flush_cached_google_default_credentials();
set_google_default_creds_env_var_with_file_contents(
"refresh_token_google_default_creds", test_refresh_token_str);
creds = grpc_google_default_credentials_create();
GPR_ASSERT(creds != NULL);
refresh = (grpc_refresh_token_credentials *)composite_inner_creds(
creds, GRPC_CREDENTIALS_TYPE_OAUTH2);
GPR_ASSERT(strcmp(refresh->refresh_token.client_id,
"32555999999.apps.googleusercontent.com") == 0);
grpc_credentials_unref(creds);
gpr_setenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, ""); /* Reset. */
}
int main(int argc, char **argv) {
grpc_test_init(argc, argv);
test_empty_md_store();
@ -874,5 +941,7 @@ int main(int argc, char **argv) {
test_service_account_creds_signing_failure();
test_jwt_creds_success();
test_jwt_creds_signing_failure();
test_google_default_creds_auth_key();
test_google_default_creds_access_token();
return 0;
}

Loading…
Cancel
Save