xref: /aosp_15_r20/external/grpc-grpc/test/core/security/credentials_test.cc (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1 //
2 //
3 // Copyright 2015 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18 
19 #include "src/core/lib/security/credentials/credentials.h"
20 
21 #include <stdlib.h>
22 #include <string.h>
23 
24 #include <string>
25 
26 #include <gmock/gmock.h>
27 #include <openssl/rsa.h>
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/port_platform.h>
39 #include <grpc/support/string_util.h>
40 #include <grpc/support/time.h>
41 
42 #include "src/core/lib/channel/channel_args.h"
43 #include "src/core/lib/gpr/string.h"
44 #include "src/core/lib/gpr/tmpfile.h"
45 #include "src/core/lib/gprpp/crash.h"
46 #include "src/core/lib/gprpp/env.h"
47 #include "src/core/lib/gprpp/host_port.h"
48 #include "src/core/lib/gprpp/time.h"
49 #include "src/core/lib/gprpp/unique_type_name.h"
50 #include "src/core/lib/http/httpcli.h"
51 #include "src/core/lib/http/httpcli_ssl_credentials.h"
52 #include "src/core/lib/iomgr/error.h"
53 #include "src/core/lib/json/json_reader.h"
54 #include "src/core/lib/promise/exec_ctx_wakeup_scheduler.h"
55 #include "src/core/lib/promise/promise.h"
56 #include "src/core/lib/promise/seq.h"
57 #include "src/core/lib/security/context/security_context.h"
58 #include "src/core/lib/security/credentials/composite/composite_credentials.h"
59 #include "src/core/lib/security/credentials/external/aws_external_account_credentials.h"
60 #include "src/core/lib/security/credentials/external/external_account_credentials.h"
61 #include "src/core/lib/security/credentials/external/file_external_account_credentials.h"
62 #include "src/core/lib/security/credentials/external/url_external_account_credentials.h"
63 #include "src/core/lib/security/credentials/fake/fake_credentials.h"
64 #include "src/core/lib/security/credentials/google_default/google_default_credentials.h"
65 #include "src/core/lib/security/credentials/iam/iam_credentials.h"
66 #include "src/core/lib/security/credentials/jwt/jwt_credentials.h"
67 #include "src/core/lib/security/credentials/oauth2/oauth2_credentials.h"
68 #include "src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h"
69 #include "src/core/lib/security/credentials/xds/xds_credentials.h"
70 #include "src/core/lib/security/transport/auth_filters.h"
71 #include "src/core/lib/transport/error_utils.h"
72 #include "src/core/lib/uri/uri_parser.h"
73 #include "test/core/util/test_config.h"
74 
75 namespace grpc_core {
76 
77 using internal::grpc_flush_cached_google_default_credentials;
78 using internal::set_gce_tenancy_checker_for_testing;
79 
80 namespace {
81 
82 // -- Constants. --
83 
84 const char test_google_iam_authorization_token[] = "blahblahblhahb";
85 const char test_google_iam_authority_selector[] = "respectmyauthoritah";
86 const char test_oauth2_bearer_token[] = "Bearer blaaslkdjfaslkdfasdsfasf";
87 
88 // This JSON key was generated with the GCE console and revoked immediately.
89 // The identifiers have been changed as well.
90 // Maximum size for a string literal is 509 chars in C89, yay!
91 const char test_json_key_str_part1[] =
92     "{ \"private_key\": \"-----BEGIN PRIVATE KEY-----"
93     "\\nMIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAOEvJsnoHnyHkXcp\\n7mJE"
94     "qg"
95     "WGjiw71NfXByguekSKho65FxaGbsnSM9SMQAqVk7Q2rG+I0OpsT0LrWQtZ\\nyjSeg/"
96     "rWBQvS4hle4LfijkP3J5BG+"
97     "IXDMP8RfziNRQsenAXDNPkY4kJCvKux2xdD\\nOnVF6N7dL3nTYZg+"
98     "uQrNsMTz9UxVAgMBAAECgYEAzbLewe1xe9vy+2GoSsfib+28\\nDZgSE6Bu/"
99     "zuFoPrRc6qL9p2SsnV7txrunTyJkkOnPLND9ABAXybRTlcVKP/sGgza\\n/"
100     "8HpCqFYM9V8f34SBWfD4fRFT+n/"
101     "73cfRUtGXdXpseva2lh8RilIQfPhNZAncenU\\ngqXjDvpkypEusgXAykECQQD+";
102 const char test_json_key_str_part2[] =
103     "53XxNVnxBHsYb+AYEfklR96yVi8HywjVHP34+OQZ\\nCslxoHQM8s+"
104     "dBnjfScLu22JqkPv04xyxmt0QAKm9+vTdAkEA4ib7YvEAn2jXzcCI\\nEkoy2L/"
105     "XydR1GCHoacdfdAwiL2npOdnbvi4ZmdYRPY1LSTO058tQHKVXV7NLeCa3\\nAARh2QJBAMKeDA"
106     "G"
107     "W303SQv2cZTdbeaLKJbB5drz3eo3j7dDKjrTD9JupixFbzcGw\\n8FZi5c8idxiwC36kbAL6Hz"
108     "A"
109     "ZoX+ofI0CQE6KCzPJTtYNqyShgKAZdJ8hwOcvCZtf\\n6z8RJm0+"
110     "6YBd38lfh5j8mZd7aHFf6I17j5AQY7oPEc47TjJj/"
111     "5nZ68ECQQDvYuI3\\nLyK5fS8g0SYbmPOL9TlcHDOqwG0mrX9qpg5DC2fniXNSrrZ64GTDKdzZ"
112     "Y"
113     "Ap6LI9W\\nIqv4vr6y38N79TTC\\n-----END PRIVATE KEY-----\\n\", ";
114 const char test_json_key_str_part3[] =
115     "\"private_key_id\": \"e6b5137873db8d2ef81e06a47289e6434ec8a165\", "
116     "\"client_email\": "
117     "\"[email protected]."
118     "com\", \"client_id\": "
119     "\"777-abaslkan11hlb6nmim3bpspl31ud.apps.googleusercontent."
120     "com\", \"type\": \"service_account\" }";
121 
122 // Test refresh token.
123 const char test_refresh_token_str[] =
124     "{ \"client_id\": \"32555999999.apps.googleusercontent.com\","
125     "  \"client_secret\": \"EmssLNjJy1332hD4KFsecret\","
126     "  \"refresh_token\": \"1/Blahblasj424jladJDSGNf-u4Sua3HDA2ngjd42\","
127     "  \"type\": \"authorized_user\"}";
128 
129 const char test_external_account_credentials_psc_sts_str[] =
130     "{\"type\":\"external_account\",\"audience\":\"audience\",\"subject_"
131     "token_type\":\"subject_token_type\",\"service_account_impersonation_"
132     "url\":\"https://sts-xyz.p.googleapis.com:5555/"
133     "service_account_impersonation_url\",\"token_url\":\"https://"
134     "sts-xyz-123.p.googleapis.com:5555/token\",\"token_info_url\":\"https://"
135     "sts-xyz.p.googleapis.com:5555/introspect"
136     "token_info\",\"credential_source\":{\"file\":\"credentials_file_path\"},"
137     "\"quota_project_id\":\"quota_"
138     "project_id\",\"client_id\":\"client_id\",\"client_secret\":\"client_"
139     "secret\"}";
140 
141 const char test_external_account_credentials_psc_iam_str[] =
142     "{\"type\":\"external_account\",\"audience\":\"audience\",\"subject_"
143     "token_type\":\"subject_token_type\",\"service_account_impersonation_"
144     "url\":\"https://iamcredentials-xyz.p.googleapis.com:5555/"
145     "service_account_impersonation_url\",\"token_url\":\"https://"
146     "iamcredentials-xyz-123.p.googleapis.com:5555/"
147     "token\",\"token_info_url\":\"https://"
148     "iamcredentials-xyz-123.p.googleapis.com:5555/introspect"
149     "token_info\",\"credential_source\":{\"file\":\"credentials_file_path\"},"
150     "\"quota_project_id\":\"quota_"
151     "project_id\",\"client_id\":\"client_id\",\"client_secret\":\"client_"
152     "secret\"}";
153 
154 const char valid_oauth2_json_response[] =
155     "{\"access_token\":\"ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_\","
156     " \"expires_in\":3599, "
157     " \"token_type\":\"Bearer\"}";
158 
159 const char valid_sts_json_response[] =
160     "{\"access_token\":\"ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_\","
161     " \"expires_in\":3599, "
162     " \"issued_token_type\":\"urn:ietf:params:oauth:token-type:access_token\", "
163     " \"token_type\":\"Bearer\"}";
164 
165 const char test_scope[] = "perm1 perm2";
166 
167 const char test_signed_jwt[] =
168     "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImY0OTRkN2M1YWU2MGRmOTcyNmM4YW"
169     "U0MDcyZTViYTdmZDkwODg2YzcifQ";
170 const char test_signed_jwt_token_type[] =
171     "urn:ietf:params:oauth:token-type:id_token";
172 const char test_signed_jwt2[] =
173     "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImY0OTRkN2M1YWU2MGRmOTcyNmM5YW"
174     "U2MDcyZTViYTdnZDkwODg5YzcifQ";
175 const char test_signed_jwt_token_type2[] =
176     "urn:ietf:params:oauth:token-type:jwt";
177 const char test_signed_jwt_path_prefix[] = "test_sign_jwt";
178 
179 const char test_service_url[] = "https://foo.com/foo.v1";
180 const char test_service_url_no_service_name[] = "https://foo.com/";
181 const char other_test_service_url_no_service_name[] = "https://bar.com/";
182 const char test_method[] = "ThisIsNotAMethod";
183 
184 const char kTestUrlScheme[] = "https";
185 const char kTestAuthority[] = "foo.com";
186 const char kTestPath[] = "/foo.v1/ThisIsNotAMethod";
187 const char kTestOtherAuthority[] = "bar.com";
188 const char kTestOtherPath[] = "/bar.v1/ThisIsNotAMethod";
189 
190 const char test_sts_endpoint_url[] = "https://foo.com:5555/v1/token-exchange";
191 
192 const char valid_external_account_creds_token_exchange_response[] =
193     "{\"access_token\":\"token_exchange_access_token\","
194     " \"expires_in\":3599,"
195     " \"token_type\":\"Bearer\"}";
196 
197 const char
198     valid_external_account_creds_service_account_impersonation_response[] =
199         "{\"accessToken\":\"service_account_impersonation_access_token\","
200         " \"expireTime\":\"2050-01-01T00:00:00Z\"}";
201 
202 const char
203     valid_url_external_account_creds_options_credential_source_format_text[] =
204         "{\"url\":\"https://foo.com:5555/generate_subject_token_format_text\","
205         "\"headers\":{\"Metadata-Flavor\":\"Google\"}}";
206 
207 const char
208     valid_url_external_account_creds_options_credential_source_with_qurey_params_format_text
209         [] = "{\"url\":\"https://foo.com:5555/"
210              "path/to/url/creds?p1=v1&p2=v2\","
211              "\"headers\":{\"Metadata-Flavor\":\"Google\"}}";
212 
213 const char
214     valid_url_external_account_creds_retrieve_subject_token_response_format_text
215         [] = "test_subject_token";
216 
217 const char
218     valid_url_external_account_creds_options_credential_source_format_json[] =
219         "{\"url\":\"https://foo.com:5555/generate_subject_token_format_json\","
220         "\"headers\":{\"Metadata-Flavor\":\"Google\"},"
221         "\"format\":{\"type\":\"json\",\"subject_token_field_name\":\"access_"
222         "token\"}}";
223 
224 const char
225     valid_url_external_account_creds_retrieve_subject_token_response_format_json
226         [] = "{\"access_token\":\"test_subject_token\"}";
227 
228 const char invalid_url_external_account_creds_options_credential_source[] =
229     "{\"url\":\"invalid_credential_source_url\","
230     "\"headers\":{\"Metadata-Flavor\":\"Google\"}}";
231 
232 const char valid_aws_external_account_creds_retrieve_signing_keys_response[] =
233     "{\"AccessKeyId\":\"test_access_key_id\",\"SecretAccessKey\":"
234     "\"test_secret_access_key\",\"Token\":\"test_token\"}";
235 
236 const char aws_imdsv2_session_token[] = "imdsv2_session_token";
237 
238 const char valid_aws_external_account_creds_options_credential_source[] =
239     "{\"environment_id\":\"aws1\","
240     "\"region_url\":\"https://169.254.169.254:5555/region_url\","
241     "\"url\":\"https://169.254.169.254:5555/url\","
242     "\"regional_cred_verification_url\":\"https://foo.com:5555/"
243     "regional_cred_verification_url_{region}\"}";
244 
245 const char valid_aws_imdsv2_external_account_creds_options_credential_source[] =
246     "{\"environment_id\":\"aws1\","
247     "\"region_url\":\"http://169.254.169.254:5555/region_url\","
248     "\"url\":\"https://169.254.169.254:5555/url\","
249     "\"imdsv2_session_token_url\":\"https://169.254.169.254/"
250     "imdsv2_session_token_url\","
251     "\"regional_cred_verification_url\":\"https://foo.com:5555/"
252     "regional_cred_verification_url_{region}\"}";
253 
254 const char valid_aws_external_account_creds_options_credential_source_ipv6[] =
255     "{\"environment_id\":\"aws1\","
256     "\"region_url\":\"https://[fd00:ec2::254]:5555/region_url\","
257     "\"url\":\"http://[fd00:ec2::254]:5555/url\","
258     "\"imdsv2_session_token_url\":\"https://[fd00:ec2::254]/"
259     "imdsv2_session_token_url\","
260     "\"regional_cred_verification_url\":\"https://foo.com:5555/"
261     "regional_cred_verification_url_{region}\"}";
262 
263 const char
264     invalid_aws_external_account_creds_options_credential_source_unmatched_environment_id
265         [] = "{\"environment_id\":\"unsupported_aws_version\","
266              "\"region_url\":\"https://169.254.169.254:5555/region_url\","
267              "\"url\":\"https://169.254.169.254:5555/url\","
268              "\"regional_cred_verification_url\":\"https://foo.com:5555/"
269              "regional_cred_verification_url_{region}\"}";
270 
271 const char
272     invalid_aws_external_account_creds_options_credential_source_invalid_regional_cred_verification_url
273         [] = "{\"environment_id\":\"aws1\","
274              "\"region_url\":\"https://169.254.169.254:5555/region_url\","
275              "\"url\":\"https://169.254.169.254:5555/url_no_role_name\","
276              "\"regional_cred_verification_url\":\"invalid_regional_cred_"
277              "verification_url\"}";
278 
279 const char
280     invalid_aws_external_account_creds_options_credential_source_missing_role_name
281         [] = "{\"environment_id\":\"aws1\","
282              "\"region_url\":\"https://169.254.169.254:5555/region_url\","
283              "\"url\":\"https://169.254.169.254:5555/url_no_role_name\","
284              "\"regional_cred_verification_url\":\"https://foo.com:5555/"
285              "regional_cred_verification_url_{region}\"}";
286 
287 //  -- Global state flags. --
288 
289 bool g_test_is_on_gce = false;
290 
291 bool g_test_gce_tenancy_checker_called = false;
292 
293 // -- Utils. --
294 
test_json_key_str(void)295 char* test_json_key_str(void) {
296   size_t result_len = strlen(test_json_key_str_part1) +
297                       strlen(test_json_key_str_part2) +
298                       strlen(test_json_key_str_part3);
299   char* result = static_cast<char*>(gpr_malloc(result_len + 1));
300   char* current = result;
301   strcpy(result, test_json_key_str_part1);
302   current += strlen(test_json_key_str_part1);
303   strcpy(current, test_json_key_str_part2);
304   current += strlen(test_json_key_str_part2);
305   strcpy(current, test_json_key_str_part3);
306   return result;
307 }
308 
http_response(int status,const char * body)309 grpc_http_response http_response(int status, const char* body) {
310   grpc_http_response response;
311   response = {};
312   response.status = status;
313   response.body = gpr_strdup(const_cast<char*>(body));
314   response.body_length = strlen(body);
315   return response;
316 }
317 
318 // -- Tests. --
319 
TEST(CredentialsTest,TestOauth2TokenFetcherCredsParsingOk)320 TEST(CredentialsTest, TestOauth2TokenFetcherCredsParsingOk) {
321   ExecCtx exec_ctx;
322   absl::optional<Slice> token_value;
323   Duration token_lifetime;
324   grpc_http_response response = http_response(200, valid_oauth2_json_response);
325   GPR_ASSERT(grpc_oauth2_token_fetcher_credentials_parse_server_response(
326                  &response, &token_value, &token_lifetime) ==
327              GRPC_CREDENTIALS_OK);
328   GPR_ASSERT(token_lifetime == Duration::Seconds(3599));
329   GPR_ASSERT(token_value->as_string_view() ==
330              "Bearer ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_");
331   grpc_http_response_destroy(&response);
332 }
333 
TEST(CredentialsTest,TestOauth2TokenFetcherCredsParsingBadHttpStatus)334 TEST(CredentialsTest, TestOauth2TokenFetcherCredsParsingBadHttpStatus) {
335   ExecCtx exec_ctx;
336   absl::optional<Slice> token_value;
337   Duration token_lifetime;
338   grpc_http_response response = http_response(401, valid_oauth2_json_response);
339   GPR_ASSERT(grpc_oauth2_token_fetcher_credentials_parse_server_response(
340                  &response, &token_value, &token_lifetime) ==
341              GRPC_CREDENTIALS_ERROR);
342   grpc_http_response_destroy(&response);
343 }
344 
TEST(CredentialsTest,TestOauth2TokenFetcherCredsParsingEmptyHttpBody)345 TEST(CredentialsTest, TestOauth2TokenFetcherCredsParsingEmptyHttpBody) {
346   ExecCtx exec_ctx;
347   absl::optional<Slice> token_value;
348   Duration token_lifetime;
349   grpc_http_response response = http_response(200, "");
350   GPR_ASSERT(grpc_oauth2_token_fetcher_credentials_parse_server_response(
351                  &response, &token_value, &token_lifetime) ==
352              GRPC_CREDENTIALS_ERROR);
353   grpc_http_response_destroy(&response);
354 }
355 
TEST(CredentialsTest,TestOauth2TokenFetcherCredsParsingInvalidJson)356 TEST(CredentialsTest, TestOauth2TokenFetcherCredsParsingInvalidJson) {
357   ExecCtx exec_ctx;
358   absl::optional<Slice> token_value;
359   Duration token_lifetime;
360   grpc_http_response response =
361       http_response(200,
362                     "{\"access_token\":\"ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_\","
363                     " \"expires_in\":3599, "
364                     " \"token_type\":\"Bearer\"");
365   GPR_ASSERT(grpc_oauth2_token_fetcher_credentials_parse_server_response(
366                  &response, &token_value, &token_lifetime) ==
367              GRPC_CREDENTIALS_ERROR);
368   grpc_http_response_destroy(&response);
369 }
370 
TEST(CredentialsTest,TestOauth2TokenFetcherCredsParsingMissingToken)371 TEST(CredentialsTest, TestOauth2TokenFetcherCredsParsingMissingToken) {
372   ExecCtx exec_ctx;
373   absl::optional<Slice> token_value;
374   Duration token_lifetime;
375   grpc_http_response response = http_response(200,
376                                               "{"
377                                               " \"expires_in\":3599, "
378                                               " \"token_type\":\"Bearer\"}");
379   GPR_ASSERT(grpc_oauth2_token_fetcher_credentials_parse_server_response(
380                  &response, &token_value, &token_lifetime) ==
381              GRPC_CREDENTIALS_ERROR);
382   grpc_http_response_destroy(&response);
383 }
384 
TEST(CredentialsTest,TestOauth2TokenFetcherCredsParsingMissingTokenType)385 TEST(CredentialsTest, TestOauth2TokenFetcherCredsParsingMissingTokenType) {
386   ExecCtx exec_ctx;
387   absl::optional<Slice> token_value;
388   Duration token_lifetime;
389   grpc_http_response response =
390       http_response(200,
391                     "{\"access_token\":\"ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_\","
392                     " \"expires_in\":3599, "
393                     "}");
394   GPR_ASSERT(grpc_oauth2_token_fetcher_credentials_parse_server_response(
395                  &response, &token_value, &token_lifetime) ==
396              GRPC_CREDENTIALS_ERROR);
397   grpc_http_response_destroy(&response);
398 }
399 
TEST(CredentialsTest,TestOauth2TokenFetcherCredsParsingMissingTokenLifetime)400 TEST(CredentialsTest, TestOauth2TokenFetcherCredsParsingMissingTokenLifetime) {
401   ExecCtx exec_ctx;
402   absl::optional<Slice> token_value;
403   Duration token_lifetime;
404   grpc_http_response response =
405       http_response(200,
406                     "{\"access_token\":\"ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_\","
407                     " \"token_type\":\"Bearer\"}");
408   GPR_ASSERT(grpc_oauth2_token_fetcher_credentials_parse_server_response(
409                  &response, &token_value, &token_lifetime) ==
410              GRPC_CREDENTIALS_ERROR);
411   grpc_http_response_destroy(&response);
412 }
413 
414 class RequestMetadataState : public RefCounted<RequestMetadataState> {
415  public:
NewInstance(grpc_error_handle expected_error,std::string expected)416   static RefCountedPtr<RequestMetadataState> NewInstance(
417       grpc_error_handle expected_error, std::string expected) {
418     return MakeRefCounted<RequestMetadataState>(
419         expected_error, std::move(expected),
420         grpc_polling_entity_create_from_pollset_set(grpc_pollset_set_create()));
421   }
422 
RequestMetadataState(grpc_error_handle expected_error,std::string expected,grpc_polling_entity pollent)423   RequestMetadataState(grpc_error_handle expected_error, std::string expected,
424                        grpc_polling_entity pollent)
425       : expected_error_(expected_error),
426         expected_(std::move(expected)),
427         pollent_(pollent) {}
428 
~RequestMetadataState()429   ~RequestMetadataState() override {
430     grpc_pollset_set_destroy(grpc_polling_entity_pollset_set(&pollent_));
431   }
432 
RunRequestMetadataTest(grpc_call_credentials * creds,const char * url_scheme,const char * authority,const char * path)433   void RunRequestMetadataTest(grpc_call_credentials* creds,
434                               const char* url_scheme, const char* authority,
435                               const char* path) {
436     auto self = Ref();
437     get_request_metadata_args_.security_connector =
438         MakeRefCounted<BogusSecurityConnector>(url_scheme);
439     md_.Set(HttpAuthorityMetadata(), Slice::FromStaticString(authority));
440     md_.Set(HttpPathMetadata(), Slice::FromStaticString(path));
441     activity_ = MakeActivity(
442         [this, creds] {
443           return Seq(
444               creds->GetRequestMetadata(
445                   ClientMetadataHandle(&md_, Arena::PooledDeleter(nullptr)),
446                   &get_request_metadata_args_),
447               [this](absl::StatusOr<ClientMetadataHandle> metadata) {
448                 if (metadata.ok()) {
449                   GPR_ASSERT(metadata->get() == &md_);
450                 }
451                 return metadata.status();
452               });
453         },
454         ExecCtxWakeupScheduler(),
455         [self](absl::Status status) mutable {
456           self->CheckRequestMetadata(
457               absl_status_to_grpc_error(std::move(status)));
458           self.reset();
459         },
460         arena_.get(), &pollent_);
461   }
462 
463  private:
464   // No-op security connector, exists only to inject url_scheme.
465   class BogusSecurityConnector : public grpc_channel_security_connector {
466    public:
BogusSecurityConnector(absl::string_view url_scheme)467     explicit BogusSecurityConnector(absl::string_view url_scheme)
468         : grpc_channel_security_connector(url_scheme, nullptr, nullptr) {}
469 
check_peer(tsi_peer,grpc_endpoint *,const ChannelArgs &,RefCountedPtr<grpc_auth_context> *,grpc_closure *)470     void check_peer(tsi_peer, grpc_endpoint*, const ChannelArgs&,
471                     RefCountedPtr<grpc_auth_context>*, grpc_closure*) override {
472       Crash("unreachable");
473     }
474 
cancel_check_peer(grpc_closure *,grpc_error_handle)475     void cancel_check_peer(grpc_closure*, grpc_error_handle) override {
476       Crash("unreachable");
477     }
478 
cmp(const grpc_security_connector *) const479     int cmp(const grpc_security_connector*) const override {
480       GPR_UNREACHABLE_CODE(return 0);
481     }
482 
CheckCallHost(absl::string_view,grpc_auth_context *)483     ArenaPromise<absl::Status> CheckCallHost(absl::string_view,
484                                              grpc_auth_context*) override {
485       GPR_UNREACHABLE_CODE(
486           return Immediate(absl::PermissionDeniedError("should never happen")));
487     }
488 
add_handshakers(const ChannelArgs &,grpc_pollset_set *,HandshakeManager *)489     void add_handshakers(const ChannelArgs&, grpc_pollset_set*,
490                          HandshakeManager*) override {
491       Crash("unreachable");
492     }
493   };
494 
CheckRequestMetadata(grpc_error_handle error)495   void CheckRequestMetadata(grpc_error_handle error) {
496     gpr_log(GPR_INFO, "expected_error: %s",
497             StatusToString(expected_error_).c_str());
498     gpr_log(GPR_INFO, "actual_error: %s", StatusToString(error).c_str());
499     if (expected_error_.ok()) {
500       GPR_ASSERT(error.ok());
501     } else {
502       std::string expected_error;
503       GPR_ASSERT(grpc_error_get_str(
504           expected_error_, StatusStrProperty::kDescription, &expected_error));
505       std::string actual_error;
506       GPR_ASSERT(grpc_error_get_str(error, StatusStrProperty::kDescription,
507                                     &actual_error));
508       GPR_ASSERT(expected_error == actual_error);
509     }
510     md_.Remove(HttpAuthorityMetadata());
511     md_.Remove(HttpPathMetadata());
512     gpr_log(GPR_INFO, "expected metadata: %s", expected_.c_str());
513     gpr_log(GPR_INFO, "actual metadata: %s", md_.DebugString().c_str());
514   }
515 
516   grpc_error_handle expected_error_;
517   std::string expected_;
518   MemoryAllocator memory_allocator_ = MemoryAllocator(
519       ResourceQuota::Default()->memory_quota()->CreateMemoryAllocator("test"));
520   ScopedArenaPtr arena_ = MakeScopedArena(1024, &memory_allocator_);
521   grpc_metadata_batch md_;
522   grpc_call_credentials::GetRequestMetadataArgs get_request_metadata_args_;
523   grpc_polling_entity pollent_;
524   ActivityPtr activity_;
525 };
526 
TEST(CredentialsTest,TestGoogleIamCreds)527 TEST(CredentialsTest, TestGoogleIamCreds) {
528   ExecCtx exec_ctx;
529   auto state = RequestMetadataState::NewInstance(
530       absl::OkStatus(),
531       absl::StrCat(GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY, ": ",
532                    test_google_iam_authorization_token, ", ",
533                    GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY, ": ",
534                    test_google_iam_authority_selector));
535   grpc_call_credentials* creds = grpc_google_iam_credentials_create(
536       test_google_iam_authorization_token, test_google_iam_authority_selector,
537       nullptr);
538   // Check security level.
539   GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
540   state->RunRequestMetadataTest(creds, kTestUrlScheme, kTestAuthority,
541                                 kTestPath);
542   creds->Unref();
543 }
544 
TEST(CredentialsTest,TestAccessTokenCreds)545 TEST(CredentialsTest, TestAccessTokenCreds) {
546   ExecCtx exec_ctx;
547   auto state = RequestMetadataState::NewInstance(absl::OkStatus(),
548                                                  "authorization: Bearer blah");
549   grpc_call_credentials* creds =
550       grpc_access_token_credentials_create("blah", nullptr);
551   GPR_ASSERT(creds->type() == grpc_access_token_credentials::Type());
552   // Check security level.
553   GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
554   state->RunRequestMetadataTest(creds, kTestUrlScheme, kTestAuthority,
555                                 kTestPath);
556   creds->Unref();
557 }
558 
559 class check_channel_oauth2 final : public grpc_channel_credentials {
560  public:
create_security_connector(RefCountedPtr<grpc_call_credentials> call_creds,const char *,ChannelArgs *)561   RefCountedPtr<grpc_channel_security_connector> create_security_connector(
562       RefCountedPtr<grpc_call_credentials> call_creds, const char* /*target*/,
563       ChannelArgs* /*new_args*/) override {
564     GPR_ASSERT(type() == Type());
565     GPR_ASSERT(call_creds != nullptr);
566     GPR_ASSERT(call_creds->type() == grpc_access_token_credentials::Type());
567     return nullptr;
568   }
569 
Type()570   static UniqueTypeName Type() {
571     static UniqueTypeName::Factory kFactory("check_channel_oauth2");
572     return kFactory.Create();
573   }
574 
type() const575   UniqueTypeName type() const override { return Type(); }
576 
577  private:
cmp_impl(const grpc_channel_credentials * other) const578   int cmp_impl(const grpc_channel_credentials* other) const override {
579     // TODO(yashykt): Check if we can do something better here
580     return QsortCompare(static_cast<const grpc_channel_credentials*>(this),
581                         other);
582   }
583 };
584 
TEST(CredentialsTest,TestChannelOauth2CompositeCreds)585 TEST(CredentialsTest, TestChannelOauth2CompositeCreds) {
586   ExecCtx exec_ctx;
587   ChannelArgs new_args;
588   grpc_channel_credentials* channel_creds = new check_channel_oauth2();
589   grpc_call_credentials* oauth2_creds =
590       grpc_access_token_credentials_create("blah", nullptr);
591   grpc_channel_credentials* channel_oauth2_creds =
592       grpc_composite_channel_credentials_create(channel_creds, oauth2_creds,
593                                                 nullptr);
594   grpc_channel_credentials_release(channel_creds);
595   grpc_call_credentials_release(oauth2_creds);
596   channel_oauth2_creds->create_security_connector(nullptr, nullptr, &new_args);
597   grpc_channel_credentials_release(channel_oauth2_creds);
598 }
599 
TEST(CredentialsTest,TestOauth2GoogleIamCompositeCreds)600 TEST(CredentialsTest, TestOauth2GoogleIamCompositeCreds) {
601   ExecCtx exec_ctx;
602   auto state = RequestMetadataState::NewInstance(
603       absl::OkStatus(),
604       absl::StrCat(GRPC_AUTHORIZATION_METADATA_KEY, ": ",
605                    test_oauth2_bearer_token, ", ",
606                    GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY, ": ",
607                    test_google_iam_authorization_token, ", ",
608                    GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY, ": ",
609                    test_google_iam_authority_selector));
610   grpc_call_credentials* oauth2_creds = grpc_md_only_test_credentials_create(
611       "authorization", test_oauth2_bearer_token);
612 
613   // Check security level of fake credentials.
614   GPR_ASSERT(oauth2_creds->min_security_level() == GRPC_SECURITY_NONE);
615 
616   grpc_call_credentials* google_iam_creds = grpc_google_iam_credentials_create(
617       test_google_iam_authorization_token, test_google_iam_authority_selector,
618       nullptr);
619   grpc_call_credentials* composite_creds =
620       grpc_composite_call_credentials_create(oauth2_creds, google_iam_creds,
621                                              nullptr);
622   // Check security level of composite credentials.
623   GPR_ASSERT(composite_creds->min_security_level() ==
624              GRPC_PRIVACY_AND_INTEGRITY);
625 
626   oauth2_creds->Unref();
627   google_iam_creds->Unref();
628   GPR_ASSERT(composite_creds->type() ==
629              grpc_composite_call_credentials::Type());
630   const grpc_composite_call_credentials::CallCredentialsList& creds_list =
631       static_cast<const grpc_composite_call_credentials*>(composite_creds)
632           ->inner();
633   GPR_ASSERT(creds_list.size() == 2);
634   GPR_ASSERT(creds_list[0]->type() == grpc_md_only_test_credentials::Type());
635   GPR_ASSERT(creds_list[1]->type() == grpc_google_iam_credentials::Type());
636   state->RunRequestMetadataTest(composite_creds, kTestUrlScheme, kTestAuthority,
637                                 kTestPath);
638   composite_creds->Unref();
639 }
640 
641 class check_channel_oauth2_google_iam final : public grpc_channel_credentials {
642  public:
create_security_connector(RefCountedPtr<grpc_call_credentials> call_creds,const char *,ChannelArgs *)643   RefCountedPtr<grpc_channel_security_connector> create_security_connector(
644       RefCountedPtr<grpc_call_credentials> call_creds, const char* /*target*/,
645       ChannelArgs* /*new_args*/) override {
646     GPR_ASSERT(type() == Type());
647     GPR_ASSERT(call_creds != nullptr);
648     GPR_ASSERT(call_creds->type() == grpc_composite_call_credentials::Type());
649     const grpc_composite_call_credentials::CallCredentialsList& creds_list =
650         static_cast<const grpc_composite_call_credentials*>(call_creds.get())
651             ->inner();
652     GPR_ASSERT(creds_list[0]->type() == grpc_access_token_credentials::Type());
653     GPR_ASSERT(creds_list[1]->type() == grpc_google_iam_credentials::Type());
654     return nullptr;
655   }
656 
Type()657   static UniqueTypeName Type() {
658     static UniqueTypeName::Factory kFactory("check_channel_oauth2_google_iam");
659     return kFactory.Create();
660   }
661 
type() const662   UniqueTypeName type() const override { return Type(); }
663 
664  private:
cmp_impl(const grpc_channel_credentials * other) const665   int cmp_impl(const grpc_channel_credentials* other) const override {
666     // TODO(yashykt): Check if we can do something better here
667     return QsortCompare(static_cast<const grpc_channel_credentials*>(this),
668                         other);
669   }
670 };
671 
TEST(CredentialsTest,TestChannelOauth2GoogleIamCompositeCreds)672 TEST(CredentialsTest, TestChannelOauth2GoogleIamCompositeCreds) {
673   ExecCtx exec_ctx;
674   ChannelArgs new_args;
675   grpc_channel_credentials* channel_creds =
676       new check_channel_oauth2_google_iam();
677   grpc_call_credentials* oauth2_creds =
678       grpc_access_token_credentials_create("blah", nullptr);
679   grpc_channel_credentials* channel_oauth2_creds =
680       grpc_composite_channel_credentials_create(channel_creds, oauth2_creds,
681                                                 nullptr);
682   grpc_call_credentials* google_iam_creds = grpc_google_iam_credentials_create(
683       test_google_iam_authorization_token, test_google_iam_authority_selector,
684       nullptr);
685 
686   grpc_channel_credentials* channel_oauth2_iam_creds =
687       grpc_composite_channel_credentials_create(channel_oauth2_creds,
688                                                 google_iam_creds, nullptr);
689   grpc_channel_credentials_release(channel_creds);
690   grpc_call_credentials_release(oauth2_creds);
691   grpc_channel_credentials_release(channel_oauth2_creds);
692   grpc_call_credentials_release(google_iam_creds);
693 
694   channel_oauth2_iam_creds->create_security_connector(nullptr, nullptr,
695                                                       &new_args);
696 
697   grpc_channel_credentials_release(channel_oauth2_iam_creds);
698 }
699 
validate_compute_engine_http_request(const grpc_http_request * request,const char * host,const char * path)700 void validate_compute_engine_http_request(const grpc_http_request* request,
701                                           const char* host, const char* path) {
702   GPR_ASSERT(strcmp(host, "metadata.google.internal.") == 0);
703   GPR_ASSERT(
704       strcmp(path,
705              "/computeMetadata/v1/instance/service-accounts/default/token") ==
706       0);
707   GPR_ASSERT(request->hdr_count == 1);
708   GPR_ASSERT(strcmp(request->hdrs[0].key, "Metadata-Flavor") == 0);
709   GPR_ASSERT(strcmp(request->hdrs[0].value, "Google") == 0);
710 }
711 
compute_engine_httpcli_get_success_override(const grpc_http_request * request,const char * host,const char * path,Timestamp,grpc_closure * on_done,grpc_http_response * response)712 int compute_engine_httpcli_get_success_override(
713     const grpc_http_request* request, const char* host, const char* path,
714     Timestamp /*deadline*/, grpc_closure* on_done,
715     grpc_http_response* response) {
716   validate_compute_engine_http_request(request, host, path);
717   *response = http_response(200, valid_oauth2_json_response);
718   ExecCtx::Run(DEBUG_LOCATION, on_done, absl::OkStatus());
719   return 1;
720 }
721 
compute_engine_httpcli_get_failure_override(const grpc_http_request * request,const char * host,const char * path,Timestamp,grpc_closure * on_done,grpc_http_response * response)722 int compute_engine_httpcli_get_failure_override(
723     const grpc_http_request* request, const char* host, const char* path,
724     Timestamp /*deadline*/, grpc_closure* on_done,
725     grpc_http_response* response) {
726   validate_compute_engine_http_request(request, host, path);
727   *response = http_response(403, "Not Authorized.");
728   ExecCtx::Run(DEBUG_LOCATION, on_done, absl::OkStatus());
729   return 1;
730 }
731 
httpcli_post_should_not_be_called(const grpc_http_request *,const char *,const char *,const char *,size_t,Timestamp,grpc_closure *,grpc_http_response *)732 int httpcli_post_should_not_be_called(
733     const grpc_http_request* /*request*/, const char* /*host*/,
734     const char* /*path*/, const char* /*body_bytes*/, size_t /*body_size*/,
735     Timestamp /*deadline*/, grpc_closure* /*on_done*/,
736     grpc_http_response* /*response*/) {
737   GPR_ASSERT("HTTP POST should not be called" == nullptr);
738   return 1;
739 }
740 
httpcli_get_should_not_be_called(const grpc_http_request *,const char *,const char *,Timestamp,grpc_closure *,grpc_http_response *)741 int httpcli_get_should_not_be_called(const grpc_http_request* /*request*/,
742                                      const char* /*host*/, const char* /*path*/,
743                                      Timestamp /*deadline*/,
744                                      grpc_closure* /*on_done*/,
745                                      grpc_http_response* /*response*/) {
746   GPR_ASSERT("HTTP GET should not be called" == nullptr);
747   return 1;
748 }
749 
httpcli_put_should_not_be_called(const grpc_http_request *,const char *,const char *,const char *,size_t,Timestamp,grpc_closure *,grpc_http_response *)750 int httpcli_put_should_not_be_called(const grpc_http_request* /*request*/,
751                                      const char* /*host*/, const char* /*path*/,
752                                      const char* /*body_bytes*/,
753                                      size_t /*body_size*/,
754                                      Timestamp /*deadline*/,
755                                      grpc_closure* /*on_done*/,
756                                      grpc_http_response* /*response*/) {
757   GPR_ASSERT("HTTP PUT should not be called" == nullptr);
758   return 1;
759 }
760 
TEST(CredentialsTest,TestComputeEngineCredsSuccess)761 TEST(CredentialsTest, TestComputeEngineCredsSuccess) {
762   ExecCtx exec_ctx;
763   std::string emd = "authorization: Bearer ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_";
764   const char expected_creds_debug_string[] =
765       "GoogleComputeEngineTokenFetcherCredentials{"
766       "OAuth2TokenFetcherCredentials}";
767   grpc_call_credentials* creds =
768       grpc_google_compute_engine_credentials_create(nullptr);
769   // Check security level.
770   GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
771 
772   // First request: http get should be called.
773   auto state = RequestMetadataState::NewInstance(absl::OkStatus(), emd);
774   HttpRequest::SetOverride(compute_engine_httpcli_get_success_override,
775                            httpcli_post_should_not_be_called,
776                            httpcli_put_should_not_be_called);
777   state->RunRequestMetadataTest(creds, kTestUrlScheme, kTestAuthority,
778                                 kTestPath);
779   ExecCtx::Get()->Flush();
780 
781   // Second request: the cached token should be served directly.
782   state = RequestMetadataState::NewInstance(absl::OkStatus(), emd);
783   HttpRequest::SetOverride(httpcli_get_should_not_be_called,
784                            httpcli_post_should_not_be_called,
785                            httpcli_put_should_not_be_called);
786   state->RunRequestMetadataTest(creds, kTestUrlScheme, kTestAuthority,
787                                 kTestPath);
788   ExecCtx::Get()->Flush();
789 
790   GPR_ASSERT(
791       strcmp(creds->debug_string().c_str(), expected_creds_debug_string) == 0);
792   creds->Unref();
793   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
794 }
795 
TEST(CredentialsTest,TestComputeEngineCredsFailure)796 TEST(CredentialsTest, TestComputeEngineCredsFailure) {
797   ExecCtx exec_ctx;
798   const char expected_creds_debug_string[] =
799       "GoogleComputeEngineTokenFetcherCredentials{"
800       "OAuth2TokenFetcherCredentials}";
801   auto state = RequestMetadataState::NewInstance(
802       GRPC_ERROR_CREATE("Error occurred when fetching oauth2 token."), {});
803   grpc_call_credentials* creds =
804       grpc_google_compute_engine_credentials_create(nullptr);
805   HttpRequest::SetOverride(compute_engine_httpcli_get_failure_override,
806                            httpcli_post_should_not_be_called,
807                            httpcli_put_should_not_be_called);
808   state->RunRequestMetadataTest(creds, kTestUrlScheme, kTestAuthority,
809                                 kTestPath);
810   GPR_ASSERT(
811       strcmp(creds->debug_string().c_str(), expected_creds_debug_string) == 0);
812   creds->Unref();
813   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
814 }
815 
validate_refresh_token_http_request(const grpc_http_request * request,const char * host,const char * path,const char * body,size_t body_size)816 void validate_refresh_token_http_request(const grpc_http_request* request,
817                                          const char* host, const char* path,
818                                          const char* body, size_t body_size) {
819   // The content of the assertion is tested extensively in json_token_test.
820   GPR_ASSERT(body != nullptr);
821   GPR_ASSERT(body_size != 0);
822   std::string expected_body = absl::StrFormat(
823       GRPC_REFRESH_TOKEN_POST_BODY_FORMAT_STRING,
824       "32555999999.apps.googleusercontent.com", "EmssLNjJy1332hD4KFsecret",
825       "1/Blahblasj424jladJDSGNf-u4Sua3HDA2ngjd42");
826   GPR_ASSERT(expected_body.size() == body_size);
827   GPR_ASSERT(memcmp(expected_body.data(), body, body_size) == 0);
828   GPR_ASSERT(strcmp(host, GRPC_GOOGLE_OAUTH2_SERVICE_HOST) == 0);
829   GPR_ASSERT(strcmp(path, GRPC_GOOGLE_OAUTH2_SERVICE_TOKEN_PATH) == 0);
830   GPR_ASSERT(request->hdr_count == 1);
831   GPR_ASSERT(strcmp(request->hdrs[0].key, "Content-Type") == 0);
832   GPR_ASSERT(
833       strcmp(request->hdrs[0].value, "application/x-www-form-urlencoded") == 0);
834 }
835 
refresh_token_httpcli_post_success(const grpc_http_request * request,const char * host,const char * path,const char * body,size_t body_size,Timestamp,grpc_closure * on_done,grpc_http_response * response)836 int refresh_token_httpcli_post_success(const grpc_http_request* request,
837                                        const char* host, const char* path,
838                                        const char* body, size_t body_size,
839                                        Timestamp /*deadline*/,
840                                        grpc_closure* on_done,
841                                        grpc_http_response* response) {
842   validate_refresh_token_http_request(request, host, path, body, body_size);
843   *response = http_response(200, valid_oauth2_json_response);
844   ExecCtx::Run(DEBUG_LOCATION, on_done, absl::OkStatus());
845   return 1;
846 }
847 
token_httpcli_post_failure(const grpc_http_request *,const char *,const char *,const char *,size_t,Timestamp,grpc_closure * on_done,grpc_http_response * response)848 int token_httpcli_post_failure(const grpc_http_request* /*request*/,
849                                const char* /*host*/, const char* /*path*/,
850                                const char* /*body*/, size_t /*body_size*/,
851                                Timestamp /*deadline*/, grpc_closure* on_done,
852                                grpc_http_response* response) {
853   *response = http_response(403, "Not Authorized.");
854   ExecCtx::Run(DEBUG_LOCATION, on_done, absl::OkStatus());
855   return 1;
856 }
857 
TEST(CredentialsTest,TestRefreshTokenCredsSuccess)858 TEST(CredentialsTest, TestRefreshTokenCredsSuccess) {
859   ExecCtx exec_ctx;
860   std::string emd = "authorization: Bearer ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_";
861   const char expected_creds_debug_string[] =
862       "GoogleRefreshToken{ClientID:32555999999.apps.googleusercontent.com,"
863       "OAuth2TokenFetcherCredentials}";
864   grpc_call_credentials* creds = grpc_google_refresh_token_credentials_create(
865       test_refresh_token_str, nullptr);
866 
867   // Check security level.
868   GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
869 
870   // First request: http put should be called.
871   auto state = RequestMetadataState::NewInstance(absl::OkStatus(), emd);
872   HttpRequest::SetOverride(httpcli_get_should_not_be_called,
873                            refresh_token_httpcli_post_success,
874                            httpcli_put_should_not_be_called);
875   state->RunRequestMetadataTest(creds, kTestUrlScheme, kTestAuthority,
876                                 kTestPath);
877   ExecCtx::Get()->Flush();
878 
879   // Second request: the cached token should be served directly.
880   state = RequestMetadataState::NewInstance(absl::OkStatus(), emd);
881   HttpRequest::SetOverride(httpcli_get_should_not_be_called,
882                            httpcli_post_should_not_be_called,
883                            httpcli_put_should_not_be_called);
884   state->RunRequestMetadataTest(creds, kTestUrlScheme, kTestAuthority,
885                                 kTestPath);
886   ExecCtx::Get()->Flush();
887   GPR_ASSERT(
888       strcmp(creds->debug_string().c_str(), expected_creds_debug_string) == 0);
889 
890   creds->Unref();
891   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
892 }
893 
TEST(CredentialsTest,TestRefreshTokenCredsFailure)894 TEST(CredentialsTest, TestRefreshTokenCredsFailure) {
895   ExecCtx exec_ctx;
896   const char expected_creds_debug_string[] =
897       "GoogleRefreshToken{ClientID:32555999999.apps.googleusercontent.com,"
898       "OAuth2TokenFetcherCredentials}";
899   auto state = RequestMetadataState::NewInstance(
900       GRPC_ERROR_CREATE("Error occurred when fetching oauth2 token."), {});
901   grpc_call_credentials* creds = grpc_google_refresh_token_credentials_create(
902       test_refresh_token_str, nullptr);
903   HttpRequest::SetOverride(httpcli_get_should_not_be_called,
904                            token_httpcli_post_failure,
905                            httpcli_put_should_not_be_called);
906   state->RunRequestMetadataTest(creds, kTestUrlScheme, kTestAuthority,
907                                 kTestPath);
908   GPR_ASSERT(
909       strcmp(creds->debug_string().c_str(), expected_creds_debug_string) == 0);
910 
911   creds->Unref();
912   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
913 }
914 
TEST(CredentialsTest,TestValidStsCredsOptions)915 TEST(CredentialsTest, TestValidStsCredsOptions) {
916   grpc_sts_credentials_options valid_options = {
917       test_sts_endpoint_url,        // sts_endpoint_url
918       nullptr,                      // resource
919       nullptr,                      // audience
920       nullptr,                      // scope
921       nullptr,                      // requested_token_type
922       test_signed_jwt_path_prefix,  // subject_token_path
923       test_signed_jwt_token_type,   // subject_token_type
924       nullptr,                      // actor_token_path
925       nullptr                       // actor_token_type
926   };
927   absl::StatusOr<URI> sts_url = ValidateStsCredentialsOptions(&valid_options);
928   GPR_ASSERT(sts_url.ok());
929   absl::string_view host;
930   absl::string_view port;
931   GPR_ASSERT(SplitHostPort(sts_url->authority(), &host, &port));
932   GPR_ASSERT(host == "foo.com");
933   GPR_ASSERT(port == "5555");
934 }
935 
TEST(CredentialsTest,TestInvalidStsCredsOptions)936 TEST(CredentialsTest, TestInvalidStsCredsOptions) {
937   grpc_sts_credentials_options invalid_options = {
938       test_sts_endpoint_url,       // sts_endpoint_url
939       nullptr,                     // resource
940       nullptr,                     // audience
941       nullptr,                     // scope
942       nullptr,                     // requested_token_type
943       nullptr,                     // subject_token_path (Required)
944       test_signed_jwt_token_type,  // subject_token_type
945       nullptr,                     // actor_token_path
946       nullptr                      // actor_token_type
947   };
948   absl::StatusOr<URI> url_should_be_invalid =
949       ValidateStsCredentialsOptions(&invalid_options);
950   GPR_ASSERT(!url_should_be_invalid.ok());
951 
952   invalid_options = {
953       test_sts_endpoint_url,        // sts_endpoint_url
954       nullptr,                      // resource
955       nullptr,                      // audience
956       nullptr,                      // scope
957       nullptr,                      // requested_token_type
958       test_signed_jwt_path_prefix,  // subject_token_path
959       nullptr,                      // subject_token_type (Required)
960       nullptr,                      // actor_token_path
961       nullptr                       // actor_token_type
962   };
963   url_should_be_invalid = ValidateStsCredentialsOptions(&invalid_options);
964   GPR_ASSERT(!url_should_be_invalid.ok());
965 
966   invalid_options = {
967       nullptr,                      // sts_endpoint_url (Required)
968       nullptr,                      // resource
969       nullptr,                      // audience
970       nullptr,                      // scope
971       nullptr,                      // requested_token_type
972       test_signed_jwt_path_prefix,  // subject_token_path
973       test_signed_jwt_token_type,   // subject_token_type (Required)
974       nullptr,                      // actor_token_path
975       nullptr                       // actor_token_type
976   };
977   url_should_be_invalid = ValidateStsCredentialsOptions(&invalid_options);
978   GPR_ASSERT(!url_should_be_invalid.ok());
979 
980   invalid_options = {
981       "not_a_valid_uri",            // sts_endpoint_url
982       nullptr,                      // resource
983       nullptr,                      // audience
984       nullptr,                      // scope
985       nullptr,                      // requested_token_type
986       test_signed_jwt_path_prefix,  // subject_token_path
987       test_signed_jwt_token_type,   // subject_token_type (Required)
988       nullptr,                      // actor_token_path
989       nullptr                       // actor_token_type
990   };
991   url_should_be_invalid = ValidateStsCredentialsOptions(&invalid_options);
992   GPR_ASSERT(!url_should_be_invalid.ok());
993 
994   invalid_options = {
995       "ftp://ftp.is.not.a.valid.scheme/bar",  // sts_endpoint_url
996       nullptr,                                // resource
997       nullptr,                                // audience
998       nullptr,                                // scope
999       nullptr,                                // requested_token_type
1000       test_signed_jwt_path_prefix,            // subject_token_path
1001       test_signed_jwt_token_type,             // subject_token_type (Required)
1002       nullptr,                                // actor_token_path
1003       nullptr                                 // actor_token_type
1004   };
1005   url_should_be_invalid = ValidateStsCredentialsOptions(&invalid_options);
1006   GPR_ASSERT(!url_should_be_invalid.ok());
1007 }
1008 
assert_query_parameters(const URI & uri,absl::string_view expected_key,absl::string_view expected_val)1009 void assert_query_parameters(const URI& uri, absl::string_view expected_key,
1010                              absl::string_view expected_val) {
1011   const auto it = uri.query_parameter_map().find(expected_key);
1012   GPR_ASSERT(it != uri.query_parameter_map().end());
1013   if (it->second != expected_val) {
1014     gpr_log(GPR_ERROR, "%s!=%s", std::string(it->second).c_str(),
1015             std::string(expected_val).c_str());
1016   }
1017   GPR_ASSERT(it->second == expected_val);
1018 }
1019 
validate_sts_token_http_request(const grpc_http_request * request,const char * host,const char * path,const char * body,size_t body_size,bool expect_actor_token)1020 void validate_sts_token_http_request(const grpc_http_request* request,
1021                                      const char* host, const char* path,
1022                                      const char* body, size_t body_size,
1023                                      bool expect_actor_token) {
1024   // Check that the body is constructed properly.
1025   GPR_ASSERT(body != nullptr);
1026   GPR_ASSERT(body_size != 0);
1027   std::string get_url_equivalent =
1028       absl::StrFormat("%s?%s", test_sts_endpoint_url, body);
1029   absl::StatusOr<URI> url = URI::Parse(get_url_equivalent);
1030   if (!url.ok()) {
1031     gpr_log(GPR_ERROR, "%s", url.status().ToString().c_str());
1032     GPR_ASSERT(url.ok());
1033   }
1034   assert_query_parameters(*url, "resource", "resource");
1035   assert_query_parameters(*url, "audience", "audience");
1036   assert_query_parameters(*url, "scope", "scope");
1037   assert_query_parameters(*url, "requested_token_type", "requested_token_type");
1038   assert_query_parameters(*url, "subject_token", test_signed_jwt);
1039   assert_query_parameters(*url, "subject_token_type",
1040                           test_signed_jwt_token_type);
1041   if (expect_actor_token) {
1042     assert_query_parameters(*url, "actor_token", test_signed_jwt2);
1043     assert_query_parameters(*url, "actor_token_type",
1044                             test_signed_jwt_token_type2);
1045   } else {
1046     GPR_ASSERT(url->query_parameter_map().find("actor_token") ==
1047                url->query_parameter_map().end());
1048     GPR_ASSERT(url->query_parameter_map().find("actor_token_type") ==
1049                url->query_parameter_map().end());
1050   }
1051 
1052   // Check the rest of the request.
1053   GPR_ASSERT(strcmp(host, "foo.com:5555") == 0);
1054   GPR_ASSERT(strcmp(path, "/v1/token-exchange") == 0);
1055   GPR_ASSERT(request->hdr_count == 1);
1056   GPR_ASSERT(strcmp(request->hdrs[0].key, "Content-Type") == 0);
1057   GPR_ASSERT(
1058       strcmp(request->hdrs[0].value, "application/x-www-form-urlencoded") == 0);
1059 }
1060 
sts_token_httpcli_post_success(const grpc_http_request * request,const char * host,const char * path,const char * body,size_t body_size,Timestamp,grpc_closure * on_done,grpc_http_response * response)1061 int sts_token_httpcli_post_success(const grpc_http_request* request,
1062                                    const char* host, const char* path,
1063                                    const char* body, size_t body_size,
1064                                    Timestamp /*deadline*/,
1065                                    grpc_closure* on_done,
1066                                    grpc_http_response* response) {
1067   validate_sts_token_http_request(request, host, path, body, body_size, true);
1068   *response = http_response(200, valid_sts_json_response);
1069   ExecCtx::Run(DEBUG_LOCATION, on_done, absl::OkStatus());
1070   return 1;
1071 }
1072 
sts_token_httpcli_post_success_no_actor_token(const grpc_http_request * request,const char * host,const char * path,const char * body,size_t body_size,Timestamp,grpc_closure * on_done,grpc_http_response * response)1073 int sts_token_httpcli_post_success_no_actor_token(
1074     const grpc_http_request* request, const char* host, const char* path,
1075     const char* body, size_t body_size, Timestamp /*deadline*/,
1076     grpc_closure* on_done, grpc_http_response* response) {
1077   validate_sts_token_http_request(request, host, path, body, body_size, false);
1078   *response = http_response(200, valid_sts_json_response);
1079   ExecCtx::Run(DEBUG_LOCATION, on_done, absl::OkStatus());
1080   return 1;
1081 }
1082 
write_tmp_jwt_file(const char * jwt_contents)1083 char* write_tmp_jwt_file(const char* jwt_contents) {
1084   char* path;
1085   FILE* tmp = gpr_tmpfile(test_signed_jwt_path_prefix, &path);
1086   GPR_ASSERT(path != nullptr);
1087   GPR_ASSERT(tmp != nullptr);
1088   size_t jwt_length = strlen(jwt_contents);
1089   GPR_ASSERT(fwrite(jwt_contents, 1, jwt_length, tmp) == jwt_length);
1090   fclose(tmp);
1091   return path;
1092 }
1093 
TEST(CredentialsTest,TestStsCredsSuccess)1094 TEST(CredentialsTest, TestStsCredsSuccess) {
1095   ExecCtx exec_ctx;
1096   std::string emd = "authorization: Bearer ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_";
1097   const char expected_creds_debug_string[] =
1098       "StsTokenFetcherCredentials{Path:/v1/"
1099       "token-exchange,Authority:foo.com:5555,OAuth2TokenFetcherCredentials}";
1100   char* subject_token_path = write_tmp_jwt_file(test_signed_jwt);
1101   char* actor_token_path = write_tmp_jwt_file(test_signed_jwt2);
1102   grpc_sts_credentials_options valid_options = {
1103       test_sts_endpoint_url,       // sts_endpoint_url
1104       "resource",                  // resource
1105       "audience",                  // audience
1106       "scope",                     // scope
1107       "requested_token_type",      // requested_token_type
1108       subject_token_path,          // subject_token_path
1109       test_signed_jwt_token_type,  // subject_token_type
1110       actor_token_path,            // actor_token_path
1111       test_signed_jwt_token_type2  // actor_token_type
1112   };
1113   grpc_call_credentials* creds =
1114       grpc_sts_credentials_create(&valid_options, nullptr);
1115 
1116   // Check security level.
1117   GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
1118 
1119   // First request: http put should be called.
1120   auto state = RequestMetadataState::NewInstance(absl::OkStatus(), emd);
1121   HttpRequest::SetOverride(httpcli_get_should_not_be_called,
1122                            sts_token_httpcli_post_success,
1123                            httpcli_put_should_not_be_called);
1124   state->RunRequestMetadataTest(creds, kTestUrlScheme, kTestAuthority,
1125                                 kTestPath);
1126   ExecCtx::Get()->Flush();
1127 
1128   // Second request: the cached token should be served directly.
1129   state = RequestMetadataState::NewInstance(absl::OkStatus(), emd);
1130   HttpRequest::SetOverride(httpcli_get_should_not_be_called,
1131                            httpcli_post_should_not_be_called,
1132                            httpcli_put_should_not_be_called);
1133   state->RunRequestMetadataTest(creds, kTestUrlScheme, kTestAuthority,
1134                                 kTestPath);
1135   ExecCtx::Get()->Flush();
1136   GPR_ASSERT(
1137       strcmp(creds->debug_string().c_str(), expected_creds_debug_string) == 0);
1138 
1139   creds->Unref();
1140   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
1141   gpr_free(subject_token_path);
1142   gpr_free(actor_token_path);
1143 }
1144 
TEST(CredentialsTest,TestStsCredsTokenFileNotFound)1145 TEST(CredentialsTest, TestStsCredsTokenFileNotFound) {
1146   ExecCtx exec_ctx;
1147   grpc_sts_credentials_options valid_options = {
1148       test_sts_endpoint_url,           // sts_endpoint_url
1149       "resource",                      // resource
1150       "audience",                      // audience
1151       "scope",                         // scope
1152       "requested_token_type",          // requested_token_type
1153       "/some/completely/random/path",  // subject_token_path
1154       test_signed_jwt_token_type,      // subject_token_type
1155       "",                              // actor_token_path
1156       ""                               // actor_token_type
1157   };
1158   grpc_call_credentials* creds =
1159       grpc_sts_credentials_create(&valid_options, nullptr);
1160 
1161   // Check security level.
1162   GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
1163 
1164   auto state = RequestMetadataState::NewInstance(
1165       GRPC_ERROR_CREATE("Error occurred when fetching oauth2 token."), {});
1166   HttpRequest::SetOverride(httpcli_get_should_not_be_called,
1167                            httpcli_post_should_not_be_called,
1168                            httpcli_put_should_not_be_called);
1169   state->RunRequestMetadataTest(creds, kTestUrlScheme, kTestAuthority,
1170                                 kTestPath);
1171   ExecCtx::Get()->Flush();
1172 
1173   // Cleanup.
1174   creds->Unref();
1175   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
1176 }
1177 
TEST(CredentialsTest,TestStsCredsNoActorTokenSuccess)1178 TEST(CredentialsTest, TestStsCredsNoActorTokenSuccess) {
1179   ExecCtx exec_ctx;
1180   std::string emd = "authorization: Bearer ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_";
1181   const char expected_creds_debug_string[] =
1182       "StsTokenFetcherCredentials{Path:/v1/"
1183       "token-exchange,Authority:foo.com:5555,OAuth2TokenFetcherCredentials}";
1184   char* subject_token_path = write_tmp_jwt_file(test_signed_jwt);
1185   grpc_sts_credentials_options valid_options = {
1186       test_sts_endpoint_url,       // sts_endpoint_url
1187       "resource",                  // resource
1188       "audience",                  // audience
1189       "scope",                     // scope
1190       "requested_token_type",      // requested_token_type
1191       subject_token_path,          // subject_token_path
1192       test_signed_jwt_token_type,  // subject_token_type
1193       "",                          // actor_token_path
1194       ""                           // actor_token_type
1195   };
1196   grpc_call_credentials* creds =
1197       grpc_sts_credentials_create(&valid_options, nullptr);
1198 
1199   // Check security level.
1200   GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
1201 
1202   // First request: http put should be called.
1203   auto state = RequestMetadataState::NewInstance(absl::OkStatus(), emd);
1204   HttpRequest::SetOverride(httpcli_get_should_not_be_called,
1205                            sts_token_httpcli_post_success_no_actor_token,
1206                            httpcli_put_should_not_be_called);
1207   state->RunRequestMetadataTest(creds, kTestUrlScheme, kTestAuthority,
1208                                 kTestPath);
1209   ExecCtx::Get()->Flush();
1210 
1211   // Second request: the cached token should be served directly.
1212   state = RequestMetadataState::NewInstance(absl::OkStatus(), emd);
1213   HttpRequest::SetOverride(httpcli_get_should_not_be_called,
1214                            httpcli_post_should_not_be_called,
1215                            httpcli_put_should_not_be_called);
1216   state->RunRequestMetadataTest(creds, kTestUrlScheme, kTestAuthority,
1217                                 kTestPath);
1218   ExecCtx::Get()->Flush();
1219   GPR_ASSERT(
1220       strcmp(creds->debug_string().c_str(), expected_creds_debug_string) == 0);
1221 
1222   creds->Unref();
1223   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
1224   gpr_free(subject_token_path);
1225 }
1226 
TEST(CredentialsTest,TestStsCredsLoadTokenFailure)1227 TEST(CredentialsTest, TestStsCredsLoadTokenFailure) {
1228   const char expected_creds_debug_string[] =
1229       "StsTokenFetcherCredentials{Path:/v1/"
1230       "token-exchange,Authority:foo.com:5555,OAuth2TokenFetcherCredentials}";
1231   ExecCtx exec_ctx;
1232   auto state = RequestMetadataState::NewInstance(
1233       GRPC_ERROR_CREATE("Error occurred when fetching oauth2 token."), {});
1234   char* test_signed_jwt_path = write_tmp_jwt_file(test_signed_jwt);
1235   grpc_sts_credentials_options options = {
1236       test_sts_endpoint_url,       // sts_endpoint_url
1237       "resource",                  // resource
1238       "audience",                  // audience
1239       "scope",                     // scope
1240       "requested_token_type",      // requested_token_type
1241       "invalid_path",              // subject_token_path
1242       test_signed_jwt_token_type,  // subject_token_type
1243       nullptr,                     // actor_token_path
1244       nullptr                      // actor_token_type
1245   };
1246   grpc_call_credentials* creds = grpc_sts_credentials_create(&options, nullptr);
1247   HttpRequest::SetOverride(httpcli_get_should_not_be_called,
1248                            httpcli_post_should_not_be_called,
1249                            httpcli_put_should_not_be_called);
1250   state->RunRequestMetadataTest(creds, kTestUrlScheme, kTestAuthority,
1251                                 kTestPath);
1252   GPR_ASSERT(
1253       strcmp(creds->debug_string().c_str(), expected_creds_debug_string) == 0);
1254 
1255   creds->Unref();
1256   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
1257   gpr_free(test_signed_jwt_path);
1258 }
1259 
TEST(CredentialsTest,TestStsCredsHttpFailure)1260 TEST(CredentialsTest, TestStsCredsHttpFailure) {
1261   const char expected_creds_debug_string[] =
1262       "StsTokenFetcherCredentials{Path:/v1/"
1263       "token-exchange,Authority:foo.com:5555,OAuth2TokenFetcherCredentials}";
1264   ExecCtx exec_ctx;
1265   auto state = RequestMetadataState::NewInstance(
1266       GRPC_ERROR_CREATE("Error occurred when fetching oauth2 token."), {});
1267   char* test_signed_jwt_path = write_tmp_jwt_file(test_signed_jwt);
1268   grpc_sts_credentials_options valid_options = {
1269       test_sts_endpoint_url,       // sts_endpoint_url
1270       "resource",                  // resource
1271       "audience",                  // audience
1272       "scope",                     // scope
1273       "requested_token_type",      // requested_token_type
1274       test_signed_jwt_path,        // subject_token_path
1275       test_signed_jwt_token_type,  // subject_token_type
1276       nullptr,                     // actor_token_path
1277       nullptr                      // actor_token_type
1278   };
1279   grpc_call_credentials* creds =
1280       grpc_sts_credentials_create(&valid_options, nullptr);
1281   HttpRequest::SetOverride(httpcli_get_should_not_be_called,
1282                            token_httpcli_post_failure,
1283                            httpcli_put_should_not_be_called);
1284   state->RunRequestMetadataTest(creds, kTestUrlScheme, kTestAuthority,
1285                                 kTestPath);
1286   GPR_ASSERT(
1287       strcmp(creds->debug_string().c_str(), expected_creds_debug_string) == 0);
1288   creds->Unref();
1289   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
1290   gpr_free(test_signed_jwt_path);
1291 }
1292 
validate_jwt_encode_and_sign_params(const grpc_auth_json_key * json_key,const char * scope,gpr_timespec token_lifetime)1293 void validate_jwt_encode_and_sign_params(const grpc_auth_json_key* json_key,
1294                                          const char* scope,
1295                                          gpr_timespec token_lifetime) {
1296   GPR_ASSERT(grpc_auth_json_key_is_valid(json_key));
1297   GPR_ASSERT(json_key->private_key != nullptr);
1298 #if OPENSSL_VERSION_NUMBER < 0x30000000L
1299   GPR_ASSERT(RSA_check_key(json_key->private_key));
1300 #else
1301   EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(json_key->private_key, NULL);
1302   GPR_ASSERT(EVP_PKEY_private_check(ctx));
1303   EVP_PKEY_CTX_free(ctx);
1304 #endif
1305   GPR_ASSERT(json_key->type != nullptr &&
1306              strcmp(json_key->type, "service_account") == 0);
1307   GPR_ASSERT(json_key->private_key_id != nullptr &&
1308              strcmp(json_key->private_key_id,
1309                     "e6b5137873db8d2ef81e06a47289e6434ec8a165") == 0);
1310   GPR_ASSERT(json_key->client_id != nullptr &&
1311              strcmp(json_key->client_id,
1312                     "777-abaslkan11hlb6nmim3bpspl31ud.apps."
1313                     "googleusercontent.com") == 0);
1314   GPR_ASSERT(json_key->client_email != nullptr &&
1315              strcmp(json_key->client_email,
1316                     "777-abaslkan11hlb6nmim3bpspl31ud@developer."
1317                     "gserviceaccount.com") == 0);
1318   if (scope != nullptr) GPR_ASSERT(strcmp(scope, test_scope) == 0);
1319   GPR_ASSERT(gpr_time_cmp(token_lifetime, grpc_max_auth_token_lifetime()) == 0);
1320 }
1321 
encode_and_sign_jwt_success(const grpc_auth_json_key * json_key,const char * audience,gpr_timespec token_lifetime,const char * scope)1322 char* encode_and_sign_jwt_success(const grpc_auth_json_key* json_key,
1323                                   const char* audience,
1324                                   gpr_timespec token_lifetime,
1325                                   const char* scope) {
1326   if (strcmp(audience, test_service_url_no_service_name) != 0 &&
1327       strcmp(audience, other_test_service_url_no_service_name) != 0) {
1328     return nullptr;
1329   }
1330   validate_jwt_encode_and_sign_params(json_key, scope, token_lifetime);
1331   return gpr_strdup(test_signed_jwt);
1332 }
1333 
encode_and_sign_jwt_failure(const grpc_auth_json_key * json_key,const char *,gpr_timespec token_lifetime,const char * scope)1334 char* encode_and_sign_jwt_failure(const grpc_auth_json_key* json_key,
1335                                   const char* /*audience*/,
1336                                   gpr_timespec token_lifetime,
1337                                   const char* scope) {
1338   validate_jwt_encode_and_sign_params(json_key, scope, token_lifetime);
1339   return nullptr;
1340 }
1341 
encode_and_sign_jwt_should_not_be_called(const grpc_auth_json_key *,const char *,gpr_timespec,const char *)1342 char* encode_and_sign_jwt_should_not_be_called(
1343     const grpc_auth_json_key* /*json_key*/, const char* /*audience*/,
1344     gpr_timespec /*token_lifetime*/, const char* /*scope*/) {
1345   GPR_ASSERT("grpc_jwt_encode_and_sign should not be called" == nullptr);
1346   return nullptr;
1347 }
1348 
creds_as_jwt(grpc_call_credentials * creds)1349 grpc_service_account_jwt_access_credentials* creds_as_jwt(
1350     grpc_call_credentials* creds) {
1351   GPR_ASSERT(creds != nullptr);
1352   GPR_ASSERT(creds->type() ==
1353              grpc_service_account_jwt_access_credentials::Type());
1354   return reinterpret_cast<grpc_service_account_jwt_access_credentials*>(creds);
1355 }
1356 
TEST(CredentialsTest,TestJwtCredsLifetime)1357 TEST(CredentialsTest, TestJwtCredsLifetime) {
1358   char* json_key_string = test_json_key_str();
1359   const char expected_creds_debug_string_prefix[] =
1360       "JWTAccessCredentials{ExpirationTime:";
1361   // Max lifetime.
1362   grpc_call_credentials* jwt_creds =
1363       grpc_service_account_jwt_access_credentials_create(
1364           json_key_string, grpc_max_auth_token_lifetime(), nullptr);
1365   GPR_ASSERT(gpr_time_cmp(creds_as_jwt(jwt_creds)->jwt_lifetime(),
1366                           grpc_max_auth_token_lifetime()) == 0);
1367   // Check security level.
1368   GPR_ASSERT(jwt_creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
1369   GPR_ASSERT(strncmp(expected_creds_debug_string_prefix,
1370                      jwt_creds->debug_string().c_str(),
1371                      strlen(expected_creds_debug_string_prefix)) == 0);
1372   grpc_call_credentials_release(jwt_creds);
1373 
1374   // Shorter lifetime.
1375   gpr_timespec token_lifetime = {10, 0, GPR_TIMESPAN};
1376   GPR_ASSERT(gpr_time_cmp(grpc_max_auth_token_lifetime(), token_lifetime) > 0);
1377   jwt_creds = grpc_service_account_jwt_access_credentials_create(
1378       json_key_string, token_lifetime, nullptr);
1379   GPR_ASSERT(gpr_time_cmp(creds_as_jwt(jwt_creds)->jwt_lifetime(),
1380                           token_lifetime) == 0);
1381   GPR_ASSERT(strncmp(expected_creds_debug_string_prefix,
1382                      jwt_creds->debug_string().c_str(),
1383                      strlen(expected_creds_debug_string_prefix)) == 0);
1384   grpc_call_credentials_release(jwt_creds);
1385 
1386   // Cropped lifetime.
1387   gpr_timespec add_to_max = {10, 0, GPR_TIMESPAN};
1388   token_lifetime = gpr_time_add(grpc_max_auth_token_lifetime(), add_to_max);
1389   jwt_creds = grpc_service_account_jwt_access_credentials_create(
1390       json_key_string, token_lifetime, nullptr);
1391   GPR_ASSERT(gpr_time_cmp(creds_as_jwt(jwt_creds)->jwt_lifetime(),
1392                           grpc_max_auth_token_lifetime()) == 0);
1393   GPR_ASSERT(strncmp(expected_creds_debug_string_prefix,
1394                      jwt_creds->debug_string().c_str(),
1395                      strlen(expected_creds_debug_string_prefix)) == 0);
1396   grpc_call_credentials_release(jwt_creds);
1397 
1398   gpr_free(json_key_string);
1399 }
1400 
TEST(CredentialsTest,TestRemoveServiceFromJwtUri)1401 TEST(CredentialsTest, TestRemoveServiceFromJwtUri) {
1402   const char wrong_uri[] = "hello world";
1403   GPR_ASSERT(!RemoveServiceNameFromJwtUri(wrong_uri).ok());
1404   const char valid_uri[] = "https://foo.com/get/";
1405   const char expected_uri[] = "https://foo.com/";
1406   auto output = RemoveServiceNameFromJwtUri(valid_uri);
1407   GPR_ASSERT(output.ok());
1408   GPR_ASSERT(strcmp(output->c_str(), expected_uri) == 0);
1409 }
1410 
TEST(CredentialsTest,TestJwtCredsSuccess)1411 TEST(CredentialsTest, TestJwtCredsSuccess) {
1412   const char expected_creds_debug_string_prefix[] =
1413       "JWTAccessCredentials{ExpirationTime:";
1414 
1415   char* json_key_string = test_json_key_str();
1416   ExecCtx exec_ctx;
1417   std::string expected_md_value = absl::StrCat("Bearer ", test_signed_jwt);
1418   std::string emd = absl::StrCat("authorization: ", expected_md_value);
1419   grpc_call_credentials* creds =
1420       grpc_service_account_jwt_access_credentials_create(
1421           json_key_string, grpc_max_auth_token_lifetime(), nullptr);
1422 
1423   // First request: jwt_encode_and_sign should be called.
1424   auto state = RequestMetadataState::NewInstance(absl::OkStatus(), emd);
1425   grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_success);
1426   state->RunRequestMetadataTest(creds, kTestUrlScheme, kTestAuthority,
1427                                 kTestPath);
1428   ExecCtx::Get()->Flush();
1429 
1430   // Second request: the cached token should be served directly.
1431   state = RequestMetadataState::NewInstance(absl::OkStatus(), emd);
1432   grpc_jwt_encode_and_sign_set_override(
1433       encode_and_sign_jwt_should_not_be_called);
1434   state->RunRequestMetadataTest(creds, kTestUrlScheme, kTestAuthority,
1435                                 kTestPath);
1436   ExecCtx::Get()->Flush();
1437 
1438   // Third request: Different service url so jwt_encode_and_sign should be
1439   // called again (no caching).
1440   state = RequestMetadataState::NewInstance(absl::OkStatus(), emd);
1441   grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_success);
1442   state->RunRequestMetadataTest(creds, kTestUrlScheme, kTestOtherAuthority,
1443                                 kTestOtherPath);
1444   ExecCtx::Get()->Flush();
1445   GPR_ASSERT(strncmp(expected_creds_debug_string_prefix,
1446                      creds->debug_string().c_str(),
1447                      strlen(expected_creds_debug_string_prefix)) == 0);
1448 
1449   creds->Unref();
1450   gpr_free(json_key_string);
1451   grpc_jwt_encode_and_sign_set_override(nullptr);
1452 }
1453 
TEST(CredentialsTest,TestJwtCredsSigningFailure)1454 TEST(CredentialsTest, TestJwtCredsSigningFailure) {
1455   const char expected_creds_debug_string_prefix[] =
1456       "JWTAccessCredentials{ExpirationTime:";
1457   char* json_key_string = test_json_key_str();
1458   ExecCtx exec_ctx;
1459   auto state = RequestMetadataState::NewInstance(
1460       GRPC_ERROR_CREATE("Could not generate JWT."), {});
1461   grpc_call_credentials* creds =
1462       grpc_service_account_jwt_access_credentials_create(
1463           json_key_string, grpc_max_auth_token_lifetime(), nullptr);
1464 
1465   grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_failure);
1466   state->RunRequestMetadataTest(creds, kTestUrlScheme, kTestAuthority,
1467                                 kTestPath);
1468 
1469   gpr_free(json_key_string);
1470   GPR_ASSERT(strncmp(expected_creds_debug_string_prefix,
1471                      creds->debug_string().c_str(),
1472                      strlen(expected_creds_debug_string_prefix)) == 0);
1473 
1474   creds->Unref();
1475   grpc_jwt_encode_and_sign_set_override(nullptr);
1476 }
1477 
set_google_default_creds_env_var_with_file_contents(const char * file_prefix,const char * contents)1478 void set_google_default_creds_env_var_with_file_contents(
1479     const char* file_prefix, const char* contents) {
1480   size_t contents_len = strlen(contents);
1481   char* creds_file_name;
1482   FILE* creds_file = gpr_tmpfile(file_prefix, &creds_file_name);
1483   GPR_ASSERT(creds_file_name != nullptr);
1484   GPR_ASSERT(creds_file != nullptr);
1485   GPR_ASSERT(fwrite(contents, 1, contents_len, creds_file) == contents_len);
1486   fclose(creds_file);
1487   SetEnv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, creds_file_name);
1488   gpr_free(creds_file_name);
1489 }
1490 
test_gce_tenancy_checker(void)1491 bool test_gce_tenancy_checker(void) {
1492   g_test_gce_tenancy_checker_called = true;
1493   return g_test_is_on_gce;
1494 }
1495 
null_well_known_creds_path_getter(void)1496 std::string null_well_known_creds_path_getter(void) { return ""; }
1497 
TEST(CredentialsTest,TestGoogleDefaultCredsAuthKey)1498 TEST(CredentialsTest, TestGoogleDefaultCredsAuthKey) {
1499   ExecCtx exec_ctx;
1500   grpc_composite_channel_credentials* creds;
1501   char* json_key = test_json_key_str();
1502   grpc_flush_cached_google_default_credentials();
1503   set_gce_tenancy_checker_for_testing(test_gce_tenancy_checker);
1504   g_test_gce_tenancy_checker_called = false;
1505   g_test_is_on_gce = true;
1506   set_google_default_creds_env_var_with_file_contents(
1507       "json_key_google_default_creds", json_key);
1508   grpc_override_well_known_credentials_path_getter(
1509       null_well_known_creds_path_getter);
1510   gpr_free(json_key);
1511   creds = reinterpret_cast<grpc_composite_channel_credentials*>(
1512       grpc_google_default_credentials_create(nullptr));
1513   auto* default_creds =
1514       reinterpret_cast<const grpc_google_default_channel_credentials*>(
1515           creds->inner_creds());
1516   GPR_ASSERT(default_creds->ssl_creds() != nullptr);
1517   auto* jwt =
1518       reinterpret_cast<const grpc_service_account_jwt_access_credentials*>(
1519           creds->call_creds());
1520   GPR_ASSERT(
1521       strcmp(jwt->key().client_id,
1522              "777-abaslkan11hlb6nmim3bpspl31ud.apps.googleusercontent.com") ==
1523       0);
1524   GPR_ASSERT(g_test_gce_tenancy_checker_called == false);
1525   creds->Unref();
1526   SetEnv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, "");  // Reset.
1527   grpc_override_well_known_credentials_path_getter(nullptr);
1528 }
1529 
TEST(CredentialsTest,TestGoogleDefaultCredsRefreshToken)1530 TEST(CredentialsTest, TestGoogleDefaultCredsRefreshToken) {
1531   ExecCtx exec_ctx;
1532   grpc_composite_channel_credentials* creds;
1533   grpc_flush_cached_google_default_credentials();
1534   set_google_default_creds_env_var_with_file_contents(
1535       "refresh_token_google_default_creds", test_refresh_token_str);
1536   grpc_override_well_known_credentials_path_getter(
1537       null_well_known_creds_path_getter);
1538   creds = reinterpret_cast<grpc_composite_channel_credentials*>(
1539       grpc_google_default_credentials_create(nullptr));
1540   auto* default_creds =
1541       reinterpret_cast<const grpc_google_default_channel_credentials*>(
1542           creds->inner_creds());
1543   GPR_ASSERT(default_creds->ssl_creds() != nullptr);
1544   auto* refresh =
1545       reinterpret_cast<const grpc_google_refresh_token_credentials*>(
1546           creds->call_creds());
1547   GPR_ASSERT(strcmp(refresh->refresh_token().client_id,
1548                     "32555999999.apps.googleusercontent.com") == 0);
1549   creds->Unref();
1550   SetEnv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, "");  // Reset.
1551   grpc_override_well_known_credentials_path_getter(nullptr);
1552 }
1553 
TEST(CredentialsTest,TestGoogleDefaultCredsExternalAccountCredentialsPscSts)1554 TEST(CredentialsTest, TestGoogleDefaultCredsExternalAccountCredentialsPscSts) {
1555   ExecCtx exec_ctx;
1556   grpc_composite_channel_credentials* creds;
1557   grpc_flush_cached_google_default_credentials();
1558   set_google_default_creds_env_var_with_file_contents(
1559       "google_default_creds_external_account_credentials_psc_sts",
1560       test_external_account_credentials_psc_sts_str);
1561   grpc_override_well_known_credentials_path_getter(
1562       null_well_known_creds_path_getter);
1563   creds = reinterpret_cast<grpc_composite_channel_credentials*>(
1564       grpc_google_default_credentials_create(nullptr));
1565   auto* default_creds =
1566       reinterpret_cast<const grpc_google_default_channel_credentials*>(
1567           creds->inner_creds());
1568   GPR_ASSERT(default_creds->ssl_creds() != nullptr);
1569   auto* external =
1570       reinterpret_cast<const ExternalAccountCredentials*>(creds->call_creds());
1571   GPR_ASSERT(external != nullptr);
1572   creds->Unref();
1573   SetEnv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, "");  // Reset.
1574   grpc_override_well_known_credentials_path_getter(nullptr);
1575 }
1576 
TEST(CredentialsTest,TestGoogleDefaultCredsExternalAccountCredentialsPscIam)1577 TEST(CredentialsTest, TestGoogleDefaultCredsExternalAccountCredentialsPscIam) {
1578   ExecCtx exec_ctx;
1579   grpc_composite_channel_credentials* creds;
1580   grpc_flush_cached_google_default_credentials();
1581   set_google_default_creds_env_var_with_file_contents(
1582       "google_default_creds_external_account_credentials_psc_iam",
1583       test_external_account_credentials_psc_iam_str);
1584   grpc_override_well_known_credentials_path_getter(
1585       null_well_known_creds_path_getter);
1586   creds = reinterpret_cast<grpc_composite_channel_credentials*>(
1587       grpc_google_default_credentials_create(nullptr));
1588   auto* default_creds =
1589       reinterpret_cast<const grpc_google_default_channel_credentials*>(
1590           creds->inner_creds());
1591   GPR_ASSERT(default_creds->ssl_creds() != nullptr);
1592   auto* external =
1593       reinterpret_cast<const ExternalAccountCredentials*>(creds->call_creds());
1594   GPR_ASSERT(external != nullptr);
1595   creds->Unref();
1596   SetEnv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, "");  // Reset.
1597   grpc_override_well_known_credentials_path_getter(nullptr);
1598 }
1599 
default_creds_metadata_server_detection_httpcli_get_success_override(const grpc_http_request *,const char * host,const char * path,Timestamp,grpc_closure * on_done,grpc_http_response * response)1600 int default_creds_metadata_server_detection_httpcli_get_success_override(
1601     const grpc_http_request* /*request*/, const char* host, const char* path,
1602     Timestamp /*deadline*/, grpc_closure* on_done,
1603     grpc_http_response* response) {
1604   *response = http_response(200, "");
1605   grpc_http_header* headers =
1606       static_cast<grpc_http_header*>(gpr_malloc(sizeof(*headers) * 1));
1607   headers[0].key = gpr_strdup("Metadata-Flavor");
1608   headers[0].value = gpr_strdup("Google");
1609   response->hdr_count = 1;
1610   response->hdrs = headers;
1611   GPR_ASSERT(strcmp(path, "/") == 0);
1612   GPR_ASSERT(strcmp(host, "metadata.google.internal.") == 0);
1613   ExecCtx::Run(DEBUG_LOCATION, on_done, absl::OkStatus());
1614   return 1;
1615 }
1616 
TEST(CredentialsTest,TestGoogleDefaultCredsGce)1617 TEST(CredentialsTest, TestGoogleDefaultCredsGce) {
1618   ExecCtx exec_ctx;
1619   auto state = RequestMetadataState::NewInstance(
1620       absl::OkStatus(),
1621       "authorization: Bearer ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_");
1622   grpc_flush_cached_google_default_credentials();
1623   SetEnv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, "");  // Reset.
1624   grpc_override_well_known_credentials_path_getter(
1625       null_well_known_creds_path_getter);
1626   set_gce_tenancy_checker_for_testing(test_gce_tenancy_checker);
1627   g_test_gce_tenancy_checker_called = false;
1628   g_test_is_on_gce = true;
1629 
1630   // Simulate a successful detection of GCE.
1631   grpc_composite_channel_credentials* creds =
1632       reinterpret_cast<grpc_composite_channel_credentials*>(
1633           grpc_google_default_credentials_create(nullptr));
1634 
1635   // Verify that the default creds actually embeds a GCE creds.
1636   GPR_ASSERT(creds != nullptr);
1637   GPR_ASSERT(creds->call_creds() != nullptr);
1638   HttpRequest::SetOverride(compute_engine_httpcli_get_success_override,
1639                            httpcli_post_should_not_be_called,
1640                            httpcli_put_should_not_be_called);
1641   state->RunRequestMetadataTest(creds->mutable_call_creds(), kTestUrlScheme,
1642                                 kTestAuthority, kTestPath);
1643   ExecCtx::Get()->Flush();
1644 
1645   GPR_ASSERT(g_test_gce_tenancy_checker_called == true);
1646 
1647   // Cleanup.
1648   creds->Unref();
1649   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
1650   grpc_override_well_known_credentials_path_getter(nullptr);
1651 }
1652 
TEST(CredentialsTest,TestGoogleDefaultCredsNonGce)1653 TEST(CredentialsTest, TestGoogleDefaultCredsNonGce) {
1654   ExecCtx exec_ctx;
1655   auto state = RequestMetadataState::NewInstance(
1656       absl::OkStatus(),
1657       "authorization: Bearer ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_");
1658   grpc_flush_cached_google_default_credentials();
1659   SetEnv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, "");  // Reset.
1660   grpc_override_well_known_credentials_path_getter(
1661       null_well_known_creds_path_getter);
1662   set_gce_tenancy_checker_for_testing(test_gce_tenancy_checker);
1663   g_test_gce_tenancy_checker_called = false;
1664   g_test_is_on_gce = false;
1665   // Simulate a successful detection of metadata server.
1666   HttpRequest::SetOverride(
1667       default_creds_metadata_server_detection_httpcli_get_success_override,
1668       httpcli_post_should_not_be_called, httpcli_put_should_not_be_called);
1669   grpc_composite_channel_credentials* creds =
1670       reinterpret_cast<grpc_composite_channel_credentials*>(
1671           grpc_google_default_credentials_create(nullptr));
1672   // Verify that the default creds actually embeds a GCE creds.
1673   GPR_ASSERT(creds != nullptr);
1674   GPR_ASSERT(creds->call_creds() != nullptr);
1675   HttpRequest::SetOverride(compute_engine_httpcli_get_success_override,
1676                            httpcli_post_should_not_be_called,
1677                            httpcli_put_should_not_be_called);
1678   state->RunRequestMetadataTest(creds->mutable_call_creds(), kTestUrlScheme,
1679                                 kTestAuthority, kTestPath);
1680   ExecCtx::Get()->Flush();
1681   GPR_ASSERT(g_test_gce_tenancy_checker_called == true);
1682   // Cleanup.
1683   creds->Unref();
1684   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
1685   grpc_override_well_known_credentials_path_getter(nullptr);
1686 }
1687 
default_creds_gce_detection_httpcli_get_failure_override(const grpc_http_request *,const char * host,const char * path,Timestamp,grpc_closure * on_done,grpc_http_response * response)1688 int default_creds_gce_detection_httpcli_get_failure_override(
1689     const grpc_http_request* /*request*/, const char* host, const char* path,
1690     Timestamp /*deadline*/, grpc_closure* on_done,
1691     grpc_http_response* response) {
1692   // No magic header.
1693   GPR_ASSERT(strcmp(path, "/") == 0);
1694   GPR_ASSERT(strcmp(host, "metadata.google.internal.") == 0);
1695   *response = http_response(200, "");
1696   ExecCtx::Run(DEBUG_LOCATION, on_done, absl::OkStatus());
1697   return 1;
1698 }
1699 
TEST(CredentialsTest,TestNoGoogleDefaultCreds)1700 TEST(CredentialsTest, TestNoGoogleDefaultCreds) {
1701   grpc_flush_cached_google_default_credentials();
1702   SetEnv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, "");  // Reset.
1703   grpc_override_well_known_credentials_path_getter(
1704       null_well_known_creds_path_getter);
1705   set_gce_tenancy_checker_for_testing(test_gce_tenancy_checker);
1706   g_test_gce_tenancy_checker_called = false;
1707   g_test_is_on_gce = false;
1708   HttpRequest::SetOverride(
1709       default_creds_gce_detection_httpcli_get_failure_override,
1710       httpcli_post_should_not_be_called, httpcli_put_should_not_be_called);
1711   // Simulate a successful detection of GCE.
1712   GPR_ASSERT(grpc_google_default_credentials_create(nullptr) == nullptr);
1713   // Try a second one. GCE detection should occur again.
1714   g_test_gce_tenancy_checker_called = false;
1715   GPR_ASSERT(grpc_google_default_credentials_create(nullptr) == nullptr);
1716   GPR_ASSERT(g_test_gce_tenancy_checker_called == true);
1717   // Cleanup.
1718   grpc_override_well_known_credentials_path_getter(nullptr);
1719   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
1720 }
1721 
TEST(CredentialsTest,TestGoogleDefaultCredsCallCredsSpecified)1722 TEST(CredentialsTest, TestGoogleDefaultCredsCallCredsSpecified) {
1723   auto state = RequestMetadataState::NewInstance(
1724       absl::OkStatus(),
1725       "authorization: Bearer ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_");
1726   ExecCtx exec_ctx;
1727   grpc_flush_cached_google_default_credentials();
1728   grpc_call_credentials* call_creds =
1729       grpc_google_compute_engine_credentials_create(nullptr);
1730   set_gce_tenancy_checker_for_testing(test_gce_tenancy_checker);
1731   g_test_gce_tenancy_checker_called = false;
1732   g_test_is_on_gce = true;
1733   HttpRequest::SetOverride(
1734       default_creds_metadata_server_detection_httpcli_get_success_override,
1735       httpcli_post_should_not_be_called, httpcli_put_should_not_be_called);
1736   grpc_composite_channel_credentials* channel_creds =
1737       reinterpret_cast<grpc_composite_channel_credentials*>(
1738           grpc_google_default_credentials_create(call_creds));
1739   GPR_ASSERT(g_test_gce_tenancy_checker_called == false);
1740   GPR_ASSERT(channel_creds != nullptr);
1741   GPR_ASSERT(channel_creds->call_creds() != nullptr);
1742   HttpRequest::SetOverride(compute_engine_httpcli_get_success_override,
1743                            httpcli_post_should_not_be_called,
1744                            httpcli_put_should_not_be_called);
1745   state->RunRequestMetadataTest(channel_creds->mutable_call_creds(),
1746                                 kTestUrlScheme, kTestAuthority, kTestPath);
1747   ExecCtx::Get()->Flush();
1748   channel_creds->Unref();
1749   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
1750 }
1751 
1752 struct fake_call_creds : public grpc_call_credentials {
1753  public:
GetRequestMetadatagrpc_core::__anon61763aca0111::fake_call_creds1754   ArenaPromise<absl::StatusOr<ClientMetadataHandle>> GetRequestMetadata(
1755       ClientMetadataHandle initial_metadata,
1756       const grpc_call_credentials::GetRequestMetadataArgs*) override {
1757     initial_metadata->Append("foo", Slice::FromStaticString("oof"),
1758                              [](absl::string_view, const Slice&) { abort(); });
1759     return Immediate(std::move(initial_metadata));
1760   }
1761 
typegrpc_core::__anon61763aca0111::fake_call_creds1762   UniqueTypeName type() const override {
1763     static UniqueTypeName::Factory kFactory("fake");
1764     return kFactory.Create();
1765   }
1766 
1767  private:
cmp_implgrpc_core::__anon61763aca0111::fake_call_creds1768   int cmp_impl(const grpc_call_credentials* other) const override {
1769     // TODO(yashykt): Check if we can do something better here
1770     return QsortCompare(static_cast<const grpc_call_credentials*>(this), other);
1771   }
1772 };
1773 
TEST(CredentialsTest,TestGoogleDefaultCredsNotDefault)1774 TEST(CredentialsTest, TestGoogleDefaultCredsNotDefault) {
1775   auto state = RequestMetadataState::NewInstance(absl::OkStatus(), "foo: oof");
1776   ExecCtx exec_ctx;
1777   grpc_flush_cached_google_default_credentials();
1778   RefCountedPtr<grpc_call_credentials> call_creds =
1779       MakeRefCounted<fake_call_creds>();
1780   set_gce_tenancy_checker_for_testing(test_gce_tenancy_checker);
1781   g_test_gce_tenancy_checker_called = false;
1782   g_test_is_on_gce = true;
1783   HttpRequest::SetOverride(
1784       default_creds_metadata_server_detection_httpcli_get_success_override,
1785       httpcli_post_should_not_be_called, httpcli_put_should_not_be_called);
1786   grpc_composite_channel_credentials* channel_creds =
1787       reinterpret_cast<grpc_composite_channel_credentials*>(
1788           grpc_google_default_credentials_create(call_creds.release()));
1789   GPR_ASSERT(g_test_gce_tenancy_checker_called == false);
1790   GPR_ASSERT(channel_creds != nullptr);
1791   GPR_ASSERT(channel_creds->call_creds() != nullptr);
1792   state->RunRequestMetadataTest(channel_creds->mutable_call_creds(),
1793                                 kTestUrlScheme, kTestAuthority, kTestPath);
1794   ExecCtx::Get()->Flush();
1795   channel_creds->Unref();
1796   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
1797 }
1798 
1799 typedef enum {
1800   PLUGIN_INITIAL_STATE,
1801   PLUGIN_GET_METADATA_CALLED_STATE,
1802   PLUGIN_DESTROY_CALLED_STATE
1803 } plugin_state;
1804 
1805 const std::map<std::string, std::string> plugin_md = {{"foo", "bar"},
1806                                                       {"hi", "there"}};
1807 
plugin_get_metadata_success(void * state,grpc_auth_metadata_context context,grpc_credentials_plugin_metadata_cb,void *,grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX],size_t * num_creds_md,grpc_status_code *,const char **)1808 int plugin_get_metadata_success(
1809     void* state, grpc_auth_metadata_context context,
1810     grpc_credentials_plugin_metadata_cb /*cb*/, void* /*user_data*/,
1811     grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX],
1812     size_t* num_creds_md, grpc_status_code* /*status*/,
1813     const char** /*error_details*/) {
1814   GPR_ASSERT(strcmp(context.service_url, test_service_url) == 0);
1815   GPR_ASSERT(strcmp(context.method_name, test_method) == 0);
1816   GPR_ASSERT(context.channel_auth_context == nullptr);
1817   GPR_ASSERT(context.reserved == nullptr);
1818   GPR_ASSERT(plugin_md.size() < GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX);
1819   plugin_state* s = static_cast<plugin_state*>(state);
1820   *s = PLUGIN_GET_METADATA_CALLED_STATE;
1821   size_t i = 0;
1822   for (auto const& md : plugin_md) {
1823     memset(&creds_md[i], 0, sizeof(grpc_metadata));
1824     creds_md[i].key = grpc_slice_from_copied_string(md.first.c_str());
1825     creds_md[i].value = grpc_slice_from_copied_string(md.second.c_str());
1826     i += 1;
1827   }
1828   *num_creds_md = plugin_md.size();
1829   return true;  // Synchronous return.
1830 }
1831 
1832 const char* plugin_error_details = "Could not get metadata for plugin.";
1833 
plugin_get_metadata_failure(void * state,grpc_auth_metadata_context context,grpc_credentials_plugin_metadata_cb,void *,grpc_metadata[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX],size_t *,grpc_status_code * status,const char ** error_details)1834 int plugin_get_metadata_failure(
1835     void* state, grpc_auth_metadata_context context,
1836     grpc_credentials_plugin_metadata_cb /*cb*/, void* /*user_data*/,
1837     grpc_metadata /*creds_md*/[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX],
1838     size_t* /*num_creds_md*/, grpc_status_code* status,
1839     const char** error_details) {
1840   GPR_ASSERT(strcmp(context.service_url, test_service_url) == 0);
1841   GPR_ASSERT(strcmp(context.method_name, test_method) == 0);
1842   GPR_ASSERT(context.channel_auth_context == nullptr);
1843   GPR_ASSERT(context.reserved == nullptr);
1844   plugin_state* s = static_cast<plugin_state*>(state);
1845   *s = PLUGIN_GET_METADATA_CALLED_STATE;
1846   *status = GRPC_STATUS_UNAUTHENTICATED;
1847   *error_details = gpr_strdup(plugin_error_details);
1848   return true;  // Synchronous return.
1849 }
1850 
plugin_destroy(void * state)1851 void plugin_destroy(void* state) {
1852   plugin_state* s = static_cast<plugin_state*>(state);
1853   *s = PLUGIN_DESTROY_CALLED_STATE;
1854 }
1855 
plugin_debug_string(void * state)1856 char* plugin_debug_string(void* state) {
1857   plugin_state* s = static_cast<plugin_state*>(state);
1858   char* ret = nullptr;
1859   switch (*s) {
1860     case PLUGIN_INITIAL_STATE:
1861       gpr_asprintf(&ret, "TestPluginCredentials{state:INITIAL}");
1862       break;
1863     case PLUGIN_GET_METADATA_CALLED_STATE:
1864       gpr_asprintf(&ret, "TestPluginCredentials{state:GET_METADATA_CALLED}");
1865       break;
1866     case PLUGIN_DESTROY_CALLED_STATE:
1867       gpr_asprintf(&ret, "TestPluginCredentials{state:DESTROY}");
1868       break;
1869     default:
1870       gpr_asprintf(&ret, "TestPluginCredentials{state:UNKNOWN}");
1871       break;
1872   }
1873   return ret;
1874 }
1875 
TEST(CredentialsTest,TestMetadataPluginSuccess)1876 TEST(CredentialsTest, TestMetadataPluginSuccess) {
1877   const char expected_creds_debug_string[] =
1878       "TestPluginCredentials{state:GET_METADATA_CALLED}";
1879   plugin_state state = PLUGIN_INITIAL_STATE;
1880   grpc_metadata_credentials_plugin plugin;
1881   ExecCtx exec_ctx;
1882   auto md_state = RequestMetadataState::NewInstance(absl::OkStatus(),
1883                                                     "foo: bar, hi: there");
1884 
1885   plugin.state = &state;
1886   plugin.get_metadata = plugin_get_metadata_success;
1887   plugin.destroy = plugin_destroy;
1888   plugin.debug_string = plugin_debug_string;
1889 
1890   grpc_call_credentials* creds = grpc_metadata_credentials_create_from_plugin(
1891       plugin, GRPC_PRIVACY_AND_INTEGRITY, nullptr);
1892   // Check security level.
1893   GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
1894   GPR_ASSERT(state == PLUGIN_INITIAL_STATE);
1895   md_state->RunRequestMetadataTest(creds, kTestUrlScheme, kTestAuthority,
1896                                    kTestPath);
1897   GPR_ASSERT(state == PLUGIN_GET_METADATA_CALLED_STATE);
1898   GPR_ASSERT(
1899       strcmp(creds->debug_string().c_str(), expected_creds_debug_string) == 0);
1900   creds->Unref();
1901 
1902   GPR_ASSERT(state == PLUGIN_DESTROY_CALLED_STATE);
1903 }
1904 
TEST(CredentialsTest,TestMetadataPluginFailure)1905 TEST(CredentialsTest, TestMetadataPluginFailure) {
1906   const char expected_creds_debug_string[] =
1907       "TestPluginCredentials{state:GET_METADATA_CALLED}";
1908 
1909   plugin_state state = PLUGIN_INITIAL_STATE;
1910   grpc_metadata_credentials_plugin plugin;
1911   ExecCtx exec_ctx;
1912   auto md_state = RequestMetadataState::NewInstance(
1913       GRPC_ERROR_CREATE(
1914           absl::StrCat("Getting metadata from plugin failed with error: ",
1915                        plugin_error_details)),
1916       {});
1917 
1918   plugin.state = &state;
1919   plugin.get_metadata = plugin_get_metadata_failure;
1920   plugin.destroy = plugin_destroy;
1921   plugin.debug_string = plugin_debug_string;
1922 
1923   grpc_call_credentials* creds = grpc_metadata_credentials_create_from_plugin(
1924       plugin, GRPC_PRIVACY_AND_INTEGRITY, nullptr);
1925   GPR_ASSERT(state == PLUGIN_INITIAL_STATE);
1926   md_state->RunRequestMetadataTest(creds, kTestUrlScheme, kTestAuthority,
1927                                    kTestPath);
1928   GPR_ASSERT(state == PLUGIN_GET_METADATA_CALLED_STATE);
1929   GPR_ASSERT(
1930       strcmp(creds->debug_string().c_str(), expected_creds_debug_string) == 0);
1931   creds->Unref();
1932 
1933   GPR_ASSERT(state == PLUGIN_DESTROY_CALLED_STATE);
1934 }
1935 
TEST(CredentialsTest,TestGetWellKnownGoogleCredentialsFilePath)1936 TEST(CredentialsTest, TestGetWellKnownGoogleCredentialsFilePath) {
1937   auto home = GetEnv("HOME");
1938   bool restore_home_env = false;
1939 #if defined(GRPC_BAZEL_BUILD) && \
1940     (defined(GPR_POSIX_ENV) || defined(GPR_LINUX_ENV))
1941   // when running under bazel locally, the HOME variable is not set
1942   // so we set it to some fake value
1943   restore_home_env = true;
1944   SetEnv("HOME", "/fake/home/for/bazel");
1945 #endif  // defined(GRPC_BAZEL_BUILD) && (defined(GPR_POSIX_ENV) ||
1946         // defined(GPR_LINUX_ENV))
1947   std::string path = grpc_get_well_known_google_credentials_file_path();
1948   GPR_ASSERT(!path.empty());
1949 #if defined(GPR_POSIX_ENV) || defined(GPR_LINUX_ENV)
1950   restore_home_env = true;
1951   UnsetEnv("HOME");
1952   path = grpc_get_well_known_google_credentials_file_path();
1953   GPR_ASSERT(path.empty());
1954 #endif  // GPR_POSIX_ENV || GPR_LINUX_ENV
1955   if (restore_home_env) {
1956     SetOrUnsetEnv("HOME", home);
1957   }
1958 }
1959 
TEST(CredentialsTest,TestChannelCredsDuplicateWithoutCallCreds)1960 TEST(CredentialsTest, TestChannelCredsDuplicateWithoutCallCreds) {
1961   const char expected_creds_debug_string[] =
1962       "AccessTokenCredentials{Token:present}";
1963   ExecCtx exec_ctx;
1964 
1965   grpc_channel_credentials* channel_creds =
1966       grpc_fake_transport_security_credentials_create();
1967 
1968   RefCountedPtr<grpc_channel_credentials> dup =
1969       channel_creds->duplicate_without_call_credentials();
1970   GPR_ASSERT(dup == channel_creds);
1971   dup.reset();
1972 
1973   grpc_call_credentials* call_creds =
1974       grpc_access_token_credentials_create("blah", nullptr);
1975   grpc_channel_credentials* composite_creds =
1976       grpc_composite_channel_credentials_create(channel_creds, call_creds,
1977                                                 nullptr);
1978   GPR_ASSERT(strcmp(call_creds->debug_string().c_str(),
1979                     expected_creds_debug_string) == 0);
1980 
1981   call_creds->Unref();
1982   dup = composite_creds->duplicate_without_call_credentials();
1983   GPR_ASSERT(dup == channel_creds);
1984   dup.reset();
1985 
1986   channel_creds->Unref();
1987   composite_creds->Unref();
1988 }
1989 
1990 typedef struct {
1991   const char* url_scheme;
1992   const char* call_host;
1993   const char* call_method;
1994   const char* desired_service_url;
1995   const char* desired_method_name;
1996 } auth_metadata_context_test_case;
1997 
auth_metadata_context_build(const char * url_scheme,const grpc_slice & call_host,const grpc_slice & call_method,grpc_auth_context * auth_context,grpc_auth_metadata_context * auth_md_context)1998 void auth_metadata_context_build(const char* url_scheme,
1999                                  const grpc_slice& call_host,
2000                                  const grpc_slice& call_method,
2001                                  grpc_auth_context* auth_context,
2002                                  grpc_auth_metadata_context* auth_md_context) {
2003   char* service = grpc_slice_to_c_string(call_method);
2004   char* last_slash = strrchr(service, '/');
2005   char* method_name = nullptr;
2006   char* service_url = nullptr;
2007   grpc_auth_metadata_context_reset(auth_md_context);
2008   if (last_slash == nullptr) {
2009     gpr_log(GPR_ERROR, "No '/' found in fully qualified method name");
2010     service[0] = '\0';
2011     method_name = gpr_strdup("");
2012   } else if (last_slash == service) {
2013     method_name = gpr_strdup("");
2014   } else {
2015     *last_slash = '\0';
2016     method_name = gpr_strdup(last_slash + 1);
2017   }
2018   char* host_and_port = grpc_slice_to_c_string(call_host);
2019   if (url_scheme != nullptr && strcmp(url_scheme, GRPC_SSL_URL_SCHEME) == 0) {
2020     // Remove the port if it is 443.
2021     char* port_delimiter = strrchr(host_and_port, ':');
2022     if (port_delimiter != nullptr && strcmp(port_delimiter + 1, "443") == 0) {
2023       *port_delimiter = '\0';
2024     }
2025   }
2026   gpr_asprintf(&service_url, "%s://%s%s",
2027                url_scheme == nullptr ? "" : url_scheme, host_and_port, service);
2028   auth_md_context->service_url = service_url;
2029   auth_md_context->method_name = method_name;
2030   auth_md_context->channel_auth_context =
2031       auth_context == nullptr
2032           ? nullptr
2033           : auth_context->Ref(DEBUG_LOCATION, "grpc_auth_metadata_context")
2034                 .release();
2035   gpr_free(service);
2036   gpr_free(host_and_port);
2037 }
2038 
TEST(CredentialsTest,TestAuthMetadataContext)2039 TEST(CredentialsTest, TestAuthMetadataContext) {
2040   auth_metadata_context_test_case test_cases[] = {
2041       // No service nor method.
2042       {"https", "www.foo.com", "", "https://www.foo.com", ""},
2043       // No method.
2044       {"https", "www.foo.com", "/Service", "https://www.foo.com/Service", ""},
2045       // Empty service and method.
2046       {"https", "www.foo.com", "//", "https://www.foo.com/", ""},
2047       // Empty method.
2048       {"https", "www.foo.com", "/Service/", "https://www.foo.com/Service", ""},
2049       // Malformed url.
2050       {"https", "www.foo.com:", "/Service/", "https://www.foo.com:/Service",
2051        ""},
2052       // https, default explicit port.
2053       {"https", "www.foo.com:443", "/Service/FooMethod",
2054        "https://www.foo.com/Service", "FooMethod"},
2055       // https, default implicit port.
2056       {"https", "www.foo.com", "/Service/FooMethod",
2057        "https://www.foo.com/Service", "FooMethod"},
2058       // https with ipv6 literal, default explicit port.
2059       {"https", "[1080:0:0:0:8:800:200C:417A]:443", "/Service/FooMethod",
2060        "https://[1080:0:0:0:8:800:200C:417A]/Service", "FooMethod"},
2061       // https with ipv6 literal, default implicit port.
2062       {"https", "[1080:0:0:0:8:800:200C:443]", "/Service/FooMethod",
2063        "https://[1080:0:0:0:8:800:200C:443]/Service", "FooMethod"},
2064       // https, custom port.
2065       {"https", "www.foo.com:8888", "/Service/FooMethod",
2066        "https://www.foo.com:8888/Service", "FooMethod"},
2067       // https with ipv6 literal, custom port.
2068       {"https", "[1080:0:0:0:8:800:200C:417A]:8888", "/Service/FooMethod",
2069        "https://[1080:0:0:0:8:800:200C:417A]:8888/Service", "FooMethod"},
2070       // custom url scheme, https default port.
2071       {"blah", "www.foo.com:443", "/Service/FooMethod",
2072        "blah://www.foo.com:443/Service", "FooMethod"}};
2073   for (uint32_t i = 0; i < GPR_ARRAY_SIZE(test_cases); i++) {
2074     const char* url_scheme = test_cases[i].url_scheme;
2075     grpc_slice call_host =
2076         grpc_slice_from_copied_string(test_cases[i].call_host);
2077     grpc_slice call_method =
2078         grpc_slice_from_copied_string(test_cases[i].call_method);
2079     grpc_auth_metadata_context auth_md_context;
2080     memset(&auth_md_context, 0, sizeof(auth_md_context));
2081     auth_metadata_context_build(url_scheme, call_host, call_method, nullptr,
2082                                 &auth_md_context);
2083     if (strcmp(auth_md_context.service_url,
2084                test_cases[i].desired_service_url) != 0) {
2085       Crash(absl::StrFormat("Invalid service url, want: %s, got %s.",
2086                             test_cases[i].desired_service_url,
2087                             auth_md_context.service_url));
2088     }
2089     if (strcmp(auth_md_context.method_name,
2090                test_cases[i].desired_method_name) != 0) {
2091       Crash(absl::StrFormat("Invalid method name, want: %s, got %s.",
2092                             test_cases[i].desired_method_name,
2093                             auth_md_context.method_name));
2094     }
2095     GPR_ASSERT(auth_md_context.channel_auth_context == nullptr);
2096     grpc_slice_unref(call_host);
2097     grpc_slice_unref(call_method);
2098     grpc_auth_metadata_context_reset(&auth_md_context);
2099   }
2100 }
2101 
validate_external_account_creds_token_exchage_request(const grpc_http_request * request,const char * host,const char * path,const char * body,size_t body_size,bool)2102 void validate_external_account_creds_token_exchage_request(
2103     const grpc_http_request* request, const char* host, const char* path,
2104     const char* body, size_t body_size, bool /*expect_actor_token*/) {
2105   // Check that the body is constructed properly.
2106   GPR_ASSERT(body != nullptr);
2107   GPR_ASSERT(body_size != 0);
2108   std::string get_url_equivalent =
2109       absl::StrFormat("%s?%s", "https://foo.com:5555/token", body);
2110   absl::StatusOr<URI> uri = URI::Parse(get_url_equivalent);
2111   if (!uri.ok()) {
2112     gpr_log(GPR_ERROR, "%s", uri.status().ToString().c_str());
2113     GPR_ASSERT(uri.ok());
2114   }
2115   assert_query_parameters(*uri, "audience", "audience");
2116   assert_query_parameters(*uri, "grant_type",
2117                           "urn:ietf:params:oauth:grant-type:token-exchange");
2118   assert_query_parameters(*uri, "requested_token_type",
2119                           "urn:ietf:params:oauth:token-type:access_token");
2120   assert_query_parameters(*uri, "subject_token", "test_subject_token");
2121   assert_query_parameters(*uri, "subject_token_type", "subject_token_type");
2122   assert_query_parameters(*uri, "scope",
2123                           "https://www.googleapis.com/auth/cloud-platform");
2124 
2125   // Check the rest of the request.
2126   GPR_ASSERT(strcmp(host, "foo.com:5555") == 0);
2127   GPR_ASSERT(strcmp(path, "/token") == 0);
2128   GPR_ASSERT(request->hdr_count == 3);
2129   GPR_ASSERT(strcmp(request->hdrs[0].key, "Content-Type") == 0);
2130   GPR_ASSERT(
2131       strcmp(request->hdrs[0].value, "application/x-www-form-urlencoded") == 0);
2132   GPR_ASSERT(strcmp(request->hdrs[2].key, "Authorization") == 0);
2133   GPR_ASSERT(strcmp(request->hdrs[2].value,
2134                     "Basic Y2xpZW50X2lkOmNsaWVudF9zZWNyZXQ=") == 0);
2135 }
2136 
validate_external_account_creds_token_exchage_request_with_url_encode(const grpc_http_request * request,const char * host,const char * path,const char * body,size_t body_size,bool)2137 void validate_external_account_creds_token_exchage_request_with_url_encode(
2138     const grpc_http_request* request, const char* host, const char* path,
2139     const char* body, size_t body_size, bool /*expect_actor_token*/) {
2140   // Check that the body is constructed properly.
2141   GPR_ASSERT(body != nullptr);
2142   GPR_ASSERT(body_size != 0);
2143   GPR_ASSERT(
2144       strcmp(
2145           std::string(body, body_size).c_str(),
2146           "audience=audience_!%40%23%24&grant_type=urn%3Aietf%3Aparams%3Aoauth%"
2147           "3Agrant-type%3Atoken-exchange&requested_token_type=urn%3Aietf%"
2148           "3Aparams%3Aoauth%3Atoken-type%3Aaccess_token&subject_token_type="
2149           "subject_token_type_!%40%23%24&subject_token=test_subject_token&"
2150           "scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcloud-platform&"
2151           "options=%7B%7D") == 0);
2152 
2153   // Check the rest of the request.
2154   GPR_ASSERT(strcmp(host, "foo.com:5555") == 0);
2155   GPR_ASSERT(strcmp(path, "/token_url_encode") == 0);
2156   GPR_ASSERT(request->hdr_count == 3);
2157   GPR_ASSERT(strcmp(request->hdrs[0].key, "Content-Type") == 0);
2158   GPR_ASSERT(
2159       strcmp(request->hdrs[0].value, "application/x-www-form-urlencoded") == 0);
2160   GPR_ASSERT(strcmp(request->hdrs[2].key, "Authorization") == 0);
2161   GPR_ASSERT(strcmp(request->hdrs[2].value,
2162                     "Basic Y2xpZW50X2lkOmNsaWVudF9zZWNyZXQ=") == 0);
2163 }
2164 
validate_external_account_creds_service_account_impersonation_request(const grpc_http_request * request,const char * host,const char * path,const char * body,size_t body_size,bool)2165 void validate_external_account_creds_service_account_impersonation_request(
2166     const grpc_http_request* request, const char* host, const char* path,
2167     const char* body, size_t body_size, bool /*expect_actor_token*/) {
2168   // Check that the body is constructed properly.
2169   GPR_ASSERT(body != nullptr);
2170   GPR_ASSERT(body_size != 0);
2171   GPR_ASSERT(strcmp(body, "scope=scope_1%20scope_2&lifetime=3600s") == 0);
2172   // Check the rest of the request.
2173   GPR_ASSERT(strcmp(host, "foo.com:5555") == 0);
2174   GPR_ASSERT(strcmp(path, "/service_account_impersonation") == 0);
2175   GPR_ASSERT(request->hdr_count == 2);
2176   GPR_ASSERT(strcmp(request->hdrs[0].key, "Content-Type") == 0);
2177   GPR_ASSERT(
2178       strcmp(request->hdrs[0].value, "application/x-www-form-urlencoded") == 0);
2179   GPR_ASSERT(strcmp(request->hdrs[1].key, "Authorization") == 0);
2180   GPR_ASSERT(strcmp(request->hdrs[1].value,
2181                     "Bearer token_exchange_access_token") == 0);
2182 }
2183 
validate_external_account_creds_serv_acc_imp_custom_lifetime_request(const grpc_http_request * request,const char * host,const char * path,const char * body,size_t body_size,bool)2184 void validate_external_account_creds_serv_acc_imp_custom_lifetime_request(
2185     const grpc_http_request* request, const char* host, const char* path,
2186     const char* body, size_t body_size, bool /*expect_actor_token*/) {
2187   // Check that the body is constructed properly.
2188   GPR_ASSERT(body != nullptr);
2189   GPR_ASSERT(body_size != 0);
2190   GPR_ASSERT(strcmp(body, "scope=scope_1%20scope_2&lifetime=1800s") == 0);
2191   // Check the rest of the request.
2192   GPR_ASSERT(strcmp(host, "foo.com:5555") == 0);
2193   GPR_ASSERT(strcmp(path, "/service_account_impersonation") == 0);
2194   GPR_ASSERT(request->hdr_count == 2);
2195   GPR_ASSERT(strcmp(request->hdrs[0].key, "Content-Type") == 0);
2196   GPR_ASSERT(
2197       strcmp(request->hdrs[0].value, "application/x-www-form-urlencoded") == 0);
2198   GPR_ASSERT(strcmp(request->hdrs[1].key, "Authorization") == 0);
2199   GPR_ASSERT(strcmp(request->hdrs[1].value,
2200                     "Bearer token_exchange_access_token") == 0);
2201 }
2202 
external_acc_creds_serv_acc_imp_custom_lifetime_httpcli_post_success(const grpc_http_request * request,const char * host,const char * path,const char * body,size_t body_size,Timestamp,grpc_closure * on_done,grpc_http_response * response)2203 int external_acc_creds_serv_acc_imp_custom_lifetime_httpcli_post_success(
2204     const grpc_http_request* request, const char* host, const char* path,
2205     const char* body, size_t body_size, Timestamp /*deadline*/,
2206     grpc_closure* on_done, grpc_http_response* response) {
2207   if (strcmp(path, "/token") == 0) {
2208     validate_external_account_creds_token_exchage_request(
2209         request, host, path, body, body_size, true);
2210     *response = http_response(
2211         200, valid_external_account_creds_token_exchange_response);
2212   } else if (strcmp(path, "/service_account_impersonation") == 0) {
2213     validate_external_account_creds_serv_acc_imp_custom_lifetime_request(
2214         request, host, path, body, body_size, true);
2215     *response = http_response(
2216         200,
2217         valid_external_account_creds_service_account_impersonation_response);
2218   }
2219   ExecCtx::Run(DEBUG_LOCATION, on_done, absl::OkStatus());
2220   return 1;
2221 }
2222 
external_account_creds_httpcli_post_success(const grpc_http_request * request,const char * host,const char * path,const char * body,size_t body_size,Timestamp,grpc_closure * on_done,grpc_http_response * response)2223 int external_account_creds_httpcli_post_success(
2224     const grpc_http_request* request, const char* host, const char* path,
2225     const char* body, size_t body_size, Timestamp /*deadline*/,
2226     grpc_closure* on_done, grpc_http_response* response) {
2227   if (strcmp(path, "/token") == 0) {
2228     validate_external_account_creds_token_exchage_request(
2229         request, host, path, body, body_size, true);
2230     *response = http_response(
2231         200, valid_external_account_creds_token_exchange_response);
2232   } else if (strcmp(path, "/service_account_impersonation") == 0) {
2233     validate_external_account_creds_service_account_impersonation_request(
2234         request, host, path, body, body_size, true);
2235     *response = http_response(
2236         200,
2237         valid_external_account_creds_service_account_impersonation_response);
2238   } else if (strcmp(path, "/token_url_encode") == 0) {
2239     validate_external_account_creds_token_exchage_request_with_url_encode(
2240         request, host, path, body, body_size, true);
2241     *response = http_response(
2242         200, valid_external_account_creds_token_exchange_response);
2243   }
2244   ExecCtx::Run(DEBUG_LOCATION, on_done, absl::OkStatus());
2245   return 1;
2246 }
2247 
external_account_creds_httpcli_post_failure_token_exchange_response_missing_access_token(const grpc_http_request *,const char *,const char * path,const char *,size_t,Timestamp,grpc_closure * on_done,grpc_http_response * response)2248 int external_account_creds_httpcli_post_failure_token_exchange_response_missing_access_token(
2249     const grpc_http_request* /*request*/, const char* /*host*/,
2250     const char* path, const char* /*body*/, size_t /*body_size*/,
2251     Timestamp /*deadline*/, grpc_closure* on_done,
2252     grpc_http_response* response) {
2253   if (strcmp(path, "/token") == 0) {
2254     *response = http_response(200,
2255                               "{\"not_access_token\":\"not_access_token\","
2256                               "\"expires_in\":3599,"
2257                               " \"token_type\":\"Bearer\"}");
2258   } else if (strcmp(path, "/service_account_impersonation") == 0) {
2259     *response = http_response(
2260         200,
2261         valid_external_account_creds_service_account_impersonation_response);
2262   }
2263   ExecCtx::Run(DEBUG_LOCATION, on_done, absl::OkStatus());
2264   return 1;
2265 }
2266 
url_external_account_creds_httpcli_get_success(const grpc_http_request *,const char *,const char * path,Timestamp,grpc_closure * on_done,grpc_http_response * response)2267 int url_external_account_creds_httpcli_get_success(
2268     const grpc_http_request* /*request*/, const char* /*host*/,
2269     const char* path, Timestamp /*deadline*/, grpc_closure* on_done,
2270     grpc_http_response* response) {
2271   if (strcmp(path, "/generate_subject_token_format_text") == 0) {
2272     *response = http_response(
2273         200,
2274         valid_url_external_account_creds_retrieve_subject_token_response_format_text);
2275   } else if (strcmp(path, "/path/to/url/creds?p1=v1&p2=v2") == 0) {
2276     *response = http_response(
2277         200,
2278         valid_url_external_account_creds_retrieve_subject_token_response_format_text);
2279   } else if (strcmp(path, "/generate_subject_token_format_json") == 0) {
2280     *response = http_response(
2281         200,
2282         valid_url_external_account_creds_retrieve_subject_token_response_format_json);
2283   }
2284   ExecCtx::Run(DEBUG_LOCATION, on_done, absl::OkStatus());
2285   return 1;
2286 }
2287 
validate_aws_external_account_creds_token_exchage_request(const grpc_http_request * request,const char * host,const char * path,const char * body,size_t body_size,bool)2288 void validate_aws_external_account_creds_token_exchage_request(
2289     const grpc_http_request* request, const char* host, const char* path,
2290     const char* body, size_t body_size, bool /*expect_actor_token*/) {
2291   // Check that the body is constructed properly.
2292   GPR_ASSERT(body != nullptr);
2293   GPR_ASSERT(body_size != 0);
2294   // Check that the regional_cred_verification_url got constructed
2295   // with the correct AWS Region ("test_regionz" or "test_region").
2296   GPR_ASSERT(strstr(body, "regional_cred_verification_url_test_region"));
2297   std::string get_url_equivalent =
2298       absl::StrFormat("%s?%s", "https://foo.com:5555/token", body);
2299   absl::StatusOr<URI> uri = URI::Parse(get_url_equivalent);
2300   GPR_ASSERT(uri.ok());
2301   assert_query_parameters(*uri, "audience", "audience");
2302   assert_query_parameters(*uri, "grant_type",
2303                           "urn:ietf:params:oauth:grant-type:token-exchange");
2304   assert_query_parameters(*uri, "requested_token_type",
2305                           "urn:ietf:params:oauth:token-type:access_token");
2306   assert_query_parameters(*uri, "subject_token_type", "subject_token_type");
2307   assert_query_parameters(*uri, "scope",
2308                           "https://www.googleapis.com/auth/cloud-platform");
2309   // Check the rest of the request.
2310   GPR_ASSERT(strcmp(host, "foo.com:5555") == 0);
2311   GPR_ASSERT(strcmp(path, "/token") == 0);
2312   GPR_ASSERT(request->hdr_count == 3);
2313   GPR_ASSERT(strcmp(request->hdrs[0].key, "Content-Type") == 0);
2314   GPR_ASSERT(
2315       strcmp(request->hdrs[0].value, "application/x-www-form-urlencoded") == 0);
2316   GPR_ASSERT(strcmp(request->hdrs[1].key, "x-goog-api-client") == 0);
2317   EXPECT_EQ(
2318       request->hdrs[1].value,
2319       absl::StrFormat("gl-cpp/unknown auth/%s google-byoid-sdk source/aws "
2320                       "sa-impersonation/false config-lifetime/false",
2321                       grpc_version_string()));
2322   GPR_ASSERT(strcmp(request->hdrs[2].key, "Authorization") == 0);
2323   GPR_ASSERT(strcmp(request->hdrs[2].value,
2324                     "Basic Y2xpZW50X2lkOmNsaWVudF9zZWNyZXQ=") == 0);
2325 }
2326 
aws_external_account_creds_httpcli_get_success(const grpc_http_request *,const char *,const char * path,Timestamp,grpc_closure * on_done,grpc_http_response * response)2327 int aws_external_account_creds_httpcli_get_success(
2328     const grpc_http_request* /*request*/, const char* /*host*/,
2329     const char* path, Timestamp /*deadline*/, grpc_closure* on_done,
2330     grpc_http_response* response) {
2331   if (strcmp(path, "/region_url") == 0) {
2332     *response = http_response(200, "test_regionz");
2333   } else if (strcmp(path, "/url") == 0) {
2334     *response = http_response(200, "test_role_name");
2335   } else if (strcmp(path, "/url_no_role_name") == 0) {
2336     *response = http_response(200, "");
2337   } else if (strcmp(path, "/url/test_role_name") == 0) {
2338     *response = http_response(
2339         200, valid_aws_external_account_creds_retrieve_signing_keys_response);
2340   }
2341   ExecCtx::Run(DEBUG_LOCATION, on_done, absl::OkStatus());
2342   return 1;
2343 }
2344 
aws_imdsv2_external_account_creds_httpcli_get_success(const grpc_http_request * request,const char * host,const char * path,Timestamp deadline,grpc_closure * on_done,grpc_http_response * response)2345 int aws_imdsv2_external_account_creds_httpcli_get_success(
2346     const grpc_http_request* request, const char* host, const char* path,
2347     Timestamp deadline, grpc_closure* on_done, grpc_http_response* response) {
2348   GPR_ASSERT(request->hdr_count == 1);
2349   GPR_ASSERT(strcmp(request->hdrs[0].key, "x-aws-ec2-metadata-token") == 0);
2350   GPR_ASSERT(strcmp(request->hdrs[0].value, aws_imdsv2_session_token) == 0);
2351   return aws_external_account_creds_httpcli_get_success(
2352       request, host, path, deadline, on_done, response);
2353 }
2354 
aws_imdsv2_external_account_creds_httpcli_put_success(const grpc_http_request * request,const char *,const char * path,const char *,size_t,Timestamp,grpc_closure * on_done,grpc_http_response * response)2355 int aws_imdsv2_external_account_creds_httpcli_put_success(
2356     const grpc_http_request* request, const char* /*host*/, const char* path,
2357     const char* /*body*/, size_t /*body_size*/, Timestamp /*deadline*/,
2358     grpc_closure* on_done, grpc_http_response* response) {
2359   GPR_ASSERT(request->hdr_count == 1);
2360   GPR_ASSERT(strcmp(request->hdrs[0].key,
2361                     "x-aws-ec2-metadata-token-ttl-seconds") == 0);
2362   GPR_ASSERT(strcmp(request->hdrs[0].value, "300") == 0);
2363   GPR_ASSERT(strcmp(path, "/imdsv2_session_token_url") == 0);
2364   *response = http_response(200, aws_imdsv2_session_token);
2365   ExecCtx::Run(DEBUG_LOCATION, on_done, absl::OkStatus());
2366   return 1;
2367 }
2368 
aws_external_account_creds_httpcli_post_success(const grpc_http_request * request,const char * host,const char * path,const char * body,size_t body_size,Timestamp,grpc_closure * on_done,grpc_http_response * response)2369 int aws_external_account_creds_httpcli_post_success(
2370     const grpc_http_request* request, const char* host, const char* path,
2371     const char* body, size_t body_size, Timestamp /*deadline*/,
2372     grpc_closure* on_done, grpc_http_response* response) {
2373   if (strcmp(path, "/token") == 0) {
2374     validate_aws_external_account_creds_token_exchage_request(
2375         request, host, path, body, body_size, true);
2376     *response = http_response(
2377         200, valid_external_account_creds_token_exchange_response);
2378   }
2379   ExecCtx::Run(DEBUG_LOCATION, on_done, absl::OkStatus());
2380   return 1;
2381 }
2382 
2383 // The subclass of ExternalAccountCredentials for testing.
2384 // ExternalAccountCredentials is an abstract class so we can't directly test
2385 // against it.
2386 class TestExternalAccountCredentials final : public ExternalAccountCredentials {
2387  public:
TestExternalAccountCredentials(Options options,std::vector<std::string> scopes)2388   TestExternalAccountCredentials(Options options,
2389                                  std::vector<std::string> scopes)
2390       : ExternalAccountCredentials(std::move(options), std::move(scopes)) {}
2391 
GetMetricsValue()2392   std::string GetMetricsValue() { return MetricsHeaderValue(); }
2393 
2394  protected:
RetrieveSubjectToken(HTTPRequestContext *,const Options &,std::function<void (std::string,grpc_error_handle)> cb)2395   void RetrieveSubjectToken(
2396       HTTPRequestContext* /*ctx*/, const Options& /*options*/,
2397       std::function<void(std::string, grpc_error_handle)> cb) override {
2398     cb("test_subject_token", absl::OkStatus());
2399   }
2400 };
2401 
TEST(CredentialsTest,TestExternalAccountCredsMetricsHeader)2402 TEST(CredentialsTest, TestExternalAccountCredsMetricsHeader) {
2403   Json credential_source = Json::FromString("");
2404   TestExternalAccountCredentials::ServiceAccountImpersonation
2405       service_account_impersonation;
2406   service_account_impersonation.token_lifetime_seconds = 3600;
2407   TestExternalAccountCredentials::Options options = {
2408       "external_account",                 // type;
2409       "audience",                         // audience;
2410       "subject_token_type",               // subject_token_type;
2411       "",                                 // service_account_impersonation_url;
2412       service_account_impersonation,      // service_account_impersonation;
2413       "https://foo.com:5555/token",       // token_url;
2414       "https://foo.com:5555/token_info",  // token_info_url;
2415       credential_source,                  // credential_source;
2416       "quota_project_id",                 // quota_project_id;
2417       "client_id",                        // client_id;
2418       "client_secret",                    // client_secret;
2419       "",                                 // workforce_pool_user_project;
2420   };
2421   TestExternalAccountCredentials creds(options, {});
2422 
2423   EXPECT_EQ(
2424       creds.GetMetricsValue(),
2425       absl::StrFormat("gl-cpp/unknown auth/%s google-byoid-sdk source/unknown "
2426                       "sa-impersonation/false config-lifetime/false",
2427                       grpc_version_string()));
2428 }
2429 
TEST(CredentialsTest,TestExternalAccountCredsMetricsHeaderWithServiceAccountImpersonation)2430 TEST(CredentialsTest,
2431      TestExternalAccountCredsMetricsHeaderWithServiceAccountImpersonation) {
2432   Json credential_source = Json::FromString("");
2433   TestExternalAccountCredentials::ServiceAccountImpersonation
2434       service_account_impersonation;
2435   service_account_impersonation.token_lifetime_seconds = 3600;
2436   TestExternalAccountCredentials::Options options = {
2437       "external_account",    // type;
2438       "audience",            // audience;
2439       "subject_token_type",  // subject_token_type;
2440       "https://foo.com:5555/service_account_impersonation",  // service_account_impersonation_url;
2441       service_account_impersonation,      // service_account_impersonation;
2442       "https://foo.com:5555/token",       // token_url;
2443       "https://foo.com:5555/token_info",  // token_info_url;
2444       credential_source,                  // credential_source;
2445       "quota_project_id",                 // quota_project_id;
2446       "client_id",                        // client_id;
2447       "client_secret",                    // client_secret;
2448       "",                                 // workforce_pool_user_project;
2449   };
2450   TestExternalAccountCredentials creds(options, {});
2451 
2452   EXPECT_EQ(
2453       creds.GetMetricsValue(),
2454       absl::StrFormat("gl-cpp/unknown auth/%s google-byoid-sdk source/unknown "
2455                       "sa-impersonation/true config-lifetime/false",
2456                       grpc_version_string()));
2457 }
2458 
TEST(CredentialsTest,TestExternalAccountCredsMetricsHeaderWithConfigLifetime)2459 TEST(CredentialsTest, TestExternalAccountCredsMetricsHeaderWithConfigLifetime) {
2460   Json credential_source = Json::FromString("");
2461   TestExternalAccountCredentials::ServiceAccountImpersonation
2462       service_account_impersonation;
2463   service_account_impersonation.token_lifetime_seconds = 5000;
2464   TestExternalAccountCredentials::Options options = {
2465       "external_account",    // type;
2466       "audience",            // audience;
2467       "subject_token_type",  // subject_token_type;
2468       "https://foo.com:5555/service_account_impersonation",  // service_account_impersonation_url;
2469       service_account_impersonation,      // service_account_impersonation;
2470       "https://foo.com:5555/token",       // token_url;
2471       "https://foo.com:5555/token_info",  // token_info_url;
2472       credential_source,                  // credential_source;
2473       "quota_project_id",                 // quota_project_id;
2474       "client_id",                        // client_id;
2475       "client_secret",                    // client_secret;
2476       "",                                 // workforce_pool_user_project;
2477   };
2478   TestExternalAccountCredentials creds(options, {});
2479 
2480   EXPECT_EQ(
2481       creds.GetMetricsValue(),
2482       absl::StrFormat("gl-cpp/unknown auth/%s google-byoid-sdk source/unknown "
2483                       "sa-impersonation/true config-lifetime/true",
2484                       grpc_version_string()));
2485 }
2486 
TEST(CredentialsTest,TestExternalAccountCredsSuccess)2487 TEST(CredentialsTest, TestExternalAccountCredsSuccess) {
2488   ExecCtx exec_ctx;
2489   Json credential_source = Json::FromString("");
2490   TestExternalAccountCredentials::ServiceAccountImpersonation
2491       service_account_impersonation;
2492   service_account_impersonation.token_lifetime_seconds = 3600;
2493   TestExternalAccountCredentials::Options options = {
2494       "external_account",                 // type;
2495       "audience",                         // audience;
2496       "subject_token_type",               // subject_token_type;
2497       "",                                 // service_account_impersonation_url;
2498       service_account_impersonation,      // service_account_impersonation;
2499       "https://foo.com:5555/token",       // token_url;
2500       "https://foo.com:5555/token_info",  // token_info_url;
2501       credential_source,                  // credential_source;
2502       "quota_project_id",                 // quota_project_id;
2503       "client_id",                        // client_id;
2504       "client_secret",                    // client_secret;
2505       "",                                 // workforce_pool_user_project;
2506   };
2507   TestExternalAccountCredentials creds(options, {});
2508   // Check security level.
2509   GPR_ASSERT(creds.min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
2510   // First request: http put should be called.
2511   auto state = RequestMetadataState::NewInstance(
2512       absl::OkStatus(), "authorization: Bearer token_exchange_access_token");
2513   HttpRequest::SetOverride(httpcli_get_should_not_be_called,
2514                            external_account_creds_httpcli_post_success,
2515                            httpcli_put_should_not_be_called);
2516   state->RunRequestMetadataTest(&creds, kTestUrlScheme, kTestAuthority,
2517                                 kTestPath);
2518   ExecCtx::Get()->Flush();
2519   // Second request: the cached token should be served directly.
2520   state = RequestMetadataState::NewInstance(
2521       absl::OkStatus(), "authorization: Bearer token_exchange_access_token");
2522   HttpRequest::SetOverride(httpcli_get_should_not_be_called,
2523                            httpcli_post_should_not_be_called,
2524                            httpcli_put_should_not_be_called);
2525   state->RunRequestMetadataTest(&creds, kTestUrlScheme, kTestAuthority,
2526                                 kTestPath);
2527   ExecCtx::Get()->Flush();
2528   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
2529 }
2530 
TEST(CredentialsTest,TestExternalAccountCredsSuccessWithUrlEncode)2531 TEST(CredentialsTest, TestExternalAccountCredsSuccessWithUrlEncode) {
2532   std::map<std::string, std::string> emd = {
2533       {"authorization", "Bearer token_exchange_access_token"}};
2534   ExecCtx exec_ctx;
2535   Json credential_source = Json::FromString("");
2536   TestExternalAccountCredentials::ServiceAccountImpersonation
2537       service_account_impersonation;
2538   service_account_impersonation.token_lifetime_seconds = 3600;
2539   TestExternalAccountCredentials::Options options = {
2540       "external_account",             // type;
2541       "audience_!@#$",                // audience;
2542       "subject_token_type_!@#$",      // subject_token_type;
2543       "",                             // service_account_impersonation_url;
2544       service_account_impersonation,  // service_account_impersonation;
2545       "https://foo.com:5555/token_url_encode",  // token_url;
2546       "https://foo.com:5555/token_info",        // token_info_url;
2547       credential_source,                        // credential_source;
2548       "quota_project_id",                       // quota_project_id;
2549       "client_id",                              // client_id;
2550       "client_secret",                          // client_secret;
2551       "",                                       // workforce_pool_user_project;
2552   };
2553   TestExternalAccountCredentials creds(options, {});
2554   auto state = RequestMetadataState::NewInstance(
2555       absl::OkStatus(), "authorization: Bearer token_exchange_access_token");
2556   HttpRequest::SetOverride(httpcli_get_should_not_be_called,
2557                            external_account_creds_httpcli_post_success,
2558                            httpcli_put_should_not_be_called);
2559   state->RunRequestMetadataTest(&creds, kTestUrlScheme, kTestAuthority,
2560                                 kTestPath);
2561   ExecCtx::Get()->Flush();
2562   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
2563 }
2564 
TEST(CredentialsTest,TestExternalAccountCredsSuccessWithServiceAccountImpersonation)2565 TEST(CredentialsTest,
2566      TestExternalAccountCredsSuccessWithServiceAccountImpersonation) {
2567   ExecCtx exec_ctx;
2568   Json credential_source = Json::FromString("");
2569   TestExternalAccountCredentials::ServiceAccountImpersonation
2570       service_account_impersonation;
2571   service_account_impersonation.token_lifetime_seconds = 3600;
2572   TestExternalAccountCredentials::Options options = {
2573       "external_account",    // type;
2574       "audience",            // audience;
2575       "subject_token_type",  // subject_token_type;
2576       "https://foo.com:5555/service_account_impersonation",  // service_account_impersonation_url;
2577       service_account_impersonation,      // service_account_impersonation;
2578       "https://foo.com:5555/token",       // token_url;
2579       "https://foo.com:5555/token_info",  // token_info_url;
2580       credential_source,                  // credential_source;
2581       "quota_project_id",                 // quota_project_id;
2582       "client_id",                        // client_id;
2583       "client_secret",                    // client_secret;
2584       "",                                 // workforce_pool_user_project;
2585   };
2586   TestExternalAccountCredentials creds(options, {"scope_1", "scope_2"});
2587   // Check security level.
2588   GPR_ASSERT(creds.min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
2589   // First request: http put should be called.
2590   auto state = RequestMetadataState::NewInstance(
2591       absl::OkStatus(),
2592       "authorization: Bearer service_account_impersonation_access_token");
2593   HttpRequest::SetOverride(httpcli_get_should_not_be_called,
2594                            external_account_creds_httpcli_post_success,
2595                            httpcli_put_should_not_be_called);
2596   state->RunRequestMetadataTest(&creds, kTestUrlScheme, kTestAuthority,
2597                                 kTestPath);
2598   ExecCtx::Get()->Flush();
2599   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
2600 }
2601 
TEST(CredentialsTest,TestExternalAccountCredsSuccessWithServiceAccountImpersonationAndCustomTokenLifetime)2602 TEST(
2603     CredentialsTest,
2604     TestExternalAccountCredsSuccessWithServiceAccountImpersonationAndCustomTokenLifetime) {
2605   ExecCtx exec_ctx;
2606   Json credential_source = Json::FromString("");
2607   TestExternalAccountCredentials::ServiceAccountImpersonation
2608       service_account_impersonation;
2609   service_account_impersonation.token_lifetime_seconds = 1800;
2610   TestExternalAccountCredentials::Options options = {
2611       "external_account",    // type;
2612       "audience",            // audience;
2613       "subject_token_type",  // subject_token_type;
2614       "https://foo.com:5555/service_account_impersonation",  // service_account_impersonation_url;
2615       service_account_impersonation,      // service_account_impersonation;
2616       "https://foo.com:5555/token",       // token_url;
2617       "https://foo.com:5555/token_info",  // token_info_url;
2618       credential_source,                  // credential_source;
2619       "quota_project_id",                 // quota_project_id;
2620       "client_id",                        // client_id;
2621       "client_secret",                    // client_secret;
2622       "",                                 // workforce_pool_user_project;
2623   };
2624   TestExternalAccountCredentials creds(options, {"scope_1", "scope_2"});
2625   // Check security level.
2626   GPR_ASSERT(creds.min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
2627   // First request: http put should be called.
2628   auto state = RequestMetadataState::NewInstance(
2629       absl::OkStatus(),
2630       "authorization: Bearer service_account_impersonation_access_token");
2631   HttpRequest::SetOverride(
2632       httpcli_get_should_not_be_called,
2633       external_acc_creds_serv_acc_imp_custom_lifetime_httpcli_post_success,
2634       httpcli_put_should_not_be_called);
2635   state->RunRequestMetadataTest(&creds, kTestUrlScheme, kTestAuthority,
2636                                 kTestPath);
2637   ExecCtx::Get()->Flush();
2638   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
2639 }
2640 
TEST(CredentialsTest,TestExternalAccountCredsFailureWithServiceAccountImpersonationAndInvalidCustomTokenLifetime)2641 TEST(
2642     CredentialsTest,
2643     TestExternalAccountCredsFailureWithServiceAccountImpersonationAndInvalidCustomTokenLifetime) {
2644   const char* options_string1 =
2645       "{\"type\":\"external_account\",\"audience\":\"audience\","
2646       "\"subject_token_type\":\"subject_token_type\","
2647       "\"service_account_impersonation_url\":\"service_account_impersonation_"
2648       "url\",\"service_account_impersonation\":"
2649       "{\"token_lifetime_seconds\":599},"
2650       "\"token_url\":\"https://foo.com:5555/token\","
2651       "\"token_info_url\":\"https://foo.com:5555/token_info\","
2652       "\"credential_source\":{\"url\":\"https://foo.com:5555/"
2653       "generate_subject_token_format_json\","
2654       "\"headers\":{\"Metadata-Flavor\":\"Google\"},"
2655       "\"format\":{\"type\":\"json\",\"subject_token_field_name\":\"access_"
2656       "token\"}},\"quota_project_id\":\"quota_project_id\","
2657       "\"client_id\":\"client_id\",\"client_secret\":\"client_secret\"}";
2658   grpc_error_handle error1, error2;
2659   auto json1 = JsonParse(options_string1);
2660   GPR_ASSERT(json1.ok());
2661   ExternalAccountCredentials::Create(*json1, {"scope1", "scope2"}, &error1);
2662   std::string actual_error1,
2663       expected_error1 = "token_lifetime_seconds must be more than 600s";
2664   grpc_error_get_str(error1, StatusStrProperty::kDescription, &actual_error1);
2665   GPR_ASSERT(strcmp(actual_error1.c_str(), expected_error1.c_str()) == 0);
2666 
2667   const char* options_string2 =
2668       "{\"type\":\"external_account\",\"audience\":\"audience\","
2669       "\"subject_token_type\":\"subject_token_type\","
2670       "\"service_account_impersonation_url\":\"service_account_impersonation_"
2671       "url\",\"service_account_impersonation\":"
2672       "{\"token_lifetime_seconds\":43201},"
2673       "\"token_url\":\"https://foo.com:5555/token\","
2674       "\"token_info_url\":\"https://foo.com:5555/token_info\","
2675       "\"credential_source\":{\"url\":\"https://foo.com:5555/"
2676       "generate_subject_token_format_json\","
2677       "\"headers\":{\"Metadata-Flavor\":\"Google\"},"
2678       "\"format\":{\"type\":\"json\",\"subject_token_field_name\":\"access_"
2679       "token\"}},\"quota_project_id\":\"quota_project_id\","
2680       "\"client_id\":\"client_id\",\"client_secret\":\"client_secret\"}";
2681   auto json2 = JsonParse(options_string2);
2682   GPR_ASSERT(json2.ok());
2683   ExternalAccountCredentials::Create(*json2, {"scope1", "scope2"}, &error2);
2684   std::string actual_error2,
2685       expected_error2 = "token_lifetime_seconds must be less than 43200s";
2686   grpc_error_get_str(error2, StatusStrProperty::kDescription, &actual_error2);
2687   GPR_ASSERT(strcmp(actual_error2.c_str(), expected_error2.c_str()) == 0);
2688 }
2689 
TEST(CredentialsTest,TestExternalAccountCredsFailureInvalidTokenUrl)2690 TEST(CredentialsTest, TestExternalAccountCredsFailureInvalidTokenUrl) {
2691   ExecCtx exec_ctx;
2692   Json credential_source = Json::FromString("");
2693   TestExternalAccountCredentials::ServiceAccountImpersonation
2694       service_account_impersonation;
2695   service_account_impersonation.token_lifetime_seconds = 3600;
2696   TestExternalAccountCredentials::Options options = {
2697       "external_account",    // type;
2698       "audience",            // audience;
2699       "subject_token_type",  // subject_token_type;
2700       "https://foo.com:5555/service_account_impersonation",  // service_account_impersonation_url;
2701       service_account_impersonation,      // service_account_impersonation;
2702       "invalid_token_url",                // token_url;
2703       "https://foo.com:5555/token_info",  // token_info_url;
2704       credential_source,                  // credential_source;
2705       "quota_project_id",                 // quota_project_id;
2706       "client_id",                        // client_id;
2707       "client_secret",                    // client_secret;
2708       "",                                 // workforce_pool_user_project;
2709   };
2710   TestExternalAccountCredentials creds(options, {});
2711   HttpRequest::SetOverride(httpcli_get_should_not_be_called,
2712                            httpcli_post_should_not_be_called,
2713                            httpcli_put_should_not_be_called);
2714   grpc_error_handle error =
2715       GRPC_ERROR_CREATE("Invalid token url: invalid_token_url.");
2716   grpc_error_handle expected_error = GRPC_ERROR_CREATE_REFERENCING(
2717       "Error occurred when fetching oauth2 token.", &error, 1);
2718   auto state = RequestMetadataState::NewInstance(expected_error, {});
2719   state->RunRequestMetadataTest(&creds, kTestUrlScheme, kTestAuthority,
2720                                 kTestPath);
2721   ExecCtx::Get()->Flush();
2722   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
2723 }
2724 
TEST(CredentialsTest,TestExternalAccountCredsFailureInvalidServiceAccountImpersonationUrl)2725 TEST(CredentialsTest,
2726      TestExternalAccountCredsFailureInvalidServiceAccountImpersonationUrl) {
2727   ExecCtx exec_ctx;
2728   Json credential_source = Json::FromString("");
2729   TestExternalAccountCredentials::ServiceAccountImpersonation
2730       service_account_impersonation;
2731   service_account_impersonation.token_lifetime_seconds = 3600;
2732   TestExternalAccountCredentials::Options options = {
2733       "external_account",                           // type;
2734       "audience",                                   // audience;
2735       "subject_token_type",                         // subject_token_type;
2736       "invalid_service_account_impersonation_url",  // service_account_impersonation_url;
2737       service_account_impersonation,      // service_account_impersonation;
2738       "https://foo.com:5555/token",       // token_url;
2739       "https://foo.com:5555/token_info",  // token_info_url;
2740       credential_source,                  // credential_source;
2741       "quota_project_id",                 // quota_project_id;
2742       "client_id",                        // client_id;
2743       "client_secret",                    // client_secret;
2744       "",                                 // workforce_pool_user_project;
2745   };
2746   TestExternalAccountCredentials creds(options, {});
2747   HttpRequest::SetOverride(httpcli_get_should_not_be_called,
2748                            external_account_creds_httpcli_post_success,
2749                            httpcli_put_should_not_be_called);
2750   grpc_error_handle error = GRPC_ERROR_CREATE(
2751       "Invalid service account impersonation url: "
2752       "invalid_service_account_impersonation_url.");
2753   grpc_error_handle expected_error = GRPC_ERROR_CREATE_REFERENCING(
2754       "Error occurred when fetching oauth2 token.", &error, 1);
2755   auto state = RequestMetadataState::NewInstance(expected_error, {});
2756   state->RunRequestMetadataTest(&creds, kTestUrlScheme, kTestAuthority,
2757                                 kTestPath);
2758   ExecCtx::Get()->Flush();
2759   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
2760 }
2761 
TEST(CredentialsTest,TestExternalAccountCredsFailureTokenExchangeResponseMissingAccessToken)2762 TEST(CredentialsTest,
2763      TestExternalAccountCredsFailureTokenExchangeResponseMissingAccessToken) {
2764   ExecCtx exec_ctx;
2765   Json credential_source = Json::FromString("");
2766   TestExternalAccountCredentials::ServiceAccountImpersonation
2767       service_account_impersonation;
2768   service_account_impersonation.token_lifetime_seconds = 3600;
2769   TestExternalAccountCredentials::Options options = {
2770       "external_account",    // type;
2771       "audience",            // audience;
2772       "subject_token_type",  // subject_token_type;
2773       "https://foo.com:5555/service_account_impersonation",  // service_account_impersonation_url;
2774       service_account_impersonation,      // service_account_impersonation;
2775       "https://foo.com:5555/token",       // token_url;
2776       "https://foo.com:5555/token_info",  // token_info_url;
2777       credential_source,                  // credential_source
2778       "quota_project_id",                 // quota_project_id;
2779       "client_id",                        // client_id;
2780       "client_secret",                    // client_secret;
2781       "",                                 // workforce_pool_user_project;
2782   };
2783   TestExternalAccountCredentials creds(options, {});
2784   HttpRequest::SetOverride(
2785       httpcli_get_should_not_be_called,
2786       external_account_creds_httpcli_post_failure_token_exchange_response_missing_access_token,
2787       httpcli_put_should_not_be_called);
2788   grpc_error_handle error = GRPC_ERROR_CREATE(
2789       "Missing or invalid access_token in "
2790       "{\"not_access_token\":\"not_access_token\",\"expires_in\":3599,\"token_"
2791       "type\":\"Bearer\"}.");
2792   grpc_error_handle expected_error = GRPC_ERROR_CREATE_REFERENCING(
2793       "Error occurred when fetching oauth2 token.", &error, 1);
2794   auto state = RequestMetadataState::NewInstance(expected_error, {});
2795   state->RunRequestMetadataTest(&creds, kTestUrlScheme, kTestAuthority,
2796                                 kTestPath);
2797   ExecCtx::Get()->Flush();
2798   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
2799 }
2800 
TEST(CredentialsTest,TestUrlExternalAccountCredsSuccessFormatText)2801 TEST(CredentialsTest, TestUrlExternalAccountCredsSuccessFormatText) {
2802   ExecCtx exec_ctx;
2803   auto credential_source = JsonParse(
2804       valid_url_external_account_creds_options_credential_source_format_text);
2805   GPR_ASSERT(credential_source.ok());
2806   TestExternalAccountCredentials::ServiceAccountImpersonation
2807       service_account_impersonation;
2808   service_account_impersonation.token_lifetime_seconds = 3600;
2809   ExternalAccountCredentials::Options options = {
2810       "external_account",                 // type;
2811       "audience",                         // audience;
2812       "subject_token_type",               // subject_token_type;
2813       "",                                 // service_account_impersonation_url;
2814       service_account_impersonation,      // service_account_impersonation;
2815       "https://foo.com:5555/token",       // token_url;
2816       "https://foo.com:5555/token_info",  // token_info_url;
2817       *credential_source,                 // credential_source;
2818       "quota_project_id",                 // quota_project_id;
2819       "client_id",                        // client_id;
2820       "client_secret",                    // client_secret;
2821       "",                                 // workforce_pool_user_project;
2822   };
2823   grpc_error_handle error;
2824   auto creds = UrlExternalAccountCredentials::Create(options, {}, &error);
2825   GPR_ASSERT(creds != nullptr);
2826   GPR_ASSERT(error.ok());
2827   GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
2828   auto state = RequestMetadataState::NewInstance(
2829       absl::OkStatus(), "authorization: Bearer token_exchange_access_token");
2830   HttpRequest::SetOverride(url_external_account_creds_httpcli_get_success,
2831                            external_account_creds_httpcli_post_success,
2832                            httpcli_put_should_not_be_called);
2833   state->RunRequestMetadataTest(creds.get(), kTestUrlScheme, kTestAuthority,
2834                                 kTestPath);
2835   ExecCtx::Get()->Flush();
2836   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
2837 }
2838 
TEST(CredentialsTest,TestUrlExternalAccountCredsSuccessWithQureyParamsFormatText)2839 TEST(CredentialsTest,
2840      TestUrlExternalAccountCredsSuccessWithQureyParamsFormatText) {
2841   std::map<std::string, std::string> emd = {
2842       {"authorization", "Bearer token_exchange_access_token"}};
2843   ExecCtx exec_ctx;
2844   auto credential_source = JsonParse(
2845       valid_url_external_account_creds_options_credential_source_with_qurey_params_format_text);
2846   GPR_ASSERT(credential_source.ok());
2847   TestExternalAccountCredentials::ServiceAccountImpersonation
2848       service_account_impersonation;
2849   service_account_impersonation.token_lifetime_seconds = 3600;
2850   ExternalAccountCredentials::Options options = {
2851       "external_account",                 // type;
2852       "audience",                         // audience;
2853       "subject_token_type",               // subject_token_type;
2854       "",                                 // service_account_impersonation_url;
2855       service_account_impersonation,      // service_account_impersonation;
2856       "https://foo.com:5555/token",       // token_url;
2857       "https://foo.com:5555/token_info",  // token_info_url;
2858       *credential_source,                 // credential_source;
2859       "quota_project_id",                 // quota_project_id;
2860       "client_id",                        // client_id;
2861       "client_secret",                    // client_secret;
2862       "",                                 // workforce_pool_user_project;
2863   };
2864   grpc_error_handle error;
2865   auto creds = UrlExternalAccountCredentials::Create(options, {}, &error);
2866   GPR_ASSERT(creds != nullptr);
2867   GPR_ASSERT(error.ok());
2868   GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
2869   auto state = RequestMetadataState::NewInstance(
2870       absl::OkStatus(), "authorization: Bearer token_exchange_access_token");
2871   HttpRequest::SetOverride(url_external_account_creds_httpcli_get_success,
2872                            external_account_creds_httpcli_post_success,
2873                            httpcli_put_should_not_be_called);
2874   state->RunRequestMetadataTest(creds.get(), kTestUrlScheme, kTestAuthority,
2875                                 kTestPath);
2876   ExecCtx::Get()->Flush();
2877   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
2878 }
2879 
TEST(CredentialsTest,TestUrlExternalAccountCredsSuccessFormatJson)2880 TEST(CredentialsTest, TestUrlExternalAccountCredsSuccessFormatJson) {
2881   ExecCtx exec_ctx;
2882   auto credential_source = JsonParse(
2883       valid_url_external_account_creds_options_credential_source_format_json);
2884   GPR_ASSERT(credential_source.ok());
2885   TestExternalAccountCredentials::ServiceAccountImpersonation
2886       service_account_impersonation;
2887   service_account_impersonation.token_lifetime_seconds = 3600;
2888   ExternalAccountCredentials::Options options = {
2889       "external_account",                 // type;
2890       "audience",                         // audience;
2891       "subject_token_type",               // subject_token_type;
2892       "",                                 // service_account_impersonation_url;
2893       service_account_impersonation,      // service_account_impersonation;
2894       "https://foo.com:5555/token",       // token_url;
2895       "https://foo.com:5555/token_info",  // token_info_url;
2896       *credential_source,                 // credential_source;
2897       "quota_project_id",                 // quota_project_id;
2898       "client_id",                        // client_id;
2899       "client_secret",                    // client_secret;
2900       "",                                 // workforce_pool_user_project;
2901   };
2902   grpc_error_handle error;
2903   auto creds = UrlExternalAccountCredentials::Create(options, {}, &error);
2904   GPR_ASSERT(creds != nullptr);
2905   GPR_ASSERT(error.ok());
2906   GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
2907   auto state = RequestMetadataState::NewInstance(
2908       absl::OkStatus(), "authorization: Bearer token_exchange_access_token");
2909   HttpRequest::SetOverride(url_external_account_creds_httpcli_get_success,
2910                            external_account_creds_httpcli_post_success,
2911                            httpcli_put_should_not_be_called);
2912   state->RunRequestMetadataTest(creds.get(), kTestUrlScheme, kTestAuthority,
2913                                 kTestPath);
2914   ExecCtx::Get()->Flush();
2915   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
2916 }
2917 
TEST(CredentialsTest,TestUrlExternalAccountCredsFailureInvalidCredentialSourceUrl)2918 TEST(CredentialsTest,
2919      TestUrlExternalAccountCredsFailureInvalidCredentialSourceUrl) {
2920   auto credential_source =
2921       JsonParse(invalid_url_external_account_creds_options_credential_source);
2922   GPR_ASSERT(credential_source.ok());
2923   TestExternalAccountCredentials::ServiceAccountImpersonation
2924       service_account_impersonation;
2925   service_account_impersonation.token_lifetime_seconds = 3600;
2926   ExternalAccountCredentials::Options options = {
2927       "external_account",                 // type;
2928       "audience",                         // audience;
2929       "subject_token_type",               // subject_token_type;
2930       "",                                 // service_account_impersonation_url;
2931       service_account_impersonation,      // service_account_impersonation;
2932       "https://foo.com:5555/token",       // token_url;
2933       "https://foo.com:5555/token_info",  // token_info_url;
2934       *credential_source,                 // credential_source;
2935       "quota_project_id",                 // quota_project_id;
2936       "client_id",                        // client_id;
2937       "client_secret",                    // client_secret;
2938       "",                                 // workforce_pool_user_project;
2939   };
2940   grpc_error_handle error;
2941   auto creds = UrlExternalAccountCredentials::Create(options, {}, &error);
2942   GPR_ASSERT(creds == nullptr);
2943   std::string actual_error;
2944   GPR_ASSERT(grpc_error_get_str(error, StatusStrProperty::kDescription,
2945                                 &actual_error));
2946   GPR_ASSERT(absl::StartsWith(actual_error, "Invalid credential source url."));
2947 }
2948 
TEST(CredentialsTest,TestFileExternalAccountCredsSuccessFormatText)2949 TEST(CredentialsTest, TestFileExternalAccountCredsSuccessFormatText) {
2950   ExecCtx exec_ctx;
2951   char* subject_token_path = write_tmp_jwt_file("test_subject_token");
2952   auto credential_source = JsonParse(absl::StrFormat(
2953       "{\"file\":\"%s\"}",
2954       absl::StrReplaceAll(subject_token_path, {{"\\", "\\\\"}})));
2955   GPR_ASSERT(credential_source.ok());
2956   TestExternalAccountCredentials::ServiceAccountImpersonation
2957       service_account_impersonation;
2958   service_account_impersonation.token_lifetime_seconds = 3600;
2959   ExternalAccountCredentials::Options options = {
2960       "external_account",                 // type;
2961       "audience",                         // audience;
2962       "subject_token_type",               // subject_token_type;
2963       "",                                 // service_account_impersonation_url;
2964       service_account_impersonation,      // service_account_impersonation;
2965       "https://foo.com:5555/token",       // token_url;
2966       "https://foo.com:5555/token_info",  // token_info_url;
2967       *credential_source,                 // credential_source;
2968       "quota_project_id",                 // quota_project_id;
2969       "client_id",                        // client_id;
2970       "client_secret",                    // client_secret;
2971       "",                                 // workforce_pool_user_project;
2972   };
2973   grpc_error_handle error;
2974   auto creds = FileExternalAccountCredentials::Create(options, {}, &error);
2975   GPR_ASSERT(creds != nullptr);
2976   GPR_ASSERT(error.ok());
2977   GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
2978   auto state = RequestMetadataState::NewInstance(
2979       absl::OkStatus(), "authorization: Bearer token_exchange_access_token");
2980   HttpRequest::SetOverride(httpcli_get_should_not_be_called,
2981                            external_account_creds_httpcli_post_success,
2982                            httpcli_put_should_not_be_called);
2983   state->RunRequestMetadataTest(creds.get(), kTestUrlScheme, kTestAuthority,
2984                                 kTestPath);
2985   ExecCtx::Get()->Flush();
2986   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
2987   gpr_free(subject_token_path);
2988 }
2989 
TEST(CredentialsTest,TestFileExternalAccountCredsSuccessFormatJson)2990 TEST(CredentialsTest, TestFileExternalAccountCredsSuccessFormatJson) {
2991   ExecCtx exec_ctx;
2992   char* subject_token_path =
2993       write_tmp_jwt_file("{\"access_token\":\"test_subject_token\"}");
2994   auto credential_source = JsonParse(absl::StrFormat(
2995       "{\n"
2996       "\"file\":\"%s\",\n"
2997       "\"format\":\n"
2998       "{\n"
2999       "\"type\":\"json\",\n"
3000       "\"subject_token_field_name\":\"access_token\"\n"
3001       "}\n"
3002       "}",
3003       absl::StrReplaceAll(subject_token_path, {{"\\", "\\\\"}})));
3004   GPR_ASSERT(credential_source.ok());
3005   TestExternalAccountCredentials::ServiceAccountImpersonation
3006       service_account_impersonation;
3007   service_account_impersonation.token_lifetime_seconds = 3600;
3008   ExternalAccountCredentials::Options options = {
3009       "external_account",                 // type;
3010       "audience",                         // audience;
3011       "subject_token_type",               // subject_token_type;
3012       "",                                 // service_account_impersonation_url;
3013       service_account_impersonation,      // service_account_impersonation;
3014       "https://foo.com:5555/token",       // token_url;
3015       "https://foo.com:5555/token_info",  // token_info_url;
3016       *credential_source,                 // credential_source;
3017       "quota_project_id",                 // quota_project_id;
3018       "client_id",                        // client_id;
3019       "client_secret",                    // client_secret;
3020       "",                                 // workforce_pool_user_project;
3021   };
3022   grpc_error_handle error;
3023   auto creds = FileExternalAccountCredentials::Create(options, {}, &error);
3024   GPR_ASSERT(creds != nullptr);
3025   GPR_ASSERT(error.ok());
3026   GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
3027   auto state = RequestMetadataState::NewInstance(
3028       absl::OkStatus(), "authorization: Bearer token_exchange_access_token");
3029   HttpRequest::SetOverride(httpcli_get_should_not_be_called,
3030                            external_account_creds_httpcli_post_success,
3031                            httpcli_put_should_not_be_called);
3032   state->RunRequestMetadataTest(creds.get(), kTestUrlScheme, kTestAuthority,
3033                                 kTestPath);
3034   ExecCtx::Get()->Flush();
3035   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
3036   gpr_free(subject_token_path);
3037 }
3038 
TEST(CredentialsTest,TestFileExternalAccountCredsFailureFileNotFound)3039 TEST(CredentialsTest, TestFileExternalAccountCredsFailureFileNotFound) {
3040   ExecCtx exec_ctx;
3041   auto credential_source = JsonParse("{\"file\":\"non_exisiting_file\"}");
3042   GPR_ASSERT(credential_source.ok());
3043   TestExternalAccountCredentials::ServiceAccountImpersonation
3044       service_account_impersonation;
3045   service_account_impersonation.token_lifetime_seconds = 3600;
3046   ExternalAccountCredentials::Options options = {
3047       "external_account",                 // type;
3048       "audience",                         // audience;
3049       "subject_token_type",               // subject_token_type;
3050       "",                                 // service_account_impersonation_url;
3051       service_account_impersonation,      // service_account_impersonation;
3052       "https://foo.com:5555/token",       // token_url;
3053       "https://foo.com:5555/token_info",  // token_info_url;
3054       *credential_source,                 // credential_source;
3055       "quota_project_id",                 // quota_project_id;
3056       "client_id",                        // client_id;
3057       "client_secret",                    // client_secret;
3058       "",                                 // workforce_pool_user_project;
3059   };
3060   grpc_error_handle error;
3061   auto creds = FileExternalAccountCredentials::Create(options, {}, &error);
3062   GPR_ASSERT(creds != nullptr);
3063   GPR_ASSERT(error.ok());
3064   HttpRequest::SetOverride(httpcli_get_should_not_be_called,
3065                            httpcli_post_should_not_be_called,
3066                            httpcli_put_should_not_be_called);
3067   error = GRPC_ERROR_CREATE("Failed to load file");
3068   grpc_error_handle expected_error = GRPC_ERROR_CREATE_REFERENCING(
3069       "Error occurred when fetching oauth2 token.", &error, 1);
3070   auto state = RequestMetadataState::NewInstance(expected_error, {});
3071   state->RunRequestMetadataTest(creds.get(), kTestUrlScheme, kTestAuthority,
3072                                 kTestPath);
3073   ExecCtx::Get()->Flush();
3074   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
3075 }
3076 
TEST(CredentialsTest,TestFileExternalAccountCredsFailureInvalidJsonContent)3077 TEST(CredentialsTest, TestFileExternalAccountCredsFailureInvalidJsonContent) {
3078   ExecCtx exec_ctx;
3079   char* subject_token_path = write_tmp_jwt_file("not_a_valid_json_file");
3080   auto credential_source = JsonParse(absl::StrFormat(
3081       "{\n"
3082       "\"file\":\"%s\",\n"
3083       "\"format\":\n"
3084       "{\n"
3085       "\"type\":\"json\",\n"
3086       "\"subject_token_field_name\":\"access_token\"\n"
3087       "}\n"
3088       "}",
3089       absl::StrReplaceAll(subject_token_path, {{"\\", "\\\\"}})));
3090   GPR_ASSERT(credential_source.ok());
3091   TestExternalAccountCredentials::ServiceAccountImpersonation
3092       service_account_impersonation;
3093   service_account_impersonation.token_lifetime_seconds = 3600;
3094   ExternalAccountCredentials::Options options = {
3095       "external_account",                 // type;
3096       "audience",                         // audience;
3097       "subject_token_type",               // subject_token_type;
3098       "",                                 // service_account_impersonation_url;
3099       service_account_impersonation,      // service_account_impersonation;
3100       "https://foo.com:5555/token",       // token_url;
3101       "https://foo.com:5555/token_info",  // token_info_url;
3102       *credential_source,                 // credential_source;
3103       "quota_project_id",                 // quota_project_id;
3104       "client_id",                        // client_id;
3105       "client_secret",                    // client_secret;
3106       "",                                 // workforce_pool_user_project;
3107   };
3108   grpc_error_handle error;
3109   auto creds = FileExternalAccountCredentials::Create(options, {}, &error);
3110   GPR_ASSERT(creds != nullptr);
3111   GPR_ASSERT(error.ok());
3112   HttpRequest::SetOverride(httpcli_get_should_not_be_called,
3113                            httpcli_post_should_not_be_called,
3114                            httpcli_put_should_not_be_called);
3115   error =
3116       GRPC_ERROR_CREATE("The content of the file is not a valid json object.");
3117   grpc_error_handle expected_error = GRPC_ERROR_CREATE_REFERENCING(
3118       "Error occurred when fetching oauth2 token.", &error, 1);
3119   auto state = RequestMetadataState::NewInstance(expected_error, {});
3120   state->RunRequestMetadataTest(creds.get(), kTestUrlScheme, kTestAuthority,
3121                                 kTestPath);
3122   ExecCtx::Get()->Flush();
3123   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
3124   gpr_free(subject_token_path);
3125 }
3126 
TEST(CredentialsTest,TestAwsExternalAccountCredsSuccess)3127 TEST(CredentialsTest, TestAwsExternalAccountCredsSuccess) {
3128   ExecCtx exec_ctx;
3129   auto credential_source =
3130       JsonParse(valid_aws_external_account_creds_options_credential_source);
3131   GPR_ASSERT(credential_source.ok());
3132   TestExternalAccountCredentials::ServiceAccountImpersonation
3133       service_account_impersonation;
3134   service_account_impersonation.token_lifetime_seconds = 3600;
3135   ExternalAccountCredentials::Options options = {
3136       "external_account",                 // type;
3137       "audience",                         // audience;
3138       "subject_token_type",               // subject_token_type;
3139       "",                                 // service_account_impersonation_url;
3140       service_account_impersonation,      // service_account_impersonation;
3141       "https://foo.com:5555/token",       // token_url;
3142       "https://foo.com:5555/token_info",  // token_info_url;
3143       *credential_source,                 // credential_source;
3144       "quota_project_id",                 // quota_project_id;
3145       "client_id",                        // client_id;
3146       "client_secret",                    // client_secret;
3147       "",                                 // workforce_pool_user_project;
3148   };
3149   grpc_error_handle error;
3150   auto creds = AwsExternalAccountCredentials::Create(options, {}, &error);
3151   GPR_ASSERT(creds != nullptr);
3152   GPR_ASSERT(error.ok());
3153   GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
3154   auto state = RequestMetadataState::NewInstance(
3155       absl::OkStatus(), "authorization: Bearer token_exchange_access_token");
3156   HttpRequest::SetOverride(aws_external_account_creds_httpcli_get_success,
3157                            aws_external_account_creds_httpcli_post_success,
3158                            httpcli_put_should_not_be_called);
3159   state->RunRequestMetadataTest(creds.get(), kTestUrlScheme, kTestAuthority,
3160                                 kTestPath);
3161   ExecCtx::Get()->Flush();
3162   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
3163 }
3164 
TEST(CredentialsTest,TestAwsImdsv2ExternalAccountCredsSuccess)3165 TEST(CredentialsTest, TestAwsImdsv2ExternalAccountCredsSuccess) {
3166   ExecCtx exec_ctx;
3167   auto credential_source = JsonParse(
3168       valid_aws_imdsv2_external_account_creds_options_credential_source);
3169   GPR_ASSERT(credential_source.ok());
3170   TestExternalAccountCredentials::ServiceAccountImpersonation
3171       service_account_impersonation;
3172   service_account_impersonation.token_lifetime_seconds = 3600;
3173   ExternalAccountCredentials::Options options = {
3174       "external_account",                 // type;
3175       "audience",                         // audience;
3176       "subject_token_type",               // subject_token_type;
3177       "",                                 // service_account_impersonation_url;
3178       service_account_impersonation,      // service_account_impersonation;
3179       "https://foo.com:5555/token",       // token_url;
3180       "https://foo.com:5555/token_info",  // token_info_url;
3181       *credential_source,                 // credential_source;
3182       "quota_project_id",                 // quota_project_id;
3183       "client_id",                        // client_id;
3184       "client_secret",                    // client_secret;
3185       "",                                 // workforce_pool_user_project;
3186   };
3187   grpc_error_handle error;
3188   auto creds = AwsExternalAccountCredentials::Create(options, {}, &error);
3189   GPR_ASSERT(creds != nullptr);
3190   GPR_ASSERT(error.ok());
3191   GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
3192   auto state = RequestMetadataState::NewInstance(
3193       absl::OkStatus(), "authorization: Bearer token_exchange_access_token");
3194   HttpRequest::SetOverride(
3195       aws_imdsv2_external_account_creds_httpcli_get_success,
3196       aws_external_account_creds_httpcli_post_success,
3197       aws_imdsv2_external_account_creds_httpcli_put_success);
3198   state->RunRequestMetadataTest(creds.get(), kTestUrlScheme, kTestAuthority,
3199                                 kTestPath);
3200   ExecCtx::Get()->Flush();
3201   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
3202 }
3203 
TEST(CredentialsTest,TestAwsImdsv2ExternalAccountCredShouldNotUseMetadataServer)3204 TEST(CredentialsTest,
3205      TestAwsImdsv2ExternalAccountCredShouldNotUseMetadataServer) {
3206   ExecCtx exec_ctx;
3207   SetEnv("AWS_REGION", "test_regionz");
3208   SetEnv("AWS_ACCESS_KEY_ID", "test_access_key_id");
3209   SetEnv("AWS_SECRET_ACCESS_KEY", "test_secret_access_key");
3210   SetEnv("AWS_SESSION_TOKEN", "test_token");
3211   auto credential_source = JsonParse(
3212       valid_aws_imdsv2_external_account_creds_options_credential_source);
3213   GPR_ASSERT(credential_source.ok());
3214   TestExternalAccountCredentials::ServiceAccountImpersonation
3215       service_account_impersonation;
3216   service_account_impersonation.token_lifetime_seconds = 3600;
3217   ExternalAccountCredentials::Options options = {
3218       "external_account",                 // type;
3219       "audience",                         // audience;
3220       "subject_token_type",               // subject_token_type;
3221       "",                                 // service_account_impersonation_url;
3222       service_account_impersonation,      // service_account_impersonation;
3223       "https://foo.com:5555/token",       // token_url;
3224       "https://foo.com:5555/token_info",  // token_info_url;
3225       *credential_source,                 // credential_source;
3226       "quota_project_id",                 // quota_project_id;
3227       "client_id",                        // client_id;
3228       "client_secret",                    // client_secret;
3229       "",                                 // workforce_pool_user_project;
3230   };
3231   grpc_error_handle error;
3232   auto creds = AwsExternalAccountCredentials::Create(options, {}, &error);
3233   GPR_ASSERT(creds != nullptr);
3234   GPR_ASSERT(error.ok());
3235   GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
3236   auto state = RequestMetadataState::NewInstance(
3237       absl::OkStatus(), "authorization: Bearer token_exchange_access_token");
3238   HttpRequest::SetOverride(aws_external_account_creds_httpcli_get_success,
3239                            aws_external_account_creds_httpcli_post_success,
3240                            httpcli_put_should_not_be_called);
3241   state->RunRequestMetadataTest(creds.get(), kTestUrlScheme, kTestAuthority,
3242                                 kTestPath);
3243   ExecCtx::Get()->Flush();
3244   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
3245   UnsetEnv("AWS_REGION");
3246   UnsetEnv("AWS_ACCESS_KEY_ID");
3247   UnsetEnv("AWS_SECRET_ACCESS_KEY");
3248   UnsetEnv("AWS_SESSION_TOKEN");
3249 }
3250 
TEST(CredentialsTest,TestAwsImdsv2ExternalAccountCredShouldNotUseMetadataServerOptionalTokenMissing)3251 TEST(
3252     CredentialsTest,
3253     TestAwsImdsv2ExternalAccountCredShouldNotUseMetadataServerOptionalTokenMissing) {
3254   ExecCtx exec_ctx;
3255   SetEnv("AWS_REGION", "test_regionz");
3256   SetEnv("AWS_ACCESS_KEY_ID", "test_access_key_id");
3257   SetEnv("AWS_SECRET_ACCESS_KEY", "test_secret_access_key");
3258   auto credential_source = JsonParse(
3259       valid_aws_imdsv2_external_account_creds_options_credential_source);
3260   GPR_ASSERT(credential_source.ok());
3261   TestExternalAccountCredentials::ServiceAccountImpersonation
3262       service_account_impersonation;
3263   service_account_impersonation.token_lifetime_seconds = 3600;
3264   ExternalAccountCredentials::Options options = {
3265       "external_account",                 // type;
3266       "audience",                         // audience;
3267       "subject_token_type",               // subject_token_type;
3268       "",                                 // service_account_impersonation_url;
3269       service_account_impersonation,      // service_account_impersonation;
3270       "https://foo.com:5555/token",       // token_url;
3271       "https://foo.com:5555/token_info",  // token_info_url;
3272       *credential_source,                 // credential_source;
3273       "quota_project_id",                 // quota_project_id;
3274       "client_id",                        // client_id;
3275       "client_secret",                    // client_secret;
3276       "",                                 // workforce_pool_user_project;
3277   };
3278   grpc_error_handle error;
3279   auto creds = AwsExternalAccountCredentials::Create(options, {}, &error);
3280   GPR_ASSERT(creds != nullptr);
3281   GPR_ASSERT(error.ok());
3282   GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
3283   auto state = RequestMetadataState::NewInstance(
3284       absl::OkStatus(), "authorization: Bearer token_exchange_access_token");
3285   HttpRequest::SetOverride(aws_external_account_creds_httpcli_get_success,
3286                            aws_external_account_creds_httpcli_post_success,
3287                            httpcli_put_should_not_be_called);
3288   state->RunRequestMetadataTest(creds.get(), kTestUrlScheme, kTestAuthority,
3289                                 kTestPath);
3290   ExecCtx::Get()->Flush();
3291   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
3292   UnsetEnv("AWS_REGION");
3293   UnsetEnv("AWS_ACCESS_KEY_ID");
3294   UnsetEnv("AWS_SECRET_ACCESS_KEY");
3295 }
3296 
TEST(CredentialsTest,TestAwsExternalAccountCredsSuccessIpv6)3297 TEST(CredentialsTest, TestAwsExternalAccountCredsSuccessIpv6) {
3298   ExecCtx exec_ctx;
3299   auto credential_source = JsonParse(
3300       valid_aws_external_account_creds_options_credential_source_ipv6);
3301   GPR_ASSERT(credential_source.ok());
3302   TestExternalAccountCredentials::ServiceAccountImpersonation
3303       service_account_impersonation;
3304   service_account_impersonation.token_lifetime_seconds = 3600;
3305   ExternalAccountCredentials::Options options = {
3306       "external_account",                 // type;
3307       "audience",                         // audience;
3308       "subject_token_type",               // subject_token_type;
3309       "",                                 // service_account_impersonation_url;
3310       service_account_impersonation,      // service_account_impersonation;
3311       "https://foo.com:5555/token",       // token_url;
3312       "https://foo.com:5555/token_info",  // token_info_url;
3313       *credential_source,                 // credential_source;
3314       "quota_project_id",                 // quota_project_id;
3315       "client_id",                        // client_id;
3316       "client_secret",                    // client_secret;
3317       "",                                 // workforce_pool_user_project;
3318   };
3319   grpc_error_handle error;
3320   auto creds = AwsExternalAccountCredentials::Create(options, {}, &error);
3321   GPR_ASSERT(creds != nullptr);
3322   GPR_ASSERT(error.ok());
3323   GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
3324   auto state = RequestMetadataState::NewInstance(
3325       absl::OkStatus(), "authorization: Bearer token_exchange_access_token");
3326   HttpRequest::SetOverride(
3327       aws_imdsv2_external_account_creds_httpcli_get_success,
3328       aws_external_account_creds_httpcli_post_success,
3329       aws_imdsv2_external_account_creds_httpcli_put_success);
3330   state->RunRequestMetadataTest(creds.get(), kTestUrlScheme, kTestAuthority,
3331                                 kTestPath);
3332   ExecCtx::Get()->Flush();
3333   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
3334 }
3335 
TEST(CredentialsTest,TestAwsExternalAccountCredsSuccessPathRegionEnvKeysUrl)3336 TEST(CredentialsTest, TestAwsExternalAccountCredsSuccessPathRegionEnvKeysUrl) {
3337   ExecCtx exec_ctx;
3338   SetEnv("AWS_REGION", "test_regionz");
3339   auto credential_source =
3340       JsonParse(valid_aws_external_account_creds_options_credential_source);
3341   GPR_ASSERT(credential_source.ok());
3342   TestExternalAccountCredentials::ServiceAccountImpersonation
3343       service_account_impersonation;
3344   service_account_impersonation.token_lifetime_seconds = 3600;
3345   ExternalAccountCredentials::Options options = {
3346       "external_account",                 // type;
3347       "audience",                         // audience;
3348       "subject_token_type",               // subject_token_type;
3349       "",                                 // service_account_impersonation_url;
3350       service_account_impersonation,      // service_account_impersonation;
3351       "https://foo.com:5555/token",       // token_url;
3352       "https://foo.com:5555/token_info",  // token_info_url;
3353       *credential_source,                 // credential_source;
3354       "quota_project_id",                 // quota_project_id;
3355       "client_id",                        // client_id;
3356       "client_secret",                    // client_secret;
3357       "",                                 // workforce_pool_user_project;
3358   };
3359   grpc_error_handle error;
3360   auto creds = AwsExternalAccountCredentials::Create(options, {}, &error);
3361   GPR_ASSERT(creds != nullptr);
3362   GPR_ASSERT(error.ok());
3363   GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
3364   auto state = RequestMetadataState::NewInstance(
3365       absl::OkStatus(), "authorization: Bearer token_exchange_access_token");
3366   HttpRequest::SetOverride(aws_external_account_creds_httpcli_get_success,
3367                            aws_external_account_creds_httpcli_post_success,
3368                            httpcli_put_should_not_be_called);
3369   state->RunRequestMetadataTest(creds.get(), kTestUrlScheme, kTestAuthority,
3370                                 kTestPath);
3371   ExecCtx::Get()->Flush();
3372   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
3373   UnsetEnv("AWS_REGION");
3374 }
3375 
TEST(CredentialsTest,TestAwsExternalAccountCredsSuccessPathDefaultRegionEnvKeysUrl)3376 TEST(CredentialsTest,
3377      TestAwsExternalAccountCredsSuccessPathDefaultRegionEnvKeysUrl) {
3378   ExecCtx exec_ctx;
3379   SetEnv("AWS_DEFAULT_REGION", "test_regionz");
3380   auto credential_source =
3381       JsonParse(valid_aws_external_account_creds_options_credential_source);
3382   GPR_ASSERT(credential_source.ok());
3383   TestExternalAccountCredentials::ServiceAccountImpersonation
3384       service_account_impersonation;
3385   service_account_impersonation.token_lifetime_seconds = 3600;
3386   ExternalAccountCredentials::Options options = {
3387       "external_account",                 // type;
3388       "audience",                         // audience;
3389       "subject_token_type",               // subject_token_type;
3390       "",                                 // service_account_impersonation_url;
3391       service_account_impersonation,      // service_account_impersonation;
3392       "https://foo.com:5555/token",       // token_url;
3393       "https://foo.com:5555/token_info",  // token_info_url;
3394       *credential_source,                 // credential_source;
3395       "quota_project_id",                 // quota_project_id;
3396       "client_id",                        // client_id;
3397       "client_secret",                    // client_secret;
3398       "",                                 // workforce_pool_user_project;
3399   };
3400   grpc_error_handle error;
3401   auto creds = AwsExternalAccountCredentials::Create(options, {}, &error);
3402   GPR_ASSERT(creds != nullptr);
3403   GPR_ASSERT(error.ok());
3404   GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
3405   auto state = RequestMetadataState::NewInstance(
3406       absl::OkStatus(), "authorization: Bearer token_exchange_access_token");
3407   HttpRequest::SetOverride(aws_external_account_creds_httpcli_get_success,
3408                            aws_external_account_creds_httpcli_post_success,
3409                            httpcli_put_should_not_be_called);
3410   state->RunRequestMetadataTest(creds.get(), kTestUrlScheme, kTestAuthority,
3411                                 kTestPath);
3412   ExecCtx::Get()->Flush();
3413   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
3414   UnsetEnv("AWS_DEFAULT_REGION");
3415 }
3416 
TEST(CredentialsTest,TestAwsExternalAccountCredsSuccessPathDuplicateRegionEnvKeysUrl)3417 TEST(CredentialsTest,
3418      TestAwsExternalAccountCredsSuccessPathDuplicateRegionEnvKeysUrl) {
3419   ExecCtx exec_ctx;
3420   // Make sure that AWS_REGION gets used over AWS_DEFAULT_REGION
3421   SetEnv("AWS_REGION", "test_regionz");
3422   SetEnv("AWS_DEFAULT_REGION", "ERROR_REGION");
3423   auto credential_source =
3424       JsonParse(valid_aws_external_account_creds_options_credential_source);
3425   GPR_ASSERT(credential_source.ok());
3426   TestExternalAccountCredentials::ServiceAccountImpersonation
3427       service_account_impersonation;
3428   service_account_impersonation.token_lifetime_seconds = 3600;
3429   ExternalAccountCredentials::Options options = {
3430       "external_account",                 // type;
3431       "audience",                         // audience;
3432       "subject_token_type",               // subject_token_type;
3433       "",                                 // service_account_impersonation_url;
3434       service_account_impersonation,      // service_account_impersonation;
3435       "https://foo.com:5555/token",       // token_url;
3436       "https://foo.com:5555/token_info",  // token_info_url;
3437       *credential_source,                 // credential_source;
3438       "quota_project_id",                 // quota_project_id;
3439       "client_id",                        // client_id;
3440       "client_secret",                    // client_secret;
3441       "",                                 // workforce_pool_user_project;
3442   };
3443   grpc_error_handle error;
3444   auto creds = AwsExternalAccountCredentials::Create(options, {}, &error);
3445   GPR_ASSERT(creds != nullptr);
3446   GPR_ASSERT(error.ok());
3447   GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
3448   auto state = RequestMetadataState::NewInstance(
3449       absl::OkStatus(), "authorization: Bearer token_exchange_access_token");
3450   HttpRequest::SetOverride(aws_external_account_creds_httpcli_get_success,
3451                            aws_external_account_creds_httpcli_post_success,
3452                            httpcli_put_should_not_be_called);
3453   state->RunRequestMetadataTest(creds.get(), kTestUrlScheme, kTestAuthority,
3454                                 kTestPath);
3455   ExecCtx::Get()->Flush();
3456   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
3457   UnsetEnv("AWS_REGION");
3458   UnsetEnv("AWS_DEFAULT_REGION");
3459 }
3460 
TEST(CredentialsTest,TestAwsExternalAccountCredsSuccessPathRegionUrlKeysEnv)3461 TEST(CredentialsTest, TestAwsExternalAccountCredsSuccessPathRegionUrlKeysEnv) {
3462   ExecCtx exec_ctx;
3463   SetEnv("AWS_ACCESS_KEY_ID", "test_access_key_id");
3464   SetEnv("AWS_SECRET_ACCESS_KEY", "test_secret_access_key");
3465   SetEnv("AWS_SESSION_TOKEN", "test_token");
3466   auto credential_source =
3467       JsonParse(valid_aws_external_account_creds_options_credential_source);
3468   GPR_ASSERT(credential_source.ok());
3469   TestExternalAccountCredentials::ServiceAccountImpersonation
3470       service_account_impersonation;
3471   service_account_impersonation.token_lifetime_seconds = 3600;
3472   ExternalAccountCredentials::Options options = {
3473       "external_account",                 // type;
3474       "audience",                         // audience;
3475       "subject_token_type",               // subject_token_type;
3476       "",                                 // service_account_impersonation_url;
3477       service_account_impersonation,      // service_account_impersonation;
3478       "https://foo.com:5555/token",       // token_url;
3479       "https://foo.com:5555/token_info",  // token_info_url;
3480       *credential_source,                 // credential_source;
3481       "quota_project_id",                 // quota_project_id;
3482       "client_id",                        // client_id;
3483       "client_secret",                    // client_secret;
3484       "",                                 // workforce_pool_user_project;
3485   };
3486   grpc_error_handle error;
3487   auto creds = AwsExternalAccountCredentials::Create(options, {}, &error);
3488   GPR_ASSERT(creds != nullptr);
3489   GPR_ASSERT(error.ok());
3490   GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
3491   auto state = RequestMetadataState::NewInstance(
3492       absl::OkStatus(), "authorization: Bearer token_exchange_access_token");
3493   HttpRequest::SetOverride(aws_external_account_creds_httpcli_get_success,
3494                            aws_external_account_creds_httpcli_post_success,
3495                            httpcli_put_should_not_be_called);
3496   state->RunRequestMetadataTest(creds.get(), kTestUrlScheme, kTestAuthority,
3497                                 kTestPath);
3498   ExecCtx::Get()->Flush();
3499   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
3500   UnsetEnv("AWS_ACCESS_KEY_ID");
3501   UnsetEnv("AWS_SECRET_ACCESS_KEY");
3502   UnsetEnv("AWS_SESSION_TOKEN");
3503 }
3504 
TEST(CredentialsTest,TestAwsExternalAccountCredsSuccessPathRegionEnvKeysEnv)3505 TEST(CredentialsTest, TestAwsExternalAccountCredsSuccessPathRegionEnvKeysEnv) {
3506   ExecCtx exec_ctx;
3507   SetEnv("AWS_REGION", "test_regionz");
3508   SetEnv("AWS_ACCESS_KEY_ID", "test_access_key_id");
3509   SetEnv("AWS_SECRET_ACCESS_KEY", "test_secret_access_key");
3510   SetEnv("AWS_SESSION_TOKEN", "test_token");
3511   auto credential_source =
3512       JsonParse(valid_aws_external_account_creds_options_credential_source);
3513   GPR_ASSERT(credential_source.ok());
3514   TestExternalAccountCredentials::ServiceAccountImpersonation
3515       service_account_impersonation;
3516   service_account_impersonation.token_lifetime_seconds = 3600;
3517   ExternalAccountCredentials::Options options = {
3518       "external_account",                 // type;
3519       "audience",                         // audience;
3520       "subject_token_type",               // subject_token_type;
3521       "",                                 // service_account_impersonation_url;
3522       service_account_impersonation,      // service_account_impersonation;
3523       "https://foo.com:5555/token",       // token_url;
3524       "https://foo.com:5555/token_info",  // token_info_url;
3525       *credential_source,                 // credential_source;
3526       "quota_project_id",                 // quota_project_id;
3527       "client_id",                        // client_id;
3528       "client_secret",                    // client_secret;
3529       "",                                 // workforce_pool_user_project;
3530   };
3531   grpc_error_handle error;
3532   auto creds = AwsExternalAccountCredentials::Create(options, {}, &error);
3533   GPR_ASSERT(creds != nullptr);
3534   GPR_ASSERT(error.ok());
3535   GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
3536   auto state = RequestMetadataState::NewInstance(
3537       absl::OkStatus(), "authorization: Bearer token_exchange_access_token");
3538   HttpRequest::SetOverride(aws_external_account_creds_httpcli_get_success,
3539                            aws_external_account_creds_httpcli_post_success,
3540                            httpcli_put_should_not_be_called);
3541   state->RunRequestMetadataTest(creds.get(), kTestUrlScheme, kTestAuthority,
3542                                 kTestPath);
3543   ExecCtx::Get()->Flush();
3544   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
3545   UnsetEnv("AWS_REGION");
3546   UnsetEnv("AWS_ACCESS_KEY_ID");
3547   UnsetEnv("AWS_SECRET_ACCESS_KEY");
3548   UnsetEnv("AWS_SESSION_TOKEN");
3549 }
3550 
TEST(CredentialsTest,TestAwsExternalAccountCredsSuccessPathDefaultRegionEnvKeysEnv)3551 TEST(CredentialsTest,
3552      TestAwsExternalAccountCredsSuccessPathDefaultRegionEnvKeysEnv) {
3553   std::map<std::string, std::string> emd = {
3554       {"authorization", "Bearer token_exchange_access_token"}};
3555   ExecCtx exec_ctx;
3556   SetEnv("AWS_DEFAULT_REGION", "test_regionz");
3557   SetEnv("AWS_ACCESS_KEY_ID", "test_access_key_id");
3558   SetEnv("AWS_SECRET_ACCESS_KEY", "test_secret_access_key");
3559   SetEnv("AWS_SESSION_TOKEN", "test_token");
3560   auto credential_source =
3561       JsonParse(valid_aws_external_account_creds_options_credential_source);
3562   GPR_ASSERT(credential_source.ok());
3563   TestExternalAccountCredentials::ServiceAccountImpersonation
3564       service_account_impersonation;
3565   service_account_impersonation.token_lifetime_seconds = 3600;
3566   ExternalAccountCredentials::Options options = {
3567       "external_account",                 // type;
3568       "audience",                         // audience;
3569       "subject_token_type",               // subject_token_type;
3570       "",                                 // service_account_impersonation_url;
3571       service_account_impersonation,      // service_account_impersonation;
3572       "https://foo.com:5555/token",       // token_url;
3573       "https://foo.com:5555/token_info",  // token_info_url;
3574       *credential_source,                 // credential_source;
3575       "quota_project_id",                 // quota_project_id;
3576       "client_id",                        // client_id;
3577       "client_secret",                    // client_secret;
3578       "",                                 // workforce_pool_user_project;
3579   };
3580   grpc_error_handle error;
3581   auto creds = AwsExternalAccountCredentials::Create(options, {}, &error);
3582   GPR_ASSERT(creds != nullptr);
3583   GPR_ASSERT(error.ok());
3584   GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
3585   auto state = RequestMetadataState::NewInstance(
3586       absl::OkStatus(), "authorization: Bearer token_exchange_access_token");
3587   HttpRequest::SetOverride(aws_external_account_creds_httpcli_get_success,
3588                            aws_external_account_creds_httpcli_post_success,
3589                            httpcli_put_should_not_be_called);
3590   state->RunRequestMetadataTest(creds.get(), kTestUrlScheme, kTestAuthority,
3591                                 kTestPath);
3592   ExecCtx::Get()->Flush();
3593   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
3594   UnsetEnv("AWS_DEFAULT_REGION");
3595   UnsetEnv("AWS_ACCESS_KEY_ID");
3596   UnsetEnv("AWS_SECRET_ACCESS_KEY");
3597   UnsetEnv("AWS_SESSION_TOKEN");
3598 }
3599 
TEST(CredentialsTest,TestAwsExternalAccountCredsSuccessPathDuplicateRegionEnvKeysEnv)3600 TEST(CredentialsTest,
3601      TestAwsExternalAccountCredsSuccessPathDuplicateRegionEnvKeysEnv) {
3602   ExecCtx exec_ctx;
3603   // Make sure that AWS_REGION gets used over AWS_DEFAULT_REGION
3604   SetEnv("AWS_REGION", "test_regionz");
3605   SetEnv("AWS_DEFAULT_REGION", "ERROR_REGION");
3606   SetEnv("AWS_ACCESS_KEY_ID", "test_access_key_id");
3607   SetEnv("AWS_SECRET_ACCESS_KEY", "test_secret_access_key");
3608   SetEnv("AWS_SESSION_TOKEN", "test_token");
3609   auto credential_source =
3610       JsonParse(valid_aws_external_account_creds_options_credential_source);
3611   GPR_ASSERT(credential_source.ok());
3612   TestExternalAccountCredentials::ServiceAccountImpersonation
3613       service_account_impersonation;
3614   service_account_impersonation.token_lifetime_seconds = 3600;
3615   ExternalAccountCredentials::Options options = {
3616       "external_account",                 // type;
3617       "audience",                         // audience;
3618       "subject_token_type",               // subject_token_type;
3619       "",                                 // service_account_impersonation_url;
3620       service_account_impersonation,      // service_account_impersonation;
3621       "https://foo.com:5555/token",       // token_url;
3622       "https://foo.com:5555/token_info",  // token_info_url;
3623       *credential_source,                 // credential_source;
3624       "quota_project_id",                 // quota_project_id;
3625       "client_id",                        // client_id;
3626       "client_secret",                    // client_secret;
3627       "",                                 // workforce_pool_user_project;
3628   };
3629   grpc_error_handle error;
3630   auto creds = AwsExternalAccountCredentials::Create(options, {}, &error);
3631   GPR_ASSERT(creds != nullptr);
3632   GPR_ASSERT(error.ok());
3633   GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
3634   auto state = RequestMetadataState::NewInstance(
3635       absl::OkStatus(), "authorization: Bearer token_exchange_access_token");
3636   HttpRequest::SetOverride(aws_external_account_creds_httpcli_get_success,
3637                            aws_external_account_creds_httpcli_post_success,
3638                            httpcli_put_should_not_be_called);
3639   state->RunRequestMetadataTest(creds.get(), kTestUrlScheme, kTestAuthority,
3640                                 kTestPath);
3641   ExecCtx::Get()->Flush();
3642   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
3643   UnsetEnv("AWS_REGION");
3644   UnsetEnv("AWS_DEFAULT_REGION");
3645   UnsetEnv("AWS_ACCESS_KEY_ID");
3646   UnsetEnv("AWS_SECRET_ACCESS_KEY");
3647   UnsetEnv("AWS_SESSION_TOKEN");
3648 }
3649 
TEST(CredentialsTest,TestExternalAccountCredentialsCreateSuccess)3650 TEST(CredentialsTest, TestExternalAccountCredentialsCreateSuccess) {
3651   // url credentials
3652   const char* url_options_string =
3653       "{\"type\":\"external_account\",\"audience\":\"audience\",\"subject_"
3654       "token_type\":\"subject_token_type\",\"service_account_impersonation_"
3655       "url\":\"service_account_impersonation_url\","
3656       "\"token_url\":\"https://foo.com:5555/"
3657       "token\",\"token_info_url\":\"https://foo.com:5555/"
3658       "token_info\",\"credential_source\":{\"url\":\"https://foo.com:5555/"
3659       "generate_subject_token_format_json\",\"headers\":{\"Metadata-Flavor\":"
3660       "\"Google\"},\"format\":{\"type\":\"json\",\"subject_token_field_name\":"
3661       "\"access_token\"}},\"quota_project_id\":\"quota_"
3662       "project_id\",\"client_id\":\"client_id\",\"client_secret\":\"client_"
3663       "secret\"}";
3664   const char* url_scopes_string = "scope1,scope2";
3665   grpc_call_credentials* url_creds = grpc_external_account_credentials_create(
3666       url_options_string, url_scopes_string);
3667   GPR_ASSERT(url_creds != nullptr);
3668   url_creds->Unref();
3669   // file credentials
3670   const char* file_options_string =
3671       "{\"type\":\"external_account\",\"audience\":\"audience\",\"subject_"
3672       "token_type\":\"subject_token_type\",\"service_account_impersonation_"
3673       "url\":\"service_account_impersonation_url\","
3674       "\"token_url\":\"https://foo.com:5555/"
3675       "token\",\"token_info_url\":\"https://foo.com:5555/"
3676       "token_info\",\"credential_source\":{\"file\":\"credentials_file_path\"},"
3677       "\"quota_project_id\":\"quota_"
3678       "project_id\",\"client_id\":\"client_id\",\"client_secret\":\"client_"
3679       "secret\"}";
3680   const char* file_scopes_string = "scope1,scope2";
3681   grpc_call_credentials* file_creds = grpc_external_account_credentials_create(
3682       file_options_string, file_scopes_string);
3683   GPR_ASSERT(file_creds != nullptr);
3684   file_creds->Unref();
3685   // aws credentials
3686   const char* aws_options_string =
3687       "{\"type\":\"external_account\",\"audience\":\"audience\",\"subject_"
3688       "token_type\":\"subject_token_type\",\"service_account_impersonation_"
3689       "url\":\"service_account_impersonation_url\","
3690       "\"token_url\":\"https://"
3691       "foo.com:5555/token\",\"token_info_url\":\"https://foo.com:5555/"
3692       "token_info\",\"credential_source\":{\"environment_id\":\"aws1\","
3693       "\"region_url\":\"https://169.254.169.254:5555/"
3694       "region_url\",\"url\":\"https://"
3695       "169.254.169.254:5555/url\",\"regional_cred_verification_url\":\"https://"
3696       "foo.com:5555/regional_cred_verification_url_{region}\"},"
3697       "\"quota_project_id\":\"quota_"
3698       "project_id\",\"client_id\":\"client_id\",\"client_secret\":\"client_"
3699       "secret\"}";
3700   const char* aws_scopes_string = "scope1,scope2";
3701   grpc_call_credentials* aws_creds = grpc_external_account_credentials_create(
3702       aws_options_string, aws_scopes_string);
3703   GPR_ASSERT(aws_creds != nullptr);
3704   aws_creds->Unref();
3705 }
3706 
TEST(CredentialsTest,TestAwsExternalAccountCredsFailureUnmatchedEnvironmentId)3707 TEST(CredentialsTest,
3708      TestAwsExternalAccountCredsFailureUnmatchedEnvironmentId) {
3709   auto credential_source = JsonParse(
3710       invalid_aws_external_account_creds_options_credential_source_unmatched_environment_id);
3711   GPR_ASSERT(credential_source.ok());
3712   TestExternalAccountCredentials::ServiceAccountImpersonation
3713       service_account_impersonation;
3714   service_account_impersonation.token_lifetime_seconds = 3600;
3715   ExternalAccountCredentials::Options options = {
3716       "external_account",                 // type;
3717       "audience",                         // audience;
3718       "subject_token_type",               // subject_token_type;
3719       "",                                 // service_account_impersonation_url;
3720       service_account_impersonation,      // service_account_impersonation;
3721       "https://foo.com:5555/token",       // token_url;
3722       "https://foo.com:5555/token_info",  // token_info_url;
3723       *credential_source,                 // credential_source;
3724       "quota_project_id",                 // quota_project_id;
3725       "client_id",                        // client_id;
3726       "client_secret",                    // client_secret;
3727       "",                                 // workforce_pool_user_project;
3728   };
3729   grpc_error_handle error;
3730   auto creds = AwsExternalAccountCredentials::Create(options, {}, &error);
3731   GPR_ASSERT(creds == nullptr);
3732   std::string expected_error = "environment_id does not match.";
3733   std::string actual_error;
3734   GPR_ASSERT(grpc_error_get_str(error, StatusStrProperty::kDescription,
3735                                 &actual_error));
3736   GPR_ASSERT(expected_error == actual_error);
3737 }
3738 
TEST(CredentialsTest,TestAwsExternalAccountCredsFailureInvalidRegionalCredVerificationUrl)3739 TEST(CredentialsTest,
3740      TestAwsExternalAccountCredsFailureInvalidRegionalCredVerificationUrl) {
3741   ExecCtx exec_ctx;
3742   auto credential_source = JsonParse(
3743       invalid_aws_external_account_creds_options_credential_source_invalid_regional_cred_verification_url);
3744   GPR_ASSERT(credential_source.ok());
3745   TestExternalAccountCredentials::ServiceAccountImpersonation
3746       service_account_impersonation;
3747   service_account_impersonation.token_lifetime_seconds = 3600;
3748   ExternalAccountCredentials::Options options = {
3749       "external_account",                 // type;
3750       "audience",                         // audience;
3751       "subject_token_type",               // subject_token_type;
3752       "",                                 // service_account_impersonation_url;
3753       service_account_impersonation,      // service_account_impersonation;
3754       "https://foo.com:5555/token",       // token_url;
3755       "https://foo.com:5555/token_info",  // token_info_url;
3756       *credential_source,                 // credential_source;
3757       "quota_project_id",                 // quota_project_id;
3758       "client_id",                        // client_id;
3759       "client_secret",                    // client_secret;
3760       "",                                 // workforce_pool_user_project;
3761   };
3762   grpc_error_handle error;
3763   auto creds = AwsExternalAccountCredentials::Create(options, {}, &error);
3764   GPR_ASSERT(creds != nullptr);
3765   GPR_ASSERT(error.ok());
3766   GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
3767   error = GRPC_ERROR_CREATE("Creating aws request signer failed.");
3768   grpc_error_handle expected_error = GRPC_ERROR_CREATE_REFERENCING(
3769       "Error occurred when fetching oauth2 token.", &error, 1);
3770   auto state = RequestMetadataState::NewInstance(expected_error, {});
3771   HttpRequest::SetOverride(aws_external_account_creds_httpcli_get_success,
3772                            aws_external_account_creds_httpcli_post_success,
3773                            httpcli_put_should_not_be_called);
3774   state->RunRequestMetadataTest(creds.get(), kTestUrlScheme, kTestAuthority,
3775                                 kTestPath);
3776   ExecCtx::Get()->Flush();
3777   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
3778 }
3779 
TEST(CredentialsTest,TestAwsExternalAccountCredsFailureMissingRoleName)3780 TEST(CredentialsTest, TestAwsExternalAccountCredsFailureMissingRoleName) {
3781   ExecCtx exec_ctx;
3782   auto credential_source = JsonParse(
3783       invalid_aws_external_account_creds_options_credential_source_missing_role_name);
3784   GPR_ASSERT(credential_source.ok());
3785   TestExternalAccountCredentials::ServiceAccountImpersonation
3786       service_account_impersonation;
3787   service_account_impersonation.token_lifetime_seconds = 3600;
3788   ExternalAccountCredentials::Options options = {
3789       "external_account",                 // type;
3790       "audience",                         // audience;
3791       "subject_token_type",               // subject_token_type;
3792       "",                                 // service_account_impersonation_url;
3793       service_account_impersonation,      // service_account_impersonation;
3794       "https://foo.com:5555/token",       // token_url;
3795       "https://foo.com:5555/token_info",  // token_info_url;
3796       *credential_source,                 // credential_source;
3797       "quota_project_id",                 // quota_project_id;
3798       "client_id",                        // client_id;
3799       "client_secret",                    // client_secret;
3800       "",                                 // workforce_pool_user_project;
3801   };
3802   grpc_error_handle error;
3803   auto creds = AwsExternalAccountCredentials::Create(options, {}, &error);
3804   GPR_ASSERT(creds != nullptr);
3805   GPR_ASSERT(error.ok());
3806   GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY);
3807   error = GRPC_ERROR_CREATE("Missing role name when retrieving signing keys.");
3808   grpc_error_handle expected_error = GRPC_ERROR_CREATE_REFERENCING(
3809       "Error occurred when fetching oauth2 token.", &error, 1);
3810   auto state = RequestMetadataState::NewInstance(expected_error, {});
3811   HttpRequest::SetOverride(aws_external_account_creds_httpcli_get_success,
3812                            aws_external_account_creds_httpcli_post_success,
3813                            httpcli_put_should_not_be_called);
3814   state->RunRequestMetadataTest(creds.get(), kTestUrlScheme, kTestAuthority,
3815                                 kTestPath);
3816   ExecCtx::Get()->Flush();
3817   HttpRequest::SetOverride(nullptr, nullptr, nullptr);
3818 }
3819 
TEST(CredentialsTest,TestExternalAccountCredentialsCreateFailureInvalidJsonFormat)3820 TEST(CredentialsTest,
3821      TestExternalAccountCredentialsCreateFailureInvalidJsonFormat) {
3822   const char* options_string = "invalid_json";
3823   grpc_call_credentials* creds =
3824       grpc_external_account_credentials_create(options_string, "");
3825   GPR_ASSERT(creds == nullptr);
3826 }
3827 
TEST(CredentialsTest,TestExternalAccountCredentialsCreateFailureInvalidOptionsFormat)3828 TEST(CredentialsTest,
3829      TestExternalAccountCredentialsCreateFailureInvalidOptionsFormat) {
3830   const char* options_string = "{\"random_key\":\"random_value\"}";
3831   grpc_call_credentials* creds =
3832       grpc_external_account_credentials_create(options_string, "");
3833   GPR_ASSERT(creds == nullptr);
3834 }
3835 
TEST(CredentialsTest,TestExternalAccountCredentialsCreateFailureInvalidOptionsCredentialSource)3836 TEST(
3837     CredentialsTest,
3838     TestExternalAccountCredentialsCreateFailureInvalidOptionsCredentialSource) {
3839   const char* options_string =
3840       "{\"type\":\"external_account\",\"audience\":\"audience\",\"subject_"
3841       "token_type\":\"subject_token_type\",\"service_account_impersonation_"
3842       "url\":\"service_account_impersonation_url\","
3843       "\"token_url\":\"https://foo.com:5555/"
3844       "token\",\"token_info_url\":\"https://foo.com:5555/"
3845       "token_info\",\"credential_source\":{\"random_key\":\"random_value\"},"
3846       "\"quota_project_id\":\"quota_"
3847       "project_id\",\"client_id\":\"client_id\",\"client_secret\":\"client_"
3848       "secret\"}";
3849   grpc_call_credentials* creds =
3850       grpc_external_account_credentials_create(options_string, "");
3851   GPR_ASSERT(creds == nullptr);
3852 }
3853 
TEST(CredentialsTest,TestExternalAccountCredentialsCreateSuccessWorkforcePool)3854 TEST(CredentialsTest,
3855      TestExternalAccountCredentialsCreateSuccessWorkforcePool) {
3856   const char* url_options_string =
3857       "{\"type\":\"external_account\",\"audience\":\"//iam.googleapis.com/"
3858       "locations/location/workforcePools/pool/providers/provider\",\"subject_"
3859       "token_type\":\"subject_token_type\",\"service_account_impersonation_"
3860       "url\":\"service_account_impersonation_url\","
3861       "\"token_url\":\"https://foo.com:5555/"
3862       "token\",\"token_info_url\":\"https://foo.com:5555/"
3863       "token_info\",\"credential_source\":{\"url\":\"https://foo.com:5555/"
3864       "generate_subject_token_format_json\",\"headers\":{\"Metadata-Flavor\":"
3865       "\"Google\"},\"format\":{\"type\":\"json\",\"subject_token_field_name\":"
3866       "\"access_token\"}},\"quota_project_id\":\"quota_"
3867       "project_id\",\"client_id\":\"client_id\",\"client_secret\":\"client_"
3868       "secret\",\"workforce_pool_user_project\":\"workforce_pool_user_"
3869       "project\"}";
3870   const char* url_scopes_string = "scope1,scope2";
3871   grpc_call_credentials* url_creds = grpc_external_account_credentials_create(
3872       url_options_string, url_scopes_string);
3873   GPR_ASSERT(url_creds != nullptr);
3874   url_creds->Unref();
3875 }
3876 
TEST(CredentialsTest,TestExternalAccountCredentialsCreateFailureInvalidWorkforcePoolAudience)3877 TEST(CredentialsTest,
3878      TestExternalAccountCredentialsCreateFailureInvalidWorkforcePoolAudience) {
3879   const char* url_options_string =
3880       "{\"type\":\"external_account\",\"audience\":\"invalid_workforce_pool_"
3881       "audience\",\"subject_"
3882       "token_type\":\"subject_token_type\",\"service_account_impersonation_"
3883       "url\":\"service_account_impersonation_url\","
3884       "\"token_url\":\"https://foo.com:5555/"
3885       "token\",\"token_info_url\":\"https://foo.com:5555/"
3886       "token_info\",\"credential_source\":{\"url\":\"https://foo.com:5555/"
3887       "generate_subject_token_format_json\",\"headers\":{\"Metadata-Flavor\":"
3888       "\"Google\"},\"format\":{\"type\":\"json\",\"subject_token_field_name\":"
3889       "\"access_token\"}},\"quota_project_id\":\"quota_"
3890       "project_id\",\"client_id\":\"client_id\",\"client_secret\":\"client_"
3891       "secret\",\"workforce_pool_user_project\":\"workforce_pool_user_"
3892       "project\"}";
3893   const char* url_scopes_string = "scope1,scope2";
3894   grpc_call_credentials* url_creds = grpc_external_account_credentials_create(
3895       url_options_string, url_scopes_string);
3896   GPR_ASSERT(url_creds == nullptr);
3897 }
3898 
TEST(CredentialsTest,TestInsecureCredentialsCompareSuccess)3899 TEST(CredentialsTest, TestInsecureCredentialsCompareSuccess) {
3900   auto insecure_creds_1 = grpc_insecure_credentials_create();
3901   auto insecure_creds_2 = grpc_insecure_credentials_create();
3902   ASSERT_EQ(insecure_creds_1->cmp(insecure_creds_2), 0);
3903   grpc_arg arg_1 = grpc_channel_credentials_to_arg(insecure_creds_1);
3904   grpc_channel_args args_1 = {1, &arg_1};
3905   grpc_arg arg_2 = grpc_channel_credentials_to_arg(insecure_creds_2);
3906   grpc_channel_args args_2 = {1, &arg_2};
3907   EXPECT_EQ(grpc_channel_args_compare(&args_1, &args_2), 0);
3908   grpc_channel_credentials_release(insecure_creds_1);
3909   grpc_channel_credentials_release(insecure_creds_2);
3910 }
3911 
TEST(CredentialsTest,TestInsecureCredentialsCompareFailure)3912 TEST(CredentialsTest, TestInsecureCredentialsCompareFailure) {
3913   auto* insecure_creds = grpc_insecure_credentials_create();
3914   auto* fake_creds = grpc_fake_transport_security_credentials_create();
3915   ASSERT_NE(insecure_creds->cmp(fake_creds), 0);
3916   ASSERT_NE(fake_creds->cmp(insecure_creds), 0);
3917   grpc_arg arg_1 = grpc_channel_credentials_to_arg(insecure_creds);
3918   grpc_channel_args args_1 = {1, &arg_1};
3919   grpc_arg arg_2 = grpc_channel_credentials_to_arg(fake_creds);
3920   grpc_channel_args args_2 = {1, &arg_2};
3921   EXPECT_NE(grpc_channel_args_compare(&args_1, &args_2), 0);
3922   grpc_channel_credentials_release(fake_creds);
3923   grpc_channel_credentials_release(insecure_creds);
3924 }
3925 
TEST(CredentialsTest,TestInsecureCredentialsSingletonCreate)3926 TEST(CredentialsTest, TestInsecureCredentialsSingletonCreate) {
3927   auto* insecure_creds_1 = grpc_insecure_credentials_create();
3928   auto* insecure_creds_2 = grpc_insecure_credentials_create();
3929   EXPECT_EQ(insecure_creds_1, insecure_creds_2);
3930 }
3931 
TEST(CredentialsTest,TestFakeCallCredentialsCompareSuccess)3932 TEST(CredentialsTest, TestFakeCallCredentialsCompareSuccess) {
3933   auto call_creds = MakeRefCounted<fake_call_creds>();
3934   GPR_ASSERT(call_creds->cmp(call_creds.get()) == 0);
3935 }
3936 
TEST(CredentialsTest,TestFakeCallCredentialsCompareFailure)3937 TEST(CredentialsTest, TestFakeCallCredentialsCompareFailure) {
3938   auto fake_creds = MakeRefCounted<fake_call_creds>();
3939   auto* md_creds = grpc_md_only_test_credentials_create("key", "value");
3940   GPR_ASSERT(fake_creds->cmp(md_creds) != 0);
3941   GPR_ASSERT(md_creds->cmp(fake_creds.get()) != 0);
3942   grpc_call_credentials_release(md_creds);
3943 }
3944 
TEST(CredentialsTest,TestHttpRequestSSLCredentialsCompare)3945 TEST(CredentialsTest, TestHttpRequestSSLCredentialsCompare) {
3946   auto creds_1 = CreateHttpRequestSSLCredentials();
3947   auto creds_2 = CreateHttpRequestSSLCredentials();
3948   EXPECT_EQ(creds_1->cmp(creds_2.get()), 0);
3949   EXPECT_EQ(creds_2->cmp(creds_1.get()), 0);
3950 }
3951 
TEST(CredentialsTest,TestHttpRequestSSLCredentialsSingleton)3952 TEST(CredentialsTest, TestHttpRequestSSLCredentialsSingleton) {
3953   auto creds_1 = CreateHttpRequestSSLCredentials();
3954   auto creds_2 = CreateHttpRequestSSLCredentials();
3955   EXPECT_EQ(creds_1, creds_2);
3956 }
3957 
TEST(CredentialsTest,TestCompositeChannelCredsCompareSuccess)3958 TEST(CredentialsTest, TestCompositeChannelCredsCompareSuccess) {
3959   auto* insecure_creds = grpc_insecure_credentials_create();
3960   auto fake_creds = MakeRefCounted<fake_call_creds>();
3961   auto* composite_creds_1 = grpc_composite_channel_credentials_create(
3962       insecure_creds, fake_creds.get(), nullptr);
3963   auto* composite_creds_2 = grpc_composite_channel_credentials_create(
3964       insecure_creds, fake_creds.get(), nullptr);
3965   EXPECT_EQ(composite_creds_1->cmp(composite_creds_2), 0);
3966   EXPECT_EQ(composite_creds_2->cmp(composite_creds_1), 0);
3967   grpc_channel_credentials_release(insecure_creds);
3968   grpc_channel_credentials_release(composite_creds_1);
3969   grpc_channel_credentials_release(composite_creds_2);
3970 }
3971 
TEST(CredentialsTest,RecursiveCompositeCredsDuplicateWithoutCallCreds)3972 TEST(CredentialsTest, RecursiveCompositeCredsDuplicateWithoutCallCreds) {
3973   auto* insecure_creds = grpc_insecure_credentials_create();
3974   auto inner_fake_creds = MakeRefCounted<fake_call_creds>();
3975   auto outer_fake_creds = MakeRefCounted<fake_call_creds>();
3976   auto* inner_composite_creds = grpc_composite_channel_credentials_create(
3977       insecure_creds, inner_fake_creds.get(), nullptr);
3978   auto* outer_composite_creds = grpc_composite_channel_credentials_create(
3979       inner_composite_creds, outer_fake_creds.get(), nullptr);
3980   auto duplicate_without_call_creds =
3981       outer_composite_creds->duplicate_without_call_credentials();
3982   EXPECT_EQ(duplicate_without_call_creds.get(), insecure_creds);
3983   grpc_channel_credentials_release(insecure_creds);
3984   grpc_channel_credentials_release(inner_composite_creds);
3985   grpc_channel_credentials_release(outer_composite_creds);
3986 }
3987 
TEST(CredentialsTest,TestCompositeChannelCredsCompareFailureDifferentChannelCreds)3988 TEST(CredentialsTest,
3989      TestCompositeChannelCredsCompareFailureDifferentChannelCreds) {
3990   auto* insecure_creds = grpc_insecure_credentials_create();
3991   auto* fake_channel_creds = grpc_fake_transport_security_credentials_create();
3992   auto fake_creds = MakeRefCounted<fake_call_creds>();
3993   auto* composite_creds_1 = grpc_composite_channel_credentials_create(
3994       insecure_creds, fake_creds.get(), nullptr);
3995   auto* composite_creds_2 = grpc_composite_channel_credentials_create(
3996       fake_channel_creds, fake_creds.get(), nullptr);
3997   EXPECT_NE(composite_creds_1->cmp(composite_creds_2), 0);
3998   EXPECT_NE(composite_creds_2->cmp(composite_creds_1), 0);
3999   grpc_channel_credentials_release(insecure_creds);
4000   grpc_channel_credentials_release(fake_channel_creds);
4001   grpc_channel_credentials_release(composite_creds_1);
4002   grpc_channel_credentials_release(composite_creds_2);
4003 }
4004 
TEST(CredentialsTest,TestCompositeChannelCredsCompareFailureDifferentCallCreds)4005 TEST(CredentialsTest,
4006      TestCompositeChannelCredsCompareFailureDifferentCallCreds) {
4007   auto* insecure_creds = grpc_insecure_credentials_create();
4008   auto fake_creds = MakeRefCounted<fake_call_creds>();
4009   auto* md_creds = grpc_md_only_test_credentials_create("key", "value");
4010   auto* composite_creds_1 = grpc_composite_channel_credentials_create(
4011       insecure_creds, fake_creds.get(), nullptr);
4012   auto* composite_creds_2 = grpc_composite_channel_credentials_create(
4013       insecure_creds, md_creds, nullptr);
4014   EXPECT_NE(composite_creds_1->cmp(composite_creds_2), 0);
4015   EXPECT_NE(composite_creds_2->cmp(composite_creds_1), 0);
4016   grpc_channel_credentials_release(insecure_creds);
4017   grpc_call_credentials_release(md_creds);
4018   grpc_channel_credentials_release(composite_creds_1);
4019   grpc_channel_credentials_release(composite_creds_2);
4020 }
4021 
TEST(CredentialsTest,TestTlsCredentialsCompareSuccess)4022 TEST(CredentialsTest, TestTlsCredentialsCompareSuccess) {
4023   auto* tls_creds_1 =
4024       grpc_tls_credentials_create(grpc_tls_credentials_options_create());
4025   auto* tls_creds_2 =
4026       grpc_tls_credentials_create(grpc_tls_credentials_options_create());
4027   EXPECT_EQ(tls_creds_1->cmp(tls_creds_2), 0);
4028   EXPECT_EQ(tls_creds_2->cmp(tls_creds_1), 0);
4029   grpc_channel_credentials_release(tls_creds_1);
4030   grpc_channel_credentials_release(tls_creds_2);
4031 }
4032 
TEST(CredentialsTest,TestTlsCredentialsWithVerifierCompareSuccess)4033 TEST(CredentialsTest, TestTlsCredentialsWithVerifierCompareSuccess) {
4034   auto* options_1 = grpc_tls_credentials_options_create();
4035   options_1->set_certificate_verifier(
4036       MakeRefCounted<HostNameCertificateVerifier>());
4037   auto* tls_creds_1 = grpc_tls_credentials_create(options_1);
4038   auto* options_2 = grpc_tls_credentials_options_create();
4039   options_2->set_certificate_verifier(
4040       MakeRefCounted<HostNameCertificateVerifier>());
4041   auto* tls_creds_2 = grpc_tls_credentials_create(options_2);
4042   EXPECT_EQ(tls_creds_1->cmp(tls_creds_2), 0);
4043   EXPECT_EQ(tls_creds_2->cmp(tls_creds_1), 0);
4044   grpc_channel_credentials_release(tls_creds_1);
4045   grpc_channel_credentials_release(tls_creds_2);
4046 }
4047 
TEST(CredentialsTest,TestTlsCredentialsCompareFailure)4048 TEST(CredentialsTest, TestTlsCredentialsCompareFailure) {
4049   auto* options_1 = grpc_tls_credentials_options_create();
4050   options_1->set_check_call_host(true);
4051   auto* tls_creds_1 = grpc_tls_credentials_create(options_1);
4052   auto* options_2 = grpc_tls_credentials_options_create();
4053   options_2->set_check_call_host(false);
4054   auto* tls_creds_2 = grpc_tls_credentials_create(options_2);
4055   EXPECT_NE(tls_creds_1->cmp(tls_creds_2), 0);
4056   EXPECT_NE(tls_creds_2->cmp(tls_creds_1), 0);
4057   grpc_channel_credentials_release(tls_creds_1);
4058   grpc_channel_credentials_release(tls_creds_2);
4059 }
4060 
TEST(CredentialsTest,TestTlsCredentialsWithVerifierCompareFailure)4061 TEST(CredentialsTest, TestTlsCredentialsWithVerifierCompareFailure) {
4062   auto* options_1 = grpc_tls_credentials_options_create();
4063   options_1->set_certificate_verifier(
4064       MakeRefCounted<HostNameCertificateVerifier>());
4065   auto* tls_creds_1 = grpc_tls_credentials_create(options_1);
4066   auto* options_2 = grpc_tls_credentials_options_create();
4067   grpc_tls_certificate_verifier_external verifier = {nullptr, nullptr, nullptr,
4068                                                      nullptr};
4069   options_2->set_certificate_verifier(
4070       MakeRefCounted<ExternalCertificateVerifier>(&verifier));
4071   auto* tls_creds_2 = grpc_tls_credentials_create(options_2);
4072   EXPECT_NE(tls_creds_1->cmp(tls_creds_2), 0);
4073   EXPECT_NE(tls_creds_2->cmp(tls_creds_1), 0);
4074   grpc_channel_credentials_release(tls_creds_1);
4075   grpc_channel_credentials_release(tls_creds_2);
4076 }
4077 
TEST(CredentialsTest,TestXdsCredentialsCompareSucces)4078 TEST(CredentialsTest, TestXdsCredentialsCompareSucces) {
4079   auto* insecure_creds = grpc_insecure_credentials_create();
4080   auto* xds_creds_1 = grpc_xds_credentials_create(insecure_creds);
4081   auto* xds_creds_2 = grpc_xds_credentials_create(insecure_creds);
4082   EXPECT_EQ(xds_creds_1->cmp(xds_creds_2), 0);
4083   EXPECT_EQ(xds_creds_2->cmp(xds_creds_1), 0);
4084   grpc_channel_credentials_release(insecure_creds);
4085   grpc_channel_credentials_release(xds_creds_1);
4086   grpc_channel_credentials_release(xds_creds_2);
4087 }
4088 
TEST(CredentialsTest,TestXdsCredentialsCompareFailure)4089 TEST(CredentialsTest, TestXdsCredentialsCompareFailure) {
4090   auto* insecure_creds = grpc_insecure_credentials_create();
4091   auto* fake_creds = grpc_fake_transport_security_credentials_create();
4092   auto* xds_creds_1 = grpc_xds_credentials_create(insecure_creds);
4093   auto* xds_creds_2 = grpc_xds_credentials_create(fake_creds);
4094   EXPECT_NE(xds_creds_1->cmp(xds_creds_2), 0);
4095   EXPECT_NE(xds_creds_2->cmp(xds_creds_1), 0);
4096   grpc_channel_credentials_release(insecure_creds);
4097   grpc_channel_credentials_release(fake_creds);
4098   grpc_channel_credentials_release(xds_creds_1);
4099   grpc_channel_credentials_release(xds_creds_2);
4100 }
4101 
4102 }  // namespace
4103 }  // namespace grpc_core
4104 
main(int argc,char ** argv)4105 int main(int argc, char** argv) {
4106   testing::InitGoogleTest(&argc, argv);
4107   grpc::testing::TestEnvironment env(&argc, argv);
4108   grpc_init();
4109   auto result = RUN_ALL_TESTS();
4110   grpc_shutdown();
4111   return result;
4112 }
4113