1 // Copyright 2021 gRPC authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <grpc/support/port_platform.h>
16
17 #include "src/core/lib/security/authorization/grpc_authorization_policy_provider.h"
18
19 #include <stdint.h>
20
21 #include <utility>
22
23 #include "absl/types/optional.h"
24
25 #include <grpc/grpc_security.h>
26 #include <grpc/slice.h>
27 #include <grpc/status.h>
28 #include <grpc/support/log.h>
29 #include <grpc/support/string_util.h>
30 #include <grpc/support/time.h>
31
32 #include "src/core/lib/debug/trace.h"
33 #include "src/core/lib/gprpp/status_helper.h"
34 #include "src/core/lib/iomgr/error.h"
35 #include "src/core/lib/iomgr/load_file.h"
36 #include "src/core/lib/security/authorization/grpc_authorization_engine.h"
37 #include "src/core/lib/security/authorization/rbac_translator.h"
38 #include "src/core/lib/slice/slice.h"
39 #include "src/core/lib/slice/slice_internal.h"
40
41 namespace grpc_core {
42
43 extern TraceFlag grpc_authz_trace;
44
45 absl::StatusOr<RefCountedPtr<grpc_authorization_policy_provider>>
Create(absl::string_view authz_policy)46 StaticDataAuthorizationPolicyProvider::Create(absl::string_view authz_policy) {
47 auto policies_or = GenerateRbacPolicies(authz_policy);
48 if (!policies_or.ok()) {
49 return policies_or.status();
50 }
51 return MakeRefCounted<StaticDataAuthorizationPolicyProvider>(
52 std::move(*policies_or));
53 }
54
StaticDataAuthorizationPolicyProvider(RbacPolicies policies)55 StaticDataAuthorizationPolicyProvider::StaticDataAuthorizationPolicyProvider(
56 RbacPolicies policies)
57 : allow_engine_(MakeRefCounted<GrpcAuthorizationEngine>(
58 std::move(policies.allow_policy))),
59 deny_engine_(policies.deny_policy.has_value()
60 ? MakeRefCounted<GrpcAuthorizationEngine>(
61 std::move(*policies.deny_policy))
62 : nullptr) {}
63
64 namespace {
65
ReadPolicyFromFile(absl::string_view policy_path)66 absl::StatusOr<std::string> ReadPolicyFromFile(absl::string_view policy_path) {
67 grpc_slice policy_slice = grpc_empty_slice();
68 grpc_error_handle error =
69 grpc_load_file(std::string(policy_path).c_str(), 0, &policy_slice);
70 if (!error.ok()) {
71 absl::Status status = absl::InvalidArgumentError(StatusToString(error));
72 return status;
73 }
74 std::string policy_contents(StringViewFromSlice(policy_slice));
75 CSliceUnref(policy_slice);
76 return policy_contents;
77 }
78
TimeoutSecondsToDeadline(int64_t seconds)79 gpr_timespec TimeoutSecondsToDeadline(int64_t seconds) {
80 return gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
81 gpr_time_from_seconds(seconds, GPR_TIMESPAN));
82 }
83
84 } // namespace
85
86 absl::StatusOr<RefCountedPtr<grpc_authorization_policy_provider>>
Create(absl::string_view authz_policy_path,unsigned int refresh_interval_sec)87 FileWatcherAuthorizationPolicyProvider::Create(
88 absl::string_view authz_policy_path, unsigned int refresh_interval_sec) {
89 GPR_ASSERT(!authz_policy_path.empty());
90 GPR_ASSERT(refresh_interval_sec > 0);
91 absl::Status status;
92 auto provider = MakeRefCounted<FileWatcherAuthorizationPolicyProvider>(
93 authz_policy_path, refresh_interval_sec, &status);
94 if (!status.ok()) return status;
95 return provider;
96 }
97
FileWatcherAuthorizationPolicyProvider(absl::string_view authz_policy_path,unsigned int refresh_interval_sec,absl::Status * status)98 FileWatcherAuthorizationPolicyProvider::FileWatcherAuthorizationPolicyProvider(
99 absl::string_view authz_policy_path, unsigned int refresh_interval_sec,
100 absl::Status* status)
101 : authz_policy_path_(std::string(authz_policy_path)),
102 refresh_interval_sec_(refresh_interval_sec) {
103 gpr_event_init(&shutdown_event_);
104 // Initial read is done synchronously.
105 *status = ForceUpdate();
106 if (!status->ok()) {
107 return;
108 }
109 auto thread_lambda = [](void* arg) {
110 WeakRefCountedPtr<FileWatcherAuthorizationPolicyProvider> provider(
111 static_cast<FileWatcherAuthorizationPolicyProvider*>(arg));
112 GPR_ASSERT(provider != nullptr);
113 while (true) {
114 void* value = gpr_event_wait(
115 &provider->shutdown_event_,
116 TimeoutSecondsToDeadline(provider->refresh_interval_sec_));
117 if (value != nullptr) {
118 return;
119 }
120 absl::Status status = provider->ForceUpdate();
121 if (GRPC_TRACE_FLAG_ENABLED(grpc_authz_trace) && !status.ok()) {
122 gpr_log(GPR_ERROR,
123 "authorization policy reload status. code=%d error_details=%s",
124 status.code(), std::string(status.message()).c_str());
125 }
126 }
127 };
128 refresh_thread_ = std::make_unique<Thread>(
129 "FileWatcherAuthorizationPolicyProvider_refreshing_thread", thread_lambda,
130 WeakRef().release());
131 refresh_thread_->Start();
132 }
133
SetCallbackForTesting(std::function<void (bool contents_changed,absl::Status status)> cb)134 void FileWatcherAuthorizationPolicyProvider::SetCallbackForTesting(
135 std::function<void(bool contents_changed, absl::Status status)> cb) {
136 MutexLock lock(&mu_);
137 cb_ = std::move(cb);
138 }
139
ForceUpdate()140 absl::Status FileWatcherAuthorizationPolicyProvider::ForceUpdate() {
141 bool contents_changed = false;
142 auto done_early = [&](absl::Status status) {
143 MutexLock lock(&mu_);
144 if (cb_ != nullptr) {
145 cb_(contents_changed, status);
146 }
147 return status;
148 };
149 absl::StatusOr<std::string> file_contents =
150 ReadPolicyFromFile(authz_policy_path_);
151 if (!file_contents.ok()) {
152 return done_early(file_contents.status());
153 }
154 if (file_contents_ == *file_contents) {
155 return done_early(absl::OkStatus());
156 }
157 file_contents_ = std::move(*file_contents);
158 contents_changed = true;
159 auto rbac_policies_or = GenerateRbacPolicies(file_contents_);
160 if (!rbac_policies_or.ok()) {
161 return done_early(rbac_policies_or.status());
162 }
163 MutexLock lock(&mu_);
164 allow_engine_ = MakeRefCounted<GrpcAuthorizationEngine>(
165 std::move(rbac_policies_or->allow_policy));
166 if (rbac_policies_or->deny_policy.has_value()) {
167 deny_engine_ = MakeRefCounted<GrpcAuthorizationEngine>(
168 std::move(*rbac_policies_or->deny_policy));
169 } else {
170 deny_engine_.reset();
171 }
172 if (cb_ != nullptr) {
173 cb_(contents_changed, absl::OkStatus());
174 }
175 if (GRPC_TRACE_FLAG_ENABLED(grpc_authz_trace)) {
176 gpr_log(GPR_INFO,
177 "authorization policy reload status: successfully loaded new "
178 "policy\n%s",
179 file_contents_.c_str());
180 }
181 return absl::OkStatus();
182 }
183
Orphan()184 void FileWatcherAuthorizationPolicyProvider::Orphan() {
185 gpr_event_set(&shutdown_event_, reinterpret_cast<void*>(1));
186 if (refresh_thread_ != nullptr) {
187 refresh_thread_->Join();
188 }
189 }
190
191 } // namespace grpc_core
192
193 // Wrapper APIs declared in grpc_security.h
194
195 grpc_authorization_policy_provider*
grpc_authorization_policy_provider_static_data_create(const char * authz_policy,grpc_status_code * code,const char ** error_details)196 grpc_authorization_policy_provider_static_data_create(
197 const char* authz_policy, grpc_status_code* code,
198 const char** error_details) {
199 GPR_ASSERT(authz_policy != nullptr);
200 auto provider_or =
201 grpc_core::StaticDataAuthorizationPolicyProvider::Create(authz_policy);
202 if (!provider_or.ok()) {
203 *code = static_cast<grpc_status_code>(provider_or.status().code());
204 *error_details =
205 gpr_strdup(std::string(provider_or.status().message()).c_str());
206 return nullptr;
207 }
208 return provider_or->release();
209 }
210
211 grpc_authorization_policy_provider*
grpc_authorization_policy_provider_file_watcher_create(const char * authz_policy_path,unsigned int refresh_interval_sec,grpc_status_code * code,const char ** error_details)212 grpc_authorization_policy_provider_file_watcher_create(
213 const char* authz_policy_path, unsigned int refresh_interval_sec,
214 grpc_status_code* code, const char** error_details) {
215 GPR_ASSERT(authz_policy_path != nullptr);
216 auto provider_or = grpc_core::FileWatcherAuthorizationPolicyProvider::Create(
217 authz_policy_path, refresh_interval_sec);
218 if (!provider_or.ok()) {
219 *code = static_cast<grpc_status_code>(provider_or.status().code());
220 *error_details =
221 gpr_strdup(std::string(provider_or.status().message()).c_str());
222 return nullptr;
223 }
224 return provider_or->release();
225 }
226
grpc_authorization_policy_provider_release(grpc_authorization_policy_provider * provider)227 void grpc_authorization_policy_provider_release(
228 grpc_authorization_policy_provider* provider) {
229 if (provider != nullptr) provider->Unref();
230 }
231