3 * Copyright 2015 gRPC authors.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include "src/cpp/client/secure_credentials.h"
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>
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"
44 static grpc::internal::GrpcLibraryInitializer g_gli_initializer;
45 SecureChannelCredentials::SecureChannelCredentials(
46 grpc_channel_credentials* c_creds)
48 g_gli_initializer.summon();
51 std::shared_ptr<Channel> SecureChannelCredentials::CreateChannelImpl(
52 const std::string& target, const ChannelArguments& args) {
53 return CreateChannelWithInterceptors(
55 std::vector<std::unique_ptr<
56 grpc::experimental::ClientInterceptorFactoryInterface>>());
59 std::shared_ptr<Channel>
60 SecureChannelCredentials::CreateChannelWithInterceptors(
61 const std::string& target, const ChannelArguments& args,
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,
71 std::move(interceptor_creators));
74 SecureCallCredentials::SecureCallCredentials(grpc_call_credentials* c_creds)
76 g_gli_initializer.summon();
79 bool SecureCallCredentials::ApplyToCall(grpc_call* call) {
80 return grpc_call_set_credentials(call, c_creds_) == GRPC_CALL_OK;
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));
92 } // namespace internal
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));
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));
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()};
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,
121 return internal::WrapChannelCredentials(c_creds);
124 namespace experimental {
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();
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.");
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.");
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.");
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.");
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.");
181 options->subject_token_type.assign(value);
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);
197 return grpc::Status();
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.");
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;
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);
218 if (sts_creds_path == nullptr) {
219 status = grpc::Status(grpc::StatusCode::NOT_FOUND,
220 "STS_CREDENTIALS environment variable not set.");
223 error = grpc_load_file(sts_creds_path, 1, &json_string);
224 if (error != GRPC_ERROR_NONE) {
226 grpc::Status(grpc::StatusCode::NOT_FOUND, grpc_error_string(error));
229 status = StsCredentialsOptionsFromJson(
230 reinterpret_cast<const char*>(GRPC_SLICE_START_PTR(json_string)),
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();
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));
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));
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());
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);
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));
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()));
303 } // namespace experimental
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));
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) {
318 "Trying to create JWTCredentials with non-positive lifetime");
319 return WrapCallCredentials(nullptr);
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));
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));
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));
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));
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
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(),
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));
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));
400 void DeleteWrapper(void* wrapper, grpc_error* /*ignored*/) {
401 MetadataCredentialsPluginWrapper* w =
402 static_cast<MetadataCredentialsPluginWrapper*>(wrapper);
407 char* MetadataCredentialsPluginWrapper::DebugString(void* wrapper) {
409 MetadataCredentialsPluginWrapper* w =
410 static_cast<MetadataCredentialsPluginWrapper*>(wrapper);
411 return gpr_strdup(w->plugin_->DebugString().c_str());
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),
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) {
429 MetadataCredentialsPluginWrapper* w =
430 static_cast<MetadataCredentialsPluginWrapper*>(wrapper);
433 *status = GRPC_STATUS_OK;
434 *error_details = nullptr;
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);
450 // Synchronous return.
451 w->InvokePlugin(context, cb, user_data, creds_md, num_creds_md, status,
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);
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;
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));
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);
487 md.push_back(md_entry);
489 if (creds_md != nullptr) {
490 // Synchronous return.
491 if (md.size() > GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX) {
493 *status_code = GRPC_STATUS_INTERNAL;
494 *error_details = gpr_strdup(
495 "blocking plugin credentials returned too many metadata keys");
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;
504 *status_code = static_cast<grpc_status_code>(status.error_code());
506 status.ok() ? nullptr : gpr_strdup(status.error_message().c_str());
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());
517 MetadataCredentialsPluginWrapper::MetadataCredentialsPluginWrapper(
518 std::unique_ptr<MetadataCredentialsPlugin> plugin)
519 : thread_pool_(CreateDefaultThreadPool()), plugin_(std::move(plugin)) {}