1 //
2 //
3 // Copyright 2020 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18
19 #include <grpc/support/port_platform.h>
20
21 #include "src/core/ext/xds/file_watcher_certificate_provider_factory.h"
22
23 #include <algorithm>
24 #include <initializer_list>
25 #include <map>
26 #include <memory>
27 #include <vector>
28
29 #include "absl/strings/str_format.h"
30 #include "absl/strings/str_join.h"
31
32 #include <grpc/support/log.h>
33 #include <grpc/support/time.h>
34
35 #include "src/core/lib/config/core_configuration.h"
36 #include "src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.h"
37
38 namespace grpc_core {
39
40 namespace {
41
42 constexpr absl::string_view kFileWatcherPlugin = "file_watcher";
43
44 } // namespace
45
46 //
47 // FileWatcherCertificateProviderFactory::Config
48 //
49
name() const50 absl::string_view FileWatcherCertificateProviderFactory::Config::name() const {
51 return kFileWatcherPlugin;
52 }
53
ToString() const54 std::string FileWatcherCertificateProviderFactory::Config::ToString() const {
55 std::vector<std::string> parts;
56 parts.push_back("{");
57 if (!identity_cert_file_.empty()) {
58 parts.push_back(
59 absl::StrFormat("certificate_file=\"%s\", ", identity_cert_file_));
60 }
61 if (!identity_cert_file_.empty()) {
62 parts.push_back(
63 absl::StrFormat("private_key_file=\"%s\", ", private_key_file_));
64 }
65 if (!identity_cert_file_.empty()) {
66 parts.push_back(
67 absl::StrFormat("ca_certificate_file=\"%s\", ", root_cert_file_));
68 }
69 parts.push_back(
70 absl::StrFormat("refresh_interval=%ldms}", refresh_interval_.millis()));
71 return absl::StrJoin(parts, "");
72 }
73
74 const JsonLoaderInterface*
JsonLoader(const JsonArgs &)75 FileWatcherCertificateProviderFactory::Config::JsonLoader(const JsonArgs&) {
76 static const auto* loader =
77 JsonObjectLoader<Config>()
78 .OptionalField("certificate_file", &Config::identity_cert_file_)
79 .OptionalField("private_key_file", &Config::private_key_file_)
80 .OptionalField("ca_certificate_file", &Config::root_cert_file_)
81 .OptionalField("refresh_interval", &Config::refresh_interval_)
82 .Finish();
83 return loader;
84 }
85
JsonPostLoad(const Json & json,const JsonArgs &,ValidationErrors * errors)86 void FileWatcherCertificateProviderFactory::Config::JsonPostLoad(
87 const Json& json, const JsonArgs& /*args*/, ValidationErrors* errors) {
88 if ((json.object().find("certificate_file") == json.object().end()) !=
89 (json.object().find("private_key_file") == json.object().end())) {
90 errors->AddError(
91 "fields \"certificate_file\" and \"private_key_file\" must be both set "
92 "or both unset");
93 }
94 if ((json.object().find("certificate_file") == json.object().end()) &&
95 (json.object().find("ca_certificate_file") == json.object().end())) {
96 errors->AddError(
97 "at least one of \"certificate_file\" and \"ca_certificate_file\" must "
98 "be specified");
99 }
100 }
101
102 //
103 // FileWatcherCertificateProviderFactory
104 //
105
name() const106 absl::string_view FileWatcherCertificateProviderFactory::name() const {
107 return kFileWatcherPlugin;
108 }
109
110 RefCountedPtr<CertificateProviderFactory::Config>
CreateCertificateProviderConfig(const Json & config_json,const JsonArgs & args,ValidationErrors * errors)111 FileWatcherCertificateProviderFactory::CreateCertificateProviderConfig(
112 const Json& config_json, const JsonArgs& args, ValidationErrors* errors) {
113 return LoadFromJson<RefCountedPtr<Config>>(config_json, args, errors);
114 }
115
116 RefCountedPtr<grpc_tls_certificate_provider>
CreateCertificateProvider(RefCountedPtr<CertificateProviderFactory::Config> config)117 FileWatcherCertificateProviderFactory::CreateCertificateProvider(
118 RefCountedPtr<CertificateProviderFactory::Config> config) {
119 if (config->name() != name()) {
120 gpr_log(GPR_ERROR, "Wrong config type Actual:%s vs Expected:%s",
121 std::string(config->name()).c_str(), std::string(name()).c_str());
122 return nullptr;
123 }
124 auto* file_watcher_config =
125 static_cast<FileWatcherCertificateProviderFactory::Config*>(config.get());
126 return MakeRefCounted<FileWatcherCertificateProvider>(
127 file_watcher_config->private_key_file(),
128 file_watcher_config->identity_cert_file(),
129 file_watcher_config->root_cert_file(),
130 file_watcher_config->refresh_interval().millis() / GPR_MS_PER_SEC);
131 }
132
RegisterFileWatcherCertificateProvider(CoreConfiguration::Builder * builder)133 void RegisterFileWatcherCertificateProvider(
134 CoreConfiguration::Builder* builder) {
135 builder->certificate_provider_registry()->RegisterCertificateProviderFactory(
136 std::make_unique<FileWatcherCertificateProviderFactory>());
137 }
138
139 } // namespace grpc_core
140