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