Imported Upstream version 1.36.0
[platform/upstream/grpc.git] / test / core / security / credentials_test.cc
1 /*
2  *
3  * Copyright 2015 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18
19 #include <grpc/support/port_platform.h>
20
21 #include "src/core/lib/security/credentials/credentials.h"
22
23 #include <openssl/rsa.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include <string>
28
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"
33
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>
40
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"
59
60 using grpc_core::internal::grpc_flush_cached_google_default_credentials;
61 using grpc_core::internal::set_gce_tenancy_checker_for_testing;
62
63 /* -- Constants. -- */
64
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";
69
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"
76     "qg"
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"
88     "G"
89     "W303SQv2cZTdbeaLKJbB5drz3eo3j7dDKjrTD9JupixFbzcGw\\n8FZi5c8idxiwC36kbAL6Hz"
90     "A"
91     "ZoX+ofI0CQE6KCzPJTtYNqyShgKAZdJ8hwOcvCZtf\\n6z8RJm0+"
92     "6YBd38lfh5j8mZd7aHFf6I17j5AQY7oPEc47TjJj/"
93     "5nZ68ECQQDvYuI3\\nLyK5fS8g0SYbmPOL9TlcHDOqwG0mrX9qpg5DC2fniXNSrrZ64GTDKdzZ"
94     "Y"
95     "Ap6LI9W\\nIqv4vr6y38N79TTC\\n-----END PRIVATE KEY-----\\n\", ";
96 static const char test_json_key_str_part3[] =
97     "\"private_key_id\": \"e6b5137873db8d2ef81e06a47289e6434ec8a165\", "
98     "\"client_email\": "
99     "\"777-abaslkan11hlb6nmim3bpspl31ud@developer.gserviceaccount."
100     "com\", \"client_id\": "
101     "\"777-abaslkan11hlb6nmim3bpspl31ud.apps.googleusercontent."
102     "com\", \"type\": \"service_account\" }";
103
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\"}";
110
111 static const char valid_oauth2_json_response[] =
112     "{\"access_token\":\"ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_\","
113     " \"expires_in\":3599, "
114     " \"token_type\":\"Bearer\"}";
115
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\"}";
121
122 static const char test_scope[] = "perm1 perm2";
123
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";
135
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";
138
139 static const char test_sts_endpoint_url[] =
140     "https://foo.com:5555/v1/token-exchange";
141
142 static const char test_method[] = "ThisIsNotAMethod";
143
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\"}";
148
149 static const char
150     valid_external_account_creds_service_account_impersonation_response[] =
151         "{\"accessToken\":\"service_account_impersonation_access_token\","
152         " \"expireTime\":\"2050-01-01T00:00:00Z\"}";
153
154 static const char
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\"}}";
158
159 static const char
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\"}}";
164
165 static const char
166     valid_url_external_account_creds_retrieve_subject_token_response_format_text
167         [] = "test_subject_token";
168
169 static const char
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_"
174         "token\"}}";
175
176 static const char
177     valid_url_external_account_creds_retrieve_subject_token_response_format_json
178         [] = "{\"access_token\":\"test_subject_token\"}";
179
180 static const char
181     invalid_url_external_account_creds_options_credential_source[] =
182         "{\"url\":\"invalid_credential_source_url\","
183         "\"headers\":{\"Metadata-Flavor\":\"Google\"}}";
184
185 static const char
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\"}";
189
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}\"}";
196
197 static const char
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}\"}";
204
205 static const char
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}\"}";
212
213 static const char
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}\"}";
220
221 static const char
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}\"}";
228
229 static const char
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\"}";
236
237 /*  -- Global state flags. -- */
238
239 static bool g_test_is_on_gce = false;
240
241 static bool g_test_gce_tenancy_checker_called = false;
242
243 /* -- Utils. -- */
244
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);
256   return result;
257 }
258
259 static grpc_httpcli_response http_response(int status, const char* body) {
260   grpc_httpcli_response response;
261   response = {};
262   response.status = status;
263   response.body = gpr_strdup(const_cast<char*>(body));
264   response.body_length = strlen(body);
265   return response;
266 }
267
268 /* -- Tests. -- */
269
270 static void test_empty_md_array(void) {
271   grpc_core::ExecCtx exec_ctx;
272   grpc_credentials_mdelem_array md_array;
273   md_array = {};
274   GPR_ASSERT(md_array.md == nullptr);
275   GPR_ASSERT(md_array.size == 0);
276   grpc_credentials_mdelem_array_destroy(&md_array);
277 }
278
279 static void test_add_to_empty_md_array(void) {
280   grpc_core::ExecCtx exec_ctx;
281   grpc_credentials_mdelem_array md_array;
282   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);
292 }
293
294 static void test_add_abunch_to_md_array(void) {
295   grpc_core::ExecCtx exec_ctx;
296   grpc_credentials_mdelem_array md_array;
297   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);
305   }
306   for (size_t i = 0; i < num_entries; ++i) {
307     GPR_ASSERT(grpc_mdelem_eq(md_array.md[i], md));
308   }
309   GRPC_MDELEM_UNREF(md);
310   grpc_credentials_mdelem_array_destroy(&md_array);
311 }
312
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_") ==
325              0);
326   GRPC_MDELEM_UNREF(token_md);
327   grpc_http_response_destroy(&response);
328 }
329
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);
340 }
341
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);
351 }
352
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 =
358       http_response(200,
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);
366 }
367
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,
373                                                  "{"
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);
380 }
381
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 =
387       http_response(200,
388                     "{\"access_token\":\"ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_\","
389                     " \"expires_in\":3599, "
390                     "}");
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);
395 }
396
397 static void test_oauth2_token_fetcher_creds_parsing_missing_token_lifetime(
398     void) {
399   grpc_core::ExecCtx exec_ctx;
400   grpc_mdelem token_md = GRPC_MDNULL;
401   grpc_millis token_lifetime;
402   grpc_httpcli_response response =
403       http_response(200,
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);
410 }
411
412 typedef struct {
413   const char* key;
414   const char* value;
415 } expected_md;
416
417 typedef struct {
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;
426
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) {
430     size_t j;
431     for (j = 0; j < md_array->size; ++j) {
432       if (0 ==
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);
436         break;
437       }
438     }
439     if (j == md_array->size) {
440       gpr_log(GPR_ERROR, "key %s not found", expected[i].key);
441       GPR_ASSERT(0);
442     }
443   }
444 }
445
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);
453   } else {
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;
458     GPR_ASSERT(
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);
462   }
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));
469   gpr_free(state);
470 }
471
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;
480   state->pollent =
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);
484   return state;
485 }
486
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,
493                                   &error)) {
494     // Synchronous result.  Invoke the callback directly.
495     check_request_metadata(state, error);
496     GRPC_ERROR_UNREF(error);
497   }
498 }
499
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,
510       nullptr);
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,
514                                             nullptr, nullptr};
515   run_request_metadata_test(creds, auth_md_ctx, state);
516   creds->Unref();
517 }
518
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,
527                                             nullptr, nullptr};
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);
532   creds->Unref();
533 }
534
535 namespace {
536 class check_channel_oauth2 final : public grpc_channel_credentials {
537  public:
538   check_channel_oauth2() : grpc_channel_credentials("mock") {}
539   ~check_channel_oauth2() override = default;
540
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) ==
549                0);
550     return nullptr;
551   }
552 };
553 }  // namespace
554
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,
563                                                 nullptr);
564   grpc_channel_credentials_release(channel_creds);
565   grpc_call_credentials_release(oauth2_creds);
566   channel_oauth2_creds->create_security_connector(nullptr, nullptr, nullptr,
567                                                   &new_args);
568   grpc_channel_credentials_release(channel_oauth2_creds);
569 }
570
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,
582                                             nullptr, nullptr};
583   grpc_call_credentials* oauth2_creds = grpc_md_only_test_credentials_create(
584       "authorization", test_oauth2_bearer_token, false);
585
586   /* Check security level of fake credentials. */
587   GPR_ASSERT(oauth2_creds->min_security_level() == GRPC_SECURITY_NONE);
588
589   grpc_call_credentials* google_iam_creds = grpc_google_iam_credentials_create(
590       test_google_iam_authorization_token, test_google_iam_authority_selector,
591       nullptr);
592   grpc_call_credentials* composite_creds =
593       grpc_composite_call_credentials_create(oauth2_creds, google_iam_creds,
594                                              nullptr);
595   /* Check security level of composite credentials. */
596   GPR_ASSERT(composite_creds->min_security_level() ==
597              GRPC_PRIVACY_AND_INTEGRITY);
598
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)
605           ->inner();
606   GPR_ASSERT(creds_list.size() == 2);
607   GPR_ASSERT(strcmp(creds_list[0]->type(), GRPC_CALL_CREDENTIALS_TYPE_OAUTH2) ==
608              0);
609   GPR_ASSERT(strcmp(creds_list[1]->type(), GRPC_CALL_CREDENTIALS_TYPE_IAM) ==
610              0);
611   run_request_metadata_test(composite_creds, auth_md_ctx, state);
612   composite_creds->Unref();
613 }
614
615 namespace {
616 class check_channel_oauth2_google_iam final : public grpc_channel_credentials {
617  public:
618   check_channel_oauth2_google_iam() : grpc_channel_credentials("mock") {}
619   ~check_channel_oauth2_google_iam() override = default;
620
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);
628     GPR_ASSERT(
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())
632             ->inner();
633     GPR_ASSERT(
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) ==
636                0);
637     return nullptr;
638   }
639 };
640 }  // namespace
641
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,
651                                                 nullptr);
652   grpc_call_credentials* google_iam_creds = grpc_google_iam_credentials_create(
653       test_google_iam_authorization_token, test_google_iam_authority_selector,
654       nullptr);
655
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);
663
664   channel_oauth2_iam_creds->create_security_connector(nullptr, nullptr, nullptr,
665                                                       &new_args);
666
667   grpc_channel_credentials_release(channel_oauth2_iam_creds);
668 }
669
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);
674   GPR_ASSERT(
675       strcmp(request->http.path,
676              "/computeMetadata/v1/instance/service-accounts/default/token") ==
677       0);
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);
681 }
682
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);
689   return 1;
690 }
691
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);
698   return 1;
699 }
700
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);
706   return 1;
707 }
708
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);
713   return 1;
714 }
715
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,
726                                             nullptr, nullptr};
727   /* Check security level. */
728   GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
729
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();
737
738   /* Second request: the cached token should be served directly. */
739   state =
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();
745
746   GPR_ASSERT(
747       strcmp(creds->debug_string().c_str(), expected_creds_debug_string) == 0);
748   creds->Unref();
749   grpc_httpcli_set_override(nullptr, nullptr);
750 }
751
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."),
760       nullptr, 0);
761   grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
762                                             nullptr, nullptr};
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);
768   GPR_ASSERT(
769       strcmp(creds->debug_string().c_str(), expected_creds_debug_string) == 0);
770   creds->Unref();
771   grpc_httpcli_set_override(nullptr, nullptr);
772 }
773
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);
787   GPR_ASSERT(
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);
793 }
794
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);
802   return 1;
803 }
804
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);
813   return 1;
814 }
815
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,
824                                             nullptr, nullptr};
825   grpc_call_credentials* creds = grpc_google_refresh_token_credentials_create(
826       test_refresh_token_str, nullptr);
827
828   /* Check security level. */
829   GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
830
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();
838
839   /* Second request: the cached token should be served directly. */
840   state =
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();
846   GPR_ASSERT(
847       strcmp(creds->debug_string().c_str(), expected_creds_debug_string) == 0);
848
849   creds->Unref();
850   grpc_httpcli_set_override(nullptr, nullptr);
851 }
852
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."),
861       nullptr, 0);
862   grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
863                                             nullptr, nullptr};
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);
869   GPR_ASSERT(
870       strcmp(creds->debug_string().c_str(), expected_creds_debug_string) == 0);
871
872   creds->Unref();
873   grpc_httpcli_set_override(nullptr, nullptr);
874 }
875
876 static void test_valid_sts_creds_options(void) {
877   grpc_sts_credentials_options valid_options = {
878       test_sts_endpoint_url,        // sts_endpoint_url
879       nullptr,                      // resource
880       nullptr,                      // audience
881       nullptr,                      // scope
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
887   };
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");
896 }
897
898 static void test_invalid_sts_creds_options(void) {
899   grpc_sts_credentials_options invalid_options = {
900       test_sts_endpoint_url,       // sts_endpoint_url
901       nullptr,                     // resource
902       nullptr,                     // audience
903       nullptr,                     // scope
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
909   };
910   absl::StatusOr<grpc_core::URI> url_should_be_invalid =
911       grpc_core::ValidateStsCredentialsOptions(&invalid_options);
912   GPR_ASSERT(!url_should_be_invalid.ok());
913
914   invalid_options = {
915       test_sts_endpoint_url,        // sts_endpoint_url
916       nullptr,                      // resource
917       nullptr,                      // audience
918       nullptr,                      // scope
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
924   };
925   url_should_be_invalid =
926       grpc_core::ValidateStsCredentialsOptions(&invalid_options);
927   GPR_ASSERT(!url_should_be_invalid.ok());
928
929   invalid_options = {
930       nullptr,                      // sts_endpoint_url (Required)
931       nullptr,                      // resource
932       nullptr,                      // audience
933       nullptr,                      // scope
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
939   };
940   url_should_be_invalid =
941       grpc_core::ValidateStsCredentialsOptions(&invalid_options);
942   GPR_ASSERT(!url_should_be_invalid.ok());
943
944   invalid_options = {
945       "not_a_valid_uri",            // sts_endpoint_url
946       nullptr,                      // resource
947       nullptr,                      // audience
948       nullptr,                      // scope
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
954   };
955   url_should_be_invalid =
956       grpc_core::ValidateStsCredentialsOptions(&invalid_options);
957   GPR_ASSERT(!url_should_be_invalid.ok());
958
959   invalid_options = {
960       "ftp://ftp.is.not.a.valid.scheme/bar",  // sts_endpoint_url
961       nullptr,                                // resource
962       nullptr,                                // audience
963       nullptr,                                // scope
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
969   };
970   url_should_be_invalid =
971       grpc_core::ValidateStsCredentialsOptions(&invalid_options);
972   GPR_ASSERT(!url_should_be_invalid.ok());
973 }
974
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());
983   }
984   GPR_ASSERT(it->second == expected_val);
985 }
986
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);
998   if (!url.ok()) {
999     gpr_log(GPR_ERROR, "%s", url.status().ToString().c_str());
1000     GPR_ASSERT(url.ok());
1001   }
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);
1013   } else {
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());
1018   }
1019
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);
1027 }
1028
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);
1037   return 1;
1038 }
1039
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);
1047   return 1;
1048 }
1049
1050 static char* write_tmp_jwt_file(const char* jwt_contents) {
1051   char* path;
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);
1057   fclose(tmp);
1058   return path;
1059 }
1060
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,
1069                                             nullptr, nullptr};
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
1076       "scope",                     // scope
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
1082   };
1083   grpc_call_credentials* creds =
1084       grpc_sts_credentials_create(&valid_options, nullptr);
1085
1086   /* Check security level. */
1087   GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
1088
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();
1096
1097   /* Second request: the cached token should be served directly. */
1098   state =
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();
1104   GPR_ASSERT(
1105       strcmp(creds->debug_string().c_str(), expected_creds_debug_string) == 0);
1106
1107   creds->Unref();
1108   grpc_httpcli_set_override(nullptr, nullptr);
1109   gpr_free(subject_token_path);
1110   gpr_free(actor_token_path);
1111 }
1112
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,
1116                                             nullptr, nullptr};
1117   grpc_sts_credentials_options valid_options = {
1118       test_sts_endpoint_url,           // sts_endpoint_url
1119       "resource",                      // resource
1120       "audience",                      // audience
1121       "scope",                         // scope
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
1127   };
1128   grpc_call_credentials* creds =
1129       grpc_sts_credentials_create(&valid_options, nullptr);
1130
1131   /* Check security level. */
1132   GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
1133
1134   request_metadata_state* state = make_request_metadata_state(
1135       GRPC_ERROR_CREATE_FROM_STATIC_STRING(
1136           "Error occurred when fetching oauth2 token."),
1137       nullptr, 0);
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();
1142
1143   /* Cleanup. */
1144   creds->Unref();
1145   grpc_httpcli_set_override(nullptr, nullptr);
1146 }
1147
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,
1156                                             nullptr, nullptr};
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
1162       "scope",                     // scope
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
1168   };
1169   grpc_call_credentials* creds =
1170       grpc_sts_credentials_create(&valid_options, nullptr);
1171
1172   /* Check security level. */
1173   GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
1174
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();
1182
1183   /* Second request: the cached token should be served directly. */
1184   state =
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();
1190   GPR_ASSERT(
1191       strcmp(creds->debug_string().c_str(), expected_creds_debug_string) == 0);
1192
1193   creds->Unref();
1194   grpc_httpcli_set_override(nullptr, nullptr);
1195   gpr_free(subject_token_path);
1196 }
1197
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."),
1206       nullptr, 0);
1207   grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
1208                                             nullptr, nullptr};
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
1214       "scope",                     // scope
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
1220   };
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);
1225   GPR_ASSERT(
1226       strcmp(creds->debug_string().c_str(), expected_creds_debug_string) == 0);
1227
1228   creds->Unref();
1229   grpc_httpcli_set_override(nullptr, nullptr);
1230   gpr_free(test_signed_jwt_path);
1231 }
1232
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."),
1241       nullptr, 0);
1242   grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
1243                                             nullptr, nullptr};
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
1249       "scope",                     // scope
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
1255   };
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);
1261   GPR_ASSERT(
1262       strcmp(creds->debug_string().c_str(), expected_creds_debug_string) == 0);
1263   creds->Unref();
1264   grpc_httpcli_set_override(nullptr, nullptr);
1265   gpr_free(test_signed_jwt_path);
1266 }
1267
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);
1289 }
1290
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);
1297 }
1298
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);
1304   return nullptr;
1305 }
1306
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);
1311   return nullptr;
1312 }
1313
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);
1319 }
1320
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:";
1325   // Max lifetime.
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);
1337
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);
1349
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);
1361
1362   gpr_free(json_key_string);
1363 }
1364
1365 static void test_jwt_creds_success(void) {
1366   const char expected_creds_debug_string_prefix[] =
1367       "JWTAccessCredentials{ExpirationTime:";
1368
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,
1372                                             nullptr, nullptr};
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);
1378
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();
1385
1386   /* Second request: the cached token should be served directly. */
1387   state =
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();
1393
1394   /* Third request: Different service url so jwt_encode_and_sign should be
1395      called again (no caching). */
1396   state =
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);
1405
1406   creds->Unref();
1407   gpr_free(json_key_string);
1408   grpc_jwt_encode_and_sign_set_override(nullptr);
1409 }
1410
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,
1417                                             nullptr, nullptr};
1418   request_metadata_state* state = make_request_metadata_state(
1419       GRPC_ERROR_CREATE_FROM_STATIC_STRING("Could not generate JWT."), nullptr,
1420       0);
1421   grpc_call_credentials* creds =
1422       grpc_service_account_jwt_access_credentials_create(
1423           json_key_string, grpc_max_auth_token_lifetime(), nullptr);
1424
1425   grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_failure);
1426   run_request_metadata_test(creds, auth_md_ctx, state);
1427
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);
1432
1433   creds->Unref();
1434   grpc_jwt_encode_and_sign_set_override(nullptr);
1435 }
1436
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);
1445   fclose(creds_file);
1446   gpr_setenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, creds_file_name);
1447   gpr_free(creds_file_name);
1448 }
1449
1450 static bool test_gce_tenancy_checker(void) {
1451   g_test_gce_tenancy_checker_called = true;
1452   return g_test_is_on_gce;
1453 }
1454
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);
1465   gpr_free(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);
1472   auto* jwt =
1473       reinterpret_cast<const grpc_service_account_jwt_access_credentials*>(
1474           creds->call_creds());
1475   GPR_ASSERT(
1476       strcmp(jwt->key().client_id,
1477              "777-abaslkan11hlb6nmim3bpspl31ud.apps.googleusercontent.com") ==
1478       0);
1479   GPR_ASSERT(g_test_gce_tenancy_checker_called == false);
1480   creds->Unref();
1481   gpr_setenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, ""); /* Reset. */
1482 }
1483
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);
1496   auto* refresh =
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);
1501   creds->Unref();
1502   gpr_setenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, ""); /* Reset. */
1503 }
1504
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);
1518   return 1;
1519 }
1520
1521 static std::string null_well_known_creds_path_getter(void) { return ""; }
1522
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,
1530                                             nullptr, nullptr};
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;
1538
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));
1543
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();
1551
1552   GPR_ASSERT(g_test_gce_tenancy_checker_called == true);
1553
1554   /* Cleanup. */
1555   creds->Unref();
1556   grpc_httpcli_set_override(nullptr, nullptr);
1557   grpc_override_well_known_credentials_path_getter(nullptr);
1558 }
1559
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,
1567                                             nullptr, nullptr};
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);
1590   /* Cleanup. */
1591   creds->Unref();
1592   grpc_httpcli_set_override(nullptr, nullptr);
1593   grpc_override_well_known_credentials_path_getter(nullptr);
1594 }
1595
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);
1604   return 1;
1605 }
1606
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);
1624   /* Cleanup. */
1625   grpc_override_well_known_credentials_path_getter(nullptr);
1626   grpc_httpcli_set_override(nullptr, nullptr);
1627 }
1628
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,
1635                                             nullptr, nullptr};
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,
1655                             state);
1656   grpc_core::ExecCtx::Get()->Flush();
1657   channel_creds->Unref();
1658   grpc_httpcli_set_override(nullptr, nullptr);
1659 }
1660
1661 struct fake_call_creds : public grpc_call_credentials {
1662  public:
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);
1669   }
1670
1671   ~fake_call_creds() override { GRPC_MDELEM_UNREF(dummy_md_); }
1672
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_);
1679     return true;
1680   }
1681
1682   void cancel_get_request_metadata(grpc_credentials_mdelem_array* /*md_array*/,
1683                                    grpc_error* /*error*/) override {}
1684
1685  private:
1686   grpc_mdelem dummy_md_;
1687 };
1688
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,
1694                                             nullptr, nullptr};
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,
1712                             state);
1713   grpc_core::ExecCtx::Get()->Flush();
1714   channel_creds->Unref();
1715   grpc_httpcli_set_override(nullptr, nullptr);
1716 }
1717
1718 typedef enum {
1719   PLUGIN_INITIAL_STATE,
1720   PLUGIN_GET_METADATA_CALLED_STATE,
1721   PLUGIN_DESTROY_CALLED_STATE
1722 } plugin_state;
1723
1724 static const expected_md plugin_md[] = {{"foo", "bar"}, {"hi", "there"}};
1725
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);
1744   }
1745   *num_creds_md = GPR_ARRAY_SIZE(plugin_md);
1746   return true;  // Synchronous return.
1747 }
1748
1749 static const char* plugin_error_details = "Could not get metadata for plugin.";
1750
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.
1766 }
1767
1768 static void plugin_destroy(void* state) {
1769   plugin_state* s = static_cast<plugin_state*>(state);
1770   *s = PLUGIN_DESTROY_CALLED_STATE;
1771 }
1772
1773 static char* plugin_debug_string(void* state) {
1774   plugin_state* s = static_cast<plugin_state*>(state);
1775   char* ret = nullptr;
1776   switch (*s) {
1777     case PLUGIN_INITIAL_STATE:
1778       gpr_asprintf(&ret, "TestPluginCredentials{state:INITIAL}");
1779       break;
1780     case PLUGIN_GET_METADATA_CALLED_STATE:
1781       gpr_asprintf(&ret, "TestPluginCredentials{state:GET_METADATA_CALLED}");
1782       break;
1783     case PLUGIN_DESTROY_CALLED_STATE:
1784       gpr_asprintf(&ret, "TestPluginCredentials{state:DESTROY}");
1785       break;
1786     default:
1787       gpr_asprintf(&ret, "TestPluginCredentials{state:UNKNOWN}");
1788       break;
1789   }
1790   return ret;
1791 }
1792
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,
1800                                             nullptr, nullptr};
1801   request_metadata_state* md_state = make_request_metadata_state(
1802       GRPC_ERROR_NONE, plugin_md, GPR_ARRAY_SIZE(plugin_md));
1803
1804   plugin.state = &state;
1805   plugin.get_metadata = plugin_get_metadata_success;
1806   plugin.destroy = plugin_destroy;
1807   plugin.debug_string = plugin_debug_string;
1808
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);
1816   GPR_ASSERT(
1817       strcmp(creds->debug_string().c_str(), expected_creds_debug_string) == 0);
1818   creds->Unref();
1819
1820   GPR_ASSERT(state == PLUGIN_DESTROY_CALLED_STATE);
1821 }
1822
1823 static void test_metadata_plugin_failure(void) {
1824   const char expected_creds_debug_string[] =
1825       "TestPluginCredentials{state:GET_METADATA_CALLED}";
1826
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,
1831                                             nullptr, nullptr};
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);
1836
1837   plugin.state = &state;
1838   plugin.get_metadata = plugin_get_metadata_failure;
1839   plugin.destroy = plugin_destroy;
1840   plugin.debug_string = plugin_debug_string;
1841
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);
1847   GPR_ASSERT(
1848       strcmp(creds->debug_string().c_str(), expected_creds_debug_string) == 0);
1849   creds->Unref();
1850
1851   GPR_ASSERT(state == PLUGIN_DESTROY_CALLED_STATE);
1852 }
1853
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) {
1874     if (home) {
1875       gpr_setenv("HOME", home);
1876     } else {
1877       gpr_unsetenv("HOME");
1878     }
1879   }
1880   gpr_free(home);
1881 }
1882
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;
1887
1888   grpc_channel_credentials* channel_creds =
1889       grpc_fake_transport_security_credentials_create();
1890
1891   grpc_core::RefCountedPtr<grpc_channel_credentials> dup =
1892       channel_creds->duplicate_without_call_credentials();
1893   GPR_ASSERT(dup == channel_creds);
1894   dup.reset();
1895
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,
1900                                                 nullptr);
1901   GPR_ASSERT(strcmp(call_creds->debug_string().c_str(),
1902                     expected_creds_debug_string) == 0);
1903
1904   call_creds->Unref();
1905   dup = composite_creds->duplicate_without_call_credentials();
1906   GPR_ASSERT(dup == channel_creds);
1907   dup.reset();
1908
1909   channel_creds->Unref();
1910   composite_creds->Unref();
1911 }
1912
1913 typedef struct {
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;
1920
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", ""},
1925       // No method.
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/", ""},
1929       // Empty method.
1930       {"https", "www.foo.com", "/Service/", "https://www.foo.com/Service", ""},
1931       // Malformed url.
1932       {"https", "www.foo.com:", "/Service/", "https://www.foo.com:/Service",
1933        ""},
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);
1969       GPR_ASSERT(false);
1970     }
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);
1975       GPR_ASSERT(false);
1976     }
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);
1981   }
1982 }
1983
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);
1995   if (!uri.ok()) {
1996     gpr_log(GPR_ERROR, "%s", uri.status().ToString().c_str());
1997     GPR_ASSERT(uri.ok());
1998   }
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");
2008
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);
2019 }
2020
2021 static void
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);
2029   GPR_ASSERT(
2030       strcmp(
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") ==
2037       0);
2038
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);
2049 }
2050
2051 static void
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);
2070 }
2071
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,
2078                                                           body_size, true);
2079     *response = http_response(
2080         200, valid_external_account_creds_token_exchange_response);
2081   } else if (strcmp(request->http.path, "/service_account_impersonation") ==
2082              0) {
2083     validate_external_account_creds_service_account_impersonation_request(
2084         request, body, body_size, true);
2085     *response = http_response(
2086         200,
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);
2093   }
2094   grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, GRPC_ERROR_NONE);
2095   return 1;
2096 }
2097
2098 static int
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") ==
2109              0) {
2110     *response = http_response(
2111         200,
2112         valid_external_account_creds_service_account_impersonation_response);
2113   }
2114   grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, GRPC_ERROR_NONE);
2115   return 1;
2116 }
2117
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(
2123         200,
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") ==
2126              0) {
2127     *response = http_response(
2128         200,
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(
2133         200,
2134         valid_url_external_account_creds_retrieve_subject_token_response_format_json);
2135   }
2136   grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, GRPC_ERROR_NONE);
2137   return 1;
2138 }
2139
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);
2170 }
2171
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);
2184   }
2185   grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, GRPC_ERROR_NONE);
2186   return 1;
2187 }
2188
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,
2195                                                               body_size, true);
2196     *response = http_response(
2197         200, valid_external_account_creds_token_exchange_response);
2198   }
2199   grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, GRPC_ERROR_NONE);
2200   return 1;
2201 }
2202
2203 // The subclass of ExternalAccountCredentials for testing.
2204 // ExternalAccountCredentials is an abstract class so we can't directly test
2205 // against it.
2206 class TestExternalAccountCredentials final
2207     : public grpc_core::ExternalAccountCredentials {
2208  public:
2209   TestExternalAccountCredentials(Options options,
2210                                  std::vector<std::string> scopes)
2211       : ExternalAccountCredentials(std::move(options), std::move(scopes)) {}
2212
2213  protected:
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);
2218   }
2219 };
2220
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,
2225                                             nullptr, nullptr};
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;
2238   };
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. */
2250   state =
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);
2257 }
2258
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,
2263                                             nullptr, nullptr};
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;
2276   };
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);
2285 }
2286
2287 static void
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,
2293                                             nullptr, nullptr};
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;
2306   };
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);
2318 }
2319
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,
2323                                             nullptr, nullptr};
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;
2336   };
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);
2350 }
2351
2352 static void
2353 test_external_account_creds_failure_invalid_service_account_impersonation_url(
2354     void) {
2355   grpc_core::ExecCtx exec_ctx;
2356   grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
2357                                             nullptr, nullptr};
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;
2370   };
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);
2385 }
2386
2387 static void
2388 test_external_account_creds_failure_token_exchange_response_missing_access_token(
2389     void) {
2390   grpc_core::ExecCtx exec_ctx;
2391   grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
2392                                             nullptr, nullptr};
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;
2405   };
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);
2422 }
2423
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,
2428                                             nullptr, nullptr};
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,
2432       &error);
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;
2445   };
2446   auto creds =
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);
2458 }
2459
2460 static void
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,
2465                                             nullptr, nullptr};
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,
2469       &error);
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;
2482   };
2483   auto creds =
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);
2495 }
2496
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,
2501                                             nullptr, nullptr};
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,
2505       &error);
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;
2518   };
2519   auto creds =
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);
2531 }
2532
2533 static void
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;
2550   };
2551   auto creds =
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);
2561 }
2562
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,
2567                                             nullptr, nullptr};
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(
2571       absl::StrFormat(
2572           "{\"file\":\"%s\"}",
2573           absl::StrReplaceAll(subject_token_path, {{"\\", "\\\\"}})),
2574       &error);
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;
2587   };
2588   auto creds =
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);
2602 }
2603
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,
2608                                             nullptr, nullptr};
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(
2613       absl::StrFormat(
2614           "{\n"
2615           "\"file\":\"%s\",\n"
2616           "\"format\":\n"
2617           "{\n"
2618           "\"type\":\"json\",\n"
2619           "\"subject_token_field_name\":\"access_token\"\n"
2620           "}\n"
2621           "}",
2622           absl::StrReplaceAll(subject_token_path, {{"\\", "\\\\"}})),
2623       &error);
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;
2636   };
2637   auto creds =
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);
2651 }
2652
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,
2656                                             nullptr, nullptr};
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;
2672   };
2673   auto creds =
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);
2688 }
2689
2690 static void test_file_external_account_creds_failure_invalid_json_content(
2691     void) {
2692   grpc_core::ExecCtx exec_ctx;
2693   grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
2694                                             nullptr, nullptr};
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(
2698       absl::StrFormat(
2699           "{\n"
2700           "\"file\":\"%s\",\n"
2701           "\"format\":\n"
2702           "{\n"
2703           "\"type\":\"json\",\n"
2704           "\"subject_token_field_name\":\"access_token\"\n"
2705           "}\n"
2706           "}",
2707           absl::StrReplaceAll(subject_token_path, {{"\\", "\\\\"}})),
2708       &error);
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;
2721   };
2722   auto creds =
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);
2739 }
2740
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,
2745                                             nullptr, nullptr};
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;
2761   };
2762   auto creds =
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);
2774 }
2775
2776 static void test_aws_external_account_creds_success_path_region_env_keys_url(
2777     void) {
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,
2781                                             nullptr, nullptr};
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;
2798   };
2799   auto creds =
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");
2812 }
2813
2814 static void test_aws_external_account_creds_success_path_region_url_keys_env(
2815     void) {
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,
2819                                             nullptr, nullptr};
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;
2838   };
2839   auto creds =
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");
2854 }
2855
2856 static void test_aws_external_account_creds_success_path_region_env_keys_env(
2857     void) {
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,
2861                                             nullptr, nullptr};
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;
2881   };
2882   auto creds =
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");
2898 }
2899
2900 static void test_aws_external_account_creds_failure_unmatched_environment_id(
2901     void) {
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,
2905       &error);
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;
2918   };
2919   auto creds =
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);
2929 }
2930
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,
2934                                             nullptr, nullptr};
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,
2938       &error);
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;
2951   };
2952   auto creds =
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);
2969 }
2970
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,
2974                                             nullptr, nullptr};
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,
2978       &error);
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;
2991   };
2992   auto creds =
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);
3008 }
3009
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,
3013                                             nullptr, nullptr};
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,
3017       &error);
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;
3030   };
3031   auto creds =
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);
3048 }
3049
3050 static void
3051 test_aws_external_account_creds_failure_invalid_regional_cred_verification_url(
3052     void) {
3053   grpc_core::ExecCtx exec_ctx;
3054   grpc_auth_metadata_context auth_md_ctx = {test_service_url, test_method,
3055                                             nullptr, nullptr};
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,
3059       &error);
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;
3072   };
3073   auto creds =
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);
3090 }
3091
3092 static void test_external_account_credentials_create_success(void) {
3093   // url credentials
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_"
3104       "secret\"}";
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);
3109   url_creds->Unref();
3110   // file credentials
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_"
3119       "secret\"}";
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();
3125   // aws credentials
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_"
3137       "secret\"}";
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);
3142   aws_creds->Unref();
3143 }
3144
3145 static void
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);
3151 }
3152
3153 static void
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);
3159 }
3160
3161 static void
3162 test_external_account_credentials_create_failure_invalid_options_credential_source(
3163     void) {
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_"
3172       "secret\"}";
3173   grpc_call_credentials* creds =
3174       grpc_external_account_credentials_create(options_string, "");
3175   GPR_ASSERT(creds == nullptr);
3176 }
3177
3178 int main(int argc, char** argv) {
3179   grpc::testing::TestEnvironment env(argc, argv);
3180   grpc_init();
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();
3249   grpc_shutdown();
3250   return 0;
3251 }