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 #include <grpc/support/log.h>
21 #include <grpc/support/string_util.h>
22 #include <grpcpp/channel.h>
23 #include <grpcpp/impl/grpc_library.h>
24 #include <grpcpp/support/channel_arguments.h>
25 #include "src/cpp/client/create_channel_internal.h"
26 #include "src/cpp/common/secure_auth_context.h"
27
28 namespace grpc {
29
30 static internal::GrpcLibraryInitializer g_gli_initializer;
SecureChannelCredentials(grpc_channel_credentials * c_creds)31 SecureChannelCredentials::SecureChannelCredentials(
32 grpc_channel_credentials* c_creds)
33 : c_creds_(c_creds) {
34 g_gli_initializer.summon();
35 }
36
CreateChannel(const string & target,const grpc::ChannelArguments & args)37 std::shared_ptr<grpc::Channel> SecureChannelCredentials::CreateChannel(
38 const string& target, const grpc::ChannelArguments& args) {
39 grpc_channel_args channel_args;
40 args.SetChannelArgs(&channel_args);
41 return CreateChannelInternal(
42 args.GetSslTargetNameOverride(),
43 grpc_secure_channel_create(c_creds_, target.c_str(), &channel_args,
44 nullptr));
45 }
46
SecureCallCredentials(grpc_call_credentials * c_creds)47 SecureCallCredentials::SecureCallCredentials(grpc_call_credentials* c_creds)
48 : c_creds_(c_creds) {
49 g_gli_initializer.summon();
50 }
51
ApplyToCall(grpc_call * call)52 bool SecureCallCredentials::ApplyToCall(grpc_call* call) {
53 return grpc_call_set_credentials(call, c_creds_) == GRPC_CALL_OK;
54 }
55
56 namespace {
WrapChannelCredentials(grpc_channel_credentials * creds)57 std::shared_ptr<ChannelCredentials> WrapChannelCredentials(
58 grpc_channel_credentials* creds) {
59 return creds == nullptr ? nullptr
60 : std::shared_ptr<ChannelCredentials>(
61 new SecureChannelCredentials(creds));
62 }
63
WrapCallCredentials(grpc_call_credentials * creds)64 std::shared_ptr<CallCredentials> WrapCallCredentials(
65 grpc_call_credentials* creds) {
66 return creds == nullptr ? nullptr
67 : std::shared_ptr<CallCredentials>(
68 new SecureCallCredentials(creds));
69 }
70 } // namespace
71
GoogleDefaultCredentials()72 std::shared_ptr<ChannelCredentials> GoogleDefaultCredentials() {
73 GrpcLibraryCodegen init; // To call grpc_init().
74 return WrapChannelCredentials(grpc_google_default_credentials_create());
75 }
76
77 // Builds SSL Credentials given SSL specific options
SslCredentials(const SslCredentialsOptions & options)78 std::shared_ptr<ChannelCredentials> SslCredentials(
79 const SslCredentialsOptions& options) {
80 GrpcLibraryCodegen init; // To call grpc_init().
81 grpc_ssl_pem_key_cert_pair pem_key_cert_pair = {
82 options.pem_private_key.c_str(), options.pem_cert_chain.c_str()};
83
84 grpc_channel_credentials* c_creds = grpc_ssl_credentials_create(
85 options.pem_root_certs.empty() ? nullptr : options.pem_root_certs.c_str(),
86 options.pem_private_key.empty() ? nullptr : &pem_key_cert_pair, nullptr,
87 nullptr);
88 return WrapChannelCredentials(c_creds);
89 }
90
91 namespace experimental {
92
93 // Builds ALTS Credentials given ALTS specific options
AltsCredentials(const AltsCredentialsOptions & options)94 std::shared_ptr<ChannelCredentials> AltsCredentials(
95 const AltsCredentialsOptions& options) {
96 GrpcLibraryCodegen init; // To call grpc_init().
97 grpc_alts_credentials_options* c_options =
98 grpc_alts_credentials_client_options_create();
99 for (auto service_account = options.target_service_accounts.begin();
100 service_account != options.target_service_accounts.end();
101 service_account++) {
102 grpc_alts_credentials_client_options_add_target_service_account(
103 c_options, service_account->c_str());
104 }
105 grpc_channel_credentials* c_creds = grpc_alts_credentials_create(c_options);
106 grpc_alts_credentials_options_destroy(c_options);
107 return WrapChannelCredentials(c_creds);
108 }
109
110 // Builds Local Credentials
LocalCredentials(grpc_local_connect_type type)111 std::shared_ptr<ChannelCredentials> LocalCredentials(
112 grpc_local_connect_type type) {
113 GrpcLibraryCodegen init; // To call grpc_init().
114 return WrapChannelCredentials(grpc_local_credentials_create(type));
115 }
116
117 } // namespace experimental
118
119 // Builds credentials for use when running in GCE
GoogleComputeEngineCredentials()120 std::shared_ptr<CallCredentials> GoogleComputeEngineCredentials() {
121 GrpcLibraryCodegen init; // To call grpc_init().
122 return WrapCallCredentials(
123 grpc_google_compute_engine_credentials_create(nullptr));
124 }
125
126 // Builds JWT credentials.
ServiceAccountJWTAccessCredentials(const grpc::string & json_key,long token_lifetime_seconds)127 std::shared_ptr<CallCredentials> ServiceAccountJWTAccessCredentials(
128 const grpc::string& json_key, long token_lifetime_seconds) {
129 GrpcLibraryCodegen init; // To call grpc_init().
130 if (token_lifetime_seconds <= 0) {
131 gpr_log(GPR_ERROR,
132 "Trying to create JWTCredentials with non-positive lifetime");
133 return WrapCallCredentials(nullptr);
134 }
135 gpr_timespec lifetime =
136 gpr_time_from_seconds(token_lifetime_seconds, GPR_TIMESPAN);
137 return WrapCallCredentials(grpc_service_account_jwt_access_credentials_create(
138 json_key.c_str(), lifetime, nullptr));
139 }
140
141 // Builds refresh token credentials.
GoogleRefreshTokenCredentials(const grpc::string & json_refresh_token)142 std::shared_ptr<CallCredentials> GoogleRefreshTokenCredentials(
143 const grpc::string& json_refresh_token) {
144 GrpcLibraryCodegen init; // To call grpc_init().
145 return WrapCallCredentials(grpc_google_refresh_token_credentials_create(
146 json_refresh_token.c_str(), nullptr));
147 }
148
149 // Builds access token credentials.
AccessTokenCredentials(const grpc::string & access_token)150 std::shared_ptr<CallCredentials> AccessTokenCredentials(
151 const grpc::string& access_token) {
152 GrpcLibraryCodegen init; // To call grpc_init().
153 return WrapCallCredentials(
154 grpc_access_token_credentials_create(access_token.c_str(), nullptr));
155 }
156
157 // Builds IAM credentials.
GoogleIAMCredentials(const grpc::string & authorization_token,const grpc::string & authority_selector)158 std::shared_ptr<CallCredentials> GoogleIAMCredentials(
159 const grpc::string& authorization_token,
160 const grpc::string& authority_selector) {
161 GrpcLibraryCodegen init; // To call grpc_init().
162 return WrapCallCredentials(grpc_google_iam_credentials_create(
163 authorization_token.c_str(), authority_selector.c_str(), nullptr));
164 }
165
166 // Combines one channel credentials and one call credentials into a channel
167 // composite credentials.
CompositeChannelCredentials(const std::shared_ptr<ChannelCredentials> & channel_creds,const std::shared_ptr<CallCredentials> & call_creds)168 std::shared_ptr<ChannelCredentials> CompositeChannelCredentials(
169 const std::shared_ptr<ChannelCredentials>& channel_creds,
170 const std::shared_ptr<CallCredentials>& call_creds) {
171 // Note that we are not saving shared_ptrs to the two credentials passed in
172 // here. This is OK because the underlying C objects (i.e., channel_creds and
173 // call_creds) into grpc_composite_credentials_create will see their refcounts
174 // incremented.
175 SecureChannelCredentials* s_channel_creds =
176 channel_creds->AsSecureCredentials();
177 SecureCallCredentials* s_call_creds = call_creds->AsSecureCredentials();
178 if (s_channel_creds && s_call_creds) {
179 return WrapChannelCredentials(grpc_composite_channel_credentials_create(
180 s_channel_creds->GetRawCreds(), s_call_creds->GetRawCreds(), nullptr));
181 }
182 return nullptr;
183 }
184
CompositeCallCredentials(const std::shared_ptr<CallCredentials> & creds1,const std::shared_ptr<CallCredentials> & creds2)185 std::shared_ptr<CallCredentials> CompositeCallCredentials(
186 const std::shared_ptr<CallCredentials>& creds1,
187 const std::shared_ptr<CallCredentials>& creds2) {
188 SecureCallCredentials* s_creds1 = creds1->AsSecureCredentials();
189 SecureCallCredentials* s_creds2 = creds2->AsSecureCredentials();
190 if (s_creds1 != nullptr && s_creds2 != nullptr) {
191 return WrapCallCredentials(grpc_composite_call_credentials_create(
192 s_creds1->GetRawCreds(), s_creds2->GetRawCreds(), nullptr));
193 }
194 return nullptr;
195 }
196
Destroy(void * wrapper)197 void MetadataCredentialsPluginWrapper::Destroy(void* wrapper) {
198 if (wrapper == nullptr) return;
199 MetadataCredentialsPluginWrapper* w =
200 static_cast<MetadataCredentialsPluginWrapper*>(wrapper);
201 delete w;
202 }
203
GetMetadata(void * wrapper,grpc_auth_metadata_context context,grpc_credentials_plugin_metadata_cb cb,void * user_data,grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX],size_t * num_creds_md,grpc_status_code * status,const char ** error_details)204 int MetadataCredentialsPluginWrapper::GetMetadata(
205 void* wrapper, grpc_auth_metadata_context context,
206 grpc_credentials_plugin_metadata_cb cb, void* user_data,
207 grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX],
208 size_t* num_creds_md, grpc_status_code* status,
209 const char** error_details) {
210 GPR_ASSERT(wrapper);
211 MetadataCredentialsPluginWrapper* w =
212 static_cast<MetadataCredentialsPluginWrapper*>(wrapper);
213 if (!w->plugin_) {
214 *num_creds_md = 0;
215 *status = GRPC_STATUS_OK;
216 *error_details = nullptr;
217 return true;
218 }
219 if (w->plugin_->IsBlocking()) {
220 // Asynchronous return.
221 w->thread_pool_->Add(
222 std::bind(&MetadataCredentialsPluginWrapper::InvokePlugin, w, context,
223 cb, user_data, nullptr, nullptr, nullptr, nullptr));
224 return 0;
225 } else {
226 // Synchronous return.
227 w->InvokePlugin(context, cb, user_data, creds_md, num_creds_md, status,
228 error_details);
229 return 1;
230 }
231 }
232
233 namespace {
234
UnrefMetadata(const std::vector<grpc_metadata> & md)235 void UnrefMetadata(const std::vector<grpc_metadata>& md) {
236 for (auto it = md.begin(); it != md.end(); ++it) {
237 grpc_slice_unref(it->key);
238 grpc_slice_unref(it->value);
239 }
240 }
241
242 } // namespace
243
InvokePlugin(grpc_auth_metadata_context context,grpc_credentials_plugin_metadata_cb cb,void * user_data,grpc_metadata creds_md[4],size_t * num_creds_md,grpc_status_code * status_code,const char ** error_details)244 void MetadataCredentialsPluginWrapper::InvokePlugin(
245 grpc_auth_metadata_context context, grpc_credentials_plugin_metadata_cb cb,
246 void* user_data, grpc_metadata creds_md[4], size_t* num_creds_md,
247 grpc_status_code* status_code, const char** error_details) {
248 std::multimap<grpc::string, grpc::string> metadata;
249
250 // const_cast is safe since the SecureAuthContext does not take owndership and
251 // the object is passed as a const ref to plugin_->GetMetadata.
252 SecureAuthContext cpp_channel_auth_context(
253 const_cast<grpc_auth_context*>(context.channel_auth_context), false);
254
255 Status status = plugin_->GetMetadata(context.service_url, context.method_name,
256 cpp_channel_auth_context, &metadata);
257 std::vector<grpc_metadata> md;
258 for (auto it = metadata.begin(); it != metadata.end(); ++it) {
259 grpc_metadata md_entry;
260 md_entry.key = SliceFromCopiedString(it->first);
261 md_entry.value = SliceFromCopiedString(it->second);
262 md_entry.flags = 0;
263 md.push_back(md_entry);
264 }
265 if (creds_md != nullptr) {
266 // Synchronous return.
267 if (md.size() > GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX) {
268 *num_creds_md = 0;
269 *status_code = GRPC_STATUS_INTERNAL;
270 *error_details = gpr_strdup(
271 "blocking plugin credentials returned too many metadata keys");
272 UnrefMetadata(md);
273 } else {
274 for (const auto& elem : md) {
275 creds_md[*num_creds_md].key = elem.key;
276 creds_md[*num_creds_md].value = elem.value;
277 creds_md[*num_creds_md].flags = elem.flags;
278 ++(*num_creds_md);
279 }
280 *status_code = static_cast<grpc_status_code>(status.error_code());
281 *error_details =
282 status.ok() ? nullptr : gpr_strdup(status.error_message().c_str());
283 }
284 } else {
285 // Asynchronous return.
286 cb(user_data, md.empty() ? nullptr : &md[0], md.size(),
287 static_cast<grpc_status_code>(status.error_code()),
288 status.error_message().c_str());
289 UnrefMetadata(md);
290 }
291 }
292
MetadataCredentialsPluginWrapper(std::unique_ptr<MetadataCredentialsPlugin> plugin)293 MetadataCredentialsPluginWrapper::MetadataCredentialsPluginWrapper(
294 std::unique_ptr<MetadataCredentialsPlugin> plugin)
295 : thread_pool_(CreateDefaultThreadPool()), plugin_(std::move(plugin)) {}
296
MetadataCredentialsFromPlugin(std::unique_ptr<MetadataCredentialsPlugin> plugin)297 std::shared_ptr<CallCredentials> MetadataCredentialsFromPlugin(
298 std::unique_ptr<MetadataCredentialsPlugin> plugin) {
299 GrpcLibraryCodegen init; // To call grpc_init().
300 const char* type = plugin->GetType();
301 MetadataCredentialsPluginWrapper* wrapper =
302 new MetadataCredentialsPluginWrapper(std::move(plugin));
303 grpc_metadata_credentials_plugin c_plugin = {
304 MetadataCredentialsPluginWrapper::GetMetadata,
305 MetadataCredentialsPluginWrapper::Destroy, wrapper, type};
306 return WrapCallCredentials(
307 grpc_metadata_credentials_create_from_plugin(c_plugin, nullptr));
308 }
309
310 } // namespace grpc
311