Design and implementation of the core credentials plugin API.

- We use C++ as an example to show how this API can be used while still
  providing an idiomatic interface in the wrapped language of choice.
- No testing yet.
pull/3217/head
Julien Boeuf 9 years ago
parent 29ee3f40be
commit 2d041188db
  1. 21
      include/grpc++/security/credentials.h
  2. 86
      src/core/security/credentials.c
  3. 9
      src/core/security/credentials.h
  4. 60
      src/cpp/client/secure_credentials.cc
  5. 19
      src/cpp/client/secure_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;
@ -129,6 +132,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

@ -1185,3 +1185,89 @@ 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 {
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);
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) 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;
}

@ -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 */

@ -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

@ -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

Loading…
Cancel
Save