Imported Upstream version 1.34.0
[platform/upstream/grpc.git] / src / cpp / client / secure_credentials.cc
1 /*
2  *
3  * Copyright 2015 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/cpp/client/secure_credentials.h"
20
21 #include <grpc/impl/codegen/slice.h>
22 #include <grpc/slice.h>
23 #include <grpc/support/alloc.h>
24 #include <grpc/support/log.h>
25 #include <grpc/support/string_util.h>
26 #include <grpcpp/channel.h>
27 #include <grpcpp/impl/codegen/status.h>
28 #include <grpcpp/impl/grpc_library.h>
29 #include <grpcpp/support/channel_arguments.h>
30
31 // TODO(yashykt): We shouldn't be including "src/core" headers.
32 #include "src/core/lib/gpr/env.h"
33 #include "src/core/lib/iomgr/error.h"
34 #include "src/core/lib/iomgr/executor.h"
35 #include "src/core/lib/iomgr/load_file.h"
36 #include "src/core/lib/json/json.h"
37 #include "src/core/lib/security/transport/auth_filters.h"
38 #include "src/core/lib/security/util/json_util.h"
39 #include "src/cpp/client/create_channel_internal.h"
40 #include "src/cpp/common/secure_auth_context.h"
41
42 namespace grpc {
43
44 static grpc::internal::GrpcLibraryInitializer g_gli_initializer;
45 SecureChannelCredentials::SecureChannelCredentials(
46     grpc_channel_credentials* c_creds)
47     : c_creds_(c_creds) {
48   g_gli_initializer.summon();
49 }
50
51 std::shared_ptr<Channel> SecureChannelCredentials::CreateChannelImpl(
52     const std::string& target, const ChannelArguments& args) {
53   return CreateChannelWithInterceptors(
54       target, args,
55       std::vector<std::unique_ptr<
56           grpc::experimental::ClientInterceptorFactoryInterface>>());
57 }
58
59 std::shared_ptr<Channel>
60 SecureChannelCredentials::CreateChannelWithInterceptors(
61     const std::string& target, const ChannelArguments& args,
62     std::vector<
63         std::unique_ptr<grpc::experimental::ClientInterceptorFactoryInterface>>
64         interceptor_creators) {
65   grpc_channel_args channel_args;
66   args.SetChannelArgs(&channel_args);
67   return ::grpc::CreateChannelInternal(
68       args.GetSslTargetNameOverride(),
69       grpc_secure_channel_create(c_creds_, target.c_str(), &channel_args,
70                                  nullptr),
71       std::move(interceptor_creators));
72 }
73
74 SecureCallCredentials::SecureCallCredentials(grpc_call_credentials* c_creds)
75     : c_creds_(c_creds) {
76   g_gli_initializer.summon();
77 }
78
79 bool SecureCallCredentials::ApplyToCall(grpc_call* call) {
80   return grpc_call_set_credentials(call, c_creds_) == GRPC_CALL_OK;
81 }
82
83 namespace internal {
84
85 std::shared_ptr<ChannelCredentials> WrapChannelCredentials(
86     grpc_channel_credentials* creds) {
87   return creds == nullptr ? nullptr
88                           : std::shared_ptr<ChannelCredentials>(
89                                 new SecureChannelCredentials(creds));
90 }
91
92 }  // namespace internal
93
94 namespace {
95
96 std::shared_ptr<CallCredentials> WrapCallCredentials(
97     grpc_call_credentials* creds) {
98   return creds == nullptr ? nullptr
99                           : std::shared_ptr<CallCredentials>(
100                                 new SecureCallCredentials(creds));
101 }
102 }  // namespace
103
104 std::shared_ptr<ChannelCredentials> GoogleDefaultCredentials() {
105   grpc::GrpcLibraryCodegen init;  // To call grpc_init().
106   return internal::WrapChannelCredentials(
107       grpc_google_default_credentials_create(nullptr));
108 }
109
110 // Builds SSL Credentials given SSL specific options
111 std::shared_ptr<ChannelCredentials> SslCredentials(
112     const SslCredentialsOptions& options) {
113   grpc::GrpcLibraryCodegen init;  // To call grpc_init().
114   grpc_ssl_pem_key_cert_pair pem_key_cert_pair = {
115       options.pem_private_key.c_str(), options.pem_cert_chain.c_str()};
116
117   grpc_channel_credentials* c_creds = grpc_ssl_credentials_create(
118       options.pem_root_certs.empty() ? nullptr : options.pem_root_certs.c_str(),
119       options.pem_private_key.empty() ? nullptr : &pem_key_cert_pair, nullptr,
120       nullptr);
121   return internal::WrapChannelCredentials(c_creds);
122 }
123
124 namespace experimental {
125
126 namespace {
127
128 void ClearStsCredentialsOptions(StsCredentialsOptions* options) {
129   if (options == nullptr) return;
130   options->token_exchange_service_uri.clear();
131   options->resource.clear();
132   options->audience.clear();
133   options->scope.clear();
134   options->requested_token_type.clear();
135   options->subject_token_path.clear();
136   options->subject_token_type.clear();
137   options->actor_token_path.clear();
138   options->actor_token_type.clear();
139 }
140
141 }  // namespace
142
143 // Builds STS credentials options from JSON.
144 grpc::Status StsCredentialsOptionsFromJson(const std::string& json_string,
145                                            StsCredentialsOptions* options) {
146   if (options == nullptr) {
147     return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
148                         "options cannot be nullptr.");
149   }
150   ClearStsCredentialsOptions(options);
151   grpc_error* error = GRPC_ERROR_NONE;
152   grpc_core::Json json = grpc_core::Json::Parse(json_string.c_str(), &error);
153   if (error != GRPC_ERROR_NONE ||
154       json.type() != grpc_core::Json::Type::OBJECT) {
155     GRPC_ERROR_UNREF(error);
156     return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, "Invalid json.");
157   }
158
159   // Required fields.
160   const char* value = grpc_json_get_string_property(
161       json, "token_exchange_service_uri", nullptr);
162   if (value == nullptr) {
163     ClearStsCredentialsOptions(options);
164     return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
165                         "token_exchange_service_uri must be specified.");
166   }
167   options->token_exchange_service_uri.assign(value);
168   value = grpc_json_get_string_property(json, "subject_token_path", nullptr);
169   if (value == nullptr) {
170     ClearStsCredentialsOptions(options);
171     return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
172                         "subject_token_path must be specified.");
173   }
174   options->subject_token_path.assign(value);
175   value = grpc_json_get_string_property(json, "subject_token_type", nullptr);
176   if (value == nullptr) {
177     ClearStsCredentialsOptions(options);
178     return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
179                         "subject_token_type must be specified.");
180   }
181   options->subject_token_type.assign(value);
182
183   // Optional fields.
184   value = grpc_json_get_string_property(json, "resource", nullptr);
185   if (value != nullptr) options->resource.assign(value);
186   value = grpc_json_get_string_property(json, "audience", nullptr);
187   if (value != nullptr) options->audience.assign(value);
188   value = grpc_json_get_string_property(json, "scope", nullptr);
189   if (value != nullptr) options->scope.assign(value);
190   value = grpc_json_get_string_property(json, "requested_token_type", nullptr);
191   if (value != nullptr) options->requested_token_type.assign(value);
192   value = grpc_json_get_string_property(json, "actor_token_path", nullptr);
193   if (value != nullptr) options->actor_token_path.assign(value);
194   value = grpc_json_get_string_property(json, "actor_token_type", nullptr);
195   if (value != nullptr) options->actor_token_type.assign(value);
196
197   return grpc::Status();
198 }
199
200 // Builds STS credentials Options from the $STS_CREDENTIALS env var.
201 grpc::Status StsCredentialsOptionsFromEnv(StsCredentialsOptions* options) {
202   if (options == nullptr) {
203     return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
204                         "options cannot be nullptr.");
205   }
206   ClearStsCredentialsOptions(options);
207   grpc_slice json_string = grpc_empty_slice();
208   char* sts_creds_path = gpr_getenv("STS_CREDENTIALS");
209   grpc_error* error = GRPC_ERROR_NONE;
210   grpc::Status status;
211   auto cleanup = [&json_string, &sts_creds_path, &error, &status]() {
212     grpc_slice_unref_internal(json_string);
213     gpr_free(sts_creds_path);
214     GRPC_ERROR_UNREF(error);
215     return status;
216   };
217
218   if (sts_creds_path == nullptr) {
219     status = grpc::Status(grpc::StatusCode::NOT_FOUND,
220                           "STS_CREDENTIALS environment variable not set.");
221     return cleanup();
222   }
223   error = grpc_load_file(sts_creds_path, 1, &json_string);
224   if (error != GRPC_ERROR_NONE) {
225     status =
226         grpc::Status(grpc::StatusCode::NOT_FOUND, grpc_error_string(error));
227     return cleanup();
228   }
229   status = StsCredentialsOptionsFromJson(
230       reinterpret_cast<const char*>(GRPC_SLICE_START_PTR(json_string)),
231       options);
232   return cleanup();
233 }
234
235 // C++ to Core STS Credentials options.
236 grpc_sts_credentials_options StsCredentialsCppToCoreOptions(
237     const StsCredentialsOptions& options) {
238   grpc_sts_credentials_options opts;
239   memset(&opts, 0, sizeof(opts));
240   opts.token_exchange_service_uri = options.token_exchange_service_uri.c_str();
241   opts.resource = options.resource.c_str();
242   opts.audience = options.audience.c_str();
243   opts.scope = options.scope.c_str();
244   opts.requested_token_type = options.requested_token_type.c_str();
245   opts.subject_token_path = options.subject_token_path.c_str();
246   opts.subject_token_type = options.subject_token_type.c_str();
247   opts.actor_token_path = options.actor_token_path.c_str();
248   opts.actor_token_type = options.actor_token_type.c_str();
249   return opts;
250 }
251
252 // Builds STS credentials.
253 std::shared_ptr<CallCredentials> StsCredentials(
254     const StsCredentialsOptions& options) {
255   auto opts = StsCredentialsCppToCoreOptions(options);
256   return WrapCallCredentials(grpc_sts_credentials_create(&opts, nullptr));
257 }
258
259 std::shared_ptr<CallCredentials> MetadataCredentialsFromPlugin(
260     std::unique_ptr<MetadataCredentialsPlugin> plugin,
261     grpc_security_level min_security_level) {
262   grpc::GrpcLibraryCodegen init;  // To call grpc_init().
263   const char* type = plugin->GetType();
264   grpc::MetadataCredentialsPluginWrapper* wrapper =
265       new grpc::MetadataCredentialsPluginWrapper(std::move(plugin));
266   grpc_metadata_credentials_plugin c_plugin = {
267       grpc::MetadataCredentialsPluginWrapper::GetMetadata,
268       grpc::MetadataCredentialsPluginWrapper::DebugString,
269       grpc::MetadataCredentialsPluginWrapper::Destroy, wrapper, type};
270   return WrapCallCredentials(grpc_metadata_credentials_create_from_plugin(
271       c_plugin, min_security_level, nullptr));
272 }
273
274 // Builds ALTS Credentials given ALTS specific options
275 std::shared_ptr<ChannelCredentials> AltsCredentials(
276     const AltsCredentialsOptions& options) {
277   grpc::GrpcLibraryCodegen init;  // To call grpc_init().
278   grpc_alts_credentials_options* c_options =
279       grpc_alts_credentials_client_options_create();
280   for (const auto& service_account : options.target_service_accounts) {
281     grpc_alts_credentials_client_options_add_target_service_account(
282         c_options, service_account.c_str());
283   }
284   grpc_channel_credentials* c_creds = grpc_alts_credentials_create(c_options);
285   grpc_alts_credentials_options_destroy(c_options);
286   return internal::WrapChannelCredentials(c_creds);
287 }
288
289 // Builds Local Credentials
290 std::shared_ptr<ChannelCredentials> LocalCredentials(
291     grpc_local_connect_type type) {
292   grpc::GrpcLibraryCodegen init;  // To call grpc_init().
293   return internal::WrapChannelCredentials(grpc_local_credentials_create(type));
294 }
295
296 // Builds TLS Credentials given TLS options.
297 std::shared_ptr<ChannelCredentials> TlsCredentials(
298     const TlsChannelCredentialsOptions& options) {
299   return internal::WrapChannelCredentials(
300       grpc_tls_credentials_create(options.c_credentials_options()));
301 }
302
303 }  // namespace experimental
304
305 // Builds credentials for use when running in GCE
306 std::shared_ptr<CallCredentials> GoogleComputeEngineCredentials() {
307   grpc::GrpcLibraryCodegen init;  // To call grpc_init().
308   return WrapCallCredentials(
309       grpc_google_compute_engine_credentials_create(nullptr));
310 }
311
312 // Builds JWT credentials.
313 std::shared_ptr<CallCredentials> ServiceAccountJWTAccessCredentials(
314     const std::string& json_key, long token_lifetime_seconds) {
315   grpc::GrpcLibraryCodegen init;  // To call grpc_init().
316   if (token_lifetime_seconds <= 0) {
317     gpr_log(GPR_ERROR,
318             "Trying to create JWTCredentials with non-positive lifetime");
319     return WrapCallCredentials(nullptr);
320   }
321   gpr_timespec lifetime =
322       gpr_time_from_seconds(token_lifetime_seconds, GPR_TIMESPAN);
323   return WrapCallCredentials(grpc_service_account_jwt_access_credentials_create(
324       json_key.c_str(), lifetime, nullptr));
325 }
326
327 // Builds refresh token credentials.
328 std::shared_ptr<CallCredentials> GoogleRefreshTokenCredentials(
329     const std::string& json_refresh_token) {
330   grpc::GrpcLibraryCodegen init;  // To call grpc_init().
331   return WrapCallCredentials(grpc_google_refresh_token_credentials_create(
332       json_refresh_token.c_str(), nullptr));
333 }
334
335 // Builds access token credentials.
336 std::shared_ptr<CallCredentials> AccessTokenCredentials(
337     const std::string& access_token) {
338   grpc::GrpcLibraryCodegen init;  // To call grpc_init().
339   return WrapCallCredentials(
340       grpc_access_token_credentials_create(access_token.c_str(), nullptr));
341 }
342
343 // Builds IAM credentials.
344 std::shared_ptr<CallCredentials> GoogleIAMCredentials(
345     const std::string& authorization_token,
346     const std::string& authority_selector) {
347   grpc::GrpcLibraryCodegen init;  // To call grpc_init().
348   return WrapCallCredentials(grpc_google_iam_credentials_create(
349       authorization_token.c_str(), authority_selector.c_str(), nullptr));
350 }
351
352 // Combines one channel credentials and one call credentials into a channel
353 // composite credentials.
354 std::shared_ptr<ChannelCredentials> CompositeChannelCredentials(
355     const std::shared_ptr<ChannelCredentials>& channel_creds,
356     const std::shared_ptr<CallCredentials>& call_creds) {
357   // Note that we are not saving shared_ptrs to the two credentials passed in
358   // here. This is OK because the underlying C objects (i.e., channel_creds and
359   // call_creds) into grpc_composite_credentials_create will see their refcounts
360   // incremented.
361   SecureChannelCredentials* s_channel_creds =
362       channel_creds->AsSecureCredentials();
363   SecureCallCredentials* s_call_creds = call_creds->AsSecureCredentials();
364   if (s_channel_creds && s_call_creds) {
365     return internal::WrapChannelCredentials(
366         grpc_composite_channel_credentials_create(
367             s_channel_creds->GetRawCreds(), s_call_creds->GetRawCreds(),
368             nullptr));
369   }
370   return nullptr;
371 }
372
373 std::shared_ptr<CallCredentials> CompositeCallCredentials(
374     const std::shared_ptr<CallCredentials>& creds1,
375     const std::shared_ptr<CallCredentials>& creds2) {
376   SecureCallCredentials* s_creds1 = creds1->AsSecureCredentials();
377   SecureCallCredentials* s_creds2 = creds2->AsSecureCredentials();
378   if (s_creds1 != nullptr && s_creds2 != nullptr) {
379     return WrapCallCredentials(grpc_composite_call_credentials_create(
380         s_creds1->GetRawCreds(), s_creds2->GetRawCreds(), nullptr));
381   }
382   return nullptr;
383 }
384
385 std::shared_ptr<CallCredentials> MetadataCredentialsFromPlugin(
386     std::unique_ptr<MetadataCredentialsPlugin> plugin) {
387   grpc::GrpcLibraryCodegen init;  // To call grpc_init().
388   const char* type = plugin->GetType();
389   grpc::MetadataCredentialsPluginWrapper* wrapper =
390       new grpc::MetadataCredentialsPluginWrapper(std::move(plugin));
391   grpc_metadata_credentials_plugin c_plugin = {
392       grpc::MetadataCredentialsPluginWrapper::GetMetadata,
393       grpc::MetadataCredentialsPluginWrapper::DebugString,
394       grpc::MetadataCredentialsPluginWrapper::Destroy, wrapper, type};
395   return WrapCallCredentials(grpc_metadata_credentials_create_from_plugin(
396       c_plugin, GRPC_PRIVACY_AND_INTEGRITY, nullptr));
397 }
398
399 namespace {
400 void DeleteWrapper(void* wrapper, grpc_error* /*ignored*/) {
401   MetadataCredentialsPluginWrapper* w =
402       static_cast<MetadataCredentialsPluginWrapper*>(wrapper);
403   delete w;
404 }
405 }  // namespace
406
407 char* MetadataCredentialsPluginWrapper::DebugString(void* wrapper) {
408   GPR_ASSERT(wrapper);
409   MetadataCredentialsPluginWrapper* w =
410       static_cast<MetadataCredentialsPluginWrapper*>(wrapper);
411   return gpr_strdup(w->plugin_->DebugString().c_str());
412 }
413
414 void MetadataCredentialsPluginWrapper::Destroy(void* wrapper) {
415   if (wrapper == nullptr) return;
416   grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
417   grpc_core::ExecCtx exec_ctx;
418   grpc_core::Executor::Run(GRPC_CLOSURE_CREATE(DeleteWrapper, wrapper, nullptr),
419                            GRPC_ERROR_NONE);
420 }
421
422 int MetadataCredentialsPluginWrapper::GetMetadata(
423     void* wrapper, grpc_auth_metadata_context context,
424     grpc_credentials_plugin_metadata_cb cb, void* user_data,
425     grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX],
426     size_t* num_creds_md, grpc_status_code* status,
427     const char** error_details) {
428   GPR_ASSERT(wrapper);
429   MetadataCredentialsPluginWrapper* w =
430       static_cast<MetadataCredentialsPluginWrapper*>(wrapper);
431   if (!w->plugin_) {
432     *num_creds_md = 0;
433     *status = GRPC_STATUS_OK;
434     *error_details = nullptr;
435     return 1;
436   }
437   if (w->plugin_->IsBlocking()) {
438     // The internals of context may be destroyed if GetMetadata is cancelled.
439     // Make a copy for InvokePlugin.
440     grpc_auth_metadata_context context_copy = grpc_auth_metadata_context();
441     grpc_auth_metadata_context_copy(&context, &context_copy);
442     // Asynchronous return.
443     w->thread_pool_->Add([w, context_copy, cb, user_data]() mutable {
444       w->MetadataCredentialsPluginWrapper::InvokePlugin(
445           context_copy, cb, user_data, nullptr, nullptr, nullptr, nullptr);
446       grpc_auth_metadata_context_reset(&context_copy);
447     });
448     return 0;
449   } else {
450     // Synchronous return.
451     w->InvokePlugin(context, cb, user_data, creds_md, num_creds_md, status,
452                     error_details);
453     return 1;
454   }
455 }
456
457 namespace {
458
459 void UnrefMetadata(const std::vector<grpc_metadata>& md) {
460   for (const auto& metadatum : md) {
461     grpc_slice_unref(metadatum.key);
462     grpc_slice_unref(metadatum.value);
463   }
464 }
465
466 }  // namespace
467
468 void MetadataCredentialsPluginWrapper::InvokePlugin(
469     grpc_auth_metadata_context context, grpc_credentials_plugin_metadata_cb cb,
470     void* user_data, grpc_metadata creds_md[4], size_t* num_creds_md,
471     grpc_status_code* status_code, const char** error_details) {
472   std::multimap<std::string, std::string> metadata;
473
474   // const_cast is safe since the SecureAuthContext only inc/dec the refcount
475   // and the object is passed as a const ref to plugin_->GetMetadata.
476   SecureAuthContext cpp_channel_auth_context(
477       const_cast<grpc_auth_context*>(context.channel_auth_context));
478
479   Status status = plugin_->GetMetadata(context.service_url, context.method_name,
480                                        cpp_channel_auth_context, &metadata);
481   std::vector<grpc_metadata> md;
482   for (auto& metadatum : metadata) {
483     grpc_metadata md_entry;
484     md_entry.key = SliceFromCopiedString(metadatum.first);
485     md_entry.value = SliceFromCopiedString(metadatum.second);
486     md_entry.flags = 0;
487     md.push_back(md_entry);
488   }
489   if (creds_md != nullptr) {
490     // Synchronous return.
491     if (md.size() > GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX) {
492       *num_creds_md = 0;
493       *status_code = GRPC_STATUS_INTERNAL;
494       *error_details = gpr_strdup(
495           "blocking plugin credentials returned too many metadata keys");
496       UnrefMetadata(md);
497     } else {
498       for (const auto& elem : md) {
499         creds_md[*num_creds_md].key = elem.key;
500         creds_md[*num_creds_md].value = elem.value;
501         creds_md[*num_creds_md].flags = elem.flags;
502         ++(*num_creds_md);
503       }
504       *status_code = static_cast<grpc_status_code>(status.error_code());
505       *error_details =
506           status.ok() ? nullptr : gpr_strdup(status.error_message().c_str());
507     }
508   } else {
509     // Asynchronous return.
510     cb(user_data, md.empty() ? nullptr : &md[0], md.size(),
511        static_cast<grpc_status_code>(status.error_code()),
512        status.error_message().c_str());
513     UnrefMetadata(md);
514   }
515 }
516
517 MetadataCredentialsPluginWrapper::MetadataCredentialsPluginWrapper(
518     std::unique_ptr<MetadataCredentialsPlugin> plugin)
519     : thread_pool_(CreateDefaultThreadPool()), plugin_(std::move(plugin)) {}
520
521 }  // namespace grpc