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