• 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 <grpc/support/port_platform.h>
20 
21 #include "src/core/lib/security/credentials/credentials.h"
22 
23 #include <string.h>
24 
25 #include <grpc/support/alloc.h>
26 #include <grpc/support/log.h>
27 #include <grpc/support/sync.h>
28 
29 #include "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h"
30 #include "src/core/lib/channel/channel_args.h"
31 #include "src/core/lib/gpr/env.h"
32 #include "src/core/lib/gpr/string.h"
33 #include "src/core/lib/http/httpcli.h"
34 #include "src/core/lib/http/parser.h"
35 #include "src/core/lib/iomgr/load_file.h"
36 #include "src/core/lib/iomgr/polling_entity.h"
37 #include "src/core/lib/security/credentials/alts/alts_credentials.h"
38 #include "src/core/lib/security/credentials/alts/check_gcp_environment.h"
39 #include "src/core/lib/security/credentials/google_default/google_default_credentials.h"
40 #include "src/core/lib/security/credentials/jwt/jwt_credentials.h"
41 #include "src/core/lib/security/credentials/oauth2/oauth2_credentials.h"
42 #include "src/core/lib/slice/slice_internal.h"
43 #include "src/core/lib/slice/slice_string_helpers.h"
44 #include "src/core/lib/surface/api_trace.h"
45 
46 /* -- Constants. -- */
47 
48 #define GRPC_COMPUTE_ENGINE_DETECTION_HOST "metadata.google.internal"
49 
50 /* -- Default credentials. -- */
51 
52 static grpc_channel_credentials* g_default_credentials = nullptr;
53 static int g_compute_engine_detection_done = 0;
54 static gpr_mu g_state_mu;
55 static gpr_once g_once = GPR_ONCE_INIT;
56 static grpc_core::internal::grpc_gce_tenancy_checker g_gce_tenancy_checker =
57     grpc_alts_is_running_on_gcp;
58 
init_default_credentials(void)59 static void init_default_credentials(void) { gpr_mu_init(&g_state_mu); }
60 
61 typedef struct {
62   grpc_polling_entity pollent;
63   int is_done;
64   int success;
65   grpc_http_response response;
66 } compute_engine_detector;
67 
google_default_credentials_destruct(grpc_channel_credentials * creds)68 static void google_default_credentials_destruct(
69     grpc_channel_credentials* creds) {
70   grpc_google_default_channel_credentials* c =
71       reinterpret_cast<grpc_google_default_channel_credentials*>(creds);
72   grpc_channel_credentials_unref(c->alts_creds);
73   grpc_channel_credentials_unref(c->ssl_creds);
74 }
75 
google_default_create_security_connector(grpc_channel_credentials * creds,grpc_call_credentials * call_creds,const char * target,const grpc_channel_args * args,grpc_channel_security_connector ** sc,grpc_channel_args ** new_args)76 static grpc_security_status google_default_create_security_connector(
77     grpc_channel_credentials* creds, grpc_call_credentials* call_creds,
78     const char* target, const grpc_channel_args* args,
79     grpc_channel_security_connector** sc, grpc_channel_args** new_args) {
80   grpc_google_default_channel_credentials* c =
81       reinterpret_cast<grpc_google_default_channel_credentials*>(creds);
82   bool is_grpclb_load_balancer = grpc_channel_arg_get_bool(
83       grpc_channel_args_find(args, GRPC_ARG_ADDRESS_IS_GRPCLB_LOAD_BALANCER),
84       false);
85   bool is_backend_from_grpclb_load_balancer = grpc_channel_arg_get_bool(
86       grpc_channel_args_find(
87           args, GRPC_ARG_ADDRESS_IS_BACKEND_FROM_GRPCLB_LOAD_BALANCER),
88       false);
89   bool use_alts =
90       is_grpclb_load_balancer || is_backend_from_grpclb_load_balancer;
91   grpc_security_status status = GRPC_SECURITY_ERROR;
92   status = use_alts ? c->alts_creds->vtable->create_security_connector(
93                           c->alts_creds, call_creds, target, args, sc, new_args)
94                     : c->ssl_creds->vtable->create_security_connector(
95                           c->ssl_creds, call_creds, target, args, sc, new_args);
96   /* grpclb-specific channel args are removed from the channel args set
97    * to ensure backends and fallback adresses will have the same set of channel
98    * args. By doing that, it guarantees the connections to backends will not be
99    * torn down and re-connected when switching in and out of fallback mode.
100    */
101   if (use_alts) {
102     static const char* args_to_remove[] = {
103         GRPC_ARG_ADDRESS_IS_GRPCLB_LOAD_BALANCER,
104         GRPC_ARG_ADDRESS_IS_BACKEND_FROM_GRPCLB_LOAD_BALANCER,
105     };
106     *new_args = grpc_channel_args_copy_and_add_and_remove(
107         args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), nullptr, 0);
108   }
109   return status;
110 }
111 
112 static grpc_channel_credentials_vtable google_default_credentials_vtable = {
113     google_default_credentials_destruct,
114     google_default_create_security_connector, nullptr};
115 
116 /* Takes ownership of creds_path if not NULL. */
create_default_creds_from_path(char * creds_path,grpc_call_credentials ** creds)117 static grpc_error* create_default_creds_from_path(
118     char* creds_path, grpc_call_credentials** creds) {
119   grpc_json* json = nullptr;
120   grpc_auth_json_key key;
121   grpc_auth_refresh_token token;
122   grpc_call_credentials* result = nullptr;
123   grpc_slice creds_data = grpc_empty_slice();
124   grpc_error* error = GRPC_ERROR_NONE;
125   if (creds_path == nullptr) {
126     error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("creds_path unset");
127     goto end;
128   }
129   error = grpc_load_file(creds_path, 0, &creds_data);
130   if (error != GRPC_ERROR_NONE) {
131     goto end;
132   }
133   json = grpc_json_parse_string_with_len(
134       reinterpret_cast<char*> GRPC_SLICE_START_PTR(creds_data),
135       GRPC_SLICE_LENGTH(creds_data));
136   if (json == nullptr) {
137     error = grpc_error_set_str(
138         GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed to parse JSON"),
139         GRPC_ERROR_STR_RAW_BYTES, grpc_slice_ref_internal(creds_data));
140     goto end;
141   }
142 
143   /* First, try an auth json key. */
144   key = grpc_auth_json_key_create_from_json(json);
145   if (grpc_auth_json_key_is_valid(&key)) {
146     result =
147         grpc_service_account_jwt_access_credentials_create_from_auth_json_key(
148             key, grpc_max_auth_token_lifetime());
149     if (result == nullptr) {
150       error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
151           "grpc_service_account_jwt_access_credentials_create_from_auth_json_"
152           "key failed");
153     }
154     goto end;
155   }
156 
157   /* Then try a refresh token if the auth json key was invalid. */
158   token = grpc_auth_refresh_token_create_from_json(json);
159   if (grpc_auth_refresh_token_is_valid(&token)) {
160     result =
161         grpc_refresh_token_credentials_create_from_auth_refresh_token(token);
162     if (result == nullptr) {
163       error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
164           "grpc_refresh_token_credentials_create_from_auth_refresh_token "
165           "failed");
166     }
167     goto end;
168   }
169 
170 end:
171   GPR_ASSERT((result == nullptr) + (error == GRPC_ERROR_NONE) == 1);
172   if (creds_path != nullptr) gpr_free(creds_path);
173   grpc_slice_unref_internal(creds_data);
174   if (json != nullptr) grpc_json_destroy(json);
175   *creds = result;
176   return error;
177 }
178 
grpc_google_default_credentials_create(void)179 grpc_channel_credentials* grpc_google_default_credentials_create(void) {
180   grpc_channel_credentials* result = nullptr;
181   grpc_call_credentials* call_creds = nullptr;
182   grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
183       "Failed to create Google credentials");
184   grpc_error* err;
185   grpc_core::ExecCtx exec_ctx;
186 
187   GRPC_API_TRACE("grpc_google_default_credentials_create(void)", 0, ());
188 
189   gpr_once_init(&g_once, init_default_credentials);
190 
191   gpr_mu_lock(&g_state_mu);
192 
193   if (g_default_credentials != nullptr) {
194     result = grpc_channel_credentials_ref(g_default_credentials);
195     goto end;
196   }
197 
198   /* First, try the environment variable. */
199   err = create_default_creds_from_path(
200       gpr_getenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR), &call_creds);
201   if (err == GRPC_ERROR_NONE) goto end;
202   error = grpc_error_add_child(error, err);
203 
204   /* Then the well-known file. */
205   err = create_default_creds_from_path(
206       grpc_get_well_known_google_credentials_file_path(), &call_creds);
207   if (err == GRPC_ERROR_NONE) goto end;
208   error = grpc_error_add_child(error, err);
209 
210   /* At last try to see if we're on compute engine (do the detection only once
211      since it requires a network test). */
212   if (!g_compute_engine_detection_done) {
213     int need_compute_engine_creds = g_gce_tenancy_checker();
214     g_compute_engine_detection_done = 1;
215     if (need_compute_engine_creds) {
216       call_creds = grpc_google_compute_engine_credentials_create(nullptr);
217       if (call_creds == nullptr) {
218         error = grpc_error_add_child(
219             error, GRPC_ERROR_CREATE_FROM_STATIC_STRING(
220                        "Failed to get credentials from network"));
221       }
222     }
223   }
224 
225 end:
226   if (result == nullptr) {
227     if (call_creds != nullptr) {
228       /* Create google default credentials. */
229       auto creds = static_cast<grpc_google_default_channel_credentials*>(
230           gpr_zalloc(sizeof(grpc_google_default_channel_credentials)));
231       creds->base.vtable = &google_default_credentials_vtable;
232       creds->base.type = GRPC_CHANNEL_CREDENTIALS_TYPE_GOOGLE_DEFAULT;
233       gpr_ref_init(&creds->base.refcount, 1);
234       creds->ssl_creds =
235           grpc_ssl_credentials_create(nullptr, nullptr, nullptr, nullptr);
236       GPR_ASSERT(creds->ssl_creds != nullptr);
237       grpc_alts_credentials_options* options =
238           grpc_alts_credentials_client_options_create();
239       creds->alts_creds = grpc_alts_credentials_create(options);
240       grpc_alts_credentials_options_destroy(options);
241       /* Add a global reference so that it can be cached and re-served. */
242       g_default_credentials = grpc_composite_channel_credentials_create(
243           &creds->base, call_creds, nullptr);
244       GPR_ASSERT(g_default_credentials != nullptr);
245       grpc_channel_credentials_unref(&creds->base);
246       grpc_call_credentials_unref(call_creds);
247       result = grpc_channel_credentials_ref(g_default_credentials);
248     } else {
249       gpr_log(GPR_ERROR, "Could not create google default credentials.");
250     }
251   }
252   gpr_mu_unlock(&g_state_mu);
253   if (result == nullptr) {
254     GRPC_LOG_IF_ERROR("grpc_google_default_credentials_create", error);
255   } else {
256     GRPC_ERROR_UNREF(error);
257   }
258 
259   return result;
260 }
261 
262 namespace grpc_core {
263 namespace internal {
264 
set_gce_tenancy_checker_for_testing(grpc_gce_tenancy_checker checker)265 void set_gce_tenancy_checker_for_testing(grpc_gce_tenancy_checker checker) {
266   g_gce_tenancy_checker = checker;
267 }
268 
269 }  // namespace internal
270 }  // namespace grpc_core
271 
grpc_flush_cached_google_default_credentials(void)272 void grpc_flush_cached_google_default_credentials(void) {
273   grpc_core::ExecCtx exec_ctx;
274   gpr_once_init(&g_once, init_default_credentials);
275   gpr_mu_lock(&g_state_mu);
276   if (g_default_credentials != nullptr) {
277     grpc_channel_credentials_unref(g_default_credentials);
278     g_default_credentials = nullptr;
279   }
280   g_compute_engine_detection_done = 0;
281   gpr_mu_unlock(&g_state_mu);
282 }
283 
284 /* -- Well known credentials path. -- */
285 
286 static grpc_well_known_credentials_path_getter creds_path_getter = nullptr;
287 
grpc_get_well_known_google_credentials_file_path(void)288 char* grpc_get_well_known_google_credentials_file_path(void) {
289   if (creds_path_getter != nullptr) return creds_path_getter();
290   return grpc_get_well_known_google_credentials_file_path_impl();
291 }
292 
grpc_override_well_known_credentials_path_getter(grpc_well_known_credentials_path_getter getter)293 void grpc_override_well_known_credentials_path_getter(
294     grpc_well_known_credentials_path_getter getter) {
295   creds_path_getter = getter;
296 }
297