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 <grpc/support/port_platform.h>
21 #include "src/core/lib/security/credentials/credentials.h"
23 #include <openssl/rsa.h>
29 #include "absl/strings/match.h"
30 #include "absl/strings/str_cat.h"
31 #include "absl/strings/str_format.h"
32 #include "absl/strings/str_replace.h"
34 #include <grpc/grpc_security.h>
35 #include <grpc/slice.h>
36 #include <grpc/support/alloc.h>
37 #include <grpc/support/log.h>
38 #include <grpc/support/string_util.h>
39 #include <grpc/support/time.h>
41 #include "src/core/lib/gpr/env.h"
42 #include "src/core/lib/gpr/string.h"
43 #include "src/core/lib/gpr/tmpfile.h"
44 #include "src/core/lib/gprpp/host_port.h"
45 #include "src/core/lib/http/httpcli.h"
46 #include "src/core/lib/iomgr/error.h"
47 #include "src/core/lib/security/credentials/composite/composite_credentials.h"
48 #include "src/core/lib/security/credentials/external/aws_external_account_credentials.h"
49 #include "src/core/lib/security/credentials/external/external_account_credentials.h"
50 #include "src/core/lib/security/credentials/external/file_external_account_credentials.h"
51 #include "src/core/lib/security/credentials/external/url_external_account_credentials.h"
52 #include "src/core/lib/security/credentials/fake/fake_credentials.h"
53 #include "src/core/lib/security/credentials/google_default/google_default_credentials.h"
54 #include "src/core/lib/security/credentials/jwt/jwt_credentials.h"
55 #include "src/core/lib/security/credentials/oauth2/oauth2_credentials.h"
56 #include "src/core/lib/security/transport/auth_filters.h"
57 #include "src/core/lib/uri/uri_parser.h"
58 #include "test/core/util/test_config.h"
60 using grpc_core::internal::grpc_flush_cached_google_default_credentials;
61 using grpc_core::internal::set_gce_tenancy_checker_for_testing;
63 /* -- Constants. -- */
65 static const char test_google_iam_authorization_token[] = "blahblahblhahb";
66 static const char test_google_iam_authority_selector[] = "respectmyauthoritah";
67 static const char test_oauth2_bearer_token[] =
68 "Bearer blaaslkdjfaslkdfasdsfasf";
70 /* This JSON key was generated with the GCE console and revoked immediately.
71 The identifiers have been changed as well.
72 Maximum size for a string literal is 509 chars in C89, yay! */
73 static const char test_json_key_str_part1[] =
74 "{ \"private_key\": \"-----BEGIN PRIVATE KEY-----"
75 "\\nMIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAOEvJsnoHnyHkXcp\\n7mJE"
77 "WGjiw71NfXByguekSKho65FxaGbsnSM9SMQAqVk7Q2rG+I0OpsT0LrWQtZ\\nyjSeg/"
78 "rWBQvS4hle4LfijkP3J5BG+"
79 "IXDMP8RfziNRQsenAXDNPkY4kJCvKux2xdD\\nOnVF6N7dL3nTYZg+"
80 "uQrNsMTz9UxVAgMBAAECgYEAzbLewe1xe9vy+2GoSsfib+28\\nDZgSE6Bu/"
81 "zuFoPrRc6qL9p2SsnV7txrunTyJkkOnPLND9ABAXybRTlcVKP/sGgza\\n/"
82 "8HpCqFYM9V8f34SBWfD4fRFT+n/"
83 "73cfRUtGXdXpseva2lh8RilIQfPhNZAncenU\\ngqXjDvpkypEusgXAykECQQD+";
84 static const char test_json_key_str_part2[] =
85 "53XxNVnxBHsYb+AYEfklR96yVi8HywjVHP34+OQZ\\nCslxoHQM8s+"
86 "dBnjfScLu22JqkPv04xyxmt0QAKm9+vTdAkEA4ib7YvEAn2jXzcCI\\nEkoy2L/"
87 "XydR1GCHoacdfdAwiL2npOdnbvi4ZmdYRPY1LSTO058tQHKVXV7NLeCa3\\nAARh2QJBAMKeDA"
89 "W303SQv2cZTdbeaLKJbB5drz3eo3j7dDKjrTD9JupixFbzcGw\\n8FZi5c8idxiwC36kbAL6Hz"
91 "ZoX+ofI0CQE6KCzPJTtYNqyShgKAZdJ8hwOcvCZtf\\n6z8RJm0+"
92 "6YBd38lfh5j8mZd7aHFf6I17j5AQY7oPEc47TjJj/"
93 "5nZ68ECQQDvYuI3\\nLyK5fS8g0SYbmPOL9TlcHDOqwG0mrX9qpg5DC2fniXNSrrZ64GTDKdzZ"
95 "Ap6LI9W\\nIqv4vr6y38N79TTC\\n-----END PRIVATE KEY-----\\n\", ";
96 static const char test_json_key_str_part3[] =
97 "\"private_key_id\": \"e6b5137873db8d2ef81e06a47289e6434ec8a165\", "
99 "\"777-abaslkan11hlb6nmim3bpspl31ud@developer.gserviceaccount."
100 "com\", \"client_id\": "
101 "\"777-abaslkan11hlb6nmim3bpspl31ud.apps.googleusercontent."
102 "com\", \"type\": \"service_account\" }";
104 /* Test refresh token. */
105 static const char test_refresh_token_str[] =
106 "{ \"client_id\": \"32555999999.apps.googleusercontent.com\","
107 " \"client_secret\": \"EmssLNjJy1332hD4KFsecret\","
108 " \"refresh_token\": \"1/Blahblasj424jladJDSGNf-u4Sua3HDA2ngjd42\","
109 " \"type\": \"authorized_user\"}";
111 static const char valid_oauth2_json_response[] =
112 "{\"access_token\":\"ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_\","
113 " \"expires_in\":3599, "
114 " \"token_type\":\"Bearer\"}";
116 static const char valid_sts_json_response[] =
117 "{\"access_token\":\"ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_\","
118 " \"expires_in\":3599, "
119 " \"issued_token_type\":\"urn:ietf:params:oauth:token-type:access_token\", "
120 " \"token_type\":\"Bearer\"}";
122 static const char test_scope[] = "perm1 perm2";
124 static const char test_signed_jwt[] =
125 "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImY0OTRkN2M1YWU2MGRmOTcyNmM4YW"
126 "U0MDcyZTViYTdmZDkwODg2YzcifQ";
127 static const char test_signed_jwt_token_type[] =
128 "urn:ietf:params:oauth:token-type:id_token";
129 static const char test_signed_jwt2[] =
130 "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImY0OTRkN2M1YWU2MGRmOTcyNmM5YW"
131 "U2MDcyZTViYTdnZDkwODg5YzcifQ";
132 static const char test_signed_jwt_token_type2[] =
133 "urn:ietf:params:oauth:token-type:jwt";
134 static const char test_signed_jwt_path_prefix[] = "test_sign_jwt";
136 static const char test_service_url[] = "https://foo.com/foo.v1";
137 static const char other_test_service_url[] = "https://bar.com/bar.v1";
139 static const char test_sts_endpoint_url[] =
140 "https://foo.com:5555/v1/token-exchange";
142 static const char test_method[] = "ThisIsNotAMethod";
144 static const char valid_external_account_creds_token_exchange_response[] =
145 "{\"access_token\":\"token_exchange_access_token\","
146 " \"expires_in\":3599,"
147 " \"token_type\":\"Bearer\"}";
150 valid_external_account_creds_service_account_impersonation_response[] =
151 "{\"accessToken\":\"service_account_impersonation_access_token\","
152 " \"expireTime\":\"2050-01-01T00:00:00Z\"}";
155 valid_url_external_account_creds_options_credential_source_format_text[] =
156 "{\"url\":\"https://foo.com:5555/generate_subject_token_format_text\","
157 "\"headers\":{\"Metadata-Flavor\":\"Google\"}}";
160 valid_url_external_account_creds_options_credential_source_with_qurey_params_format_text
161 [] = "{\"url\":\"https://foo.com:5555/"
162 "path/to/url/creds?p1=v1&p2=v2\","
163 "\"headers\":{\"Metadata-Flavor\":\"Google\"}}";
166 valid_url_external_account_creds_retrieve_subject_token_response_format_text
167 [] = "test_subject_token";
170 valid_url_external_account_creds_options_credential_source_format_json[] =
171 "{\"url\":\"https://foo.com:5555/generate_subject_token_format_json\","
172 "\"headers\":{\"Metadata-Flavor\":\"Google\"},"
173 "\"format\":{\"type\":\"json\",\"subject_token_field_name\":\"access_"
177 valid_url_external_account_creds_retrieve_subject_token_response_format_json
178 [] = "{\"access_token\":\"test_subject_token\"}";
181 invalid_url_external_account_creds_options_credential_source[] =
182 "{\"url\":\"invalid_credential_source_url\","
183 "\"headers\":{\"Metadata-Flavor\":\"Google\"}}";
186 valid_aws_external_account_creds_retrieve_signing_keys_response[] =
187 "{\"AccessKeyId\":\"test_access_key_id\",\"SecretAccessKey\":"
188 "\"test_secret_access_key\",\"Token\":\"test_token\"}";
190 static const char valid_aws_external_account_creds_options_credential_source[] =
191 "{\"environment_id\":\"aws1\","
192 "\"region_url\":\"https://foo.com:5555/region_url\","
193 "\"url\":\"https://foo.com:5555/url\","
194 "\"regional_cred_verification_url\":\"https://foo.com:5555/"
195 "regional_cred_verification_url_{region}\"}";
198 invalid_aws_external_account_creds_options_credential_source_unmatched_environment_id
199 [] = "{\"environment_id\":\"unsupported_aws_version\","
200 "\"region_url\":\"https://foo.com:5555/region_url\","
201 "\"url\":\"https://foo.com:5555/url\","
202 "\"regional_cred_verification_url\":\"https://foo.com:5555/"
203 "regional_cred_verification_url_{region}\"}";
206 invalid_aws_external_account_creds_options_credential_source_invalid_region_url
207 [] = "{\"environment_id\":\"aws1\","
208 "\"region_url\":\"invalid_region_url\","
209 "\"url\":\"https://foo.com:5555/url\","
210 "\"regional_cred_verification_url\":\"https://foo.com:5555/"
211 "regional_cred_verification_url_{region}\"}";
214 invalid_aws_external_account_creds_options_credential_source_invalid_url[] =
215 "{\"environment_id\":\"aws1\","
216 "\"region_url\":\"https://foo.com:5555/region_url\","
217 "\"url\":\"invalid_url\","
218 "\"regional_cred_verification_url\":\"https://foo.com:5555/"
219 "regional_cred_verification_url_{region}\"}";
222 invalid_aws_external_account_creds_options_credential_source_missing_role_name
223 [] = "{\"environment_id\":\"aws1\","
224 "\"region_url\":\"https://foo.com:5555/region_url\","
225 "\"url\":\"https://foo.com:5555/url_no_role_name\","
226 "\"regional_cred_verification_url\":\"https://foo.com:5555/"
227 "regional_cred_verification_url_{region}\"}";
230 invalid_aws_external_account_creds_options_credential_source_invalid_regional_cred_verification_url
231 [] = "{\"environment_id\":\"aws1\","
232 "\"region_url\":\"https://foo.com:5555/region_url\","
233 "\"url\":\"https://foo.com:5555/url_no_role_name\","
234 "\"regional_cred_verification_url\":\"invalid_regional_cred_"
235 "verification_url\"}";
237 /* -- Global state flags. -- */
239 static bool g_test_is_on_gce = false;
241 static bool g_test_gce_tenancy_checker_called = false;
245 static char* test_json_key_str(void) {
246 size_t result_len = strlen(test_json_key_str_part1) +
247 strlen(test_json_key_str_part2) +
248 strlen(test_json_key_str_part3);
249 char* result = static_cast<char*>(gpr_malloc(result_len + 1));
250 char* current = result;
251 strcpy(result, test_json_key_str_part1);
252 current += strlen(test_json_key_str_part1);
253 strcpy(current, test_json_key_str_part2);
254 current += strlen(test_json_key_str_part2);
255 strcpy(current, test_json_key_str_part3);
259 static grpc_httpcli_response http_response(int status, const char* body) {
260 grpc_httpcli_response response;
262 response.status = status;
263 response.body = gpr_strdup(const_cast<char*>(body));
264 response.body_length = strlen(body);
270 static void test_empty_md_array(void) {
271 grpc_core::ExecCtx exec_ctx;
272 grpc_credentials_mdelem_array md_array;
274 GPR_ASSERT(md_array.md == nullptr);
275 GPR_ASSERT(md_array.size == 0);
276 grpc_credentials_mdelem_array_destroy(&md_array);
279 static void test_add_to_empty_md_array(void) {
280 grpc_core::ExecCtx exec_ctx;
281 grpc_credentials_mdelem_array md_array;
283 const char* key = "hello";
284 const char* value = "there blah blah blah blah blah blah blah";
285 grpc_mdelem md = grpc_mdelem_from_slices(
286 grpc_slice_from_copied_string(key), grpc_slice_from_copied_string(value));
287 grpc_credentials_mdelem_array_add(&md_array, md);
288 GPR_ASSERT(md_array.size == 1);
289 GPR_ASSERT(grpc_mdelem_eq(md, md_array.md[0]));
290 GRPC_MDELEM_UNREF(md);
291 grpc_credentials_mdelem_array_destroy(&md_array);
294 static void test_add_abunch_to_md_array(void) {
295 grpc_core::ExecCtx exec_ctx;
296 grpc_credentials_mdelem_array md_array;
298 const char* key = "hello";
299 const char* value = "there blah blah blah blah blah blah blah";
300 grpc_mdelem md = grpc_mdelem_from_slices(
301 grpc_slice_from_copied_string(key), grpc_slice_from_copied_string(value));
302 size_t num_entries = 1000;
303 for (size_t i = 0; i < num_entries; ++i) {
304 grpc_credentials_mdelem_array_add(&md_array, md);
306 for (size_t i = 0; i < num_entries; ++i) {
307 GPR_ASSERT(grpc_mdelem_eq(md_array.md[i], md));
309 GRPC_MDELEM_UNREF(md);
310 grpc_credentials_mdelem_array_destroy(&md_array);
313 static void test_oauth2_token_fetcher_creds_parsing_ok(void) {
314 grpc_core::ExecCtx exec_ctx;
315 grpc_mdelem token_md = GRPC_MDNULL;
316 grpc_millis token_lifetime;
317 grpc_httpcli_response response =
318 http_response(200, valid_oauth2_json_response);
319 GPR_ASSERT(grpc_oauth2_token_fetcher_credentials_parse_server_response(
320 &response, &token_md, &token_lifetime) == GRPC_CREDENTIALS_OK);
321 GPR_ASSERT(token_lifetime == 3599 * GPR_MS_PER_SEC);
322 GPR_ASSERT(grpc_slice_str_cmp(GRPC_MDKEY(token_md), "authorization") == 0);
323 GPR_ASSERT(grpc_slice_str_cmp(GRPC_MDVALUE(token_md),
324 "Bearer ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_") ==
326 GRPC_MDELEM_UNREF(token_md);
327 grpc_http_response_destroy(&response);
330 static void test_oauth2_token_fetcher_creds_parsing_bad_http_status(void) {
331 grpc_core::ExecCtx exec_ctx;
332 grpc_mdelem token_md = GRPC_MDNULL;
333 grpc_millis token_lifetime;
334 grpc_httpcli_response response =
335 http_response(401, valid_oauth2_json_response);
336 GPR_ASSERT(grpc_oauth2_token_fetcher_credentials_parse_server_response(
337 &response, &token_md, &token_lifetime) ==
338 GRPC_CREDENTIALS_ERROR);
339 grpc_http_response_destroy(&response);
342 static void test_oauth2_token_fetcher_creds_parsing_empty_http_body(void) {
343 grpc_core::ExecCtx exec_ctx;
344 grpc_mdelem token_md = GRPC_MDNULL;
345 grpc_millis token_lifetime;
346 grpc_httpcli_response response = http_response(200, "");
347 GPR_ASSERT(grpc_oauth2_token_fetcher_credentials_parse_server_response(
348 &response, &token_md, &token_lifetime) ==
349 GRPC_CREDENTIALS_ERROR);
350 grpc_http_response_destroy(&response);
353 static void test_oauth2_token_fetcher_creds_parsing_invalid_json(void) {
354 grpc_core::ExecCtx exec_ctx;
355 grpc_mdelem token_md = GRPC_MDNULL;
356 grpc_millis token_lifetime;
357 grpc_httpcli_response response =
359 "{\"access_token\":\"ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_\","
360 " \"expires_in\":3599, "
361 " \"token_type\":\"Bearer\"");
362 GPR_ASSERT(grpc_oauth2_token_fetcher_credentials_parse_server_response(
363 &response, &token_md, &token_lifetime) ==
364 GRPC_CREDENTIALS_ERROR);
365 grpc_http_response_destroy(&response);
368 static void test_oauth2_token_fetcher_creds_parsing_missing_token(void) {
369 grpc_core::ExecCtx exec_ctx;
370 grpc_mdelem token_md = GRPC_MDNULL;
371 grpc_millis token_lifetime;
372 grpc_httpcli_response response = http_response(200,
374 " \"expires_in\":3599, "
375 " \"token_type\":\"Bearer\"}");
376 GPR_ASSERT(grpc_oauth2_token_fetcher_credentials_parse_server_response(
377 &response, &token_md, &token_lifetime) ==
378 GRPC_CREDENTIALS_ERROR);
379 grpc_http_response_destroy(&response);
382 static void test_oauth2_token_fetcher_creds_parsing_missing_token_type(void) {
383 grpc_core::ExecCtx exec_ctx;
384 grpc_mdelem token_md = GRPC_MDNULL;
385 grpc_millis token_lifetime;
386 grpc_httpcli_response response =
388 "{\"access_token\":\"ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_\","
389 " \"expires_in\":3599, "
391 GPR_ASSERT(grpc_oauth2_token_fetcher_credentials_parse_server_response(
392 &response, &token_md, &token_lifetime) ==
393 GRPC_CREDENTIALS_ERROR);
394 grpc_http_response_destroy(&response);
397 static void test_oauth2_token_fetcher_creds_parsing_missing_token_lifetime(
399 grpc_core::ExecCtx exec_ctx;
400 grpc_mdelem token_md = GRPC_MDNULL;
401 grpc_millis token_lifetime;
402 grpc_httpcli_response response =
404 "{\"access_token\":\"ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_\","
405 " \"token_type\":\"Bearer\"}");
406 GPR_ASSERT(grpc_oauth2_token_fetcher_credentials_parse_server_response(
407 &response, &token_md, &token_lifetime) ==
408 GRPC_CREDENTIALS_ERROR);
409 grpc_http_response_destroy(&response);
418 grpc_error* expected_error;
419 const expected_md* expected;
420 size_t expected_size;
421 grpc_credentials_mdelem_array md_array;
422 grpc_closure on_request_metadata;
423 grpc_call_credentials* creds;
424 grpc_polling_entity pollent;
425 } request_metadata_state;
427 static void check_metadata(const expected_md* expected,
428 grpc_credentials_mdelem_array* md_array) {
429 for (size_t i = 0; i < md_array->size; ++i) {
431 for (j = 0; j < md_array->size; ++j) {
433 grpc_slice_str_cmp(GRPC_MDKEY(md_array->md[j]), expected[i].key)) {
434 GPR_ASSERT(grpc_slice_str_cmp(GRPC_MDVALUE(md_array->md[j]),
435 expected[i].value) == 0);
439 if (j == md_array->size) {
440 gpr_log(GPR_ERROR, "key %s not found", expected[i].key);
446 static void check_request_metadata(void* arg, grpc_error* error) {
447 request_metadata_state* state = static_cast<request_metadata_state*>(arg);
448 gpr_log(GPR_INFO, "expected_error: %s",
449 grpc_error_string(state->expected_error));
450 gpr_log(GPR_INFO, "actual_error: %s", grpc_error_string(error));
451 if (state->expected_error == GRPC_ERROR_NONE) {
452 GPR_ASSERT(error == GRPC_ERROR_NONE);
454 grpc_slice expected_error;
455 GPR_ASSERT(grpc_error_get_str(state->expected_error,
456 GRPC_ERROR_STR_DESCRIPTION, &expected_error));
457 grpc_slice actual_error;
459 grpc_error_get_str(error, GRPC_ERROR_STR_DESCRIPTION, &actual_error));
460 GPR_ASSERT(grpc_slice_cmp(expected_error, actual_error) == 0);
461 GRPC_ERROR_UNREF(state->expected_error);
463 gpr_log(GPR_INFO, "expected_size=%" PRIdPTR " actual_size=%" PRIdPTR,
464 state->expected_size, state->md_array.size);
465 GPR_ASSERT(state->md_array.size == state->expected_size);
466 check_metadata(state->expected, &state->md_array);
467 grpc_credentials_mdelem_array_destroy(&state->md_array);
468 grpc_pollset_set_destroy(grpc_polling_entity_pollset_set(&state->pollent));
472 static request_metadata_state* make_request_metadata_state(
473 grpc_error* expected_error, const expected_md* expected,
474 size_t expected_size) {
475 request_metadata_state* state =
476 static_cast<request_metadata_state*>(gpr_zalloc(sizeof(*state)));
477 state->expected_error = expected_error;
478 state->expected = expected;
479 state->expected_size = expected_size;
481 grpc_polling_entity_create_from_pollset_set(grpc_pollset_set_create());
482 GRPC_CLOSURE_INIT(&state->on_request_metadata, check_request_metadata, state,
483 grpc_schedule_on_exec_ctx);
487 static void run_request_metadata_test(grpc_call_credentials* creds,
488 grpc_auth_metadata_context auth_md_ctx,
489 request_metadata_state* state) {
490 grpc_error* error = GRPC_ERROR_NONE;
491 if (creds->get_request_metadata(&state->pollent, auth_md_ctx,
492 &state->md_array, &state->on_request_metadata,
494 // Synchronous result. Invoke the callback directly.
495 check_request_metadata(state, error);
496 GRPC_ERROR_UNREF(error);
500 static void test_google_iam_creds(void) {
501 grpc_core::ExecCtx exec_ctx;
502 expected_md emd[] = {{GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY,
503 test_google_iam_authorization_token},
504 {GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY,
505 test_google_iam_authority_selector}};
506 request_metadata_state* state =
507 make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
508 grpc_call_credentials* creds = grpc_google_iam_credentials_create(
509 test_google_iam_authorization_token, test_google_iam_authority_selector,
511 /* Check security level. */
512 GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
513 grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
515 run_request_metadata_test(creds, auth_md_ctx, state);
519 static void test_access_token_creds(void) {
520 grpc_core::ExecCtx exec_ctx;
521 expected_md emd[] = {{GRPC_AUTHORIZATION_METADATA_KEY, "Bearer blah"}};
522 request_metadata_state* state =
523 make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
524 grpc_call_credentials* creds =
525 grpc_access_token_credentials_create("blah", nullptr);
526 grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
528 GPR_ASSERT(strcmp(creds->type(), GRPC_CALL_CREDENTIALS_TYPE_OAUTH2) == 0);
529 /* Check security level. */
530 GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
531 run_request_metadata_test(creds, auth_md_ctx, state);
536 class check_channel_oauth2 final : public grpc_channel_credentials {
538 check_channel_oauth2() : grpc_channel_credentials("mock") {}
539 ~check_channel_oauth2() override = default;
541 grpc_core::RefCountedPtr<grpc_channel_security_connector>
542 create_security_connector(
543 grpc_core::RefCountedPtr<grpc_call_credentials> call_creds,
544 const char* /*target*/, const grpc_channel_args* /*args*/,
545 grpc_channel_args** /*new_args*/) override {
546 GPR_ASSERT(strcmp(type(), "mock") == 0);
547 GPR_ASSERT(call_creds != nullptr);
548 GPR_ASSERT(strcmp(call_creds->type(), GRPC_CALL_CREDENTIALS_TYPE_OAUTH2) ==
555 static void test_channel_oauth2_composite_creds(void) {
556 grpc_core::ExecCtx exec_ctx;
557 grpc_channel_args* new_args;
558 grpc_channel_credentials* channel_creds = new check_channel_oauth2();
559 grpc_call_credentials* oauth2_creds =
560 grpc_access_token_credentials_create("blah", nullptr);
561 grpc_channel_credentials* channel_oauth2_creds =
562 grpc_composite_channel_credentials_create(channel_creds, oauth2_creds,
564 grpc_channel_credentials_release(channel_creds);
565 grpc_call_credentials_release(oauth2_creds);
566 channel_oauth2_creds->create_security_connector(nullptr, nullptr, nullptr,
568 grpc_channel_credentials_release(channel_oauth2_creds);
571 static void test_oauth2_google_iam_composite_creds(void) {
572 grpc_core::ExecCtx exec_ctx;
573 expected_md emd[] = {
574 {GRPC_AUTHORIZATION_METADATA_KEY, test_oauth2_bearer_token},
575 {GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY,
576 test_google_iam_authorization_token},
577 {GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY,
578 test_google_iam_authority_selector}};
579 request_metadata_state* state =
580 make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
581 grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
583 grpc_call_credentials* oauth2_creds = grpc_md_only_test_credentials_create(
584 "authorization", test_oauth2_bearer_token, false);
586 /* Check security level of fake credentials. */
587 GPR_ASSERT(oauth2_creds->min_security_level() == GRPC_SECURITY_NONE);
589 grpc_call_credentials* google_iam_creds = grpc_google_iam_credentials_create(
590 test_google_iam_authorization_token, test_google_iam_authority_selector,
592 grpc_call_credentials* composite_creds =
593 grpc_composite_call_credentials_create(oauth2_creds, google_iam_creds,
595 /* Check security level of composite credentials. */
596 GPR_ASSERT(composite_creds->min_security_level() ==
597 GRPC_PRIVACY_AND_INTEGRITY);
599 oauth2_creds->Unref();
600 google_iam_creds->Unref();
601 GPR_ASSERT(strcmp(composite_creds->type(),
602 GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0);
603 const grpc_composite_call_credentials::CallCredentialsList& creds_list =
604 static_cast<const grpc_composite_call_credentials*>(composite_creds)
606 GPR_ASSERT(creds_list.size() == 2);
607 GPR_ASSERT(strcmp(creds_list[0]->type(), GRPC_CALL_CREDENTIALS_TYPE_OAUTH2) ==
609 GPR_ASSERT(strcmp(creds_list[1]->type(), GRPC_CALL_CREDENTIALS_TYPE_IAM) ==
611 run_request_metadata_test(composite_creds, auth_md_ctx, state);
612 composite_creds->Unref();
616 class check_channel_oauth2_google_iam final : public grpc_channel_credentials {
618 check_channel_oauth2_google_iam() : grpc_channel_credentials("mock") {}
619 ~check_channel_oauth2_google_iam() override = default;
621 grpc_core::RefCountedPtr<grpc_channel_security_connector>
622 create_security_connector(
623 grpc_core::RefCountedPtr<grpc_call_credentials> call_creds,
624 const char* /*target*/, const grpc_channel_args* /*args*/,
625 grpc_channel_args** /*new_args*/) override {
626 GPR_ASSERT(strcmp(type(), "mock") == 0);
627 GPR_ASSERT(call_creds != nullptr);
629 strcmp(call_creds->type(), GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0);
630 const grpc_composite_call_credentials::CallCredentialsList& creds_list =
631 static_cast<const grpc_composite_call_credentials*>(call_creds.get())
634 strcmp(creds_list[0]->type(), GRPC_CALL_CREDENTIALS_TYPE_OAUTH2) == 0);
635 GPR_ASSERT(strcmp(creds_list[1]->type(), GRPC_CALL_CREDENTIALS_TYPE_IAM) ==
642 static void test_channel_oauth2_google_iam_composite_creds(void) {
643 grpc_core::ExecCtx exec_ctx;
644 grpc_channel_args* new_args;
645 grpc_channel_credentials* channel_creds =
646 new check_channel_oauth2_google_iam();
647 grpc_call_credentials* oauth2_creds =
648 grpc_access_token_credentials_create("blah", nullptr);
649 grpc_channel_credentials* channel_oauth2_creds =
650 grpc_composite_channel_credentials_create(channel_creds, oauth2_creds,
652 grpc_call_credentials* google_iam_creds = grpc_google_iam_credentials_create(
653 test_google_iam_authorization_token, test_google_iam_authority_selector,
656 grpc_channel_credentials* channel_oauth2_iam_creds =
657 grpc_composite_channel_credentials_create(channel_oauth2_creds,
658 google_iam_creds, nullptr);
659 grpc_channel_credentials_release(channel_creds);
660 grpc_call_credentials_release(oauth2_creds);
661 grpc_channel_credentials_release(channel_oauth2_creds);
662 grpc_call_credentials_release(google_iam_creds);
664 channel_oauth2_iam_creds->create_security_connector(nullptr, nullptr, nullptr,
667 grpc_channel_credentials_release(channel_oauth2_iam_creds);
670 static void validate_compute_engine_http_request(
671 const grpc_httpcli_request* request) {
672 GPR_ASSERT(request->handshaker != &grpc_httpcli_ssl);
673 GPR_ASSERT(strcmp(request->host, "metadata.google.internal.") == 0);
675 strcmp(request->http.path,
676 "/computeMetadata/v1/instance/service-accounts/default/token") ==
678 GPR_ASSERT(request->http.hdr_count == 1);
679 GPR_ASSERT(strcmp(request->http.hdrs[0].key, "Metadata-Flavor") == 0);
680 GPR_ASSERT(strcmp(request->http.hdrs[0].value, "Google") == 0);
683 static int compute_engine_httpcli_get_success_override(
684 const grpc_httpcli_request* request, grpc_millis /*deadline*/,
685 grpc_closure* on_done, grpc_httpcli_response* response) {
686 validate_compute_engine_http_request(request);
687 *response = http_response(200, valid_oauth2_json_response);
688 grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, GRPC_ERROR_NONE);
692 static int compute_engine_httpcli_get_failure_override(
693 const grpc_httpcli_request* request, grpc_millis /*deadline*/,
694 grpc_closure* on_done, grpc_httpcli_response* response) {
695 validate_compute_engine_http_request(request);
696 *response = http_response(403, "Not Authorized.");
697 grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, GRPC_ERROR_NONE);
701 static int httpcli_post_should_not_be_called(
702 const grpc_httpcli_request* /*request*/, const char* /*body_bytes*/,
703 size_t /*body_size*/, grpc_millis /*deadline*/, grpc_closure* /*on_done*/,
704 grpc_httpcli_response* /*response*/) {
705 GPR_ASSERT("HTTP POST should not be called" == nullptr);
709 static int httpcli_get_should_not_be_called(
710 const grpc_httpcli_request* /*request*/, grpc_millis /*deadline*/,
711 grpc_closure* /*on_done*/, grpc_httpcli_response* /*response*/) {
712 GPR_ASSERT("HTTP GET should not be called" == nullptr);
716 static void test_compute_engine_creds_success() {
717 grpc_core::ExecCtx exec_ctx;
718 expected_md emd[] = {
719 {"authorization", "Bearer ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_"}};
720 const char expected_creds_debug_string[] =
721 "GoogleComputeEngineTokenFetcherCredentials{"
722 "OAuth2TokenFetcherCredentials}";
723 grpc_call_credentials* creds =
724 grpc_google_compute_engine_credentials_create(nullptr);
725 grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
727 /* Check security level. */
728 GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
730 /* First request: http get should be called. */
731 request_metadata_state* state =
732 make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
733 grpc_httpcli_set_override(compute_engine_httpcli_get_success_override,
734 httpcli_post_should_not_be_called);
735 run_request_metadata_test(creds, auth_md_ctx, state);
736 grpc_core::ExecCtx::Get()->Flush();
738 /* Second request: the cached token should be served directly. */
740 make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
741 grpc_httpcli_set_override(httpcli_get_should_not_be_called,
742 httpcli_post_should_not_be_called);
743 run_request_metadata_test(creds, auth_md_ctx, state);
744 grpc_core::ExecCtx::Get()->Flush();
747 strcmp(creds->debug_string().c_str(), expected_creds_debug_string) == 0);
749 grpc_httpcli_set_override(nullptr, nullptr);
752 static void test_compute_engine_creds_failure(void) {
753 grpc_core::ExecCtx exec_ctx;
754 const char expected_creds_debug_string[] =
755 "GoogleComputeEngineTokenFetcherCredentials{"
756 "OAuth2TokenFetcherCredentials}";
757 request_metadata_state* state = make_request_metadata_state(
758 GRPC_ERROR_CREATE_FROM_STATIC_STRING(
759 "Error occurred when fetching oauth2 token."),
761 grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
763 grpc_call_credentials* creds =
764 grpc_google_compute_engine_credentials_create(nullptr);
765 grpc_httpcli_set_override(compute_engine_httpcli_get_failure_override,
766 httpcli_post_should_not_be_called);
767 run_request_metadata_test(creds, auth_md_ctx, state);
769 strcmp(creds->debug_string().c_str(), expected_creds_debug_string) == 0);
771 grpc_httpcli_set_override(nullptr, nullptr);
774 static void validate_refresh_token_http_request(
775 const grpc_httpcli_request* request, const char* body, size_t body_size) {
776 /* The content of the assertion is tested extensively in json_token_test. */
777 GPR_ASSERT(body != nullptr);
778 GPR_ASSERT(body_size != 0);
779 std::string expected_body = absl::StrFormat(
780 GRPC_REFRESH_TOKEN_POST_BODY_FORMAT_STRING,
781 "32555999999.apps.googleusercontent.com", "EmssLNjJy1332hD4KFsecret",
782 "1/Blahblasj424jladJDSGNf-u4Sua3HDA2ngjd42");
783 GPR_ASSERT(expected_body.size() == body_size);
784 GPR_ASSERT(memcmp(expected_body.data(), body, body_size) == 0);
785 GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl);
786 GPR_ASSERT(strcmp(request->host, GRPC_GOOGLE_OAUTH2_SERVICE_HOST) == 0);
788 strcmp(request->http.path, GRPC_GOOGLE_OAUTH2_SERVICE_TOKEN_PATH) == 0);
789 GPR_ASSERT(request->http.hdr_count == 1);
790 GPR_ASSERT(strcmp(request->http.hdrs[0].key, "Content-Type") == 0);
791 GPR_ASSERT(strcmp(request->http.hdrs[0].value,
792 "application/x-www-form-urlencoded") == 0);
795 static int refresh_token_httpcli_post_success(
796 const grpc_httpcli_request* request, const char* body, size_t body_size,
797 grpc_millis /*deadline*/, grpc_closure* on_done,
798 grpc_httpcli_response* response) {
799 validate_refresh_token_http_request(request, body, body_size);
800 *response = http_response(200, valid_oauth2_json_response);
801 grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, GRPC_ERROR_NONE);
805 static int token_httpcli_post_failure(const grpc_httpcli_request* /*request*/,
806 const char* /*body*/,
807 size_t /*body_size*/,
808 grpc_millis /*deadline*/,
809 grpc_closure* on_done,
810 grpc_httpcli_response* response) {
811 *response = http_response(403, "Not Authorized.");
812 grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, GRPC_ERROR_NONE);
816 static void test_refresh_token_creds_success(void) {
817 grpc_core::ExecCtx exec_ctx;
818 expected_md emd[] = {
819 {"authorization", "Bearer ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_"}};
820 const char expected_creds_debug_string[] =
821 "GoogleRefreshToken{ClientID:32555999999.apps.googleusercontent.com,"
822 "OAuth2TokenFetcherCredentials}";
823 grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
825 grpc_call_credentials* creds = grpc_google_refresh_token_credentials_create(
826 test_refresh_token_str, nullptr);
828 /* Check security level. */
829 GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
831 /* First request: http put should be called. */
832 request_metadata_state* state =
833 make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
834 grpc_httpcli_set_override(httpcli_get_should_not_be_called,
835 refresh_token_httpcli_post_success);
836 run_request_metadata_test(creds, auth_md_ctx, state);
837 grpc_core::ExecCtx::Get()->Flush();
839 /* Second request: the cached token should be served directly. */
841 make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
842 grpc_httpcli_set_override(httpcli_get_should_not_be_called,
843 httpcli_post_should_not_be_called);
844 run_request_metadata_test(creds, auth_md_ctx, state);
845 grpc_core::ExecCtx::Get()->Flush();
847 strcmp(creds->debug_string().c_str(), expected_creds_debug_string) == 0);
850 grpc_httpcli_set_override(nullptr, nullptr);
853 static void test_refresh_token_creds_failure(void) {
854 grpc_core::ExecCtx exec_ctx;
855 const char expected_creds_debug_string[] =
856 "GoogleRefreshToken{ClientID:32555999999.apps.googleusercontent.com,"
857 "OAuth2TokenFetcherCredentials}";
858 request_metadata_state* state = make_request_metadata_state(
859 GRPC_ERROR_CREATE_FROM_STATIC_STRING(
860 "Error occurred when fetching oauth2 token."),
862 grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
864 grpc_call_credentials* creds = grpc_google_refresh_token_credentials_create(
865 test_refresh_token_str, nullptr);
866 grpc_httpcli_set_override(httpcli_get_should_not_be_called,
867 token_httpcli_post_failure);
868 run_request_metadata_test(creds, auth_md_ctx, state);
870 strcmp(creds->debug_string().c_str(), expected_creds_debug_string) == 0);
873 grpc_httpcli_set_override(nullptr, nullptr);
876 static void test_valid_sts_creds_options(void) {
877 grpc_sts_credentials_options valid_options = {
878 test_sts_endpoint_url, // sts_endpoint_url
882 nullptr, // requested_token_type
883 test_signed_jwt_path_prefix, // subject_token_path
884 test_signed_jwt_token_type, // subject_token_type
885 nullptr, // actor_token_path
886 nullptr // actor_token_type
888 absl::StatusOr<grpc_core::URI> sts_url =
889 grpc_core::ValidateStsCredentialsOptions(&valid_options);
890 GPR_ASSERT(sts_url.ok());
891 absl::string_view host;
892 absl::string_view port;
893 GPR_ASSERT(grpc_core::SplitHostPort(sts_url->authority(), &host, &port));
894 GPR_ASSERT(host == "foo.com");
895 GPR_ASSERT(port == "5555");
898 static void test_invalid_sts_creds_options(void) {
899 grpc_sts_credentials_options invalid_options = {
900 test_sts_endpoint_url, // sts_endpoint_url
904 nullptr, // requested_token_type
905 nullptr, // subject_token_path (Required)
906 test_signed_jwt_token_type, // subject_token_type
907 nullptr, // actor_token_path
908 nullptr // actor_token_type
910 absl::StatusOr<grpc_core::URI> url_should_be_invalid =
911 grpc_core::ValidateStsCredentialsOptions(&invalid_options);
912 GPR_ASSERT(!url_should_be_invalid.ok());
915 test_sts_endpoint_url, // sts_endpoint_url
919 nullptr, // requested_token_type
920 test_signed_jwt_path_prefix, // subject_token_path
921 nullptr, // subject_token_type (Required)
922 nullptr, // actor_token_path
923 nullptr // actor_token_type
925 url_should_be_invalid =
926 grpc_core::ValidateStsCredentialsOptions(&invalid_options);
927 GPR_ASSERT(!url_should_be_invalid.ok());
930 nullptr, // sts_endpoint_url (Required)
934 nullptr, // requested_token_type
935 test_signed_jwt_path_prefix, // subject_token_path
936 test_signed_jwt_token_type, // subject_token_type (Required)
937 nullptr, // actor_token_path
938 nullptr // actor_token_type
940 url_should_be_invalid =
941 grpc_core::ValidateStsCredentialsOptions(&invalid_options);
942 GPR_ASSERT(!url_should_be_invalid.ok());
945 "not_a_valid_uri", // sts_endpoint_url
949 nullptr, // requested_token_type
950 test_signed_jwt_path_prefix, // subject_token_path
951 test_signed_jwt_token_type, // subject_token_type (Required)
952 nullptr, // actor_token_path
953 nullptr // actor_token_type
955 url_should_be_invalid =
956 grpc_core::ValidateStsCredentialsOptions(&invalid_options);
957 GPR_ASSERT(!url_should_be_invalid.ok());
960 "ftp://ftp.is.not.a.valid.scheme/bar", // sts_endpoint_url
964 nullptr, // requested_token_type
965 test_signed_jwt_path_prefix, // subject_token_path
966 test_signed_jwt_token_type, // subject_token_type (Required)
967 nullptr, // actor_token_path
968 nullptr // actor_token_type
970 url_should_be_invalid =
971 grpc_core::ValidateStsCredentialsOptions(&invalid_options);
972 GPR_ASSERT(!url_should_be_invalid.ok());
975 static void assert_query_parameters(const grpc_core::URI& uri,
976 absl::string_view expected_key,
977 absl::string_view expected_val) {
978 const auto it = uri.query_parameter_map().find(expected_key);
979 GPR_ASSERT(it != uri.query_parameter_map().end());
980 if (it->second != expected_val) {
981 gpr_log(GPR_ERROR, "%s!=%s", std::string(it->second).c_str(),
982 std::string(expected_val).c_str());
984 GPR_ASSERT(it->second == expected_val);
987 static void validate_sts_token_http_request(const grpc_httpcli_request* request,
988 const char* body, size_t body_size,
989 bool expect_actor_token) {
990 // Check that the body is constructed properly.
991 GPR_ASSERT(body != nullptr);
992 GPR_ASSERT(body_size != 0);
993 GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl);
994 std::string get_url_equivalent =
995 absl::StrFormat("%s?%s", test_sts_endpoint_url, body);
996 absl::StatusOr<grpc_core::URI> url =
997 grpc_core::URI::Parse(get_url_equivalent);
999 gpr_log(GPR_ERROR, "%s", url.status().ToString().c_str());
1000 GPR_ASSERT(url.ok());
1002 assert_query_parameters(*url, "resource", "resource");
1003 assert_query_parameters(*url, "audience", "audience");
1004 assert_query_parameters(*url, "scope", "scope");
1005 assert_query_parameters(*url, "requested_token_type", "requested_token_type");
1006 assert_query_parameters(*url, "subject_token", test_signed_jwt);
1007 assert_query_parameters(*url, "subject_token_type",
1008 test_signed_jwt_token_type);
1009 if (expect_actor_token) {
1010 assert_query_parameters(*url, "actor_token", test_signed_jwt2);
1011 assert_query_parameters(*url, "actor_token_type",
1012 test_signed_jwt_token_type2);
1014 GPR_ASSERT(url->query_parameter_map().find("actor_token") ==
1015 url->query_parameter_map().end());
1016 GPR_ASSERT(url->query_parameter_map().find("actor_token_type") ==
1017 url->query_parameter_map().end());
1020 // Check the rest of the request.
1021 GPR_ASSERT(strcmp(request->host, "foo.com:5555") == 0);
1022 GPR_ASSERT(strcmp(request->http.path, "/v1/token-exchange") == 0);
1023 GPR_ASSERT(request->http.hdr_count == 1);
1024 GPR_ASSERT(strcmp(request->http.hdrs[0].key, "Content-Type") == 0);
1025 GPR_ASSERT(strcmp(request->http.hdrs[0].value,
1026 "application/x-www-form-urlencoded") == 0);
1029 static int sts_token_httpcli_post_success(const grpc_httpcli_request* request,
1030 const char* body, size_t body_size,
1031 grpc_millis /*deadline*/,
1032 grpc_closure* on_done,
1033 grpc_httpcli_response* response) {
1034 validate_sts_token_http_request(request, body, body_size, true);
1035 *response = http_response(200, valid_sts_json_response);
1036 grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, GRPC_ERROR_NONE);
1040 static int sts_token_httpcli_post_success_no_actor_token(
1041 const grpc_httpcli_request* request, const char* body, size_t body_size,
1042 grpc_millis /*deadline*/, grpc_closure* on_done,
1043 grpc_httpcli_response* response) {
1044 validate_sts_token_http_request(request, body, body_size, false);
1045 *response = http_response(200, valid_sts_json_response);
1046 grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, GRPC_ERROR_NONE);
1050 static char* write_tmp_jwt_file(const char* jwt_contents) {
1052 FILE* tmp = gpr_tmpfile(test_signed_jwt_path_prefix, &path);
1053 GPR_ASSERT(path != nullptr);
1054 GPR_ASSERT(tmp != nullptr);
1055 size_t jwt_length = strlen(jwt_contents);
1056 GPR_ASSERT(fwrite(jwt_contents, 1, jwt_length, tmp) == jwt_length);
1061 static void test_sts_creds_success(void) {
1062 grpc_core::ExecCtx exec_ctx;
1063 expected_md emd[] = {
1064 {"authorization", "Bearer ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_"}};
1065 const char expected_creds_debug_string[] =
1066 "StsTokenFetcherCredentials{Path:/v1/"
1067 "token-exchange,Authority:foo.com:5555,OAuth2TokenFetcherCredentials}";
1068 grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
1070 char* subject_token_path = write_tmp_jwt_file(test_signed_jwt);
1071 char* actor_token_path = write_tmp_jwt_file(test_signed_jwt2);
1072 grpc_sts_credentials_options valid_options = {
1073 test_sts_endpoint_url, // sts_endpoint_url
1074 "resource", // resource
1075 "audience", // audience
1077 "requested_token_type", // requested_token_type
1078 subject_token_path, // subject_token_path
1079 test_signed_jwt_token_type, // subject_token_type
1080 actor_token_path, // actor_token_path
1081 test_signed_jwt_token_type2 // actor_token_type
1083 grpc_call_credentials* creds =
1084 grpc_sts_credentials_create(&valid_options, nullptr);
1086 /* Check security level. */
1087 GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
1089 /* First request: http put should be called. */
1090 request_metadata_state* state =
1091 make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
1092 grpc_httpcli_set_override(httpcli_get_should_not_be_called,
1093 sts_token_httpcli_post_success);
1094 run_request_metadata_test(creds, auth_md_ctx, state);
1095 grpc_core::ExecCtx::Get()->Flush();
1097 /* Second request: the cached token should be served directly. */
1099 make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
1100 grpc_httpcli_set_override(httpcli_get_should_not_be_called,
1101 httpcli_post_should_not_be_called);
1102 run_request_metadata_test(creds, auth_md_ctx, state);
1103 grpc_core::ExecCtx::Get()->Flush();
1105 strcmp(creds->debug_string().c_str(), expected_creds_debug_string) == 0);
1108 grpc_httpcli_set_override(nullptr, nullptr);
1109 gpr_free(subject_token_path);
1110 gpr_free(actor_token_path);
1113 static void test_sts_creds_token_file_not_found(void) {
1114 grpc_core::ExecCtx exec_ctx;
1115 grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
1117 grpc_sts_credentials_options valid_options = {
1118 test_sts_endpoint_url, // sts_endpoint_url
1119 "resource", // resource
1120 "audience", // audience
1122 "requested_token_type", // requested_token_type
1123 "/some/completely/random/path", // subject_token_path
1124 test_signed_jwt_token_type, // subject_token_type
1125 "", // actor_token_path
1126 "" // actor_token_type
1128 grpc_call_credentials* creds =
1129 grpc_sts_credentials_create(&valid_options, nullptr);
1131 /* Check security level. */
1132 GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
1134 request_metadata_state* state = make_request_metadata_state(
1135 GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1136 "Error occurred when fetching oauth2 token."),
1138 grpc_httpcli_set_override(httpcli_get_should_not_be_called,
1139 httpcli_post_should_not_be_called);
1140 run_request_metadata_test(creds, auth_md_ctx, state);
1141 grpc_core::ExecCtx::Get()->Flush();
1145 grpc_httpcli_set_override(nullptr, nullptr);
1148 static void test_sts_creds_no_actor_token_success(void) {
1149 grpc_core::ExecCtx exec_ctx;
1150 expected_md emd[] = {
1151 {"authorization", "Bearer ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_"}};
1152 const char expected_creds_debug_string[] =
1153 "StsTokenFetcherCredentials{Path:/v1/"
1154 "token-exchange,Authority:foo.com:5555,OAuth2TokenFetcherCredentials}";
1155 grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
1157 char* subject_token_path = write_tmp_jwt_file(test_signed_jwt);
1158 grpc_sts_credentials_options valid_options = {
1159 test_sts_endpoint_url, // sts_endpoint_url
1160 "resource", // resource
1161 "audience", // audience
1163 "requested_token_type", // requested_token_type
1164 subject_token_path, // subject_token_path
1165 test_signed_jwt_token_type, // subject_token_type
1166 "", // actor_token_path
1167 "" // actor_token_type
1169 grpc_call_credentials* creds =
1170 grpc_sts_credentials_create(&valid_options, nullptr);
1172 /* Check security level. */
1173 GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
1175 /* First request: http put should be called. */
1176 request_metadata_state* state =
1177 make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
1178 grpc_httpcli_set_override(httpcli_get_should_not_be_called,
1179 sts_token_httpcli_post_success_no_actor_token);
1180 run_request_metadata_test(creds, auth_md_ctx, state);
1181 grpc_core::ExecCtx::Get()->Flush();
1183 /* Second request: the cached token should be served directly. */
1185 make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
1186 grpc_httpcli_set_override(httpcli_get_should_not_be_called,
1187 httpcli_post_should_not_be_called);
1188 run_request_metadata_test(creds, auth_md_ctx, state);
1189 grpc_core::ExecCtx::Get()->Flush();
1191 strcmp(creds->debug_string().c_str(), expected_creds_debug_string) == 0);
1194 grpc_httpcli_set_override(nullptr, nullptr);
1195 gpr_free(subject_token_path);
1198 static void test_sts_creds_load_token_failure(void) {
1199 const char expected_creds_debug_string[] =
1200 "StsTokenFetcherCredentials{Path:/v1/"
1201 "token-exchange,Authority:foo.com:5555,OAuth2TokenFetcherCredentials}";
1202 grpc_core::ExecCtx exec_ctx;
1203 request_metadata_state* state = make_request_metadata_state(
1204 GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1205 "Error occurred when fetching oauth2 token."),
1207 grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
1209 char* test_signed_jwt_path = write_tmp_jwt_file(test_signed_jwt);
1210 grpc_sts_credentials_options options = {
1211 test_sts_endpoint_url, // sts_endpoint_url
1212 "resource", // resource
1213 "audience", // audience
1215 "requested_token_type", // requested_token_type
1216 "invalid_path", // subject_token_path
1217 test_signed_jwt_token_type, // subject_token_type
1218 nullptr, // actor_token_path
1219 nullptr // actor_token_type
1221 grpc_call_credentials* creds = grpc_sts_credentials_create(&options, nullptr);
1222 grpc_httpcli_set_override(httpcli_get_should_not_be_called,
1223 httpcli_post_should_not_be_called);
1224 run_request_metadata_test(creds, auth_md_ctx, state);
1226 strcmp(creds->debug_string().c_str(), expected_creds_debug_string) == 0);
1229 grpc_httpcli_set_override(nullptr, nullptr);
1230 gpr_free(test_signed_jwt_path);
1233 static void test_sts_creds_http_failure(void) {
1234 const char expected_creds_debug_string[] =
1235 "StsTokenFetcherCredentials{Path:/v1/"
1236 "token-exchange,Authority:foo.com:5555,OAuth2TokenFetcherCredentials}";
1237 grpc_core::ExecCtx exec_ctx;
1238 request_metadata_state* state = make_request_metadata_state(
1239 GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1240 "Error occurred when fetching oauth2 token."),
1242 grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
1244 char* test_signed_jwt_path = write_tmp_jwt_file(test_signed_jwt);
1245 grpc_sts_credentials_options valid_options = {
1246 test_sts_endpoint_url, // sts_endpoint_url
1247 "resource", // resource
1248 "audience", // audience
1250 "requested_token_type", // requested_token_type
1251 test_signed_jwt_path, // subject_token_path
1252 test_signed_jwt_token_type, // subject_token_type
1253 nullptr, // actor_token_path
1254 nullptr // actor_token_type
1256 grpc_call_credentials* creds =
1257 grpc_sts_credentials_create(&valid_options, nullptr);
1258 grpc_httpcli_set_override(httpcli_get_should_not_be_called,
1259 token_httpcli_post_failure);
1260 run_request_metadata_test(creds, auth_md_ctx, state);
1262 strcmp(creds->debug_string().c_str(), expected_creds_debug_string) == 0);
1264 grpc_httpcli_set_override(nullptr, nullptr);
1265 gpr_free(test_signed_jwt_path);
1268 static void validate_jwt_encode_and_sign_params(
1269 const grpc_auth_json_key* json_key, const char* scope,
1270 gpr_timespec token_lifetime) {
1271 GPR_ASSERT(grpc_auth_json_key_is_valid(json_key));
1272 GPR_ASSERT(json_key->private_key != nullptr);
1273 GPR_ASSERT(RSA_check_key(json_key->private_key));
1274 GPR_ASSERT(json_key->type != nullptr &&
1275 strcmp(json_key->type, "service_account") == 0);
1276 GPR_ASSERT(json_key->private_key_id != nullptr &&
1277 strcmp(json_key->private_key_id,
1278 "e6b5137873db8d2ef81e06a47289e6434ec8a165") == 0);
1279 GPR_ASSERT(json_key->client_id != nullptr &&
1280 strcmp(json_key->client_id,
1281 "777-abaslkan11hlb6nmim3bpspl31ud.apps."
1282 "googleusercontent.com") == 0);
1283 GPR_ASSERT(json_key->client_email != nullptr &&
1284 strcmp(json_key->client_email,
1285 "777-abaslkan11hlb6nmim3bpspl31ud@developer."
1286 "gserviceaccount.com") == 0);
1287 if (scope != nullptr) GPR_ASSERT(strcmp(scope, test_scope) == 0);
1288 GPR_ASSERT(gpr_time_cmp(token_lifetime, grpc_max_auth_token_lifetime()) == 0);
1291 static char* encode_and_sign_jwt_success(const grpc_auth_json_key* json_key,
1292 const char* /*audience*/,
1293 gpr_timespec token_lifetime,
1294 const char* scope) {
1295 validate_jwt_encode_and_sign_params(json_key, scope, token_lifetime);
1296 return gpr_strdup(test_signed_jwt);
1299 static char* encode_and_sign_jwt_failure(const grpc_auth_json_key* json_key,
1300 const char* /*audience*/,
1301 gpr_timespec token_lifetime,
1302 const char* scope) {
1303 validate_jwt_encode_and_sign_params(json_key, scope, token_lifetime);
1307 static char* encode_and_sign_jwt_should_not_be_called(
1308 const grpc_auth_json_key* /*json_key*/, const char* /*audience*/,
1309 gpr_timespec /*token_lifetime*/, const char* /*scope*/) {
1310 GPR_ASSERT("grpc_jwt_encode_and_sign should not be called" == nullptr);
1314 static grpc_service_account_jwt_access_credentials* creds_as_jwt(
1315 grpc_call_credentials* creds) {
1316 GPR_ASSERT(creds != nullptr);
1317 GPR_ASSERT(strcmp(creds->type(), GRPC_CALL_CREDENTIALS_TYPE_JWT) == 0);
1318 return reinterpret_cast<grpc_service_account_jwt_access_credentials*>(creds);
1321 static void test_jwt_creds_lifetime(void) {
1322 char* json_key_string = test_json_key_str();
1323 const char expected_creds_debug_string_prefix[] =
1324 "JWTAccessCredentials{ExpirationTime:";
1326 grpc_call_credentials* jwt_creds =
1327 grpc_service_account_jwt_access_credentials_create(
1328 json_key_string, grpc_max_auth_token_lifetime(), nullptr);
1329 GPR_ASSERT(gpr_time_cmp(creds_as_jwt(jwt_creds)->jwt_lifetime(),
1330 grpc_max_auth_token_lifetime()) == 0);
1331 /* Check security level. */
1332 GPR_ASSERT(jwt_creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
1333 GPR_ASSERT(strncmp(expected_creds_debug_string_prefix,
1334 jwt_creds->debug_string().c_str(),
1335 strlen(expected_creds_debug_string_prefix)) == 0);
1336 grpc_call_credentials_release(jwt_creds);
1338 // Shorter lifetime.
1339 gpr_timespec token_lifetime = {10, 0, GPR_TIMESPAN};
1340 GPR_ASSERT(gpr_time_cmp(grpc_max_auth_token_lifetime(), token_lifetime) > 0);
1341 jwt_creds = grpc_service_account_jwt_access_credentials_create(
1342 json_key_string, token_lifetime, nullptr);
1343 GPR_ASSERT(gpr_time_cmp(creds_as_jwt(jwt_creds)->jwt_lifetime(),
1344 token_lifetime) == 0);
1345 GPR_ASSERT(strncmp(expected_creds_debug_string_prefix,
1346 jwt_creds->debug_string().c_str(),
1347 strlen(expected_creds_debug_string_prefix)) == 0);
1348 grpc_call_credentials_release(jwt_creds);
1350 // Cropped lifetime.
1351 gpr_timespec add_to_max = {10, 0, GPR_TIMESPAN};
1352 token_lifetime = gpr_time_add(grpc_max_auth_token_lifetime(), add_to_max);
1353 jwt_creds = grpc_service_account_jwt_access_credentials_create(
1354 json_key_string, token_lifetime, nullptr);
1355 GPR_ASSERT(gpr_time_cmp(creds_as_jwt(jwt_creds)->jwt_lifetime(),
1356 grpc_max_auth_token_lifetime()) == 0);
1357 GPR_ASSERT(strncmp(expected_creds_debug_string_prefix,
1358 jwt_creds->debug_string().c_str(),
1359 strlen(expected_creds_debug_string_prefix)) == 0);
1360 grpc_call_credentials_release(jwt_creds);
1362 gpr_free(json_key_string);
1365 static void test_jwt_creds_success(void) {
1366 const char expected_creds_debug_string_prefix[] =
1367 "JWTAccessCredentials{ExpirationTime:";
1369 char* json_key_string = test_json_key_str();
1370 grpc_core::ExecCtx exec_ctx;
1371 grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
1373 std::string expected_md_value = absl::StrCat("Bearer ", test_signed_jwt);
1374 expected_md emd[] = {{"authorization", expected_md_value.c_str()}};
1375 grpc_call_credentials* creds =
1376 grpc_service_account_jwt_access_credentials_create(
1377 json_key_string, grpc_max_auth_token_lifetime(), nullptr);
1379 /* First request: jwt_encode_and_sign should be called. */
1380 request_metadata_state* state =
1381 make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
1382 grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_success);
1383 run_request_metadata_test(creds, auth_md_ctx, state);
1384 grpc_core::ExecCtx::Get()->Flush();
1386 /* Second request: the cached token should be served directly. */
1388 make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
1389 grpc_jwt_encode_and_sign_set_override(
1390 encode_and_sign_jwt_should_not_be_called);
1391 run_request_metadata_test(creds, auth_md_ctx, state);
1392 grpc_core::ExecCtx::Get()->Flush();
1394 /* Third request: Different service url so jwt_encode_and_sign should be
1395 called again (no caching). */
1397 make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
1398 auth_md_ctx.service_url = other_test_service_url;
1399 grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_success);
1400 run_request_metadata_test(creds, auth_md_ctx, state);
1401 grpc_core::ExecCtx::Get()->Flush();
1402 GPR_ASSERT(strncmp(expected_creds_debug_string_prefix,
1403 creds->debug_string().c_str(),
1404 strlen(expected_creds_debug_string_prefix)) == 0);
1407 gpr_free(json_key_string);
1408 grpc_jwt_encode_and_sign_set_override(nullptr);
1411 static void test_jwt_creds_signing_failure(void) {
1412 const char expected_creds_debug_string_prefix[] =
1413 "JWTAccessCredentials{ExpirationTime:";
1414 char* json_key_string = test_json_key_str();
1415 grpc_core::ExecCtx exec_ctx;
1416 grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
1418 request_metadata_state* state = make_request_metadata_state(
1419 GRPC_ERROR_CREATE_FROM_STATIC_STRING("Could not generate JWT."), nullptr,
1421 grpc_call_credentials* creds =
1422 grpc_service_account_jwt_access_credentials_create(
1423 json_key_string, grpc_max_auth_token_lifetime(), nullptr);
1425 grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_failure);
1426 run_request_metadata_test(creds, auth_md_ctx, state);
1428 gpr_free(json_key_string);
1429 GPR_ASSERT(strncmp(expected_creds_debug_string_prefix,
1430 creds->debug_string().c_str(),
1431 strlen(expected_creds_debug_string_prefix)) == 0);
1434 grpc_jwt_encode_and_sign_set_override(nullptr);
1437 static void set_google_default_creds_env_var_with_file_contents(
1438 const char* file_prefix, const char* contents) {
1439 size_t contents_len = strlen(contents);
1440 char* creds_file_name;
1441 FILE* creds_file = gpr_tmpfile(file_prefix, &creds_file_name);
1442 GPR_ASSERT(creds_file_name != nullptr);
1443 GPR_ASSERT(creds_file != nullptr);
1444 GPR_ASSERT(fwrite(contents, 1, contents_len, creds_file) == contents_len);
1446 gpr_setenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, creds_file_name);
1447 gpr_free(creds_file_name);
1450 static bool test_gce_tenancy_checker(void) {
1451 g_test_gce_tenancy_checker_called = true;
1452 return g_test_is_on_gce;
1455 static void test_google_default_creds_auth_key(void) {
1456 grpc_core::ExecCtx exec_ctx;
1457 grpc_composite_channel_credentials* creds;
1458 char* json_key = test_json_key_str();
1459 grpc_flush_cached_google_default_credentials();
1460 set_gce_tenancy_checker_for_testing(test_gce_tenancy_checker);
1461 g_test_gce_tenancy_checker_called = false;
1462 g_test_is_on_gce = true;
1463 set_google_default_creds_env_var_with_file_contents(
1464 "json_key_google_default_creds", json_key);
1466 creds = reinterpret_cast<grpc_composite_channel_credentials*>(
1467 grpc_google_default_credentials_create(nullptr));
1468 auto* default_creds =
1469 reinterpret_cast<const grpc_google_default_channel_credentials*>(
1470 creds->inner_creds());
1471 GPR_ASSERT(default_creds->ssl_creds() != nullptr);
1473 reinterpret_cast<const grpc_service_account_jwt_access_credentials*>(
1474 creds->call_creds());
1476 strcmp(jwt->key().client_id,
1477 "777-abaslkan11hlb6nmim3bpspl31ud.apps.googleusercontent.com") ==
1479 GPR_ASSERT(g_test_gce_tenancy_checker_called == false);
1481 gpr_setenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, ""); /* Reset. */
1484 static void test_google_default_creds_refresh_token(void) {
1485 grpc_core::ExecCtx exec_ctx;
1486 grpc_composite_channel_credentials* creds;
1487 grpc_flush_cached_google_default_credentials();
1488 set_google_default_creds_env_var_with_file_contents(
1489 "refresh_token_google_default_creds", test_refresh_token_str);
1490 creds = reinterpret_cast<grpc_composite_channel_credentials*>(
1491 grpc_google_default_credentials_create(nullptr));
1492 auto* default_creds =
1493 reinterpret_cast<const grpc_google_default_channel_credentials*>(
1494 creds->inner_creds());
1495 GPR_ASSERT(default_creds->ssl_creds() != nullptr);
1497 reinterpret_cast<const grpc_google_refresh_token_credentials*>(
1498 creds->call_creds());
1499 GPR_ASSERT(strcmp(refresh->refresh_token().client_id,
1500 "32555999999.apps.googleusercontent.com") == 0);
1502 gpr_setenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, ""); /* Reset. */
1505 static int default_creds_metadata_server_detection_httpcli_get_success_override(
1506 const grpc_httpcli_request* request, grpc_millis /*deadline*/,
1507 grpc_closure* on_done, grpc_httpcli_response* response) {
1508 *response = http_response(200, "");
1509 grpc_http_header* headers =
1510 static_cast<grpc_http_header*>(gpr_malloc(sizeof(*headers) * 1));
1511 headers[0].key = gpr_strdup("Metadata-Flavor");
1512 headers[0].value = gpr_strdup("Google");
1513 response->hdr_count = 1;
1514 response->hdrs = headers;
1515 GPR_ASSERT(strcmp(request->http.path, "/") == 0);
1516 GPR_ASSERT(strcmp(request->host, "metadata.google.internal.") == 0);
1517 grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, GRPC_ERROR_NONE);
1521 static std::string null_well_known_creds_path_getter(void) { return ""; }
1523 static void test_google_default_creds_gce(void) {
1524 grpc_core::ExecCtx exec_ctx;
1525 expected_md emd[] = {
1526 {"authorization", "Bearer ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_"}};
1527 request_metadata_state* state =
1528 make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
1529 grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
1531 grpc_flush_cached_google_default_credentials();
1532 gpr_setenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, ""); /* Reset. */
1533 grpc_override_well_known_credentials_path_getter(
1534 null_well_known_creds_path_getter);
1535 set_gce_tenancy_checker_for_testing(test_gce_tenancy_checker);
1536 g_test_gce_tenancy_checker_called = false;
1537 g_test_is_on_gce = true;
1539 /* Simulate a successful detection of GCE. */
1540 grpc_composite_channel_credentials* creds =
1541 reinterpret_cast<grpc_composite_channel_credentials*>(
1542 grpc_google_default_credentials_create(nullptr));
1544 /* Verify that the default creds actually embeds a GCE creds. */
1545 GPR_ASSERT(creds != nullptr);
1546 GPR_ASSERT(creds->call_creds() != nullptr);
1547 grpc_httpcli_set_override(compute_engine_httpcli_get_success_override,
1548 httpcli_post_should_not_be_called);
1549 run_request_metadata_test(creds->mutable_call_creds(), auth_md_ctx, state);
1550 grpc_core::ExecCtx::Get()->Flush();
1552 GPR_ASSERT(g_test_gce_tenancy_checker_called == true);
1556 grpc_httpcli_set_override(nullptr, nullptr);
1557 grpc_override_well_known_credentials_path_getter(nullptr);
1560 static void test_google_default_creds_non_gce(void) {
1561 grpc_core::ExecCtx exec_ctx;
1562 expected_md emd[] = {
1563 {"authorization", "Bearer ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_"}};
1564 request_metadata_state* state =
1565 make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
1566 grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
1568 grpc_flush_cached_google_default_credentials();
1569 gpr_setenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, ""); /* Reset. */
1570 grpc_override_well_known_credentials_path_getter(
1571 null_well_known_creds_path_getter);
1572 set_gce_tenancy_checker_for_testing(test_gce_tenancy_checker);
1573 g_test_gce_tenancy_checker_called = false;
1574 g_test_is_on_gce = false;
1575 /* Simulate a successful detection of metadata server. */
1576 grpc_httpcli_set_override(
1577 default_creds_metadata_server_detection_httpcli_get_success_override,
1578 httpcli_post_should_not_be_called);
1579 grpc_composite_channel_credentials* creds =
1580 reinterpret_cast<grpc_composite_channel_credentials*>(
1581 grpc_google_default_credentials_create(nullptr));
1582 /* Verify that the default creds actually embeds a GCE creds. */
1583 GPR_ASSERT(creds != nullptr);
1584 GPR_ASSERT(creds->call_creds() != nullptr);
1585 grpc_httpcli_set_override(compute_engine_httpcli_get_success_override,
1586 httpcli_post_should_not_be_called);
1587 run_request_metadata_test(creds->mutable_call_creds(), auth_md_ctx, state);
1588 grpc_core::ExecCtx::Get()->Flush();
1589 GPR_ASSERT(g_test_gce_tenancy_checker_called == true);
1592 grpc_httpcli_set_override(nullptr, nullptr);
1593 grpc_override_well_known_credentials_path_getter(nullptr);
1596 static int default_creds_gce_detection_httpcli_get_failure_override(
1597 const grpc_httpcli_request* request, grpc_millis /*deadline*/,
1598 grpc_closure* on_done, grpc_httpcli_response* response) {
1599 /* No magic header. */
1600 GPR_ASSERT(strcmp(request->http.path, "/") == 0);
1601 GPR_ASSERT(strcmp(request->host, "metadata.google.internal.") == 0);
1602 *response = http_response(200, "");
1603 grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, GRPC_ERROR_NONE);
1607 static void test_no_google_default_creds(void) {
1608 grpc_flush_cached_google_default_credentials();
1609 gpr_setenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, ""); /* Reset. */
1610 grpc_override_well_known_credentials_path_getter(
1611 null_well_known_creds_path_getter);
1612 set_gce_tenancy_checker_for_testing(test_gce_tenancy_checker);
1613 g_test_gce_tenancy_checker_called = false;
1614 g_test_is_on_gce = false;
1615 grpc_httpcli_set_override(
1616 default_creds_gce_detection_httpcli_get_failure_override,
1617 httpcli_post_should_not_be_called);
1618 /* Simulate a successful detection of GCE. */
1619 GPR_ASSERT(grpc_google_default_credentials_create(nullptr) == nullptr);
1620 /* Try a second one. GCE detection should occur again. */
1621 g_test_gce_tenancy_checker_called = false;
1622 GPR_ASSERT(grpc_google_default_credentials_create(nullptr) == nullptr);
1623 GPR_ASSERT(g_test_gce_tenancy_checker_called == true);
1625 grpc_override_well_known_credentials_path_getter(nullptr);
1626 grpc_httpcli_set_override(nullptr, nullptr);
1629 static void test_google_default_creds_call_creds_specified(void) {
1630 expected_md emd[] = {
1631 {"authorization", "Bearer ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_"}};
1632 request_metadata_state* state =
1633 make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
1634 grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
1636 grpc_core::ExecCtx exec_ctx;
1637 grpc_flush_cached_google_default_credentials();
1638 grpc_call_credentials* call_creds =
1639 grpc_google_compute_engine_credentials_create(nullptr);
1640 set_gce_tenancy_checker_for_testing(test_gce_tenancy_checker);
1641 g_test_gce_tenancy_checker_called = false;
1642 g_test_is_on_gce = true;
1643 grpc_httpcli_set_override(
1644 default_creds_metadata_server_detection_httpcli_get_success_override,
1645 httpcli_post_should_not_be_called);
1646 grpc_composite_channel_credentials* channel_creds =
1647 reinterpret_cast<grpc_composite_channel_credentials*>(
1648 grpc_google_default_credentials_create(call_creds));
1649 GPR_ASSERT(g_test_gce_tenancy_checker_called == false);
1650 GPR_ASSERT(channel_creds != nullptr);
1651 GPR_ASSERT(channel_creds->call_creds() != nullptr);
1652 grpc_httpcli_set_override(compute_engine_httpcli_get_success_override,
1653 httpcli_post_should_not_be_called);
1654 run_request_metadata_test(channel_creds->mutable_call_creds(), auth_md_ctx,
1656 grpc_core::ExecCtx::Get()->Flush();
1657 channel_creds->Unref();
1658 grpc_httpcli_set_override(nullptr, nullptr);
1661 struct fake_call_creds : public grpc_call_credentials {
1663 explicit fake_call_creds() : grpc_call_credentials("fake") {
1664 grpc_slice key = grpc_slice_from_static_string("foo");
1665 grpc_slice value = grpc_slice_from_static_string("oof");
1666 dummy_md_ = grpc_mdelem_from_slices(key, value);
1667 grpc_slice_unref(key);
1668 grpc_slice_unref(value);
1671 ~fake_call_creds() override { GRPC_MDELEM_UNREF(dummy_md_); }
1673 bool get_request_metadata(grpc_polling_entity* /*pollent*/,
1674 grpc_auth_metadata_context /*context*/,
1675 grpc_credentials_mdelem_array* md_array,
1676 grpc_closure* /*on_request_metadata*/,
1677 grpc_error** /*error*/) override {
1678 grpc_credentials_mdelem_array_add(md_array, dummy_md_);
1682 void cancel_get_request_metadata(grpc_credentials_mdelem_array* /*md_array*/,
1683 grpc_error* /*error*/) override {}
1686 grpc_mdelem dummy_md_;
1689 static void test_google_default_creds_not_default(void) {
1690 expected_md emd[] = {{"foo", "oof"}};
1691 request_metadata_state* state =
1692 make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
1693 grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
1695 grpc_core::ExecCtx exec_ctx;
1696 grpc_flush_cached_google_default_credentials();
1697 grpc_core::RefCountedPtr<grpc_call_credentials> call_creds =
1698 grpc_core::MakeRefCounted<fake_call_creds>();
1699 set_gce_tenancy_checker_for_testing(test_gce_tenancy_checker);
1700 g_test_gce_tenancy_checker_called = false;
1701 g_test_is_on_gce = true;
1702 grpc_httpcli_set_override(
1703 default_creds_metadata_server_detection_httpcli_get_success_override,
1704 httpcli_post_should_not_be_called);
1705 grpc_composite_channel_credentials* channel_creds =
1706 reinterpret_cast<grpc_composite_channel_credentials*>(
1707 grpc_google_default_credentials_create(call_creds.release()));
1708 GPR_ASSERT(g_test_gce_tenancy_checker_called == false);
1709 GPR_ASSERT(channel_creds != nullptr);
1710 GPR_ASSERT(channel_creds->call_creds() != nullptr);
1711 run_request_metadata_test(channel_creds->mutable_call_creds(), auth_md_ctx,
1713 grpc_core::ExecCtx::Get()->Flush();
1714 channel_creds->Unref();
1715 grpc_httpcli_set_override(nullptr, nullptr);
1719 PLUGIN_INITIAL_STATE,
1720 PLUGIN_GET_METADATA_CALLED_STATE,
1721 PLUGIN_DESTROY_CALLED_STATE
1724 static const expected_md plugin_md[] = {{"foo", "bar"}, {"hi", "there"}};
1726 static int plugin_get_metadata_success(
1727 void* state, grpc_auth_metadata_context context,
1728 grpc_credentials_plugin_metadata_cb /*cb*/, void* /*user_data*/,
1729 grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX],
1730 size_t* num_creds_md, grpc_status_code* /*status*/,
1731 const char** /*error_details*/) {
1732 GPR_ASSERT(strcmp(context.service_url, test_service_url) == 0);
1733 GPR_ASSERT(strcmp(context.method_name, test_method) == 0);
1734 GPR_ASSERT(context.channel_auth_context == nullptr);
1735 GPR_ASSERT(context.reserved == nullptr);
1736 GPR_ASSERT(GPR_ARRAY_SIZE(plugin_md) <
1737 GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX);
1738 plugin_state* s = static_cast<plugin_state*>(state);
1739 *s = PLUGIN_GET_METADATA_CALLED_STATE;
1740 for (size_t i = 0; i < GPR_ARRAY_SIZE(plugin_md); ++i) {
1741 memset(&creds_md[i], 0, sizeof(grpc_metadata));
1742 creds_md[i].key = grpc_slice_from_copied_string(plugin_md[i].key);
1743 creds_md[i].value = grpc_slice_from_copied_string(plugin_md[i].value);
1745 *num_creds_md = GPR_ARRAY_SIZE(plugin_md);
1746 return true; // Synchronous return.
1749 static const char* plugin_error_details = "Could not get metadata for plugin.";
1751 static int plugin_get_metadata_failure(
1752 void* state, grpc_auth_metadata_context context,
1753 grpc_credentials_plugin_metadata_cb /*cb*/, void* /*user_data*/,
1754 grpc_metadata /*creds_md*/[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX],
1755 size_t* /*num_creds_md*/, grpc_status_code* status,
1756 const char** error_details) {
1757 GPR_ASSERT(strcmp(context.service_url, test_service_url) == 0);
1758 GPR_ASSERT(strcmp(context.method_name, test_method) == 0);
1759 GPR_ASSERT(context.channel_auth_context == nullptr);
1760 GPR_ASSERT(context.reserved == nullptr);
1761 plugin_state* s = static_cast<plugin_state*>(state);
1762 *s = PLUGIN_GET_METADATA_CALLED_STATE;
1763 *status = GRPC_STATUS_UNAUTHENTICATED;
1764 *error_details = gpr_strdup(plugin_error_details);
1765 return true; // Synchronous return.
1768 static void plugin_destroy(void* state) {
1769 plugin_state* s = static_cast<plugin_state*>(state);
1770 *s = PLUGIN_DESTROY_CALLED_STATE;
1773 static char* plugin_debug_string(void* state) {
1774 plugin_state* s = static_cast<plugin_state*>(state);
1775 char* ret = nullptr;
1777 case PLUGIN_INITIAL_STATE:
1778 gpr_asprintf(&ret, "TestPluginCredentials{state:INITIAL}");
1780 case PLUGIN_GET_METADATA_CALLED_STATE:
1781 gpr_asprintf(&ret, "TestPluginCredentials{state:GET_METADATA_CALLED}");
1783 case PLUGIN_DESTROY_CALLED_STATE:
1784 gpr_asprintf(&ret, "TestPluginCredentials{state:DESTROY}");
1787 gpr_asprintf(&ret, "TestPluginCredentials{state:UNKNOWN}");
1793 static void test_metadata_plugin_success(void) {
1794 const char expected_creds_debug_string[] =
1795 "TestPluginCredentials{state:GET_METADATA_CALLED}";
1796 plugin_state state = PLUGIN_INITIAL_STATE;
1797 grpc_metadata_credentials_plugin plugin;
1798 grpc_core::ExecCtx exec_ctx;
1799 grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
1801 request_metadata_state* md_state = make_request_metadata_state(
1802 GRPC_ERROR_NONE, plugin_md, GPR_ARRAY_SIZE(plugin_md));
1804 plugin.state = &state;
1805 plugin.get_metadata = plugin_get_metadata_success;
1806 plugin.destroy = plugin_destroy;
1807 plugin.debug_string = plugin_debug_string;
1809 grpc_call_credentials* creds = grpc_metadata_credentials_create_from_plugin(
1810 plugin, GRPC_PRIVACY_AND_INTEGRITY, nullptr);
1811 /* Check security level. */
1812 GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
1813 GPR_ASSERT(state == PLUGIN_INITIAL_STATE);
1814 run_request_metadata_test(creds, auth_md_ctx, md_state);
1815 GPR_ASSERT(state == PLUGIN_GET_METADATA_CALLED_STATE);
1817 strcmp(creds->debug_string().c_str(), expected_creds_debug_string) == 0);
1820 GPR_ASSERT(state == PLUGIN_DESTROY_CALLED_STATE);
1823 static void test_metadata_plugin_failure(void) {
1824 const char expected_creds_debug_string[] =
1825 "TestPluginCredentials{state:GET_METADATA_CALLED}";
1827 plugin_state state = PLUGIN_INITIAL_STATE;
1828 grpc_metadata_credentials_plugin plugin;
1829 grpc_core::ExecCtx exec_ctx;
1830 grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
1832 std::string expected_error = absl::StrCat(
1833 "Getting metadata from plugin failed with error: ", plugin_error_details);
1834 request_metadata_state* md_state = make_request_metadata_state(
1835 GRPC_ERROR_CREATE_FROM_COPIED_STRING(expected_error.c_str()), nullptr, 0);
1837 plugin.state = &state;
1838 plugin.get_metadata = plugin_get_metadata_failure;
1839 plugin.destroy = plugin_destroy;
1840 plugin.debug_string = plugin_debug_string;
1842 grpc_call_credentials* creds = grpc_metadata_credentials_create_from_plugin(
1843 plugin, GRPC_PRIVACY_AND_INTEGRITY, nullptr);
1844 GPR_ASSERT(state == PLUGIN_INITIAL_STATE);
1845 run_request_metadata_test(creds, auth_md_ctx, md_state);
1846 GPR_ASSERT(state == PLUGIN_GET_METADATA_CALLED_STATE);
1848 strcmp(creds->debug_string().c_str(), expected_creds_debug_string) == 0);
1851 GPR_ASSERT(state == PLUGIN_DESTROY_CALLED_STATE);
1854 static void test_get_well_known_google_credentials_file_path(void) {
1855 char* home = gpr_getenv("HOME");
1856 bool restore_home_env = false;
1857 #if defined(GRPC_BAZEL_BUILD) && \
1858 (defined(GPR_POSIX_ENV) || defined(GPR_LINUX_ENV))
1859 // when running under bazel locally, the HOME variable is not set
1860 // so we set it to some fake value
1861 restore_home_env = true;
1862 gpr_setenv("HOME", "/fake/home/for/bazel");
1863 #endif /* defined(GRPC_BAZEL_BUILD) && (defined(GPR_POSIX_ENV) || \
1864 defined(GPR_LINUX_ENV)) */
1865 std::string path = grpc_get_well_known_google_credentials_file_path();
1866 GPR_ASSERT(!path.empty());
1867 #if defined(GPR_POSIX_ENV) || defined(GPR_LINUX_ENV)
1868 restore_home_env = true;
1869 gpr_unsetenv("HOME");
1870 path = grpc_get_well_known_google_credentials_file_path();
1871 GPR_ASSERT(path.empty());
1872 #endif /* GPR_POSIX_ENV || GPR_LINUX_ENV */
1873 if (restore_home_env) {
1875 gpr_setenv("HOME", home);
1877 gpr_unsetenv("HOME");
1883 static void test_channel_creds_duplicate_without_call_creds(void) {
1884 const char expected_creds_debug_string[] =
1885 "AccessTokenCredentials{Token:present}";
1886 grpc_core::ExecCtx exec_ctx;
1888 grpc_channel_credentials* channel_creds =
1889 grpc_fake_transport_security_credentials_create();
1891 grpc_core::RefCountedPtr<grpc_channel_credentials> dup =
1892 channel_creds->duplicate_without_call_credentials();
1893 GPR_ASSERT(dup == channel_creds);
1896 grpc_call_credentials* call_creds =
1897 grpc_access_token_credentials_create("blah", nullptr);
1898 grpc_channel_credentials* composite_creds =
1899 grpc_composite_channel_credentials_create(channel_creds, call_creds,
1901 GPR_ASSERT(strcmp(call_creds->debug_string().c_str(),
1902 expected_creds_debug_string) == 0);
1904 call_creds->Unref();
1905 dup = composite_creds->duplicate_without_call_credentials();
1906 GPR_ASSERT(dup == channel_creds);
1909 channel_creds->Unref();
1910 composite_creds->Unref();
1914 const char* url_scheme;
1915 const char* call_host;
1916 const char* call_method;
1917 const char* desired_service_url;
1918 const char* desired_method_name;
1919 } auth_metadata_context_test_case;
1921 static void test_auth_metadata_context(void) {
1922 auth_metadata_context_test_case test_cases[] = {
1923 // No service nor method.
1924 {"https", "www.foo.com", "", "https://www.foo.com", ""},
1926 {"https", "www.foo.com", "/Service", "https://www.foo.com/Service", ""},
1927 // Empty service and method.
1928 {"https", "www.foo.com", "//", "https://www.foo.com/", ""},
1930 {"https", "www.foo.com", "/Service/", "https://www.foo.com/Service", ""},
1932 {"https", "www.foo.com:", "/Service/", "https://www.foo.com:/Service",
1934 // https, default explicit port.
1935 {"https", "www.foo.com:443", "/Service/FooMethod",
1936 "https://www.foo.com/Service", "FooMethod"},
1937 // https, default implicit port.
1938 {"https", "www.foo.com", "/Service/FooMethod",
1939 "https://www.foo.com/Service", "FooMethod"},
1940 // https with ipv6 literal, default explicit port.
1941 {"https", "[1080:0:0:0:8:800:200C:417A]:443", "/Service/FooMethod",
1942 "https://[1080:0:0:0:8:800:200C:417A]/Service", "FooMethod"},
1943 // https with ipv6 literal, default implicit port.
1944 {"https", "[1080:0:0:0:8:800:200C:443]", "/Service/FooMethod",
1945 "https://[1080:0:0:0:8:800:200C:443]/Service", "FooMethod"},
1946 // https, custom port.
1947 {"https", "www.foo.com:8888", "/Service/FooMethod",
1948 "https://www.foo.com:8888/Service", "FooMethod"},
1949 // https with ipv6 literal, custom port.
1950 {"https", "[1080:0:0:0:8:800:200C:417A]:8888", "/Service/FooMethod",
1951 "https://[1080:0:0:0:8:800:200C:417A]:8888/Service", "FooMethod"},
1952 // custom url scheme, https default port.
1953 {"blah", "www.foo.com:443", "/Service/FooMethod",
1954 "blah://www.foo.com:443/Service", "FooMethod"}};
1955 for (uint32_t i = 0; i < GPR_ARRAY_SIZE(test_cases); i++) {
1956 const char* url_scheme = test_cases[i].url_scheme;
1957 grpc_slice call_host =
1958 grpc_slice_from_copied_string(test_cases[i].call_host);
1959 grpc_slice call_method =
1960 grpc_slice_from_copied_string(test_cases[i].call_method);
1961 grpc_auth_metadata_context auth_md_context;
1962 memset(&auth_md_context, 0, sizeof(auth_md_context));
1963 grpc_auth_metadata_context_build(url_scheme, call_host, call_method,
1964 nullptr, &auth_md_context);
1965 if (strcmp(auth_md_context.service_url,
1966 test_cases[i].desired_service_url) != 0) {
1967 gpr_log(GPR_ERROR, "Invalid service url, want: %s, got %s.",
1968 test_cases[i].desired_service_url, auth_md_context.service_url);
1971 if (strcmp(auth_md_context.method_name,
1972 test_cases[i].desired_method_name) != 0) {
1973 gpr_log(GPR_ERROR, "Invalid method name, want: %s, got %s.",
1974 test_cases[i].desired_method_name, auth_md_context.method_name);
1977 GPR_ASSERT(auth_md_context.channel_auth_context == nullptr);
1978 grpc_slice_unref(call_host);
1979 grpc_slice_unref(call_method);
1980 grpc_auth_metadata_context_reset(&auth_md_context);
1984 static void validate_external_account_creds_token_exchage_request(
1985 const grpc_httpcli_request* request, const char* body, size_t body_size,
1986 bool /*expect_actor_token*/) {
1987 // Check that the body is constructed properly.
1988 GPR_ASSERT(body != nullptr);
1989 GPR_ASSERT(body_size != 0);
1990 GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl);
1991 std::string get_url_equivalent =
1992 absl::StrFormat("%s?%s", "https://foo.com:5555/token", body);
1993 absl::StatusOr<grpc_core::URI> uri =
1994 grpc_core::URI::Parse(get_url_equivalent);
1996 gpr_log(GPR_ERROR, "%s", uri.status().ToString().c_str());
1997 GPR_ASSERT(uri.ok());
1999 assert_query_parameters(*uri, "audience", "audience");
2000 assert_query_parameters(*uri, "grant_type",
2001 "urn:ietf:params:oauth:grant-type:token-exchange");
2002 assert_query_parameters(*uri, "requested_token_type",
2003 "urn:ietf:params:oauth:token-type:access_token");
2004 assert_query_parameters(*uri, "subject_token", "test_subject_token");
2005 assert_query_parameters(*uri, "subject_token_type", "subject_token_type");
2006 assert_query_parameters(*uri, "scope",
2007 "https://www.googleapis.com/auth/cloud-platform");
2009 // Check the rest of the request.
2010 GPR_ASSERT(strcmp(request->host, "foo.com:5555") == 0);
2011 GPR_ASSERT(strcmp(request->http.path, "/token") == 0);
2012 GPR_ASSERT(request->http.hdr_count == 2);
2013 GPR_ASSERT(strcmp(request->http.hdrs[0].key, "Content-Type") == 0);
2014 GPR_ASSERT(strcmp(request->http.hdrs[0].value,
2015 "application/x-www-form-urlencoded") == 0);
2016 GPR_ASSERT(strcmp(request->http.hdrs[1].key, "Authorization") == 0);
2017 GPR_ASSERT(strcmp(request->http.hdrs[1].value,
2018 "Basic Y2xpZW50X2lkOmNsaWVudF9zZWNyZXQ=") == 0);
2022 validate_external_account_creds_token_exchage_request_with_url_encode(
2023 const grpc_httpcli_request* request, const char* body, size_t body_size,
2024 bool /*expect_actor_token*/) {
2025 // Check that the body is constructed properly.
2026 GPR_ASSERT(body != nullptr);
2027 GPR_ASSERT(body_size != 0);
2028 GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl);
2031 std::string(body, body_size).c_str(),
2032 "audience=audience_!%40%23%24&grant_type=urn%3Aietf%3Aparams%3Aoauth%"
2033 "3Agrant-type%3Atoken-exchange&requested_token_type=urn%3Aietf%"
2034 "3Aparams%3Aoauth%3Atoken-type%3Aaccess_token&subject_token_type="
2035 "subject_token_type_!%40%23%24&subject_token=test_subject_token&"
2036 "scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcloud-platform") ==
2039 // Check the rest of the request.
2040 GPR_ASSERT(strcmp(request->host, "foo.com:5555") == 0);
2041 GPR_ASSERT(strcmp(request->http.path, "/token_url_encode") == 0);
2042 GPR_ASSERT(request->http.hdr_count == 2);
2043 GPR_ASSERT(strcmp(request->http.hdrs[0].key, "Content-Type") == 0);
2044 GPR_ASSERT(strcmp(request->http.hdrs[0].value,
2045 "application/x-www-form-urlencoded") == 0);
2046 GPR_ASSERT(strcmp(request->http.hdrs[1].key, "Authorization") == 0);
2047 GPR_ASSERT(strcmp(request->http.hdrs[1].value,
2048 "Basic Y2xpZW50X2lkOmNsaWVudF9zZWNyZXQ=") == 0);
2052 validate_external_account_creds_service_account_impersonation_request(
2053 const grpc_httpcli_request* request, const char* body, size_t body_size,
2054 bool /*expect_actor_token*/) {
2055 // Check that the body is constructed properly.
2056 GPR_ASSERT(body != nullptr);
2057 GPR_ASSERT(body_size != 0);
2058 GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl);
2059 GPR_ASSERT(strcmp(body, "scope=scope_1 scope_2") == 0);
2060 // Check the rest of the request.
2061 GPR_ASSERT(strcmp(request->host, "foo.com:5555") == 0);
2062 GPR_ASSERT(strcmp(request->http.path, "/service_account_impersonation") == 0);
2063 GPR_ASSERT(request->http.hdr_count == 2);
2064 GPR_ASSERT(strcmp(request->http.hdrs[0].key, "Content-Type") == 0);
2065 GPR_ASSERT(strcmp(request->http.hdrs[0].value,
2066 "application/x-www-form-urlencoded") == 0);
2067 GPR_ASSERT(strcmp(request->http.hdrs[1].key, "Authorization") == 0);
2068 GPR_ASSERT(strcmp(request->http.hdrs[1].value,
2069 "Bearer token_exchange_access_token") == 0);
2072 static int external_account_creds_httpcli_post_success(
2073 const grpc_httpcli_request* request, const char* body, size_t body_size,
2074 grpc_millis /*deadline*/, grpc_closure* on_done,
2075 grpc_httpcli_response* response) {
2076 if (strcmp(request->http.path, "/token") == 0) {
2077 validate_external_account_creds_token_exchage_request(request, body,
2079 *response = http_response(
2080 200, valid_external_account_creds_token_exchange_response);
2081 } else if (strcmp(request->http.path, "/service_account_impersonation") ==
2083 validate_external_account_creds_service_account_impersonation_request(
2084 request, body, body_size, true);
2085 *response = http_response(
2087 valid_external_account_creds_service_account_impersonation_response);
2088 } else if (strcmp(request->http.path, "/token_url_encode") == 0) {
2089 validate_external_account_creds_token_exchage_request_with_url_encode(
2090 request, body, body_size, true);
2091 *response = http_response(
2092 200, valid_external_account_creds_token_exchange_response);
2094 grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, GRPC_ERROR_NONE);
2099 external_account_creds_httpcli_post_failure_token_exchange_response_missing_access_token(
2100 const grpc_httpcli_request* request, const char* /*body*/,
2101 size_t /*body_size*/, grpc_millis /*deadline*/, grpc_closure* on_done,
2102 grpc_httpcli_response* response) {
2103 if (strcmp(request->http.path, "/token") == 0) {
2104 *response = http_response(200,
2105 "{\"not_access_token\":\"not_access_token\","
2106 "\"expires_in\":3599,"
2107 " \"token_type\":\"Bearer\"}");
2108 } else if (strcmp(request->http.path, "/service_account_impersonation") ==
2110 *response = http_response(
2112 valid_external_account_creds_service_account_impersonation_response);
2114 grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, GRPC_ERROR_NONE);
2118 static int url_external_account_creds_httpcli_get_success(
2119 const grpc_httpcli_request* request, grpc_millis /*deadline*/,
2120 grpc_closure* on_done, grpc_httpcli_response* response) {
2121 if (strcmp(request->http.path, "/generate_subject_token_format_text") == 0) {
2122 *response = http_response(
2124 valid_url_external_account_creds_retrieve_subject_token_response_format_text);
2125 } else if (strcmp(request->http.path, "/path/to/url/creds?p1=v1&p2=v2") ==
2127 *response = http_response(
2129 valid_url_external_account_creds_retrieve_subject_token_response_format_text);
2130 } else if (strcmp(request->http.path,
2131 "/generate_subject_token_format_json") == 0) {
2132 *response = http_response(
2134 valid_url_external_account_creds_retrieve_subject_token_response_format_json);
2136 grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, GRPC_ERROR_NONE);
2140 static void validate_aws_external_account_creds_token_exchage_request(
2141 const grpc_httpcli_request* request, const char* body, size_t body_size,
2142 bool /*expect_actor_token*/) {
2143 // Check that the body is constructed properly.
2144 GPR_ASSERT(body != nullptr);
2145 GPR_ASSERT(body_size != 0);
2146 GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl);
2147 std::string get_url_equivalent =
2148 absl::StrFormat("%s?%s", "https://foo.com:5555/token", body);
2149 absl::StatusOr<grpc_core::URI> uri =
2150 grpc_core::URI::Parse(get_url_equivalent);
2151 GPR_ASSERT(uri.ok());
2152 assert_query_parameters(*uri, "audience", "audience");
2153 assert_query_parameters(*uri, "grant_type",
2154 "urn:ietf:params:oauth:grant-type:token-exchange");
2155 assert_query_parameters(*uri, "requested_token_type",
2156 "urn:ietf:params:oauth:token-type:access_token");
2157 assert_query_parameters(*uri, "subject_token_type", "subject_token_type");
2158 assert_query_parameters(*uri, "scope",
2159 "https://www.googleapis.com/auth/cloud-platform");
2160 // Check the rest of the request.
2161 GPR_ASSERT(strcmp(request->host, "foo.com:5555") == 0);
2162 GPR_ASSERT(strcmp(request->http.path, "/token") == 0);
2163 GPR_ASSERT(request->http.hdr_count == 2);
2164 GPR_ASSERT(strcmp(request->http.hdrs[0].key, "Content-Type") == 0);
2165 GPR_ASSERT(strcmp(request->http.hdrs[0].value,
2166 "application/x-www-form-urlencoded") == 0);
2167 GPR_ASSERT(strcmp(request->http.hdrs[1].key, "Authorization") == 0);
2168 GPR_ASSERT(strcmp(request->http.hdrs[1].value,
2169 "Basic Y2xpZW50X2lkOmNsaWVudF9zZWNyZXQ=") == 0);
2172 static int aws_external_account_creds_httpcli_get_success(
2173 const grpc_httpcli_request* request, grpc_millis /*deadline*/,
2174 grpc_closure* on_done, grpc_httpcli_response* response) {
2175 if (strcmp(request->http.path, "/region_url") == 0) {
2176 *response = http_response(200, "test_regionz");
2177 } else if (strcmp(request->http.path, "/url") == 0) {
2178 *response = http_response(200, "test_role_name");
2179 } else if (strcmp(request->http.path, "/url_no_role_name") == 0) {
2180 *response = http_response(200, "");
2181 } else if (strcmp(request->http.path, "/url/test_role_name") == 0) {
2182 *response = http_response(
2183 200, valid_aws_external_account_creds_retrieve_signing_keys_response);
2185 grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, GRPC_ERROR_NONE);
2189 static int aws_external_account_creds_httpcli_post_success(
2190 const grpc_httpcli_request* request, const char* body, size_t body_size,
2191 grpc_millis /*deadline*/, grpc_closure* on_done,
2192 grpc_httpcli_response* response) {
2193 if (strcmp(request->http.path, "/token") == 0) {
2194 validate_aws_external_account_creds_token_exchage_request(request, body,
2196 *response = http_response(
2197 200, valid_external_account_creds_token_exchange_response);
2199 grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, GRPC_ERROR_NONE);
2203 // The subclass of ExternalAccountCredentials for testing.
2204 // ExternalAccountCredentials is an abstract class so we can't directly test
2206 class TestExternalAccountCredentials final
2207 : public grpc_core::ExternalAccountCredentials {
2209 TestExternalAccountCredentials(Options options,
2210 std::vector<std::string> scopes)
2211 : ExternalAccountCredentials(std::move(options), std::move(scopes)) {}
2214 void RetrieveSubjectToken(
2215 HTTPRequestContext* /*ctx*/, const Options& /*options*/,
2216 std::function<void(std::string, grpc_error*)> cb) override {
2217 cb("test_subject_token", GRPC_ERROR_NONE);
2221 static void test_external_account_creds_success(void) {
2222 expected_md emd[] = {{"authorization", "Bearer token_exchange_access_token"}};
2223 grpc_core::ExecCtx exec_ctx;
2224 grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
2226 grpc_core::Json credential_source("");
2227 TestExternalAccountCredentials::Options options = {
2228 "external_account", // type;
2229 "audience", // audience;
2230 "subject_token_type", // subject_token_type;
2231 "", // service_account_impersonation_url;
2232 "https://foo.com:5555/token", // token_url;
2233 "https://foo.com:5555/token_info", // token_info_url;
2234 credential_source, // credential_source;
2235 "quota_project_id", // quota_project_id;
2236 "client_id", // client_id;
2237 "client_secret", // client_secret;
2239 TestExternalAccountCredentials creds(options, {});
2240 /* Check security level. */
2241 GPR_ASSERT(creds.min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
2242 /* First request: http put should be called. */
2243 request_metadata_state* state =
2244 make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
2245 grpc_httpcli_set_override(httpcli_get_should_not_be_called,
2246 external_account_creds_httpcli_post_success);
2247 run_request_metadata_test(&creds, auth_md_ctx, state);
2248 grpc_core::ExecCtx::Get()->Flush();
2249 /* Second request: the cached token should be served directly. */
2251 make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
2252 grpc_httpcli_set_override(httpcli_get_should_not_be_called,
2253 httpcli_post_should_not_be_called);
2254 run_request_metadata_test(&creds, auth_md_ctx, state);
2255 grpc_core::ExecCtx::Get()->Flush();
2256 grpc_httpcli_set_override(nullptr, nullptr);
2259 static void test_external_account_creds_success_with_url_encode(void) {
2260 expected_md emd[] = {{"authorization", "Bearer token_exchange_access_token"}};
2261 grpc_core::ExecCtx exec_ctx;
2262 grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
2264 grpc_core::Json credential_source("");
2265 TestExternalAccountCredentials::Options options = {
2266 "external_account", // type;
2267 "audience_!@#$", // audience;
2268 "subject_token_type_!@#$", // subject_token_type;
2269 "", // service_account_impersonation_url;
2270 "https://foo.com:5555/token_url_encode", // token_url;
2271 "https://foo.com:5555/token_info", // token_info_url;
2272 credential_source, // credential_source;
2273 "quota_project_id", // quota_project_id;
2274 "client_id", // client_id;
2275 "client_secret", // client_secret;
2277 TestExternalAccountCredentials creds(options, {});
2278 request_metadata_state* state =
2279 make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
2280 grpc_httpcli_set_override(httpcli_get_should_not_be_called,
2281 external_account_creds_httpcli_post_success);
2282 run_request_metadata_test(&creds, auth_md_ctx, state);
2283 grpc_core::ExecCtx::Get()->Flush();
2284 grpc_httpcli_set_override(nullptr, nullptr);
2288 test_external_account_creds_success_with_service_account_impersonation(void) {
2289 expected_md emd[] = {
2290 {"authorization", "Bearer service_account_impersonation_access_token"}};
2291 grpc_core::ExecCtx exec_ctx;
2292 grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
2294 grpc_core::Json credential_source("");
2295 TestExternalAccountCredentials::Options options = {
2296 "external_account", // type;
2297 "audience", // audience;
2298 "subject_token_type", // subject_token_type;
2299 "https://foo.com:5555/service_account_impersonation", // service_account_impersonation_url;
2300 "https://foo.com:5555/token", // token_url;
2301 "https://foo.com:5555/token_info", // token_info_url;
2302 credential_source, // credential_source;
2303 "quota_project_id", // quota_project_id;
2304 "client_id", // client_id;
2305 "client_secret", // client_secret;
2307 TestExternalAccountCredentials creds(options, {"scope_1", "scope_2"});
2308 /* Check security level. */
2309 GPR_ASSERT(creds.min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
2310 /* First request: http put should be called. */
2311 request_metadata_state* state =
2312 make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
2313 grpc_httpcli_set_override(httpcli_get_should_not_be_called,
2314 external_account_creds_httpcli_post_success);
2315 run_request_metadata_test(&creds, auth_md_ctx, state);
2316 grpc_core::ExecCtx::Get()->Flush();
2317 grpc_httpcli_set_override(nullptr, nullptr);
2320 static void test_external_account_creds_failure_invalid_token_url(void) {
2321 grpc_core::ExecCtx exec_ctx;
2322 grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
2324 grpc_core::Json credential_source("");
2325 TestExternalAccountCredentials::Options options = {
2326 "external_account", // type;
2327 "audience", // audience;
2328 "subject_token_type", // subject_token_type;
2329 "https://foo.com:5555/service_account_impersonation", // service_account_impersonation_url;
2330 "invalid_token_url", // token_url;
2331 "https://foo.com:5555/token_info", // token_info_url;
2332 credential_source, // credential_source;
2333 "quota_project_id", // quota_project_id;
2334 "client_id", // client_id;
2335 "client_secret", // client_secret;
2337 TestExternalAccountCredentials creds(options, {});
2338 grpc_httpcli_set_override(httpcli_get_should_not_be_called,
2339 httpcli_post_should_not_be_called);
2340 grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
2341 "Invalid token url: invalid_token_url.");
2342 grpc_error* expected_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
2343 "Error occurred when fetching oauth2 token.", &error, 1);
2344 request_metadata_state* state =
2345 make_request_metadata_state(expected_error, nullptr, 0);
2346 run_request_metadata_test(&creds, auth_md_ctx, state);
2347 GRPC_ERROR_UNREF(error);
2348 grpc_core::ExecCtx::Get()->Flush();
2349 grpc_httpcli_set_override(nullptr, nullptr);
2353 test_external_account_creds_failure_invalid_service_account_impersonation_url(
2355 grpc_core::ExecCtx exec_ctx;
2356 grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
2358 grpc_core::Json credential_source("");
2359 TestExternalAccountCredentials::Options options = {
2360 "external_account", // type;
2361 "audience", // audience;
2362 "subject_token_type", // subject_token_type;
2363 "invalid_service_account_impersonation_url", // service_account_impersonation_url;
2364 "https://foo.com:5555/token", // token_url;
2365 "https://foo.com:5555/token_info", // token_info_url;
2366 credential_source, // credential_source;
2367 "quota_project_id", // quota_project_id;
2368 "client_id", // client_id;
2369 "client_secret", // client_secret;
2371 TestExternalAccountCredentials creds(options, {});
2372 grpc_httpcli_set_override(httpcli_get_should_not_be_called,
2373 external_account_creds_httpcli_post_success);
2374 grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
2375 "Invalid service account impersonation url: "
2376 "invalid_service_account_impersonation_url.");
2377 grpc_error* expected_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
2378 "Error occurred when fetching oauth2 token.", &error, 1);
2379 request_metadata_state* state =
2380 make_request_metadata_state(expected_error, nullptr, 0);
2381 run_request_metadata_test(&creds, auth_md_ctx, state);
2382 GRPC_ERROR_UNREF(error);
2383 grpc_core::ExecCtx::Get()->Flush();
2384 grpc_httpcli_set_override(nullptr, nullptr);
2388 test_external_account_creds_failure_token_exchange_response_missing_access_token(
2390 grpc_core::ExecCtx exec_ctx;
2391 grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
2393 grpc_core::Json credential_source("");
2394 TestExternalAccountCredentials::Options options = {
2395 "external_account", // type;
2396 "audience", // audience;
2397 "subject_token_type", // subject_token_type;
2398 "https://foo.com:5555/service_account_impersonation", // service_account_impersonation_url;
2399 "https://foo.com:5555/token", // token_url;
2400 "https://foo.com:5555/token_info", // token_info_url;
2401 credential_source, // credential_source;
2402 "quota_project_id", // quota_project_id;
2403 "client_id", // client_id;
2404 "client_secret", // client_secret;
2406 TestExternalAccountCredentials creds(options, {});
2407 grpc_httpcli_set_override(
2408 httpcli_get_should_not_be_called,
2409 external_account_creds_httpcli_post_failure_token_exchange_response_missing_access_token);
2410 grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
2411 "Missing or invalid access_token in "
2412 "{\"not_access_token\":\"not_access_token\",\"expires_in\":3599,\"token_"
2413 "type\":\"Bearer\"}.");
2414 grpc_error* expected_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
2415 "Error occurred when fetching oauth2 token.", &error, 1);
2416 request_metadata_state* state =
2417 make_request_metadata_state(expected_error, nullptr, 0);
2418 run_request_metadata_test(&creds, auth_md_ctx, state);
2419 GRPC_ERROR_UNREF(error);
2420 grpc_core::ExecCtx::Get()->Flush();
2421 grpc_httpcli_set_override(nullptr, nullptr);
2424 static void test_url_external_account_creds_success_format_text(void) {
2425 expected_md emd[] = {{"authorization", "Bearer token_exchange_access_token"}};
2426 grpc_core::ExecCtx exec_ctx;
2427 grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
2429 grpc_error* error = GRPC_ERROR_NONE;
2430 grpc_core::Json credential_source = grpc_core::Json::Parse(
2431 valid_url_external_account_creds_options_credential_source_format_text,
2433 GPR_ASSERT(error == GRPC_ERROR_NONE);
2434 grpc_core::ExternalAccountCredentials::Options options = {
2435 "external_account", // type;
2436 "audience", // audience;
2437 "subject_token_type", // subject_token_type;
2438 "", // service_account_impersonation_url;
2439 "https://foo.com:5555/token", // token_url;
2440 "https://foo.com:5555/token_info", // token_info_url;
2441 credential_source, // credential_source;
2442 "quota_project_id", // quota_project_id;
2443 "client_id", // client_id;
2444 "client_secret", // client_secret;
2447 grpc_core::UrlExternalAccountCredentials::Create(options, {}, &error);
2448 GPR_ASSERT(creds != nullptr);
2449 GPR_ASSERT(error == GRPC_ERROR_NONE);
2450 GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
2451 request_metadata_state* state =
2452 make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
2453 grpc_httpcli_set_override(url_external_account_creds_httpcli_get_success,
2454 external_account_creds_httpcli_post_success);
2455 run_request_metadata_test(creds.get(), auth_md_ctx, state);
2456 grpc_core::ExecCtx::Get()->Flush();
2457 grpc_httpcli_set_override(nullptr, nullptr);
2461 test_url_external_account_creds_success_with_qurey_params_format_text(void) {
2462 expected_md emd[] = {{"authorization", "Bearer token_exchange_access_token"}};
2463 grpc_core::ExecCtx exec_ctx;
2464 grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
2466 grpc_error* error = GRPC_ERROR_NONE;
2467 grpc_core::Json credential_source = grpc_core::Json::Parse(
2468 valid_url_external_account_creds_options_credential_source_with_qurey_params_format_text,
2470 GPR_ASSERT(error == GRPC_ERROR_NONE);
2471 grpc_core::ExternalAccountCredentials::Options options = {
2472 "external_account", // type;
2473 "audience", // audience;
2474 "subject_token_type", // subject_token_type;
2475 "", // service_account_impersonation_url;
2476 "https://foo.com:5555/token", // token_url;
2477 "https://foo.com:5555/token_info", // token_info_url;
2478 credential_source, // credential_source;
2479 "quota_project_id", // quota_project_id;
2480 "client_id", // client_id;
2481 "client_secret", // client_secret;
2484 grpc_core::UrlExternalAccountCredentials::Create(options, {}, &error);
2485 GPR_ASSERT(creds != nullptr);
2486 GPR_ASSERT(error == GRPC_ERROR_NONE);
2487 GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
2488 request_metadata_state* state =
2489 make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
2490 grpc_httpcli_set_override(url_external_account_creds_httpcli_get_success,
2491 external_account_creds_httpcli_post_success);
2492 run_request_metadata_test(creds.get(), auth_md_ctx, state);
2493 grpc_core::ExecCtx::Get()->Flush();
2494 grpc_httpcli_set_override(nullptr, nullptr);
2497 static void test_url_external_account_creds_success_format_json(void) {
2498 expected_md emd[] = {{"authorization", "Bearer token_exchange_access_token"}};
2499 grpc_core::ExecCtx exec_ctx;
2500 grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
2502 grpc_error* error = GRPC_ERROR_NONE;
2503 grpc_core::Json credential_source = grpc_core::Json::Parse(
2504 valid_url_external_account_creds_options_credential_source_format_json,
2506 GPR_ASSERT(error == GRPC_ERROR_NONE);
2507 grpc_core::ExternalAccountCredentials::Options options = {
2508 "external_account", // type;
2509 "audience", // audience;
2510 "subject_token_type", // subject_token_type;
2511 "", // service_account_impersonation_url;
2512 "https://foo.com:5555/token", // token_url;
2513 "https://foo.com:5555/token_info", // token_info_url;
2514 credential_source, // credential_source;
2515 "quota_project_id", // quota_project_id;
2516 "client_id", // client_id;
2517 "client_secret", // client_secret;
2520 grpc_core::UrlExternalAccountCredentials::Create(options, {}, &error);
2521 GPR_ASSERT(creds != nullptr);
2522 GPR_ASSERT(error == GRPC_ERROR_NONE);
2523 GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
2524 request_metadata_state* state =
2525 make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
2526 grpc_httpcli_set_override(url_external_account_creds_httpcli_get_success,
2527 external_account_creds_httpcli_post_success);
2528 run_request_metadata_test(creds.get(), auth_md_ctx, state);
2529 grpc_core::ExecCtx::Get()->Flush();
2530 grpc_httpcli_set_override(nullptr, nullptr);
2534 test_url_external_account_creds_failure_invalid_credential_source_url(void) {
2535 grpc_error* error = GRPC_ERROR_NONE;
2536 grpc_core::Json credential_source = grpc_core::Json::Parse(
2537 invalid_url_external_account_creds_options_credential_source, &error);
2538 GPR_ASSERT(error == GRPC_ERROR_NONE);
2539 grpc_core::ExternalAccountCredentials::Options options = {
2540 "external_account", // type;
2541 "audience", // audience;
2542 "subject_token_type", // subject_token_type;
2543 "", // service_account_impersonation_url;
2544 "https://foo.com:5555/token", // token_url;
2545 "https://foo.com:5555/token_info", // token_info_url;
2546 credential_source, // credential_source;
2547 "quota_project_id", // quota_project_id;
2548 "client_id", // client_id;
2549 "client_secret", // client_secret;
2552 grpc_core::UrlExternalAccountCredentials::Create(options, {}, &error);
2553 GPR_ASSERT(creds == nullptr);
2554 grpc_slice actual_error_slice;
2555 GPR_ASSERT(grpc_error_get_str(error, GRPC_ERROR_STR_DESCRIPTION,
2556 &actual_error_slice));
2557 absl::string_view actual_error =
2558 grpc_core::StringViewFromSlice(actual_error_slice);
2559 GPR_ASSERT(absl::StartsWith(actual_error, "Invalid credential source url."));
2560 GRPC_ERROR_UNREF(error);
2563 static void test_file_external_account_creds_success_format_text(void) {
2564 expected_md emd[] = {{"authorization", "Bearer token_exchange_access_token"}};
2565 grpc_core::ExecCtx exec_ctx;
2566 grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
2568 grpc_error* error = GRPC_ERROR_NONE;
2569 char* subject_token_path = write_tmp_jwt_file("test_subject_token");
2570 grpc_core::Json credential_source = grpc_core::Json::Parse(
2572 "{\"file\":\"%s\"}",
2573 absl::StrReplaceAll(subject_token_path, {{"\\", "\\\\"}})),
2575 GPR_ASSERT(error == GRPC_ERROR_NONE);
2576 grpc_core::ExternalAccountCredentials::Options options = {
2577 "external_account", // type;
2578 "audience", // audience;
2579 "subject_token_type", // subject_token_type;
2580 "", // service_account_impersonation_url;
2581 "https://foo.com:5555/token", // token_url;
2582 "https://foo.com:5555/token_info", // token_info_url;
2583 credential_source, // credential_source;
2584 "quota_project_id", // quota_project_id;
2585 "client_id", // client_id;
2586 "client_secret", // client_secret;
2589 grpc_core::FileExternalAccountCredentials::Create(options, {}, &error);
2590 GPR_ASSERT(creds != nullptr);
2591 GPR_ASSERT(error == GRPC_ERROR_NONE);
2592 GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
2593 request_metadata_state* state =
2594 make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
2595 grpc_httpcli_set_override(httpcli_get_should_not_be_called,
2596 external_account_creds_httpcli_post_success);
2597 run_request_metadata_test(creds.get(), auth_md_ctx, state);
2598 grpc_core::ExecCtx::Get()->Flush();
2599 grpc_httpcli_set_override(nullptr, nullptr);
2600 GRPC_ERROR_UNREF(error);
2601 gpr_free(subject_token_path);
2604 static void test_file_external_account_creds_success_format_json(void) {
2605 expected_md emd[] = {{"authorization", "Bearer token_exchange_access_token"}};
2606 grpc_core::ExecCtx exec_ctx;
2607 grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
2609 grpc_error* error = GRPC_ERROR_NONE;
2610 char* subject_token_path =
2611 write_tmp_jwt_file("{\"access_token\":\"test_subject_token\"}");
2612 grpc_core::Json credential_source = grpc_core::Json::Parse(
2615 "\"file\":\"%s\",\n"
2618 "\"type\":\"json\",\n"
2619 "\"subject_token_field_name\":\"access_token\"\n"
2622 absl::StrReplaceAll(subject_token_path, {{"\\", "\\\\"}})),
2624 GPR_ASSERT(error == GRPC_ERROR_NONE);
2625 grpc_core::ExternalAccountCredentials::Options options = {
2626 "external_account", // type;
2627 "audience", // audience;
2628 "subject_token_type", // subject_token_type;
2629 "", // service_account_impersonation_url;
2630 "https://foo.com:5555/token", // token_url;
2631 "https://foo.com:5555/token_info", // token_info_url;
2632 credential_source, // credential_source;
2633 "quota_project_id", // quota_project_id;
2634 "client_id", // client_id;
2635 "client_secret", // client_secret;
2638 grpc_core::FileExternalAccountCredentials::Create(options, {}, &error);
2639 GPR_ASSERT(creds != nullptr);
2640 GPR_ASSERT(error == GRPC_ERROR_NONE);
2641 GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
2642 request_metadata_state* state =
2643 make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
2644 grpc_httpcli_set_override(httpcli_get_should_not_be_called,
2645 external_account_creds_httpcli_post_success);
2646 run_request_metadata_test(creds.get(), auth_md_ctx, state);
2647 grpc_core::ExecCtx::Get()->Flush();
2648 grpc_httpcli_set_override(nullptr, nullptr);
2649 GRPC_ERROR_UNREF(error);
2650 gpr_free(subject_token_path);
2653 static void test_file_external_account_creds_failure_file_not_found(void) {
2654 grpc_core::ExecCtx exec_ctx;
2655 grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
2657 grpc_error* error = GRPC_ERROR_NONE;
2658 grpc_core::Json credential_source =
2659 grpc_core::Json::Parse("{\"file\":\"non_exisiting_file\"}", &error);
2660 GPR_ASSERT(error == GRPC_ERROR_NONE);
2661 grpc_core::ExternalAccountCredentials::Options options = {
2662 "external_account", // type;
2663 "audience", // audience;
2664 "subject_token_type", // subject_token_type;
2665 "", // service_account_impersonation_url;
2666 "https://foo.com:5555/token", // token_url;
2667 "https://foo.com:5555/token_info", // token_info_url;
2668 credential_source, // credential_source;
2669 "quota_project_id", // quota_project_id;
2670 "client_id", // client_id;
2671 "client_secret", // client_secret;
2674 grpc_core::FileExternalAccountCredentials::Create(options, {}, &error);
2675 GPR_ASSERT(creds != nullptr);
2676 GPR_ASSERT(error == GRPC_ERROR_NONE);
2677 grpc_httpcli_set_override(httpcli_get_should_not_be_called,
2678 httpcli_post_should_not_be_called);
2679 error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed to load file");
2680 grpc_error* expected_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
2681 "Error occurred when fetching oauth2 token.", &error, 1);
2682 request_metadata_state* state =
2683 make_request_metadata_state(expected_error, nullptr, 0);
2684 run_request_metadata_test(creds.get(), auth_md_ctx, state);
2685 grpc_core::ExecCtx::Get()->Flush();
2686 grpc_httpcli_set_override(nullptr, nullptr);
2687 GRPC_ERROR_UNREF(error);
2690 static void test_file_external_account_creds_failure_invalid_json_content(
2692 grpc_core::ExecCtx exec_ctx;
2693 grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
2695 grpc_error* error = GRPC_ERROR_NONE;
2696 char* subject_token_path = write_tmp_jwt_file("not_a_valid_json_file");
2697 grpc_core::Json credential_source = grpc_core::Json::Parse(
2700 "\"file\":\"%s\",\n"
2703 "\"type\":\"json\",\n"
2704 "\"subject_token_field_name\":\"access_token\"\n"
2707 absl::StrReplaceAll(subject_token_path, {{"\\", "\\\\"}})),
2709 GPR_ASSERT(error == GRPC_ERROR_NONE);
2710 grpc_core::ExternalAccountCredentials::Options options = {
2711 "external_account", // type;
2712 "audience", // audience;
2713 "subject_token_type", // subject_token_type;
2714 "", // service_account_impersonation_url;
2715 "https://foo.com:5555/token", // token_url;
2716 "https://foo.com:5555/token_info", // token_info_url;
2717 credential_source, // credential_source;
2718 "quota_project_id", // quota_project_id;
2719 "client_id", // client_id;
2720 "client_secret", // client_secret;
2723 grpc_core::FileExternalAccountCredentials::Create(options, {}, &error);
2724 GPR_ASSERT(creds != nullptr);
2725 GPR_ASSERT(error == GRPC_ERROR_NONE);
2726 grpc_httpcli_set_override(httpcli_get_should_not_be_called,
2727 httpcli_post_should_not_be_called);
2728 error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
2729 "The content of the file is not a valid json object.");
2730 grpc_error* expected_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
2731 "Error occurred when fetching oauth2 token.", &error, 1);
2732 request_metadata_state* state =
2733 make_request_metadata_state(expected_error, nullptr, 0);
2734 run_request_metadata_test(creds.get(), auth_md_ctx, state);
2735 grpc_core::ExecCtx::Get()->Flush();
2736 grpc_httpcli_set_override(nullptr, nullptr);
2737 GRPC_ERROR_UNREF(error);
2738 gpr_free(subject_token_path);
2741 static void test_aws_external_account_creds_success(void) {
2742 expected_md emd[] = {{"authorization", "Bearer token_exchange_access_token"}};
2743 grpc_core::ExecCtx exec_ctx;
2744 grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
2746 grpc_error* error = GRPC_ERROR_NONE;
2747 grpc_core::Json credential_source = grpc_core::Json::Parse(
2748 valid_aws_external_account_creds_options_credential_source, &error);
2749 GPR_ASSERT(error == GRPC_ERROR_NONE);
2750 grpc_core::ExternalAccountCredentials::Options options = {
2751 "external_account", // type;
2752 "audience", // audience;
2753 "subject_token_type", // subject_token_type;
2754 "", // service_account_impersonation_url;
2755 "https://foo.com:5555/token", // token_url;
2756 "https://foo.com:5555/token_info", // token_info_url;
2757 credential_source, // credential_source;
2758 "quota_project_id", // quota_project_id;
2759 "client_id", // client_id;
2760 "client_secret", // client_secret;
2763 grpc_core::AwsExternalAccountCredentials::Create(options, {}, &error);
2764 GPR_ASSERT(creds != nullptr);
2765 GPR_ASSERT(error == GRPC_ERROR_NONE);
2766 GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
2767 request_metadata_state* state =
2768 make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
2769 grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success,
2770 aws_external_account_creds_httpcli_post_success);
2771 run_request_metadata_test(creds.get(), auth_md_ctx, state);
2772 grpc_core::ExecCtx::Get()->Flush();
2773 grpc_httpcli_set_override(nullptr, nullptr);
2776 static void test_aws_external_account_creds_success_path_region_env_keys_url(
2778 expected_md emd[] = {{"authorization", "Bearer token_exchange_access_token"}};
2779 grpc_core::ExecCtx exec_ctx;
2780 grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
2782 gpr_setenv("AWS_REGION", "test_regionz");
2783 grpc_error* error = GRPC_ERROR_NONE;
2784 grpc_core::Json credential_source = grpc_core::Json::Parse(
2785 valid_aws_external_account_creds_options_credential_source, &error);
2786 GPR_ASSERT(error == GRPC_ERROR_NONE);
2787 grpc_core::ExternalAccountCredentials::Options options = {
2788 "external_account", // type;
2789 "audience", // audience;
2790 "subject_token_type", // subject_token_type;
2791 "", // service_account_impersonation_url;
2792 "https://foo.com:5555/token", // token_url;
2793 "https://foo.com:5555/token_info", // token_info_url;
2794 credential_source, // credential_source;
2795 "quota_project_id", // quota_project_id;
2796 "client_id", // client_id;
2797 "client_secret", // client_secret;
2800 grpc_core::AwsExternalAccountCredentials::Create(options, {}, &error);
2801 GPR_ASSERT(creds != nullptr);
2802 GPR_ASSERT(error == GRPC_ERROR_NONE);
2803 GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
2804 request_metadata_state* state =
2805 make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
2806 grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success,
2807 aws_external_account_creds_httpcli_post_success);
2808 run_request_metadata_test(creds.get(), auth_md_ctx, state);
2809 grpc_core::ExecCtx::Get()->Flush();
2810 grpc_httpcli_set_override(nullptr, nullptr);
2811 gpr_unsetenv("AWS_REGION");
2814 static void test_aws_external_account_creds_success_path_region_url_keys_env(
2816 expected_md emd[] = {{"authorization", "Bearer token_exchange_access_token"}};
2817 grpc_core::ExecCtx exec_ctx;
2818 grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
2820 gpr_setenv("AWS_ACCESS_KEY_ID", "test_access_key_id");
2821 gpr_setenv("AWS_SECRET_ACCESS_KEY", "test_secret_access_key");
2822 gpr_setenv("AWS_SESSION_TOKEN", "test_token");
2823 grpc_error* error = GRPC_ERROR_NONE;
2824 grpc_core::Json credential_source = grpc_core::Json::Parse(
2825 valid_aws_external_account_creds_options_credential_source, &error);
2826 GPR_ASSERT(error == GRPC_ERROR_NONE);
2827 grpc_core::ExternalAccountCredentials::Options options = {
2828 "external_account", // type;
2829 "audience", // audience;
2830 "subject_token_type", // subject_token_type;
2831 "", // service_account_impersonation_url;
2832 "https://foo.com:5555/token", // token_url;
2833 "https://foo.com:5555/token_info", // token_info_url;
2834 credential_source, // credential_source;
2835 "quota_project_id", // quota_project_id;
2836 "client_id", // client_id;
2837 "client_secret", // client_secret;
2840 grpc_core::AwsExternalAccountCredentials::Create(options, {}, &error);
2841 GPR_ASSERT(creds != nullptr);
2842 GPR_ASSERT(error == GRPC_ERROR_NONE);
2843 GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
2844 request_metadata_state* state =
2845 make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
2846 grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success,
2847 aws_external_account_creds_httpcli_post_success);
2848 run_request_metadata_test(creds.get(), auth_md_ctx, state);
2849 grpc_core::ExecCtx::Get()->Flush();
2850 grpc_httpcli_set_override(nullptr, nullptr);
2851 gpr_unsetenv("AWS_ACCESS_KEY_ID");
2852 gpr_unsetenv("AWS_SECRET_ACCESS_KEY");
2853 gpr_unsetenv("AWS_SESSION_TOKEN");
2856 static void test_aws_external_account_creds_success_path_region_env_keys_env(
2858 expected_md emd[] = {{"authorization", "Bearer token_exchange_access_token"}};
2859 grpc_core::ExecCtx exec_ctx;
2860 grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
2862 gpr_setenv("AWS_REGION", "test_regionz");
2863 gpr_setenv("AWS_ACCESS_KEY_ID", "test_access_key_id");
2864 gpr_setenv("AWS_SECRET_ACCESS_KEY", "test_secret_access_key");
2865 gpr_setenv("AWS_SESSION_TOKEN", "test_token");
2866 grpc_error* error = GRPC_ERROR_NONE;
2867 grpc_core::Json credential_source = grpc_core::Json::Parse(
2868 valid_aws_external_account_creds_options_credential_source, &error);
2869 GPR_ASSERT(error == GRPC_ERROR_NONE);
2870 grpc_core::ExternalAccountCredentials::Options options = {
2871 "external_account", // type;
2872 "audience", // audience;
2873 "subject_token_type", // subject_token_type;
2874 "", // service_account_impersonation_url;
2875 "https://foo.com:5555/token", // token_url;
2876 "https://foo.com:5555/token_info", // token_info_url;
2877 credential_source, // credential_source;
2878 "quota_project_id", // quota_project_id;
2879 "client_id", // client_id;
2880 "client_secret", // client_secret;
2883 grpc_core::AwsExternalAccountCredentials::Create(options, {}, &error);
2884 GPR_ASSERT(creds != nullptr);
2885 GPR_ASSERT(error == GRPC_ERROR_NONE);
2886 GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
2887 request_metadata_state* state =
2888 make_request_metadata_state(GRPC_ERROR_NONE, emd, GPR_ARRAY_SIZE(emd));
2889 grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success,
2890 aws_external_account_creds_httpcli_post_success);
2891 run_request_metadata_test(creds.get(), auth_md_ctx, state);
2892 grpc_core::ExecCtx::Get()->Flush();
2893 grpc_httpcli_set_override(nullptr, nullptr);
2894 gpr_unsetenv("AWS_REGION");
2895 gpr_unsetenv("AWS_ACCESS_KEY_ID");
2896 gpr_unsetenv("AWS_SECRET_ACCESS_KEY");
2897 gpr_unsetenv("AWS_SESSION_TOKEN");
2900 static void test_aws_external_account_creds_failure_unmatched_environment_id(
2902 grpc_error* error = GRPC_ERROR_NONE;
2903 grpc_core::Json credential_source = grpc_core::Json::Parse(
2904 invalid_aws_external_account_creds_options_credential_source_unmatched_environment_id,
2906 GPR_ASSERT(error == GRPC_ERROR_NONE);
2907 grpc_core::ExternalAccountCredentials::Options options = {
2908 "external_account", // type;
2909 "audience", // audience;
2910 "subject_token_type", // subject_token_type;
2911 "", // service_account_impersonation_url;
2912 "https://foo.com:5555/token", // token_url;
2913 "https://foo.com:5555/token_info", // token_info_url;
2914 credential_source, // credential_source;
2915 "quota_project_id", // quota_project_id;
2916 "client_id", // client_id;
2917 "client_secret", // client_secret;
2920 grpc_core::AwsExternalAccountCredentials::Create(options, {}, &error);
2921 GPR_ASSERT(creds == nullptr);
2922 grpc_slice expected_error_slice =
2923 grpc_slice_from_static_string("environment_id does not match.");
2924 grpc_slice actual_error_slice;
2925 GPR_ASSERT(grpc_error_get_str(error, GRPC_ERROR_STR_DESCRIPTION,
2926 &actual_error_slice));
2927 GPR_ASSERT(grpc_slice_cmp(expected_error_slice, actual_error_slice) == 0);
2928 GRPC_ERROR_UNREF(error);
2931 static void test_aws_external_account_creds_failure_invalid_region_url(void) {
2932 grpc_core::ExecCtx exec_ctx;
2933 grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
2935 grpc_error* error = GRPC_ERROR_NONE;
2936 grpc_core::Json credential_source = grpc_core::Json::Parse(
2937 invalid_aws_external_account_creds_options_credential_source_invalid_region_url,
2939 GPR_ASSERT(error == GRPC_ERROR_NONE);
2940 grpc_core::ExternalAccountCredentials::Options options = {
2941 "external_account", // type;
2942 "audience", // audience;
2943 "subject_token_type", // subject_token_type;
2944 "", // service_account_impersonation_url;
2945 "https://foo.com:5555/token", // token_url;
2946 "https://foo.com:5555/token_info", // token_info_url;
2947 credential_source, // credential_source;
2948 "quota_project_id", // quota_project_id;
2949 "client_id", // client_id;
2950 "client_secret", // client_secret;
2953 grpc_core::AwsExternalAccountCredentials::Create(options, {}, &error);
2954 GPR_ASSERT(creds != nullptr);
2955 GPR_ASSERT(error == GRPC_ERROR_NONE);
2956 GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
2957 error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
2958 "Invalid region url: invalid_region_url.");
2959 grpc_error* expected_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
2960 "Error occurred when fetching oauth2 token.", &error, 1);
2961 request_metadata_state* state =
2962 make_request_metadata_state(expected_error, nullptr, 0);
2963 grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success,
2964 aws_external_account_creds_httpcli_post_success);
2965 run_request_metadata_test(creds.get(), auth_md_ctx, state);
2966 grpc_core::ExecCtx::Get()->Flush();
2967 grpc_httpcli_set_override(nullptr, nullptr);
2968 GRPC_ERROR_UNREF(error);
2971 static void test_aws_external_account_creds_failure_invalid_url(void) {
2972 grpc_core::ExecCtx exec_ctx;
2973 grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
2975 grpc_error* error = GRPC_ERROR_NONE;
2976 grpc_core::Json credential_source = grpc_core::Json::Parse(
2977 invalid_aws_external_account_creds_options_credential_source_invalid_url,
2979 GPR_ASSERT(error == GRPC_ERROR_NONE);
2980 grpc_core::ExternalAccountCredentials::Options options = {
2981 "external_account", // type;
2982 "audience", // audience;
2983 "subject_token_type", // subject_token_type;
2984 "", // service_account_impersonation_url;
2985 "https://foo.com:5555/token", // token_url;
2986 "https://foo.com:5555/token_info", // token_info_url;
2987 credential_source, // credential_source;
2988 "quota_project_id", // quota_project_id;
2989 "client_id", // client_id;
2990 "client_secret", // client_secret;
2993 grpc_core::AwsExternalAccountCredentials::Create(options, {}, &error);
2994 GPR_ASSERT(creds != nullptr);
2995 GPR_ASSERT(error == GRPC_ERROR_NONE);
2996 GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
2997 error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Invalid url: invalid_url.");
2998 grpc_error* expected_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
2999 "Error occurred when fetching oauth2 token.", &error, 1);
3000 request_metadata_state* state =
3001 make_request_metadata_state(expected_error, nullptr, 0);
3002 grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success,
3003 aws_external_account_creds_httpcli_post_success);
3004 run_request_metadata_test(creds.get(), auth_md_ctx, state);
3005 grpc_core::ExecCtx::Get()->Flush();
3006 grpc_httpcli_set_override(nullptr, nullptr);
3007 GRPC_ERROR_UNREF(error);
3010 static void test_aws_external_account_creds_failure_missing_role_name(void) {
3011 grpc_core::ExecCtx exec_ctx;
3012 grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
3014 grpc_error* error = GRPC_ERROR_NONE;
3015 grpc_core::Json credential_source = grpc_core::Json::Parse(
3016 invalid_aws_external_account_creds_options_credential_source_missing_role_name,
3018 GPR_ASSERT(error == GRPC_ERROR_NONE);
3019 grpc_core::ExternalAccountCredentials::Options options = {
3020 "external_account", // type;
3021 "audience", // audience;
3022 "subject_token_type", // subject_token_type;
3023 "", // service_account_impersonation_url;
3024 "https://foo.com:5555/token", // token_url;
3025 "https://foo.com:5555/token_info", // token_info_url;
3026 credential_source, // credential_source;
3027 "quota_project_id", // quota_project_id;
3028 "client_id", // client_id;
3029 "client_secret", // client_secret;
3032 grpc_core::AwsExternalAccountCredentials::Create(options, {}, &error);
3033 GPR_ASSERT(creds != nullptr);
3034 GPR_ASSERT(error == GRPC_ERROR_NONE);
3035 GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
3036 error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
3037 "Missing role name when retrieving signing keys.");
3038 grpc_error* expected_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
3039 "Error occurred when fetching oauth2 token.", &error, 1);
3040 request_metadata_state* state =
3041 make_request_metadata_state(expected_error, nullptr, 0);
3042 grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success,
3043 aws_external_account_creds_httpcli_post_success);
3044 run_request_metadata_test(creds.get(), auth_md_ctx, state);
3045 grpc_core::ExecCtx::Get()->Flush();
3046 grpc_httpcli_set_override(nullptr, nullptr);
3047 GRPC_ERROR_UNREF(error);
3051 test_aws_external_account_creds_failure_invalid_regional_cred_verification_url(
3053 grpc_core::ExecCtx exec_ctx;
3054 grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
3056 grpc_error* error = GRPC_ERROR_NONE;
3057 grpc_core::Json credential_source = grpc_core::Json::Parse(
3058 invalid_aws_external_account_creds_options_credential_source_invalid_regional_cred_verification_url,
3060 GPR_ASSERT(error == GRPC_ERROR_NONE);
3061 grpc_core::ExternalAccountCredentials::Options options = {
3062 "external_account", // type;
3063 "audience", // audience;
3064 "subject_token_type", // subject_token_type;
3065 "", // service_account_impersonation_url;
3066 "https://foo.com:5555/token", // token_url;
3067 "https://foo.com:5555/token_info", // token_info_url;
3068 credential_source, // credential_source;
3069 "quota_project_id", // quota_project_id;
3070 "client_id", // client_id;
3071 "client_secret", // client_secret;
3074 grpc_core::AwsExternalAccountCredentials::Create(options, {}, &error);
3075 GPR_ASSERT(creds != nullptr);
3076 GPR_ASSERT(error == GRPC_ERROR_NONE);
3077 GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
3078 error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
3079 "Creating aws request signer failed.");
3080 grpc_error* expected_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
3081 "Error occurred when fetching oauth2 token.", &error, 1);
3082 request_metadata_state* state =
3083 make_request_metadata_state(expected_error, nullptr, 0);
3084 grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success,
3085 aws_external_account_creds_httpcli_post_success);
3086 run_request_metadata_test(creds.get(), auth_md_ctx, state);
3087 grpc_core::ExecCtx::Get()->Flush();
3088 grpc_httpcli_set_override(nullptr, nullptr);
3089 GRPC_ERROR_UNREF(error);
3092 static void test_external_account_credentials_create_success(void) {
3094 const char* url_options_string =
3095 "{\"type\":\"external_account\",\"audience\":\"audience\",\"subject_"
3096 "token_type\":\"subject_token_type\",\"service_account_impersonation_"
3097 "url\":\"service_account_impersonation_url\",\"token_url\":\"https://"
3098 "foo.com:5555/token\",\"token_info_url\":\"https://foo.com:5555/"
3099 "token_info\",\"credential_source\":{\"url\":\"https://foo.com:5555/"
3100 "generate_subject_token_format_json\",\"headers\":{\"Metadata-Flavor\":"
3101 "\"Google\"},\"format\":{\"type\":\"json\",\"subject_token_field_name\":"
3102 "\"access_token\"}},\"quota_project_id\":\"quota_"
3103 "project_id\",\"client_id\":\"client_id\",\"client_secret\":\"client_"
3105 const char* url_scopes_string = "scope1,scope2";
3106 grpc_call_credentials* url_creds = grpc_external_account_credentials_create(
3107 url_options_string, url_scopes_string);
3108 GPR_ASSERT(url_creds != nullptr);
3111 const char* file_options_string =
3112 "{\"type\":\"external_account\",\"audience\":\"audience\",\"subject_"
3113 "token_type\":\"subject_token_type\",\"service_account_impersonation_"
3114 "url\":\"service_account_impersonation_url\",\"token_url\":\"https://"
3115 "foo.com:5555/token\",\"token_info_url\":\"https://foo.com:5555/"
3116 "token_info\",\"credential_source\":{\"file\":\"credentials_file_path\"},"
3117 "\"quota_project_id\":\"quota_"
3118 "project_id\",\"client_id\":\"client_id\",\"client_secret\":\"client_"
3120 const char* file_scopes_string = "scope1,scope2";
3121 grpc_call_credentials* file_creds = grpc_external_account_credentials_create(
3122 file_options_string, file_scopes_string);
3123 GPR_ASSERT(file_creds != nullptr);
3124 file_creds->Unref();
3126 const char* aws_options_string =
3127 "{\"type\":\"external_account\",\"audience\":\"audience\",\"subject_"
3128 "token_type\":\"subject_token_type\",\"service_account_impersonation_"
3129 "url\":\"service_account_impersonation_url\",\"token_url\":\"https://"
3130 "foo.com:5555/token\",\"token_info_url\":\"https://foo.com:5555/"
3131 "token_info\",\"credential_source\":{\"environment_id\":\"aws1\","
3132 "\"region_url\":\"https://foo.com:5555/region_url\",\"url\":\"https://"
3133 "foo.com:5555/url\",\"regional_cred_verification_url\":\"https://"
3134 "foo.com:5555/regional_cred_verification_url_{region}\"},"
3135 "\"quota_project_id\":\"quota_"
3136 "project_id\",\"client_id\":\"client_id\",\"client_secret\":\"client_"
3138 const char* aws_scopes_string = "scope1,scope2";
3139 grpc_call_credentials* aws_creds = grpc_external_account_credentials_create(
3140 aws_options_string, aws_scopes_string);
3141 GPR_ASSERT(aws_creds != nullptr);
3146 test_external_account_credentials_create_failure_invalid_json_format(void) {
3147 const char* options_string = "invalid_json";
3148 grpc_call_credentials* creds =
3149 grpc_external_account_credentials_create(options_string, "");
3150 GPR_ASSERT(creds == nullptr);
3154 test_external_account_credentials_create_failure_invalid_options_format(void) {
3155 const char* options_string = "{\"random_key\":\"random_value\"}";
3156 grpc_call_credentials* creds =
3157 grpc_external_account_credentials_create(options_string, "");
3158 GPR_ASSERT(creds == nullptr);
3162 test_external_account_credentials_create_failure_invalid_options_credential_source(
3164 const char* options_string =
3165 "{\"type\":\"external_account\",\"audience\":\"audience\",\"subject_"
3166 "token_type\":\"subject_token_type\",\"service_account_impersonation_"
3167 "url\":\"service_account_impersonation_url\",\"token_url\":\"https://"
3168 "foo.com:5555/token\",\"token_info_url\":\"https://foo.com:5555/"
3169 "token_info\",\"credential_source\":{\"random_key\":\"random_value\"},"
3170 "\"quota_project_id\":\"quota_"
3171 "project_id\",\"client_id\":\"client_id\",\"client_secret\":\"client_"
3173 grpc_call_credentials* creds =
3174 grpc_external_account_credentials_create(options_string, "");
3175 GPR_ASSERT(creds == nullptr);
3178 int main(int argc, char** argv) {
3179 grpc::testing::TestEnvironment env(argc, argv);
3181 test_empty_md_array();
3182 test_add_to_empty_md_array();
3183 test_add_abunch_to_md_array();
3184 test_oauth2_token_fetcher_creds_parsing_ok();
3185 test_oauth2_token_fetcher_creds_parsing_bad_http_status();
3186 test_oauth2_token_fetcher_creds_parsing_empty_http_body();
3187 test_oauth2_token_fetcher_creds_parsing_invalid_json();
3188 test_oauth2_token_fetcher_creds_parsing_missing_token();
3189 test_oauth2_token_fetcher_creds_parsing_missing_token_type();
3190 test_oauth2_token_fetcher_creds_parsing_missing_token_lifetime();
3191 test_google_iam_creds();
3192 test_access_token_creds();
3193 test_channel_oauth2_composite_creds();
3194 test_oauth2_google_iam_composite_creds();
3195 test_channel_oauth2_google_iam_composite_creds();
3196 test_compute_engine_creds_success();
3197 test_compute_engine_creds_failure();
3198 test_refresh_token_creds_success();
3199 test_refresh_token_creds_failure();
3200 test_valid_sts_creds_options();
3201 test_invalid_sts_creds_options();
3202 test_sts_creds_success();
3203 test_sts_creds_no_actor_token_success();
3204 test_sts_creds_load_token_failure();
3205 test_sts_creds_http_failure();
3206 test_sts_creds_token_file_not_found();
3207 test_jwt_creds_lifetime();
3208 test_jwt_creds_success();
3209 test_jwt_creds_signing_failure();
3210 test_google_default_creds_auth_key();
3211 test_google_default_creds_refresh_token();
3212 test_google_default_creds_gce();
3213 test_google_default_creds_non_gce();
3214 test_no_google_default_creds();
3215 test_google_default_creds_call_creds_specified();
3216 test_google_default_creds_not_default();
3217 test_metadata_plugin_success();
3218 test_metadata_plugin_failure();
3219 test_get_well_known_google_credentials_file_path();
3220 test_channel_creds_duplicate_without_call_creds();
3221 test_auth_metadata_context();
3222 test_external_account_creds_success();
3223 test_external_account_creds_success_with_url_encode();
3224 test_external_account_creds_success_with_service_account_impersonation();
3225 test_external_account_creds_failure_invalid_token_url();
3226 test_external_account_creds_failure_invalid_service_account_impersonation_url();
3227 test_external_account_creds_failure_token_exchange_response_missing_access_token();
3228 test_url_external_account_creds_success_format_text();
3229 test_url_external_account_creds_success_format_json();
3230 test_url_external_account_creds_failure_invalid_credential_source_url();
3231 test_url_external_account_creds_success_with_qurey_params_format_text();
3232 test_file_external_account_creds_success_format_text();
3233 test_file_external_account_creds_success_format_json();
3234 test_file_external_account_creds_failure_file_not_found();
3235 test_file_external_account_creds_failure_invalid_json_content();
3236 test_aws_external_account_creds_success();
3237 test_aws_external_account_creds_success_path_region_env_keys_url();
3238 test_aws_external_account_creds_success_path_region_url_keys_env();
3239 test_aws_external_account_creds_success_path_region_env_keys_env();
3240 test_aws_external_account_creds_failure_unmatched_environment_id();
3241 test_aws_external_account_creds_failure_invalid_region_url();
3242 test_aws_external_account_creds_failure_invalid_url();
3243 test_aws_external_account_creds_failure_missing_role_name();
3244 test_aws_external_account_creds_failure_invalid_regional_cred_verification_url();
3245 test_external_account_credentials_create_success();
3246 test_external_account_credentials_create_failure_invalid_json_format();
3247 test_external_account_credentials_create_failure_invalid_options_format();
3248 test_external_account_credentials_create_failure_invalid_options_credential_source();