• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 //
3 // Copyright 2016 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 "src/core/lib/security/credentials/plugin/plugin_credentials.h"
20 
21 #include <grpc/support/alloc.h>
22 #include <grpc/support/port_platform.h>
23 
24 #include <atomic>
25 #include <memory>
26 
27 #include "absl/log/check.h"
28 #include "absl/log/log.h"
29 #include "absl/status/status.h"
30 #include "absl/strings/str_cat.h"
31 #include "absl/strings/string_view.h"
32 #include "src/core/lib/iomgr/error.h"
33 #include "src/core/lib/iomgr/exec_ctx.h"
34 #include "src/core/lib/promise/promise.h"
35 #include "src/core/lib/slice/slice.h"
36 #include "src/core/lib/slice/slice_internal.h"
37 #include "src/core/lib/surface/validate_metadata.h"
38 #include "src/core/lib/transport/metadata_batch.h"
39 
~grpc_plugin_credentials()40 grpc_plugin_credentials::~grpc_plugin_credentials() {
41   if (plugin_.state != nullptr && plugin_.destroy != nullptr) {
42     plugin_.destroy(plugin_.state);
43   }
44 }
45 
debug_string()46 std::string grpc_plugin_credentials::debug_string() {
47   char* debug_c_str = nullptr;
48   if (plugin_.debug_string != nullptr) {
49     debug_c_str = plugin_.debug_string(plugin_.state);
50   }
51   std::string debug_str(
52       debug_c_str != nullptr
53           ? debug_c_str
54           : "grpc_plugin_credentials did not provide a debug string");
55   gpr_free(debug_c_str);
56   return debug_str;
57 }
58 
type() const59 grpc_core::UniqueTypeName grpc_plugin_credentials::type() const {
60   static grpc_core::UniqueTypeName::Factory kFactory("Plugin");
61   return kFactory.Create();
62 }
63 
64 absl::StatusOr<grpc_core::ClientMetadataHandle>
ProcessPluginResult(const grpc_metadata * md,size_t num_md,grpc_status_code status,const char * error_details)65 grpc_plugin_credentials::PendingRequest::ProcessPluginResult(
66     const grpc_metadata* md, size_t num_md, grpc_status_code status,
67     const char* error_details) {
68   if (status != GRPC_STATUS_OK) {
69     return absl::UnavailableError(absl::StrCat(
70         "Getting metadata from plugin failed with error: ", error_details));
71   } else {
72     bool seen_illegal_header = false;
73     for (size_t i = 0; i < num_md; ++i) {
74       if (!GRPC_LOG_IF_ERROR("validate_metadata_from_plugin",
75                              grpc_validate_header_key_is_legal(md[i].key))) {
76         seen_illegal_header = true;
77         break;
78       } else if (!grpc_is_binary_header_internal(md[i].key) &&
79                  !GRPC_LOG_IF_ERROR(
80                      "validate_metadata_from_plugin",
81                      grpc_validate_header_nonbin_value_is_legal(md[i].value))) {
82         LOG(ERROR) << "Plugin added invalid metadata value.";
83         seen_illegal_header = true;
84         break;
85       }
86     }
87     if (seen_illegal_header) {
88       return absl::UnavailableError("Illegal metadata");
89     } else {
90       absl::Status error;
91       for (size_t i = 0; i < num_md; ++i) {
92         md_->Append(
93             grpc_core::StringViewFromSlice(md[i].key),
94             grpc_core::Slice(grpc_core::CSliceRef(md[i].value)),
95             [&error](absl::string_view message, const grpc_core::Slice&) {
96               error = absl::UnavailableError(message);
97             });
98       }
99       if (!error.ok()) return std::move(error);
100       return grpc_core::ClientMetadataHandle(std::move(md_));
101     }
102   }
103 }
104 
105 grpc_core::Poll<absl::StatusOr<grpc_core::ClientMetadataHandle>>
PollAsyncResult()106 grpc_plugin_credentials::PendingRequest::PollAsyncResult() {
107   if (!ready_.load(std::memory_order_acquire)) {
108     return grpc_core::Pending{};
109   }
110   return ProcessPluginResult(metadata_.data(), metadata_.size(), status_,
111                              error_details_.c_str());
112 }
113 
RequestMetadataReady(void * request,const grpc_metadata * md,size_t num_md,grpc_status_code status,const char * error_details)114 void grpc_plugin_credentials::PendingRequest::RequestMetadataReady(
115     void* request, const grpc_metadata* md, size_t num_md,
116     grpc_status_code status, const char* error_details) {
117   // called from application code
118   grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
119   grpc_core::ExecCtx exec_ctx(GRPC_EXEC_CTX_FLAG_IS_FINISHED |
120                               GRPC_EXEC_CTX_FLAG_THREAD_RESOURCE_LOOP);
121   grpc_core::RefCountedPtr<grpc_plugin_credentials::PendingRequest> r(
122       static_cast<grpc_plugin_credentials::PendingRequest*>(request));
123   GRPC_TRACE_LOG(plugin_credentials, INFO)
124       << "plugin_credentials[" << r->creds() << "]: request " << r.get()
125       << ": plugin returned asynchronously";
126   for (size_t i = 0; i < num_md; ++i) {
127     grpc_metadata p;
128     p.key = grpc_core::CSliceRef(md[i].key);
129     p.value = grpc_core::CSliceRef(md[i].value);
130     r->metadata_.push_back(p);
131   }
132   r->error_details_ = error_details == nullptr ? "" : error_details;
133   r->status_ = status;
134   r->ready_.store(true, std::memory_order_release);
135   r->waker_.Wakeup();
136 }
137 
138 grpc_core::ArenaPromise<absl::StatusOr<grpc_core::ClientMetadataHandle>>
GetRequestMetadata(grpc_core::ClientMetadataHandle initial_metadata,const grpc_call_credentials::GetRequestMetadataArgs * args)139 grpc_plugin_credentials::GetRequestMetadata(
140     grpc_core::ClientMetadataHandle initial_metadata,
141     const grpc_call_credentials::GetRequestMetadataArgs* args) {
142   if (plugin_.get_metadata == nullptr) {
143     return grpc_core::Immediate(std::move(initial_metadata));
144   }
145 
146   // Create pending_request object.
147   auto request = grpc_core::MakeRefCounted<PendingRequest>(
148       RefAsSubclass<grpc_plugin_credentials>(), std::move(initial_metadata),
149       args);
150   // Invoke the plugin.  The callback holds a ref to us.
151   GRPC_TRACE_LOG(plugin_credentials, INFO)
152       << "plugin_credentials[" << this << "]: request " << request.get()
153       << ": invoking plugin";
154   grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX];
155   size_t num_creds_md = 0;
156   grpc_status_code status = GRPC_STATUS_OK;
157   const char* error_details = nullptr;
158   // Add an extra ref to the request object for the async callback.
159   // If the request completes synchronously, we'll drop this later.
160   // If the request completes asynchronously, it will own a ref to the request
161   // object (which we release from our ownership below).
162   auto child_request = request->Ref();
163   if (!plugin_.get_metadata(plugin_.state, request->context(),
164                             PendingRequest::RequestMetadataReady,
165                             child_request.get(), creds_md, &num_creds_md,
166                             &status, &error_details)) {
167     child_request.release();
168     GRPC_TRACE_LOG(plugin_credentials, INFO)
169         << "plugin_credentials[" << this << "]: request " << request.get()
170         << ": plugin will return asynchronously";
171     return [request] { return request->PollAsyncResult(); };
172   }
173   // Synchronous return.
174   GRPC_TRACE_LOG(plugin_credentials, INFO)
175       << "plugin_credentials[" << this << "]: request " << request.get()
176       << ": plugin returned synchronously";
177   auto result = request->ProcessPluginResult(creds_md, num_creds_md, status,
178                                              error_details);
179   // Clean up.
180   for (size_t i = 0; i < num_creds_md; ++i) {
181     grpc_core::CSliceUnref(creds_md[i].key);
182     grpc_core::CSliceUnref(creds_md[i].value);
183   }
184   gpr_free(const_cast<char*>(error_details));
185 
186   return grpc_core::Immediate(std::move(result));
187 }
188 
grpc_plugin_credentials(grpc_metadata_credentials_plugin plugin,grpc_security_level min_security_level)189 grpc_plugin_credentials::grpc_plugin_credentials(
190     grpc_metadata_credentials_plugin plugin,
191     grpc_security_level min_security_level)
192     : grpc_call_credentials(min_security_level), plugin_(plugin) {}
193 
grpc_metadata_credentials_create_from_plugin(grpc_metadata_credentials_plugin plugin,grpc_security_level min_security_level,void * reserved)194 grpc_call_credentials* grpc_metadata_credentials_create_from_plugin(
195     grpc_metadata_credentials_plugin plugin,
196     grpc_security_level min_security_level, void* reserved) {
197   GRPC_TRACE_LOG(api, INFO)
198       << "grpc_metadata_credentials_create_from_plugin(reserved=" << reserved
199       << ")";
200   CHECK_EQ(reserved, nullptr);
201   return new grpc_plugin_credentials(plugin, min_security_level);
202 }
203