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 "src/core/lib/security/authorization/grpc_authorization_policy_provider.h"
16
17 #include <grpc/grpc_security.h>
18 #include <grpc/slice.h>
19 #include <grpc/status.h>
20 #include <grpc/support/port_platform.h>
21 #include <grpc/support/string_util.h>
22 #include <grpc/support/time.h>
23 #include <stdint.h>
24
25 #include <utility>
26
27 #include "absl/log/check.h"
28 #include "absl/log/log.h"
29 #include "absl/types/optional.h"
30 #include "src/core/lib/debug/trace.h"
31 #include "src/core/lib/iomgr/error.h"
32 #include "src/core/lib/security/authorization/grpc_authorization_engine.h"
33 #include "src/core/lib/security/authorization/rbac_policy.h"
34 #include "src/core/lib/security/authorization/rbac_translator.h"
35 #include "src/core/lib/slice/slice.h"
36 #include "src/core/lib/slice/slice_internal.h"
37 #include "src/core/util/load_file.h"
38 #include "src/core/util/status_helper.h"
39
40 namespace grpc_core {
41
42 absl::StatusOr<RefCountedPtr<grpc_authorization_policy_provider>>
Create(absl::string_view authz_policy)43 StaticDataAuthorizationPolicyProvider::Create(absl::string_view authz_policy) {
44 auto policies_or = GenerateRbacPolicies(authz_policy);
45 if (!policies_or.ok()) {
46 return policies_or.status();
47 }
48 return MakeRefCounted<StaticDataAuthorizationPolicyProvider>(
49 std::move(*policies_or));
50 }
51
StaticDataAuthorizationPolicyProvider(RbacPolicies policies)52 StaticDataAuthorizationPolicyProvider::StaticDataAuthorizationPolicyProvider(
53 RbacPolicies policies)
54 : allow_engine_(MakeRefCounted<GrpcAuthorizationEngine>(
55 std::move(policies.allow_policy))),
56 deny_engine_(policies.deny_policy.has_value()
57 ? MakeRefCounted<GrpcAuthorizationEngine>(
58 std::move(*policies.deny_policy))
59 : nullptr) {}
60
61 namespace {
62
ReadPolicyFromFile(absl::string_view policy_path)63 absl::StatusOr<std::string> ReadPolicyFromFile(absl::string_view policy_path) {
64 auto policy_slice =
65 LoadFile(std::string(policy_path), /*add_null_terminator=*/false);
66 if (!policy_slice.ok()) {
67 return absl::InvalidArgumentError(policy_slice.status().ToString());
68 }
69 return std::string(policy_slice->as_string_view());
70 }
71
TimeoutSecondsToDeadline(int64_t seconds)72 gpr_timespec TimeoutSecondsToDeadline(int64_t seconds) {
73 return gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
74 gpr_time_from_seconds(seconds, GPR_TIMESPAN));
75 }
76
77 } // namespace
78
79 absl::StatusOr<RefCountedPtr<grpc_authorization_policy_provider>>
Create(absl::string_view authz_policy_path,unsigned int refresh_interval_sec)80 FileWatcherAuthorizationPolicyProvider::Create(
81 absl::string_view authz_policy_path, unsigned int refresh_interval_sec) {
82 CHECK(!authz_policy_path.empty());
83 CHECK_GT(refresh_interval_sec, 0u);
84 absl::Status status;
85 auto provider = MakeRefCounted<FileWatcherAuthorizationPolicyProvider>(
86 authz_policy_path, refresh_interval_sec, &status);
87 if (!status.ok()) return status;
88 return provider;
89 }
90
FileWatcherAuthorizationPolicyProvider(absl::string_view authz_policy_path,unsigned int refresh_interval_sec,absl::Status * status)91 FileWatcherAuthorizationPolicyProvider::FileWatcherAuthorizationPolicyProvider(
92 absl::string_view authz_policy_path, unsigned int refresh_interval_sec,
93 absl::Status* status)
94 : authz_policy_path_(std::string(authz_policy_path)),
95 refresh_interval_sec_(refresh_interval_sec) {
96 gpr_event_init(&shutdown_event_);
97 // Initial read is done synchronously.
98 *status = ForceUpdate();
99 if (!status->ok()) {
100 return;
101 }
102 auto thread_lambda = [](void* arg) {
103 WeakRefCountedPtr<FileWatcherAuthorizationPolicyProvider> provider(
104 static_cast<FileWatcherAuthorizationPolicyProvider*>(arg));
105 CHECK(provider != nullptr);
106 while (true) {
107 void* value = gpr_event_wait(
108 &provider->shutdown_event_,
109 TimeoutSecondsToDeadline(provider->refresh_interval_sec_));
110 if (value != nullptr) {
111 return;
112 }
113 absl::Status status = provider->ForceUpdate();
114 if (GRPC_TRACE_FLAG_ENABLED(grpc_authz_api) && !status.ok()) {
115 LOG(ERROR) << "authorization policy reload status. code="
116 << static_cast<int>(status.code())
117 << " error_details=" << status.message();
118 }
119 }
120 };
121 refresh_thread_ = std::make_unique<Thread>(
122 "FileWatcherAuthorizationPolicyProvider_refreshing_thread", thread_lambda,
123 WeakRef().release());
124 refresh_thread_->Start();
125 }
126
SetCallbackForTesting(std::function<void (bool contents_changed,absl::Status status)> cb)127 void FileWatcherAuthorizationPolicyProvider::SetCallbackForTesting(
128 std::function<void(bool contents_changed, absl::Status status)> cb) {
129 MutexLock lock(&mu_);
130 cb_ = std::move(cb);
131 }
132
ForceUpdate()133 absl::Status FileWatcherAuthorizationPolicyProvider::ForceUpdate() {
134 bool contents_changed = false;
135 auto done_early = [&](absl::Status status) {
136 MutexLock lock(&mu_);
137 if (cb_ != nullptr) {
138 cb_(contents_changed, status);
139 }
140 return status;
141 };
142 absl::StatusOr<std::string> file_contents =
143 ReadPolicyFromFile(authz_policy_path_);
144 if (!file_contents.ok()) {
145 return done_early(file_contents.status());
146 }
147 if (file_contents_ == *file_contents) {
148 return done_early(absl::OkStatus());
149 }
150 file_contents_ = std::move(*file_contents);
151 contents_changed = true;
152 auto rbac_policies_or = GenerateRbacPolicies(file_contents_);
153 if (!rbac_policies_or.ok()) {
154 return done_early(rbac_policies_or.status());
155 }
156 MutexLock lock(&mu_);
157 allow_engine_ = MakeRefCounted<GrpcAuthorizationEngine>(
158 std::move(rbac_policies_or->allow_policy));
159 if (rbac_policies_or->deny_policy.has_value()) {
160 deny_engine_ = MakeRefCounted<GrpcAuthorizationEngine>(
161 std::move(*rbac_policies_or->deny_policy));
162 } else {
163 deny_engine_.reset();
164 }
165 if (cb_ != nullptr) {
166 cb_(contents_changed, absl::OkStatus());
167 }
168 GRPC_TRACE_LOG(grpc_authz_api, INFO)
169 << "authorization policy reload status: successfully loaded new "
170 "policy\n"
171 << file_contents_;
172 return absl::OkStatus();
173 }
174
Orphaned()175 void FileWatcherAuthorizationPolicyProvider::Orphaned() {
176 gpr_event_set(&shutdown_event_, reinterpret_cast<void*>(1));
177 if (refresh_thread_ != nullptr) {
178 refresh_thread_->Join();
179 }
180 }
181
182 } // namespace grpc_core
183
184 // Wrapper APIs declared in grpc_security.h
185
186 grpc_authorization_policy_provider*
grpc_authorization_policy_provider_static_data_create(const char * authz_policy,grpc_status_code * code,const char ** error_details)187 grpc_authorization_policy_provider_static_data_create(
188 const char* authz_policy, grpc_status_code* code,
189 const char** error_details) {
190 CHECK_NE(authz_policy, nullptr);
191 auto provider_or =
192 grpc_core::StaticDataAuthorizationPolicyProvider::Create(authz_policy);
193 if (!provider_or.ok()) {
194 *code = static_cast<grpc_status_code>(provider_or.status().code());
195 *error_details =
196 gpr_strdup(std::string(provider_or.status().message()).c_str());
197 return nullptr;
198 }
199 return provider_or->release();
200 }
201
202 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)203 grpc_authorization_policy_provider_file_watcher_create(
204 const char* authz_policy_path, unsigned int refresh_interval_sec,
205 grpc_status_code* code, const char** error_details) {
206 CHECK_NE(authz_policy_path, nullptr);
207 auto provider_or = grpc_core::FileWatcherAuthorizationPolicyProvider::Create(
208 authz_policy_path, refresh_interval_sec);
209 if (!provider_or.ok()) {
210 *code = static_cast<grpc_status_code>(provider_or.status().code());
211 *error_details =
212 gpr_strdup(std::string(provider_or.status().message()).c_str());
213 return nullptr;
214 }
215 return provider_or->release();
216 }
217
grpc_authorization_policy_provider_release(grpc_authorization_policy_provider * provider)218 void grpc_authorization_policy_provider_release(
219 grpc_authorization_policy_provider* provider) {
220 if (provider != nullptr) provider->Unref();
221 }
222