blob: b4a1306770754399da5eb1058c08567d1753cb83 [file] [log] [blame]
//
//
// Copyright 2020 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//
#include <grpc/support/port_platform.h>
#include "src/core/ext/xds/certificate_provider_store.h"
#include "absl/strings/str_cat.h"
#include <grpc/support/json.h>
#include <grpc/support/log.h>
#include "src/core/lib/config/core_configuration.h"
#include "src/core/lib/security/certificate_provider/certificate_provider_registry.h"
namespace grpc_core {
//
// CertificateProviderStore::PluginDefinition
//
const JsonLoaderInterface*
CertificateProviderStore::PluginDefinition::JsonLoader(const JsonArgs&) {
static const auto* loader =
JsonObjectLoader<PluginDefinition>()
.Field("plugin_name", &PluginDefinition::plugin_name)
.Finish();
return loader;
}
void CertificateProviderStore::PluginDefinition::JsonPostLoad(
const Json& json, const JsonArgs& args, ValidationErrors* errors) {
// Check that plugin is supported.
CertificateProviderFactory* factory = nullptr;
if (!plugin_name.empty()) {
ValidationErrors::ScopedField field(errors, ".plugin_name");
factory = CoreConfiguration::Get()
.certificate_provider_registry()
.LookupCertificateProviderFactory(plugin_name);
if (factory == nullptr) {
errors->AddError(absl::StrCat("Unrecognized plugin name: ", plugin_name));
return; // No point checking config.
}
}
// Parse the config field.
{
ValidationErrors::ScopedField field(errors, ".config");
auto it = json.object().find("config");
// The config field is optional; if not present, we use an empty JSON
// object.
Json::Object config_json;
if (it != json.object().end()) {
if (it->second.type() != Json::Type::kObject) {
errors->AddError("is not an object");
return; // No point parsing config.
} else {
config_json = it->second.object();
}
}
if (factory == nullptr) return;
// Use plugin to validate and parse config.
config = factory->CreateCertificateProviderConfig(
Json::FromObject(std::move(config_json)), args, errors);
}
}
//
// CertificateProviderStore::CertificateProviderWrapper
//
UniqueTypeName CertificateProviderStore::CertificateProviderWrapper::type()
const {
static UniqueTypeName::Factory kFactory("Wrapper");
return kFactory.Create();
}
// If a certificate provider is created, the CertificateProviderStore
// maintains a raw pointer to the created CertificateProviderWrapper so that
// future calls to `CreateOrGetCertificateProvider()` with the same key result
// in returning a ref to this created certificate provider. This entry is
// deleted when the refcount to this provider reaches zero.
RefCountedPtr<grpc_tls_certificate_provider>
CertificateProviderStore::CreateOrGetCertificateProvider(
absl::string_view key) {
RefCountedPtr<CertificateProviderWrapper> result;
MutexLock lock(&mu_);
auto it = certificate_providers_map_.find(key);
if (it == certificate_providers_map_.end()) {
result = CreateCertificateProviderLocked(key);
if (result != nullptr) {
certificate_providers_map_.insert({result->key(), result.get()});
}
} else {
result = it->second->RefIfNonZero();
if (result == nullptr) {
result = CreateCertificateProviderLocked(key);
it->second = result.get();
}
}
return result;
}
RefCountedPtr<CertificateProviderStore::CertificateProviderWrapper>
CertificateProviderStore::CreateCertificateProviderLocked(
absl::string_view key) {
auto plugin_config_it = plugin_config_map_.find(std::string(key));
if (plugin_config_it == plugin_config_map_.end()) {
return nullptr;
}
CertificateProviderFactory* factory =
CoreConfiguration::Get()
.certificate_provider_registry()
.LookupCertificateProviderFactory(
plugin_config_it->second.plugin_name);
if (factory == nullptr) {
// This should never happen since an entry is only inserted in the
// plugin_config_map_ if the corresponding factory was found when parsing
// the xDS bootstrap file.
gpr_log(GPR_ERROR, "Certificate provider factory %s not found",
plugin_config_it->second.plugin_name.c_str());
return nullptr;
}
return MakeRefCounted<CertificateProviderWrapper>(
factory->CreateCertificateProvider(plugin_config_it->second.config),
Ref(), plugin_config_it->first);
}
void CertificateProviderStore::ReleaseCertificateProvider(
absl::string_view key, CertificateProviderWrapper* wrapper) {
MutexLock lock(&mu_);
auto it = certificate_providers_map_.find(key);
if (it != certificate_providers_map_.end()) {
if (it->second == wrapper) {
certificate_providers_map_.erase(it);
}
}
}
} // namespace grpc_core