From 1928d496a237c3850365e2557ae41ae73125fc80 Mon Sep 17 00:00:00 2001 From: Julien Boeuf Date: Tue, 15 Sep 2015 15:20:11 -0700 Subject: [PATCH] Adding C++ tests and fixing a few things. --- src/core/security/client_auth_filter.c | 35 +++++----- src/core/security/credentials.c | 10 ++- test/cpp/end2end/end2end_test.cc | 91 +++++++++++++++++++++++--- 3 files changed, 108 insertions(+), 28 deletions(-) diff --git a/src/core/security/client_auth_filter.c b/src/core/security/client_auth_filter.c index f3ecfd0e60e..c8811325b9b 100644 --- a/src/core/security/client_auth_filter.c +++ b/src/core/security/client_auth_filter.c @@ -63,6 +63,7 @@ typedef struct { int sent_initial_metadata; gpr_uint8 security_context_set; grpc_linked_mdelem md_links[MAX_CREDENTIALS_METADATA_COUNT]; + char *service_url; } call_data; /* We can have a per-channel credentials. */ @@ -75,6 +76,13 @@ typedef struct { grpc_mdstr *status_key; } channel_data; +static void reset_service_url(call_data *calld) { + if (calld->service_url != NULL) { + gpr_free(calld->service_url); + calld->service_url = NULL; + } +} + static void bubble_up_error(grpc_call_element *elem, grpc_status_code status, const char *error_msg) { call_data *calld = elem->call_data; @@ -93,6 +101,7 @@ static void on_credentials_metadata(void *user_data, grpc_transport_stream_op *op = &calld->op; grpc_metadata_batch *mdb; size_t i; + reset_service_url(calld); if (status != GRPC_CREDENTIALS_OK) { bubble_up_error(elem, GRPC_STATUS_UNAUTHENTICATED, "Credentials failed to get metadata."); @@ -111,8 +120,7 @@ static void on_credentials_metadata(void *user_data, grpc_call_next_op(elem, op); } -static char *build_service_url(const char *url_scheme, call_data *calld) { - char *service_url; +void build_service_url(const char *url_scheme, call_data *calld) { char *service = gpr_strdup(grpc_mdstr_as_c_string(calld->method)); char *last_slash = strrchr(service, '/'); if (last_slash == NULL) { @@ -125,10 +133,10 @@ static char *build_service_url(const char *url_scheme, call_data *calld) { *last_slash = '\0'; } if (url_scheme == NULL) url_scheme = ""; - gpr_asprintf(&service_url, "%s://%s%s", url_scheme, + reset_service_url(calld); + gpr_asprintf(&calld->service_url, "%s://%s%s", url_scheme, grpc_mdstr_as_c_string(calld->host), service); gpr_free(service); - return service_url; } static void send_security_metadata(grpc_call_element *elem, @@ -137,7 +145,6 @@ static void send_security_metadata(grpc_call_element *elem, channel_data *chand = elem->channel_data; grpc_client_security_context *ctx = (grpc_client_security_context *)op->context[GRPC_CONTEXT_SECURITY].value; - char *service_url = NULL; grpc_credentials *channel_creds = chand->security_connector->request_metadata_creds; int channel_creds_has_md = @@ -165,13 +172,12 @@ static void send_security_metadata(grpc_call_element *elem, grpc_credentials_ref(call_creds_has_md ? ctx->creds : channel_creds); } - service_url = - build_service_url(chand->security_connector->base.url_scheme, calld); + build_service_url(chand->security_connector->base.url_scheme, calld); calld->op = *op; /* Copy op (originates from the caller's stack). */ GPR_ASSERT(calld->pollset); - grpc_credentials_get_request_metadata( - calld->creds, calld->pollset, service_url, on_credentials_metadata, elem); - gpr_free(service_url); + grpc_credentials_get_request_metadata(calld->creds, calld->pollset, + calld->service_url, + on_credentials_metadata, elem); } static void on_host_checked(void *user_data, grpc_security_status status) { @@ -274,13 +280,7 @@ static void init_call_elem(grpc_call_element *elem, const void *server_transport_data, grpc_transport_stream_op *initial_op) { call_data *calld = elem->call_data; - calld->creds = NULL; - calld->host = NULL; - calld->method = NULL; - calld->pollset = NULL; - calld->sent_initial_metadata = 0; - calld->security_context_set = 0; - + memset(calld, 0, sizeof(*calld)); GPR_ASSERT(!initial_op || !initial_op->send_ops); } @@ -294,6 +294,7 @@ static void destroy_call_elem(grpc_call_element *elem) { if (calld->method != NULL) { GRPC_MDSTR_UNREF(calld->method); } + reset_service_url(calld); } /* Constructor for channel_data */ diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c index afe980a5b04..5d3c7c90b00 100644 --- a/src/core/security/credentials.c +++ b/src/core/security/credentials.c @@ -1221,9 +1221,9 @@ static void plugin_md_request_metadata_ready(void *request, } r->cb(r->user_data, NULL, 0, GRPC_CREDENTIALS_ERROR); } else { + size_t i; grpc_credentials_md *md_array = NULL; if (num_md > 0) { - size_t i; md_array = gpr_malloc(num_md * sizeof(grpc_credentials_md)); for (i = 0; i < num_md; i++) { md_array[i].key = gpr_slice_from_copied_string(md[i].key); @@ -1232,7 +1232,13 @@ static void plugin_md_request_metadata_ready(void *request, } } r->cb(r->user_data, md_array, num_md, GRPC_CREDENTIALS_OK); - if (md_array != NULL) gpr_free(md_array); + if (md_array != NULL) { + for (i = 0; i < num_md; i++) { + gpr_slice_unref(md_array[i].key); + gpr_slice_unref(md_array[i].value); + } + gpr_free(md_array); + } } gpr_free(r); } diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc index 10a4c5ac26c..b844704d980 100644 --- a/test/cpp/end2end/end2end_test.cc +++ b/test/cpp/end2end/end2end_test.cc @@ -108,6 +108,39 @@ bool CheckIsLocalhost(const grpc::string& addr) { addr.substr(0, kIpv6.size()) == kIpv6; } +class TestMetadataCredentialsPlugin : public MetadataCredentialsPlugin { + public: + static const char kMetadataKey[]; + + TestMetadataCredentialsPlugin(grpc::string_ref metadata_value, + bool is_blocking, bool is_successful) + : metadata_value_(metadata_value.data(), metadata_value.length()), + is_blocking_(is_blocking), + is_successful_(is_successful) {} + + bool IsBlocking() const GRPC_OVERRIDE { return is_blocking_; } + + Status GetMetadata(grpc::string_ref service_url, + std::multimap* metadata) + GRPC_OVERRIDE { + EXPECT_GT(service_url.length(), 0UL); + EXPECT_TRUE(metadata != nullptr); + if (is_successful_) { + metadata->insert(std::make_pair(kMetadataKey, metadata_value_)); + return Status::OK; + } else { + return Status(StatusCode::NOT_FOUND, "Could not find plugin metadata."); + } + } + + private: + grpc::string metadata_value_; + bool is_blocking_; + bool is_successful_; +}; + +const char TestMetadataCredentialsPlugin::kMetadataKey[] = "TestPluginMetadata"; + class TestAuthMetadataProcessor : public AuthMetadataProcessor { public: static const char kGoodGuy[]; @@ -115,10 +148,15 @@ class TestAuthMetadataProcessor : public AuthMetadataProcessor { TestAuthMetadataProcessor(bool is_blocking) : is_blocking_(is_blocking) {} std::shared_ptr GetCompatibleClientCreds() { - return AccessTokenCredentials(kGoodGuy); + return MetadataCredentialsFromPlugin( + std::unique_ptr( + new TestMetadataCredentialsPlugin(kGoodGuy, is_blocking_, true))); } + std::shared_ptr GetIncompatibleClientCreds() { - return AccessTokenCredentials("Mr Hyde"); + return MetadataCredentialsFromPlugin( + std::unique_ptr( + new TestMetadataCredentialsPlugin("Mr Hyde", is_blocking_, true))); } // Interface implementation @@ -130,10 +168,11 @@ class TestAuthMetadataProcessor : public AuthMetadataProcessor { EXPECT_TRUE(consumed_auth_metadata != nullptr); EXPECT_TRUE(context != nullptr); EXPECT_TRUE(response_metadata != nullptr); - auto auth_md = auth_metadata.find(GRPC_AUTHORIZATION_METADATA_KEY); + auto auth_md = + auth_metadata.find(TestMetadataCredentialsPlugin::kMetadataKey); EXPECT_NE(auth_md, auth_metadata.end()); string_ref auth_md_value = auth_md->second; - if (auth_md_value.ends_with(kGoodGuy)) { + if (auth_md_value == kGoodGuy) { context->AddProperty(kIdentityPropName, kGoodGuy); context->SetPeerIdentityPropertyName(kIdentityPropName); consumed_auth_metadata->insert( @@ -147,7 +186,7 @@ class TestAuthMetadataProcessor : public AuthMetadataProcessor { } } - protected: + private: static const char kIdentityPropName[]; bool is_blocking_; }; @@ -876,7 +915,24 @@ TEST_F(End2endTest, OverridePerCallCredentials) { EXPECT_TRUE(s.ok()); } -TEST_F(End2endTest, NonBlockingAuthMetadataProcessorSuccess) { +TEST_F(End2endTest, NonBlockingAuthMetadataPluginFailure) { + ResetStub(false); + EchoRequest request; + EchoResponse response; + ClientContext context; + context.set_credentials( + MetadataCredentialsFromPlugin(std::unique_ptr( + new TestMetadataCredentialsPlugin( + "Does not matter, will fail anyway (see 3rd param)", false, + false)))); + request.set_message("Hello"); + + Status s = stub_->Echo(&context, request, &response); + EXPECT_FALSE(s.ok()); + EXPECT_EQ(s.error_code(), StatusCode::UNAUTHENTICATED); +} + +TEST_F(End2endTest, NonBlockingAuthMetadataPluginAndProcessorSuccess) { auto* processor = new TestAuthMetadataProcessor(false); StartServer(std::shared_ptr(processor)); ResetStub(false); @@ -899,7 +955,7 @@ TEST_F(End2endTest, NonBlockingAuthMetadataProcessorSuccess) { grpc::string("Bearer ") + TestAuthMetadataProcessor::kGoodGuy)); } -TEST_F(End2endTest, NonBlockingAuthMetadataProcessorFailure) { +TEST_F(End2endTest, NonBlockingAuthMetadataPluginAndProcessorFailure) { auto* processor = new TestAuthMetadataProcessor(false); StartServer(std::shared_ptr(processor)); ResetStub(false); @@ -914,7 +970,24 @@ TEST_F(End2endTest, NonBlockingAuthMetadataProcessorFailure) { EXPECT_EQ(s.error_code(), StatusCode::UNAUTHENTICATED); } -TEST_F(End2endTest, BlockingAuthMetadataProcessorSuccess) { +TEST_F(End2endTest, BlockingAuthMetadataPluginFailure) { + ResetStub(false); + EchoRequest request; + EchoResponse response; + ClientContext context; + context.set_credentials( + MetadataCredentialsFromPlugin(std::unique_ptr( + new TestMetadataCredentialsPlugin( + "Does not matter, will fail anyway (see 3rd param)", true, + false)))); + request.set_message("Hello"); + + Status s = stub_->Echo(&context, request, &response); + EXPECT_FALSE(s.ok()); + EXPECT_EQ(s.error_code(), StatusCode::UNAUTHENTICATED); +} + +TEST_F(End2endTest, BlockingAuthMetadataPluginAndProcessorSuccess) { auto* processor = new TestAuthMetadataProcessor(true); StartServer(std::shared_ptr(processor)); ResetStub(false); @@ -937,7 +1010,7 @@ TEST_F(End2endTest, BlockingAuthMetadataProcessorSuccess) { grpc::string("Bearer ") + TestAuthMetadataProcessor::kGoodGuy)); } -TEST_F(End2endTest, BlockingAuthMetadataProcessorFailure) { +TEST_F(End2endTest, BlockingAuthMetadataPluginAndProcessorFailure) { auto* processor = new TestAuthMetadataProcessor(true); StartServer(std::shared_ptr(processor)); ResetStub(false);