use a new gcp env check mechansim

pull/15408/head
Yihua Zhang 7 years ago
parent bdbf04cde1
commit e145c52286
  1. 113
      src/core/lib/security/credentials/google_default/google_default_credentials.cc
  2. 10
      src/core/lib/security/credentials/google_default/google_default_credentials.h
  3. 62
      test/core/security/credentials_test.cc

@ -35,6 +35,7 @@
#include "src/core/lib/iomgr/load_file.h" #include "src/core/lib/iomgr/load_file.h"
#include "src/core/lib/iomgr/polling_entity.h" #include "src/core/lib/iomgr/polling_entity.h"
#include "src/core/lib/security/credentials/alts/alts_credentials.h" #include "src/core/lib/security/credentials/alts/alts_credentials.h"
#include "src/core/lib/security/credentials/alts/check_gcp_environment.h"
#include "src/core/lib/security/credentials/google_default/google_default_credentials.h" #include "src/core/lib/security/credentials/google_default/google_default_credentials.h"
#include "src/core/lib/security/credentials/jwt/jwt_credentials.h" #include "src/core/lib/security/credentials/jwt/jwt_credentials.h"
#include "src/core/lib/security/credentials/oauth2/oauth2_credentials.h" #include "src/core/lib/security/credentials/oauth2/oauth2_credentials.h"
@ -51,8 +52,9 @@
static grpc_channel_credentials* g_default_credentials = nullptr; static grpc_channel_credentials* g_default_credentials = nullptr;
static int g_compute_engine_detection_done = 0; static int g_compute_engine_detection_done = 0;
static gpr_mu g_state_mu; static gpr_mu g_state_mu;
static gpr_mu* g_polling_mu;
static gpr_once g_once = GPR_ONCE_INIT; static gpr_once g_once = GPR_ONCE_INIT;
static grpc_core::internal::grpc_gce_tenancy_checker g_gce_tenancy_checker =
grpc_alts_is_running_on_gcp;
static void init_default_credentials(void) { gpr_mu_init(&g_state_mu); } static void init_default_credentials(void) { gpr_mu_init(&g_state_mu); }
@ -111,103 +113,6 @@ static grpc_channel_credentials_vtable google_default_credentials_vtable = {
google_default_credentials_destruct, google_default_credentials_destruct,
google_default_create_security_connector, nullptr}; google_default_create_security_connector, nullptr};
static void on_compute_engine_detection_http_response(void* user_data,
grpc_error* error) {
compute_engine_detector* detector =
static_cast<compute_engine_detector*>(user_data);
if (error == GRPC_ERROR_NONE && detector->response.status == 200 &&
detector->response.hdr_count > 0) {
/* Internet providers can return a generic response to all requests, so
it is necessary to check that metadata header is present also. */
size_t i;
for (i = 0; i < detector->response.hdr_count; i++) {
grpc_http_header* header = &detector->response.hdrs[i];
if (strcmp(header->key, "Metadata-Flavor") == 0 &&
strcmp(header->value, "Google") == 0) {
detector->success = 1;
break;
}
}
}
gpr_mu_lock(g_polling_mu);
detector->is_done = 1;
GRPC_LOG_IF_ERROR(
"Pollset kick",
grpc_pollset_kick(grpc_polling_entity_pollset(&detector->pollent),
nullptr));
gpr_mu_unlock(g_polling_mu);
}
static void destroy_pollset(void* p, grpc_error* e) {
grpc_pollset_destroy(static_cast<grpc_pollset*>(p));
}
static int is_stack_running_on_compute_engine() {
compute_engine_detector detector;
grpc_httpcli_request request;
grpc_httpcli_context context;
grpc_closure destroy_closure;
/* The http call is local. If it takes more than one sec, it is for sure not
on compute engine. */
grpc_millis max_detection_delay = GPR_MS_PER_SEC;
grpc_pollset* pollset =
static_cast<grpc_pollset*>(gpr_zalloc(grpc_pollset_size()));
grpc_pollset_init(pollset, &g_polling_mu);
detector.pollent = grpc_polling_entity_create_from_pollset(pollset);
detector.is_done = 0;
detector.success = 0;
memset(&detector.response, 0, sizeof(detector.response));
memset(&request, 0, sizeof(grpc_httpcli_request));
request.host = (char*)GRPC_COMPUTE_ENGINE_DETECTION_HOST;
request.http.path = (char*)"/";
grpc_httpcli_context_init(&context);
grpc_resource_quota* resource_quota =
grpc_resource_quota_create("google_default_credentials");
grpc_httpcli_get(
&context, &detector.pollent, resource_quota, &request,
grpc_core::ExecCtx::Get()->Now() + max_detection_delay,
GRPC_CLOSURE_CREATE(on_compute_engine_detection_http_response, &detector,
grpc_schedule_on_exec_ctx),
&detector.response);
grpc_resource_quota_unref_internal(resource_quota);
grpc_core::ExecCtx::Get()->Flush();
/* Block until we get the response. This is not ideal but this should only be
called once for the lifetime of the process by the default credentials. */
gpr_mu_lock(g_polling_mu);
while (!detector.is_done) {
grpc_pollset_worker* worker = nullptr;
if (!GRPC_LOG_IF_ERROR(
"pollset_work",
grpc_pollset_work(grpc_polling_entity_pollset(&detector.pollent),
&worker, GRPC_MILLIS_INF_FUTURE))) {
detector.is_done = 1;
detector.success = 0;
}
}
gpr_mu_unlock(g_polling_mu);
grpc_httpcli_context_destroy(&context);
GRPC_CLOSURE_INIT(&destroy_closure, destroy_pollset,
grpc_polling_entity_pollset(&detector.pollent),
grpc_schedule_on_exec_ctx);
grpc_pollset_shutdown(grpc_polling_entity_pollset(&detector.pollent),
&destroy_closure);
g_polling_mu = nullptr;
grpc_core::ExecCtx::Get()->Flush();
gpr_free(grpc_polling_entity_pollset(&detector.pollent));
grpc_http_response_destroy(&detector.response);
return detector.success;
}
/* Takes ownership of creds_path if not NULL. */ /* Takes ownership of creds_path if not NULL. */
static grpc_error* create_default_creds_from_path( static grpc_error* create_default_creds_from_path(
char* creds_path, grpc_call_credentials** creds) { char* creds_path, grpc_call_credentials** creds) {
@ -305,7 +210,7 @@ grpc_channel_credentials* grpc_google_default_credentials_create(void) {
/* At last try to see if we're on compute engine (do the detection only once /* At last try to see if we're on compute engine (do the detection only once
since it requires a network test). */ since it requires a network test). */
if (!g_compute_engine_detection_done) { if (!g_compute_engine_detection_done) {
int need_compute_engine_creds = is_stack_running_on_compute_engine(); int need_compute_engine_creds = g_gce_tenancy_checker();
g_compute_engine_detection_done = 1; g_compute_engine_detection_done = 1;
if (need_compute_engine_creds) { if (need_compute_engine_creds) {
call_creds = grpc_google_compute_engine_credentials_create(nullptr); call_creds = grpc_google_compute_engine_credentials_create(nullptr);
@ -353,6 +258,16 @@ end:
return result; return result;
} }
namespace grpc_core {
namespace internal {
void set_gce_tenancy_checker_for_testing(grpc_gce_tenancy_checker checker) {
g_gce_tenancy_checker = checker;
}
} // namespace internal
} // namespace grpc_core
void grpc_flush_cached_google_default_credentials(void) { void grpc_flush_cached_google_default_credentials(void) {
grpc_core::ExecCtx exec_ctx; grpc_core::ExecCtx exec_ctx;
gpr_once_init(&g_once, init_default_credentials); gpr_once_init(&g_once, init_default_credentials);

@ -47,5 +47,15 @@ typedef struct {
void grpc_flush_cached_google_default_credentials(void); void grpc_flush_cached_google_default_credentials(void);
namespace grpc_core {
namespace internal {
typedef bool (*grpc_gce_tenancy_checker)(void);
void set_gce_tenancy_checker_for_testing(grpc_gce_tenancy_checker checker);
} // namespace internal
} // namespace grpc_core
#endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_GOOGLE_DEFAULT_GOOGLE_DEFAULT_CREDENTIALS_H \ #endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_GOOGLE_DEFAULT_GOOGLE_DEFAULT_CREDENTIALS_H \
*/ */

@ -43,6 +43,8 @@
#include "src/core/lib/security/transport/auth_filters.h" #include "src/core/lib/security/transport/auth_filters.h"
#include "test/core/util/test_config.h" #include "test/core/util/test_config.h"
using grpc_core::internal::set_gce_tenancy_checker_for_testing;
/* -- Mock channel credentials. -- */ /* -- Mock channel credentials. -- */
static grpc_channel_credentials* grpc_mock_channel_credentials_create( static grpc_channel_credentials* grpc_mock_channel_credentials_create(
@ -120,6 +122,12 @@ static const char other_test_service_url[] = "https://bar.com/bar.v1";
static const char test_method[] = "ThisIsNotAMethod"; static const char test_method[] = "ThisIsNotAMethod";
/* -- Global state flags. -- */
static bool g_test_is_on_gce = false;
static bool g_test_gce_tenancy_checker_called = false;
/* -- Utils. -- */ /* -- Utils. -- */
static char* test_json_key_str(void) { static char* test_json_key_str(void) {
@ -910,24 +918,13 @@ static void test_google_default_creds_refresh_token(void) {
gpr_setenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, ""); /* Reset. */ gpr_setenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, ""); /* Reset. */
} }
static int default_creds_gce_detection_httpcli_get_success_override(
const grpc_httpcli_request* request, grpc_millis deadline,
grpc_closure* on_done, grpc_httpcli_response* response) {
*response = http_response(200, "");
grpc_http_header* headers =
static_cast<grpc_http_header*>(gpr_malloc(sizeof(*headers) * 1));
headers[0].key = gpr_strdup("Metadata-Flavor");
headers[0].value = gpr_strdup("Google");
response->hdr_count = 1;
response->hdrs = headers;
GPR_ASSERT(strcmp(request->http.path, "/") == 0);
GPR_ASSERT(strcmp(request->host, "metadata.google.internal") == 0);
GRPC_CLOSURE_SCHED(on_done, GRPC_ERROR_NONE);
return 1;
}
static char* null_well_known_creds_path_getter(void) { return nullptr; } static char* null_well_known_creds_path_getter(void) { return nullptr; }
static bool test_gce_tenancy_checker(void) {
g_test_gce_tenancy_checker_called = true;
return g_test_is_on_gce;
}
static void test_google_default_creds_gce(void) { static void test_google_default_creds_gce(void) {
grpc_core::ExecCtx exec_ctx; grpc_core::ExecCtx exec_ctx;
expected_md emd[] = { expected_md emd[] = {
@ -940,11 +937,11 @@ static void test_google_default_creds_gce(void) {
gpr_setenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, ""); /* Reset. */ gpr_setenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, ""); /* Reset. */
grpc_override_well_known_credentials_path_getter( grpc_override_well_known_credentials_path_getter(
null_well_known_creds_path_getter); null_well_known_creds_path_getter);
set_gce_tenancy_checker_for_testing(test_gce_tenancy_checker);
g_test_gce_tenancy_checker_called = false;
g_test_is_on_gce = true;
/* Simulate a successful detection of GCE. */ /* Simulate a successful detection of GCE. */
grpc_httpcli_set_override(
default_creds_gce_detection_httpcli_get_success_override,
httpcli_post_should_not_be_called);
grpc_composite_channel_credentials* creds = grpc_composite_channel_credentials* creds =
reinterpret_cast<grpc_composite_channel_credentials*>( reinterpret_cast<grpc_composite_channel_credentials*>(
grpc_google_default_credentials_create()); grpc_google_default_credentials_create());
@ -960,11 +957,11 @@ static void test_google_default_creds_gce(void) {
/* Check that we get a cached creds if we call /* Check that we get a cached creds if we call
grpc_google_default_credentials_create again. grpc_google_default_credentials_create again.
GCE detection should not occur anymore either. */ GCE detection should not occur anymore either. */
grpc_httpcli_set_override(httpcli_get_should_not_be_called, g_test_gce_tenancy_checker_called = false;
httpcli_post_should_not_be_called);
grpc_channel_credentials* cached_creds = grpc_channel_credentials* cached_creds =
grpc_google_default_credentials_create(); grpc_google_default_credentials_create();
GPR_ASSERT(cached_creds == &creds->base); GPR_ASSERT(cached_creds == &creds->base);
GPR_ASSERT(g_test_gce_tenancy_checker_called == false);
/* Cleanup. */ /* Cleanup. */
grpc_channel_credentials_unref(cached_creds); grpc_channel_credentials_unref(cached_creds);
@ -973,36 +970,25 @@ static void test_google_default_creds_gce(void) {
grpc_override_well_known_credentials_path_getter(nullptr); grpc_override_well_known_credentials_path_getter(nullptr);
} }
static int default_creds_gce_detection_httpcli_get_failure_override(
const grpc_httpcli_request* request, grpc_millis deadline,
grpc_closure* on_done, grpc_httpcli_response* response) {
/* No magic header. */
GPR_ASSERT(strcmp(request->http.path, "/") == 0);
GPR_ASSERT(strcmp(request->host, "metadata.google.internal") == 0);
*response = http_response(200, "");
GRPC_CLOSURE_SCHED(on_done, GRPC_ERROR_NONE);
return 1;
}
static void test_no_google_default_creds(void) { static void test_no_google_default_creds(void) {
grpc_flush_cached_google_default_credentials(); grpc_flush_cached_google_default_credentials();
gpr_setenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, ""); /* Reset. */ gpr_setenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, ""); /* Reset. */
grpc_override_well_known_credentials_path_getter( grpc_override_well_known_credentials_path_getter(
null_well_known_creds_path_getter); null_well_known_creds_path_getter);
set_gce_tenancy_checker_for_testing(test_gce_tenancy_checker);
g_test_gce_tenancy_checker_called = false;
g_test_is_on_gce = false;
/* Simulate a successful detection of GCE. */ /* Simulate a successful detection of GCE. */
grpc_httpcli_set_override(
default_creds_gce_detection_httpcli_get_failure_override,
httpcli_post_should_not_be_called);
GPR_ASSERT(grpc_google_default_credentials_create() == nullptr); GPR_ASSERT(grpc_google_default_credentials_create() == nullptr);
/* Try a cached one. GCE detection should not occur anymore. */ /* Try a cached one. GCE detection should not occur anymore. */
grpc_httpcli_set_override(httpcli_get_should_not_be_called, g_test_gce_tenancy_checker_called = false;
httpcli_post_should_not_be_called);
GPR_ASSERT(grpc_google_default_credentials_create() == nullptr); GPR_ASSERT(grpc_google_default_credentials_create() == nullptr);
GPR_ASSERT(g_test_gce_tenancy_checker_called == false);
/* Cleanup. */ /* Cleanup. */
grpc_httpcli_set_override(nullptr, nullptr);
grpc_override_well_known_credentials_path_getter(nullptr); grpc_override_well_known_credentials_path_getter(nullptr);
} }

Loading…
Cancel
Save