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