diff --git a/include/grpc++/security/credentials.h b/include/grpc++/security/credentials.h index ce5a9e0606c..03d3550197e 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 #include #include #include +#include +#include namespace grpc { class ChannelArguments; @@ -129,6 +132,24 @@ std::shared_ptr CompositeCredentials( // Credentials for an unencrypted, unauthenticated channel std::shared_ptr 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* metadata) = 0; +}; + +std::shared_ptr MetadataCredentialsFromPlugin( + std::unique_ptr plugin); + } // namespace grpc #endif // GRPCXX_CREDENTIALS_H diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c index a764413300f..afe980a5b04 100644 --- a/src/core/security/credentials.c +++ b/src/core/security/credentials.c @@ -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; +} + diff --git a/src/core/security/credentials.h b/src/core/security/credentials.h index 8e4fed7615f..38ce0f8ba6e 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 2260f6d33eb..8333b01f29b 100644 --- a/src/cpp/client/secure_credentials.cc +++ b/src/cpp/client/secure_credentials.cc @@ -144,4 +144,64 @@ std::shared_ptr CompositeCredentials( return nullptr; } +void MetadataCredentialsPluginWrapper::Destroy(void* wrapper) { + if (wrapper == nullptr) return; + MetadataCredentialsPluginWrapper* w = + reinterpret_cast(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(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 metadata; + Status status = plugin_->GetMetadata(service_url, &metadata); + std::vector 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(status.error_code()), + status.error_message().c_str()); +} + +MetadataCredentialsPluginWrapper::MetadataCredentialsPluginWrapper( + std::unique_ptr plugin) + : thread_pool_(CreateDefaultThreadPool()), plugin_(std::move(plugin)) {} + +std::shared_ptr MetadataCredentialsFromPlugin( + std::unique_ptr 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 8deff856c4c..d354827725a 100644 --- a/src/cpp/client/secure_credentials.h +++ b/src/cpp/client/secure_credentials.h @@ -39,6 +39,8 @@ #include #include +#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 plugin); + + private: + void InvokePlugin(const char* service_url, + grpc_credentials_plugin_metadata_cb cb, void* user_data); + std::unique_ptr thread_pool_; + std::unique_ptr plugin_; +}; + } // namespace grpc #endif // GRPC_INTERNAL_CPP_CLIENT_SECURE_CREDENTIALS_H