• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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