aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Yang Gao <yangg@google.com>2015-09-21 09:50:31 -0700
committerGravatar Yang Gao <yangg@google.com>2015-09-21 09:50:31 -0700
commit36a5551db44ce25729af4ac9296f0de21f6fcf84 (patch)
treecd293196f8754f3945b0e12e4f7014ff01ceabd4
parent5896984558d764ce4accee81306a5bb7e3016bc5 (diff)
parent97f80faeb4e300693b424c7bdef95b676fbccf46 (diff)
Merge pull request #3176 from jboeuf/core_creds_plugin
Design and implementation of the core credentials plugin API.
-rw-r--r--include/grpc++/security/credentials.h21
-rw-r--r--include/grpc/grpc_security.h40
-rw-r--r--src/core/security/client_auth_filter.c35
-rw-r--r--src/core/security/credentials.c92
-rw-r--r--src/core/security/credentials.h9
-rw-r--r--src/cpp/client/secure_credentials.cc60
-rw-r--r--src/cpp/client/secure_credentials.h19
-rw-r--r--test/core/security/credentials_test.c105
-rw-r--r--test/cpp/end2end/end2end_test.cc91
9 files changed, 446 insertions, 26 deletions
diff --git a/include/grpc++/security/credentials.h b/include/grpc++/security/credentials.h
index e423849714..01b9710f6b 100644
--- a/include/grpc++/security/credentials.h
+++ b/include/grpc++/security/credentials.h
@@ -34,10 +34,13 @@
#ifndef GRPCXX_CREDENTIALS_H
#define GRPCXX_CREDENTIALS_H
+#include <map>
#include <memory>
#include <grpc++/impl/grpc_library.h>
#include <grpc++/support/config.h>
+#include <grpc++/support/status.h>
+#include <grpc++/support/string_ref.h>
namespace grpc {
class ChannelArguments;
@@ -165,6 +168,24 @@ std::shared_ptr<Credentials> CompositeCredentials(
/// Credentials for an unencrypted, unauthenticated channel
std::shared_ptr<Credentials> InsecureCredentials();
+// User defined metadata credentials.
+class MetadataCredentialsPlugin {
+ public:
+ virtual ~MetadataCredentialsPlugin() {}
+
+ // If this method returns true, the Process function will be scheduled in
+ // a different thread from the one processing the call.
+ virtual bool IsBlocking() const { return true; }
+
+ // Gets the auth metatada produced by this plugin. */
+ virtual Status GetMetadata(
+ grpc::string_ref service_url,
+ std::multimap<grpc::string, grpc::string_ref>* metadata) = 0;
+};
+
+std::shared_ptr<Credentials> MetadataCredentialsFromPlugin(
+ std::unique_ptr<MetadataCredentialsPlugin> plugin);
+
} // namespace grpc
#endif // GRPCXX_CREDENTIALS_H
diff --git a/include/grpc/grpc_security.h b/include/grpc/grpc_security.h
index 87bc250429..44ced4fb43 100644
--- a/include/grpc/grpc_security.h
+++ b/include/grpc/grpc_security.h
@@ -131,6 +131,46 @@ grpc_credentials *grpc_google_iam_credentials_create(
const char *authorization_token, const char *authority_selector,
void *reserved);
+/* Callback function to be called by the metadata credentials plugin
+ implementation when the metadata is ready.
+ - user_data is the opaque pointer that was passed in the get_metadata method
+ of the grpc_metadata_credentials_plugin (see below).
+ - creds_md is an array of credentials metadata produced by the plugin. It
+ may be set to NULL in case of an error.
+ - num_creds_md is the number of items in the creds_md array.
+ - status must be GRPC_STATUS_OK in case of success or another specific error
+ code otherwise.
+ - error_details contains details about the error if any. In case of success
+ it should be NULL and will be otherwise ignored. */
+typedef void (*grpc_credentials_plugin_metadata_cb)(
+ void *user_data, const grpc_metadata *creds_md, size_t num_creds_md,
+ grpc_status_code status, const char *error_details);
+
+/* grpc_metadata_credentials plugin is an API user provided structure used to
+ create grpc_credentials objects that can be set on a channel (composed) or
+ a call. See grpc_credentials_metadata_create_from_plugin below.
+ The grpc client stack will call the get_metadata method of the plugin for
+ every call in scope for the credentials created from it. */
+typedef struct {
+ /* The implementation of this method has to be non-blocking.
+ - service_url is the fully qualified URL that the client stack is
+ connecting to.
+ - cb is the callback that needs to be called when the metadata is ready.
+ - user_data needs to be passed as the first parameter of the callback. */
+ void (*get_metadata)(void *state, const char *service_url,
+ grpc_credentials_plugin_metadata_cb cb, void *user_data);
+
+ /* Destroys the plugin state. */
+ void (*destroy)(void *state);
+
+ /* State that will be set as the first parameter of the methods above. */
+ void *state;
+} grpc_metadata_credentials_plugin;
+
+/* Creates a credentials object from a plugin. */
+grpc_credentials *grpc_metadata_credentials_create_from_plugin(
+ grpc_metadata_credentials_plugin plugin, void *reserved);
+
/* --- Secure channel creation. --- */
/* Creates a secure channel using the passed-in credentials. */
diff --git a/src/core/security/client_auth_filter.c b/src/core/security/client_auth_filter.c
index f3ecfd0e60..c8811325b9 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 a764413300..5d3c7c90b0 100644
--- a/src/core/security/credentials.c
+++ b/src/core/security/credentials.c
@@ -1185,3 +1185,95 @@ grpc_credentials *grpc_google_iam_credentials_create(
c->iam_md, GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY, authority_selector);
return &c->base;
}
+
+/* -- Plugin credentials. -- */
+
+typedef struct {
+ void *user_data;
+ grpc_credentials_metadata_cb cb;
+} grpc_metadata_plugin_request;
+
+static void plugin_destruct(grpc_credentials *creds) {
+ grpc_plugin_credentials *c = (grpc_plugin_credentials *)creds;
+ if (c->plugin.state != NULL && c->plugin.destroy != NULL) {
+ c->plugin.destroy(c->plugin.state);
+ }
+}
+
+static int plugin_has_request_metadata(const grpc_credentials *creds) {
+ return 1;
+}
+
+static int plugin_has_request_metadata_only(const grpc_credentials *creds) {
+ return 1;
+}
+
+static void plugin_md_request_metadata_ready(void *request,
+ const grpc_metadata *md,
+ size_t num_md,
+ grpc_status_code status,
+ const char *error_details) {
+ grpc_metadata_plugin_request *r = (grpc_metadata_plugin_request *)request;
+ if (status != GRPC_STATUS_OK) {
+ if (error_details != NULL) {
+ gpr_log(GPR_ERROR, "Getting metadata from plugin failed with error: %s",
+ error_details);
+ }
+ r->cb(r->user_data, NULL, 0, GRPC_CREDENTIALS_ERROR);
+ } else {
+ size_t i;
+ grpc_credentials_md *md_array = NULL;
+ if (num_md > 0) {
+ 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);
+ md_array[i].value =
+ gpr_slice_from_copied_buffer(md[i].value, md[i].value_length);
+ }
+ }
+ r->cb(r->user_data, md_array, num_md, GRPC_CREDENTIALS_OK);
+ 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);
+}
+
+static void plugin_get_request_metadata(grpc_credentials *creds,
+ grpc_pollset *pollset,
+ const char *service_url,
+ grpc_credentials_metadata_cb cb,
+ void *user_data) {
+ grpc_plugin_credentials *c = (grpc_plugin_credentials *)creds;
+ if (c->plugin.get_metadata != NULL) {
+ grpc_metadata_plugin_request *request = gpr_malloc(sizeof(*request));
+ memset(request, 0, sizeof(*request));
+ request->user_data = user_data;
+ request->cb = cb;
+ c->plugin.get_metadata(c->plugin.state, service_url,
+ plugin_md_request_metadata_ready, request);
+ } else {
+ cb(user_data, NULL, 0, GRPC_CREDENTIALS_OK);
+ }
+}
+
+static grpc_credentials_vtable plugin_vtable = {
+ plugin_destruct, plugin_has_request_metadata,
+ plugin_has_request_metadata_only, plugin_get_request_metadata, NULL};
+
+grpc_credentials *grpc_metadata_credentials_create_from_plugin(
+ grpc_metadata_credentials_plugin plugin, void *reserved) {
+ grpc_plugin_credentials *c = gpr_malloc(sizeof(*c));
+ GPR_ASSERT(reserved == NULL);
+ memset(c, 0, sizeof(*c));
+ c->base.type = GRPC_CREDENTIALS_TYPE_METADATA_PLUGIN;
+ c->base.vtable = &plugin_vtable;
+ gpr_ref_init(&c->base.refcount, 1);
+ c->plugin = plugin;
+ return &c->base;
+}
+
diff --git a/src/core/security/credentials.h b/src/core/security/credentials.h
index 8e4fed7615..38ce0f8ba6 100644
--- a/src/core/security/credentials.h
+++ b/src/core/security/credentials.h
@@ -56,6 +56,7 @@ typedef enum {
#define GRPC_CREDENTIALS_TYPE_SSL "Ssl"
#define GRPC_CREDENTIALS_TYPE_OAUTH2 "Oauth2"
+#define GRPC_CREDENTIALS_TYPE_METADATA_PLUGIN "Plugin"
#define GRPC_CREDENTIALS_TYPE_JWT "Jwt"
#define GRPC_CREDENTIALS_TYPE_IAM "Iam"
#define GRPC_CREDENTIALS_TYPE_COMPOSITE "Composite"
@@ -322,4 +323,12 @@ typedef struct {
grpc_credentials *connector_creds;
} grpc_composite_credentials;
+/* -- Plugin credentials. -- */
+
+typedef struct {
+ grpc_credentials base;
+ grpc_metadata_credentials_plugin plugin;
+ grpc_credentials_md_store *plugin_md;
+} grpc_plugin_credentials;
+
#endif /* GRPC_INTERNAL_CORE_SECURITY_CREDENTIALS_H */
diff --git a/src/cpp/client/secure_credentials.cc b/src/cpp/client/secure_credentials.cc
index 2260f6d33e..8333b01f29 100644
--- a/src/cpp/client/secure_credentials.cc
+++ b/src/cpp/client/secure_credentials.cc
@@ -144,4 +144,64 @@ std::shared_ptr<Credentials> CompositeCredentials(
return nullptr;
}
+void MetadataCredentialsPluginWrapper::Destroy(void* wrapper) {
+ if (wrapper == nullptr) return;
+ MetadataCredentialsPluginWrapper* w =
+ reinterpret_cast<MetadataCredentialsPluginWrapper*>(wrapper);
+ delete w;
+}
+
+void MetadataCredentialsPluginWrapper::GetMetadata(
+ void* wrapper, const char* service_url,
+ grpc_credentials_plugin_metadata_cb cb, void* user_data) {
+ GPR_ASSERT(wrapper != nullptr);
+ MetadataCredentialsPluginWrapper* w =
+ reinterpret_cast<MetadataCredentialsPluginWrapper*>(wrapper);
+ if (w->plugin_ == nullptr) {
+ cb(user_data, NULL, 0, GRPC_STATUS_OK, NULL);
+ return;
+ }
+ if (w->plugin_->IsBlocking()) {
+ w->thread_pool_->Add(
+ std::bind(&MetadataCredentialsPluginWrapper::InvokePlugin, w,
+ service_url, cb, user_data));
+ } else {
+ w->InvokePlugin(service_url, cb, user_data);
+ }
+}
+
+void MetadataCredentialsPluginWrapper::InvokePlugin(
+ const char* service_url, grpc_credentials_plugin_metadata_cb cb,
+ void* user_data) {
+ std::multimap<grpc::string, grpc::string_ref> metadata;
+ Status status = plugin_->GetMetadata(service_url, &metadata);
+ std::vector<grpc_metadata> md;
+ for (auto it = metadata.begin(); it != metadata.end(); ++it) {
+ md.push_back({it->first.c_str(),
+ it->second.data(),
+ it->second.size(),
+ 0,
+ {{nullptr, nullptr, nullptr, nullptr}}});
+ }
+ cb(user_data, &md[0], md.size(),
+ static_cast<grpc_status_code>(status.error_code()),
+ status.error_message().c_str());
+}
+
+MetadataCredentialsPluginWrapper::MetadataCredentialsPluginWrapper(
+ std::unique_ptr<MetadataCredentialsPlugin> plugin)
+ : thread_pool_(CreateDefaultThreadPool()), plugin_(std::move(plugin)) {}
+
+std::shared_ptr<Credentials> MetadataCredentialsFromPlugin(
+ std::unique_ptr<MetadataCredentialsPlugin> plugin) {
+ GrpcLibrary init; // To call grpc_init().
+ MetadataCredentialsPluginWrapper* wrapper =
+ new MetadataCredentialsPluginWrapper(std::move(plugin));
+ grpc_metadata_credentials_plugin c_plugin = {
+ MetadataCredentialsPluginWrapper::GetMetadata,
+ MetadataCredentialsPluginWrapper::Destroy, wrapper};
+ return WrapCredentials(
+ grpc_metadata_credentials_create_from_plugin(c_plugin, nullptr));
+}
+
} // namespace grpc
diff --git a/src/cpp/client/secure_credentials.h b/src/cpp/client/secure_credentials.h
index 8deff856c4..d354827725 100644
--- a/src/cpp/client/secure_credentials.h
+++ b/src/cpp/client/secure_credentials.h
@@ -39,6 +39,8 @@
#include <grpc++/support/config.h>
#include <grpc++/security/credentials.h>
+#include "src/cpp/server/thread_pool_interface.h"
+
namespace grpc {
class SecureCredentials GRPC_FINAL : public Credentials {
@@ -56,6 +58,23 @@ class SecureCredentials GRPC_FINAL : public Credentials {
grpc_credentials* const c_creds_;
};
+class MetadataCredentialsPluginWrapper GRPC_FINAL {
+ public:
+ static void Destroy(void* wrapper);
+ static void GetMetadata(void* wrapper, const char* service_url,
+ grpc_credentials_plugin_metadata_cb cb,
+ void* user_data);
+
+ explicit MetadataCredentialsPluginWrapper(
+ std::unique_ptr<MetadataCredentialsPlugin> plugin);
+
+ private:
+ void InvokePlugin(const char* service_url,
+ grpc_credentials_plugin_metadata_cb cb, void* user_data);
+ std::unique_ptr<ThreadPoolInterface> thread_pool_;
+ std::unique_ptr<MetadataCredentialsPlugin> plugin_;
+};
+
} // namespace grpc
#endif // GRPC_INTERNAL_CPP_CLIENT_SECURE_CREDENTIALS_H
diff --git a/test/core/security/credentials_test.c b/test/core/security/credentials_test.c
index 97ebaa0570..b8cc864317 100644
--- a/test/core/security/credentials_test.c
+++ b/test/core/security/credentials_test.c
@@ -833,6 +833,109 @@ static void test_google_default_creds_access_token(void) {
gpr_setenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, ""); /* Reset. */
}
+typedef enum {
+ PLUGIN_INITIAL_STATE,
+ PLUGIN_GET_METADATA_CALLED_STATE,
+ PLUGIN_DESTROY_CALLED_STATE
+} plugin_state;
+
+typedef struct {
+ const char *key;
+ const char *value;
+} plugin_metadata;
+
+static const plugin_metadata plugin_md[] = {{"foo", "bar"}, {"hi", "there"}};
+
+static void plugin_get_metadata_success(void *state, const char *service_url,
+ grpc_credentials_plugin_metadata_cb cb,
+ void *user_data) {
+ size_t i;
+ grpc_metadata md[GPR_ARRAY_SIZE(plugin_md)];
+ plugin_state *s = (plugin_state *)state;
+ GPR_ASSERT(strcmp(service_url, test_service_url) == 0);
+ *s = PLUGIN_GET_METADATA_CALLED_STATE;
+ for (i = 0; i < GPR_ARRAY_SIZE(plugin_md); i++) {
+ memset(&md[i], 0, sizeof(grpc_metadata));
+ md[i].key = plugin_md[i].key;
+ md[i].value = plugin_md[i].value;
+ md[i].value_length = strlen(plugin_md[i].value);
+ }
+ cb(user_data, md, GPR_ARRAY_SIZE(md), GRPC_STATUS_OK, NULL);
+}
+
+static void plugin_get_metadata_failure(void *state, const char *service_url,
+ grpc_credentials_plugin_metadata_cb cb,
+ void *user_data) {
+ plugin_state *s = (plugin_state *)state;
+ GPR_ASSERT(strcmp(service_url, test_service_url) == 0);
+ *s = PLUGIN_GET_METADATA_CALLED_STATE;
+ cb(user_data, NULL, 0, GRPC_STATUS_UNAUTHENTICATED,
+ "Could not get metadata for plugin.");
+}
+
+static void on_plugin_metadata_received_success(
+ void *user_data, grpc_credentials_md *md_elems, size_t num_md,
+ grpc_credentials_status status) {
+ size_t i = 0;
+ GPR_ASSERT(user_data == NULL);
+ GPR_ASSERT(md_elems != NULL);
+ GPR_ASSERT(num_md == GPR_ARRAY_SIZE(plugin_md));
+ for (i = 0; i < num_md; i++) {
+ GPR_ASSERT(gpr_slice_str_cmp(md_elems[i].key, plugin_md[i].key) == 0);
+ GPR_ASSERT(gpr_slice_str_cmp(md_elems[i].value, plugin_md[i].value) == 0);
+ }
+}
+
+static void on_plugin_metadata_received_failure(
+ void *user_data, grpc_credentials_md *md_elems, size_t num_md,
+ grpc_credentials_status status) {
+ GPR_ASSERT(user_data == NULL);
+ GPR_ASSERT(md_elems == NULL);
+ GPR_ASSERT(num_md == 0);
+ GPR_ASSERT(status == GRPC_CREDENTIALS_ERROR);
+}
+
+static void plugin_destroy(void *state) {
+ plugin_state *s = (plugin_state *)state;
+ *s = PLUGIN_DESTROY_CALLED_STATE;
+}
+
+static void test_metadata_plugin_success(void) {
+ grpc_credentials *creds;
+ plugin_state state = PLUGIN_INITIAL_STATE;
+ grpc_metadata_credentials_plugin plugin;
+
+ plugin.state = &state;
+ plugin.get_metadata = plugin_get_metadata_success;
+ plugin.destroy = plugin_destroy;
+
+ creds = grpc_metadata_credentials_create_from_plugin(plugin, NULL);
+ GPR_ASSERT(state == PLUGIN_INITIAL_STATE);
+ grpc_credentials_get_request_metadata(
+ creds, NULL, test_service_url, on_plugin_metadata_received_success, NULL);
+ GPR_ASSERT(state == PLUGIN_GET_METADATA_CALLED_STATE);
+ grpc_credentials_release(creds);
+ GPR_ASSERT(state == PLUGIN_DESTROY_CALLED_STATE);
+}
+
+static void test_metadata_plugin_failure(void) {
+ grpc_credentials *creds;
+ plugin_state state = PLUGIN_INITIAL_STATE;
+ grpc_metadata_credentials_plugin plugin;
+
+ plugin.state = &state;
+ plugin.get_metadata = plugin_get_metadata_failure;
+ plugin.destroy = plugin_destroy;
+
+ creds = grpc_metadata_credentials_create_from_plugin(plugin, NULL);
+ GPR_ASSERT(state == PLUGIN_INITIAL_STATE);
+ grpc_credentials_get_request_metadata(
+ creds, NULL, test_service_url, on_plugin_metadata_received_failure, NULL);
+ GPR_ASSERT(state == PLUGIN_GET_METADATA_CALLED_STATE);
+ grpc_credentials_release(creds);
+ GPR_ASSERT(state == PLUGIN_DESTROY_CALLED_STATE);
+}
+
int main(int argc, char **argv) {
grpc_test_init(argc, argv);
test_empty_md_store();
@@ -860,5 +963,7 @@ int main(int argc, char **argv) {
test_jwt_creds_signing_failure();
test_google_default_creds_auth_key();
test_google_default_creds_access_token();
+ test_metadata_plugin_success();
+ test_metadata_plugin_failure();
return 0;
}
diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc
index bd829d96e1..bfe799bd15 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<grpc::string, grpc::string_ref>* 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<Credentials> GetCompatibleClientCreds() {
- return AccessTokenCredentials(kGoodGuy);
+ return MetadataCredentialsFromPlugin(
+ std::unique_ptr<MetadataCredentialsPlugin>(
+ new TestMetadataCredentialsPlugin(kGoodGuy, is_blocking_, true)));
}
+
std::shared_ptr<Credentials> GetIncompatibleClientCreds() {
- return AccessTokenCredentials("Mr Hyde");
+ return MetadataCredentialsFromPlugin(
+ std::unique_ptr<MetadataCredentialsPlugin>(
+ 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<MetadataCredentialsPlugin>(
+ 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<AuthMetadataProcessor>(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<AuthMetadataProcessor>(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<MetadataCredentialsPlugin>(
+ 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<AuthMetadataProcessor>(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<AuthMetadataProcessor>(processor));
ResetStub(false);