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