1 /* 2 * Copyright 2021 Google LLC 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * 15 * * Neither the name of Google LLC nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 package com.google.auth.oauth2; 33 34 import static com.google.auth.Credentials.GOOGLE_DEFAULT_UNIVERSE; 35 import static com.google.auth.oauth2.MockExternalAccountCredentialsTransport.SERVICE_ACCOUNT_IMPERSONATION_URL; 36 import static com.google.auth.oauth2.OAuth2Utils.JSON_FACTORY; 37 import static org.junit.Assert.*; 38 39 import com.google.api.client.http.HttpTransport; 40 import com.google.api.client.json.GenericJson; 41 import com.google.api.client.util.Clock; 42 import com.google.auth.TestUtils; 43 import com.google.auth.http.HttpTransportFactory; 44 import java.io.ByteArrayInputStream; 45 import java.io.File; 46 import java.io.IOException; 47 import java.io.InputStream; 48 import java.nio.charset.StandardCharsets; 49 import java.util.Arrays; 50 import java.util.HashMap; 51 import java.util.List; 52 import java.util.Map; 53 import javax.annotation.Nullable; 54 import org.junit.Test; 55 import org.junit.runner.RunWith; 56 import org.junit.runners.JUnit4; 57 58 /** Tests for {@link IdentityPoolCredentials}. */ 59 @RunWith(JUnit4.class) 60 public class IdentityPoolCredentialsTest extends BaseSerializationTest { 61 62 private static final String STS_URL = "https://sts.googleapis.com/v1/token"; 63 64 private static final Map<String, Object> FILE_CREDENTIAL_SOURCE_MAP = 65 new HashMap<String, Object>() { 66 { 67 put("file", "file"); 68 } 69 }; 70 71 private static final IdentityPoolCredentialSource FILE_CREDENTIAL_SOURCE = 72 new IdentityPoolCredentialSource(FILE_CREDENTIAL_SOURCE_MAP); 73 74 private static final IdentityPoolCredentials FILE_SOURCED_CREDENTIAL = 75 IdentityPoolCredentials.newBuilder() 76 .setHttpTransportFactory(OAuth2Utils.HTTP_TRANSPORT_FACTORY) 77 .setAudience( 78 "//iam.googleapis.com/projects/123/locations/global/workloadIdentityPools/pool/providers/provider") 79 .setSubjectTokenType("subjectTokenType") 80 .setTokenUrl(STS_URL) 81 .setTokenInfoUrl("tokenInfoUrl") 82 .setCredentialSource(FILE_CREDENTIAL_SOURCE) 83 .build(); 84 85 private static final IdentityPoolSubjectTokenSupplier testProvider = 86 (ExternalAccountSupplierContext context) -> "testSubjectToken"; 87 88 private static final ExternalAccountSupplierContext emptyContext = 89 ExternalAccountSupplierContext.newBuilder().setAudience("").setSubjectTokenType("").build(); 90 91 static class MockExternalAccountCredentialsTransportFactory implements HttpTransportFactory { 92 93 MockExternalAccountCredentialsTransport transport = 94 new MockExternalAccountCredentialsTransport(); 95 96 @Override create()97 public HttpTransport create() { 98 return transport; 99 } 100 } 101 102 @Test createdScoped_clonedCredentialWithAddedScopes()103 public void createdScoped_clonedCredentialWithAddedScopes() throws IOException { 104 IdentityPoolCredentials credentials = 105 IdentityPoolCredentials.newBuilder(FILE_SOURCED_CREDENTIAL) 106 .setServiceAccountImpersonationUrl(SERVICE_ACCOUNT_IMPERSONATION_URL) 107 .setQuotaProjectId("quotaProjectId") 108 .setClientId("clientId") 109 .setClientSecret("clientSecret") 110 .setUniverseDomain("universeDomain") 111 .build(); 112 113 List<String> newScopes = Arrays.asList("scope1", "scope2"); 114 115 IdentityPoolCredentials newCredentials = credentials.createScoped(newScopes); 116 117 assertEquals(credentials.getAudience(), newCredentials.getAudience()); 118 assertEquals(credentials.getSubjectTokenType(), newCredentials.getSubjectTokenType()); 119 assertEquals(credentials.getTokenUrl(), newCredentials.getTokenUrl()); 120 assertEquals(credentials.getTokenInfoUrl(), newCredentials.getTokenInfoUrl()); 121 assertEquals( 122 credentials.getServiceAccountImpersonationUrl(), 123 newCredentials.getServiceAccountImpersonationUrl()); 124 assertEquals(credentials.getCredentialSource(), newCredentials.getCredentialSource()); 125 assertEquals(newScopes, newCredentials.getScopes()); 126 assertEquals(credentials.getQuotaProjectId(), newCredentials.getQuotaProjectId()); 127 assertEquals(credentials.getClientId(), newCredentials.getClientId()); 128 assertEquals(credentials.getClientSecret(), newCredentials.getClientSecret()); 129 assertEquals(credentials.getUniverseDomain(), newCredentials.getUniverseDomain()); 130 assertEquals("universeDomain", newCredentials.getUniverseDomain()); 131 } 132 133 @Test retrieveSubjectToken_fileSourced()134 public void retrieveSubjectToken_fileSourced() throws IOException { 135 File file = 136 File.createTempFile("RETRIEVE_SUBJECT_TOKEN", /* suffix= */ null, /* directory= */ null); 137 file.deleteOnExit(); 138 139 String credential = "credential"; 140 OAuth2Utils.writeInputStreamToFile( 141 new ByteArrayInputStream(credential.getBytes(StandardCharsets.UTF_8)), 142 file.getAbsolutePath()); 143 144 Map<String, Object> credentialSourceMap = new HashMap<>(); 145 credentialSourceMap.put("file", file.getAbsolutePath()); 146 IdentityPoolCredentialSource credentialSource = 147 new IdentityPoolCredentialSource(credentialSourceMap); 148 149 IdentityPoolCredentials credentials = 150 IdentityPoolCredentials.newBuilder(FILE_SOURCED_CREDENTIAL) 151 .setCredentialSource(credentialSource) 152 .build(); 153 154 String subjectToken = credentials.retrieveSubjectToken(); 155 156 assertEquals(credential, subjectToken); 157 } 158 159 @Test retrieveSubjectToken_fileSourcedWithJsonFormat()160 public void retrieveSubjectToken_fileSourcedWithJsonFormat() throws IOException { 161 File file = 162 File.createTempFile("RETRIEVE_SUBJECT_TOKEN", /* suffix= */ null, /* directory= */ null); 163 file.deleteOnExit(); 164 165 MockExternalAccountCredentialsTransportFactory transportFactory = 166 new MockExternalAccountCredentialsTransportFactory(); 167 168 transportFactory.transport.setMetadataServerContentType("json"); 169 170 Map<String, Object> credentialSourceMap = new HashMap<>(); 171 Map<String, String> formatMap = new HashMap<>(); 172 formatMap.put("type", "json"); 173 formatMap.put("subject_token_field_name", "subjectToken"); 174 175 credentialSourceMap.put("file", file.getAbsolutePath()); 176 credentialSourceMap.put("format", formatMap); 177 178 IdentityPoolCredentialSource credentialSource = 179 new IdentityPoolCredentialSource(credentialSourceMap); 180 181 GenericJson response = new GenericJson(); 182 response.setFactory(JSON_FACTORY); 183 response.put("subjectToken", "subjectToken"); 184 185 OAuth2Utils.writeInputStreamToFile( 186 new ByteArrayInputStream(response.toString().getBytes(StandardCharsets.UTF_8)), 187 file.getAbsolutePath()); 188 189 IdentityPoolCredentials credential = 190 IdentityPoolCredentials.newBuilder(FILE_SOURCED_CREDENTIAL) 191 .setHttpTransportFactory(transportFactory) 192 .setCredentialSource(credentialSource) 193 .build(); 194 195 String subjectToken = credential.retrieveSubjectToken(); 196 197 assertEquals("subjectToken", subjectToken); 198 } 199 200 @Test retrieveSubjectToken_fileSourcedWithNullFormat_throws()201 public void retrieveSubjectToken_fileSourcedWithNullFormat_throws() throws IOException { 202 File file = 203 File.createTempFile("RETRIEVE_SUBJECT_TOKEN", /* suffix= */ null, /* directory= */ null); 204 file.deleteOnExit(); 205 206 Map<String, Object> credentialSourceMap = new HashMap<>(); 207 Map<String, String> formatMap = new HashMap<>(); 208 formatMap.put("type", null); 209 210 credentialSourceMap.put("file", file.getAbsolutePath()); 211 credentialSourceMap.put("format", formatMap); 212 213 try { 214 new IdentityPoolCredentialSource(credentialSourceMap); 215 fail("Exception should be thrown due to null format."); 216 } catch (IllegalArgumentException e) { 217 assertEquals("Invalid credential source format type: null.", e.getMessage()); 218 } 219 } 220 221 @Test retrieveSubjectToken_noFile_throws()222 public void retrieveSubjectToken_noFile_throws() { 223 Map<String, Object> credentialSourceMap = new HashMap<>(); 224 String path = "badPath"; 225 credentialSourceMap.put("file", path); 226 IdentityPoolCredentialSource credentialSource = 227 new IdentityPoolCredentialSource(credentialSourceMap); 228 229 IdentityPoolCredentials credentials = 230 IdentityPoolCredentials.newBuilder(FILE_SOURCED_CREDENTIAL) 231 .setCredentialSource(credentialSource) 232 .build(); 233 234 try { 235 credentials.retrieveSubjectToken(); 236 fail("Exception should be thrown."); 237 } catch (IOException e) { 238 assertEquals( 239 String.format("Invalid credential location. The file at %s does not exist.", path), 240 e.getMessage()); 241 } 242 } 243 244 @Test retrieveSubjectToken_urlSourced()245 public void retrieveSubjectToken_urlSourced() throws IOException { 246 MockExternalAccountCredentialsTransportFactory transportFactory = 247 new MockExternalAccountCredentialsTransportFactory(); 248 249 IdentityPoolCredentials credential = 250 IdentityPoolCredentials.newBuilder(FILE_SOURCED_CREDENTIAL) 251 .setHttpTransportFactory(transportFactory) 252 .setCredentialSource( 253 buildUrlBasedCredentialSource(transportFactory.transport.getMetadataUrl())) 254 .build(); 255 256 String subjectToken = credential.retrieveSubjectToken(); 257 258 assertEquals(transportFactory.transport.getSubjectToken(), subjectToken); 259 } 260 261 @Test retrieveSubjectToken_urlSourcedWithJsonFormat()262 public void retrieveSubjectToken_urlSourcedWithJsonFormat() throws IOException { 263 MockExternalAccountCredentialsTransportFactory transportFactory = 264 new MockExternalAccountCredentialsTransportFactory(); 265 266 transportFactory.transport.setMetadataServerContentType("json"); 267 268 Map<String, String> formatMap = new HashMap<>(); 269 formatMap.put("type", "json"); 270 formatMap.put("subject_token_field_name", "subjectToken"); 271 272 IdentityPoolCredentialSource credentialSource = 273 buildUrlBasedCredentialSource(transportFactory.transport.getMetadataUrl(), formatMap); 274 275 IdentityPoolCredentials credential = 276 IdentityPoolCredentials.newBuilder(FILE_SOURCED_CREDENTIAL) 277 .setHttpTransportFactory(transportFactory) 278 .setCredentialSource(credentialSource) 279 .build(); 280 281 String subjectToken = credential.retrieveSubjectToken(); 282 283 assertEquals(transportFactory.transport.getSubjectToken(), subjectToken); 284 } 285 286 @Test retrieveSubjectToken_urlSourcedCredential_throws()287 public void retrieveSubjectToken_urlSourcedCredential_throws() { 288 MockExternalAccountCredentialsTransportFactory transportFactory = 289 new MockExternalAccountCredentialsTransportFactory(); 290 291 IOException response = new IOException(); 292 transportFactory.transport.addResponseErrorSequence(response); 293 294 IdentityPoolCredentials credential = 295 IdentityPoolCredentials.newBuilder(FILE_SOURCED_CREDENTIAL) 296 .setHttpTransportFactory(transportFactory) 297 .setCredentialSource( 298 buildUrlBasedCredentialSource(transportFactory.transport.getMetadataUrl())) 299 .build(); 300 301 try { 302 credential.retrieveSubjectToken(); 303 fail("Exception should be thrown."); 304 } catch (IOException e) { 305 assertEquals( 306 String.format( 307 "Error getting subject token from metadata server: %s", response.getMessage()), 308 e.getMessage()); 309 } 310 } 311 312 @Test retrieveSubjectToken_provider()313 public void retrieveSubjectToken_provider() throws IOException { 314 315 IdentityPoolCredentials credentials = 316 IdentityPoolCredentials.newBuilder(FILE_SOURCED_CREDENTIAL) 317 .setCredentialSource(null) 318 .setSubjectTokenSupplier(testProvider) 319 .build(); 320 321 String subjectToken = credentials.retrieveSubjectToken(); 322 323 assertEquals(testProvider.getSubjectToken(emptyContext), subjectToken); 324 } 325 326 @Test retrieveSubjectToken_providerThrowsError()327 public void retrieveSubjectToken_providerThrowsError() throws IOException { 328 IOException testException = new IOException("test"); 329 330 IdentityPoolSubjectTokenSupplier errorProvider = 331 (ExternalAccountSupplierContext context) -> { 332 throw testException; 333 }; 334 IdentityPoolCredentials credentials = 335 IdentityPoolCredentials.newBuilder(FILE_SOURCED_CREDENTIAL) 336 .setCredentialSource(null) 337 .setSubjectTokenSupplier(errorProvider) 338 .build(); 339 340 try { 341 String subjectToken = credentials.retrieveSubjectToken(); 342 fail("retrieveSubjectToken should fail."); 343 } catch (IOException e) { 344 assertEquals("test", e.getMessage()); 345 } 346 } 347 348 @Test retrieveSubjectToken_supplierPassesContext()349 public void retrieveSubjectToken_supplierPassesContext() throws IOException { 350 ExternalAccountSupplierContext expectedContext = 351 ExternalAccountSupplierContext.newBuilder() 352 .setAudience(FILE_SOURCED_CREDENTIAL.getAudience()) 353 .setSubjectTokenType(FILE_SOURCED_CREDENTIAL.getSubjectTokenType()) 354 .build(); 355 356 IdentityPoolSubjectTokenSupplier testSupplier = 357 (ExternalAccountSupplierContext context) -> { 358 assertEquals(expectedContext.getAudience(), context.getAudience()); 359 assertEquals(expectedContext.getSubjectTokenType(), context.getSubjectTokenType()); 360 return "token"; 361 }; 362 IdentityPoolCredentials credentials = 363 IdentityPoolCredentials.newBuilder(FILE_SOURCED_CREDENTIAL) 364 .setCredentialSource(null) 365 .setSubjectTokenSupplier(testSupplier) 366 .build(); 367 368 credentials.retrieveSubjectToken(); 369 } 370 371 @Test refreshAccessToken_withoutServiceAccountImpersonation()372 public void refreshAccessToken_withoutServiceAccountImpersonation() throws IOException { 373 MockExternalAccountCredentialsTransportFactory transportFactory = 374 new MockExternalAccountCredentialsTransportFactory(); 375 376 IdentityPoolCredentials credential = 377 IdentityPoolCredentials.newBuilder() 378 .setAudience( 379 "//iam.googleapis.com/projects/123/locations/global/workloadIdentityPools/pool/providers/provider") 380 .setSubjectTokenType("subjectTokenType") 381 .setTokenInfoUrl("tokenInfoUrl") 382 .setCredentialSource(FILE_CREDENTIAL_SOURCE) 383 .setTokenUrl(transportFactory.transport.getStsUrl()) 384 .setHttpTransportFactory(transportFactory) 385 .setCredentialSource( 386 buildUrlBasedCredentialSource(transportFactory.transport.getMetadataUrl())) 387 .build(); 388 389 AccessToken accessToken = credential.refreshAccessToken(); 390 391 assertEquals(transportFactory.transport.getAccessToken(), accessToken.getTokenValue()); 392 393 // Validate metrics header is set correctly on the sts request. 394 Map<String, List<String>> headers = 395 transportFactory.transport.getRequests().get(1).getHeaders(); 396 ExternalAccountCredentialsTest.validateMetricsHeader(headers, "url", false, false); 397 } 398 399 @Test refreshAccessToken_internalOptionsSet()400 public void refreshAccessToken_internalOptionsSet() throws IOException { 401 MockExternalAccountCredentialsTransportFactory transportFactory = 402 new MockExternalAccountCredentialsTransportFactory(); 403 404 IdentityPoolCredentials credential = 405 IdentityPoolCredentials.newBuilder(FILE_SOURCED_CREDENTIAL) 406 .setWorkforcePoolUserProject("userProject") 407 .setAudience( 408 "//iam.googleapis.com/locations/global/workforcePools/pool/providers/provider") 409 .setTokenUrl(transportFactory.transport.getStsUrl()) 410 .setHttpTransportFactory(transportFactory) 411 .setCredentialSource( 412 buildUrlBasedCredentialSource(transportFactory.transport.getMetadataUrl())) 413 .build(); 414 415 AccessToken accessToken = credential.refreshAccessToken(); 416 417 assertEquals(transportFactory.transport.getAccessToken(), accessToken.getTokenValue()); 418 419 // If the IdentityPoolCredential is initialized with a userProject, it must be passed 420 // to STS via internal options. 421 Map<String, String> query = 422 TestUtils.parseQuery(transportFactory.transport.getLastRequest().getContentAsString()); 423 assertNotNull(query.get("options")); 424 425 GenericJson expectedInternalOptions = new GenericJson(); 426 expectedInternalOptions.setFactory(OAuth2Utils.JSON_FACTORY); 427 expectedInternalOptions.put("userProject", "userProject"); 428 429 assertEquals(expectedInternalOptions.toString(), query.get("options")); 430 } 431 432 @Test refreshAccessToken_withServiceAccountImpersonation()433 public void refreshAccessToken_withServiceAccountImpersonation() throws IOException { 434 MockExternalAccountCredentialsTransportFactory transportFactory = 435 new MockExternalAccountCredentialsTransportFactory(); 436 437 transportFactory.transport.setExpireTime(TestUtils.getDefaultExpireTime()); 438 IdentityPoolCredentials credential = 439 IdentityPoolCredentials.newBuilder() 440 .setAudience( 441 "//iam.googleapis.com/projects/123/locations/global/workloadIdentityPools/pool/providers/provider") 442 .setSubjectTokenType("subjectTokenType") 443 .setTokenInfoUrl("tokenInfoUrl") 444 .setServiceAccountImpersonationUrl( 445 transportFactory.transport.getServiceAccountImpersonationUrl()) 446 .setTokenUrl(transportFactory.transport.getStsUrl()) 447 .setHttpTransportFactory(transportFactory) 448 .setCredentialSource( 449 buildUrlBasedCredentialSource(transportFactory.transport.getMetadataUrl())) 450 .build(); 451 452 AccessToken accessToken = credential.refreshAccessToken(); 453 454 assertEquals( 455 transportFactory.transport.getServiceAccountAccessToken(), accessToken.getTokenValue()); 456 457 // Validate metrics header is set correctly on the sts request. 458 Map<String, List<String>> headers = 459 transportFactory.transport.getRequests().get(2).getHeaders(); 460 ExternalAccountCredentialsTest.validateMetricsHeader(headers, "url", true, false); 461 } 462 463 @Test refreshAccessToken_withServiceAccountImpersonationOptions()464 public void refreshAccessToken_withServiceAccountImpersonationOptions() throws IOException { 465 MockExternalAccountCredentialsTransportFactory transportFactory = 466 new MockExternalAccountCredentialsTransportFactory(); 467 468 transportFactory.transport.setExpireTime(TestUtils.getDefaultExpireTime()); 469 IdentityPoolCredentials credential = 470 IdentityPoolCredentials.newBuilder() 471 .setAudience( 472 "//iam.googleapis.com/projects/123/locations/global/workloadIdentityPools/pool/providers/provider") 473 .setSubjectTokenType("subjectTokenType") 474 .setTokenInfoUrl("tokenInfoUrl") 475 .setTokenUrl(transportFactory.transport.getStsUrl()) 476 .setHttpTransportFactory(transportFactory) 477 .setServiceAccountImpersonationUrl( 478 transportFactory.transport.getServiceAccountImpersonationUrl()) 479 .setCredentialSource( 480 buildUrlBasedCredentialSource(transportFactory.transport.getMetadataUrl())) 481 .setServiceAccountImpersonationOptions( 482 ExternalAccountCredentialsTest.buildServiceAccountImpersonationOptions(2800)) 483 .build(); 484 485 AccessToken accessToken = credential.refreshAccessToken(); 486 487 assertEquals( 488 transportFactory.transport.getServiceAccountAccessToken(), accessToken.getTokenValue()); 489 490 // Validate that default lifetime was set correctly on the request. 491 GenericJson query = 492 OAuth2Utils.JSON_FACTORY 493 .createJsonParser(transportFactory.transport.getLastRequest().getContentAsString()) 494 .parseAndClose(GenericJson.class); 495 496 assertEquals("2800s", query.get("lifetime")); 497 498 // Validate metrics header is set correctly on the sts request. 499 Map<String, List<String>> headers = 500 transportFactory.transport.getRequests().get(2).getHeaders(); 501 ExternalAccountCredentialsTest.validateMetricsHeader(headers, "url", true, true); 502 } 503 504 @Test refreshAccessToken_Provider()505 public void refreshAccessToken_Provider() throws IOException { 506 MockExternalAccountCredentialsTransportFactory transportFactory = 507 new MockExternalAccountCredentialsTransportFactory(); 508 509 transportFactory.transport.setExpireTime(TestUtils.getDefaultExpireTime()); 510 IdentityPoolCredentials credential = 511 IdentityPoolCredentials.newBuilder() 512 .setSubjectTokenSupplier(testProvider) 513 .setAudience( 514 "//iam.googleapis.com/projects/123/locations/global/workloadIdentityPools/pool/providers/provider") 515 .setSubjectTokenType("subjectTokenType") 516 .setTokenInfoUrl("tokenInfoUrl") 517 .setTokenUrl(transportFactory.transport.getStsUrl()) 518 .setHttpTransportFactory(transportFactory) 519 .build(); 520 521 AccessToken accessToken = credential.refreshAccessToken(); 522 523 assertEquals(transportFactory.transport.getAccessToken(), accessToken.getTokenValue()); 524 525 // Validate metrics header is set correctly on the sts request. 526 Map<String, List<String>> headers = 527 transportFactory.transport.getRequests().get(0).getHeaders(); 528 ExternalAccountCredentialsTest.validateMetricsHeader(headers, "programmatic", false, false); 529 } 530 531 @Test refreshAccessToken_providerWithServiceAccountImpersonation()532 public void refreshAccessToken_providerWithServiceAccountImpersonation() throws IOException { 533 MockExternalAccountCredentialsTransportFactory transportFactory = 534 new MockExternalAccountCredentialsTransportFactory(); 535 536 transportFactory.transport.setExpireTime(TestUtils.getDefaultExpireTime()); 537 IdentityPoolCredentials credential = 538 IdentityPoolCredentials.newBuilder() 539 .setSubjectTokenSupplier(testProvider) 540 .setAudience( 541 "//iam.googleapis.com/projects/123/locations/global/workloadIdentityPools/pool/providers/provider") 542 .setSubjectTokenType("subjectTokenType") 543 .setTokenInfoUrl("tokenInfoUrl") 544 .setServiceAccountImpersonationUrl( 545 transportFactory.transport.getServiceAccountImpersonationUrl()) 546 .setTokenUrl(transportFactory.transport.getStsUrl()) 547 .setHttpTransportFactory(transportFactory) 548 .build(); 549 550 AccessToken accessToken = credential.refreshAccessToken(); 551 552 assertEquals( 553 transportFactory.transport.getServiceAccountAccessToken(), accessToken.getTokenValue()); 554 555 // Validate metrics header is set correctly on the sts request. 556 Map<String, List<String>> headers = 557 transportFactory.transport.getRequests().get(0).getHeaders(); 558 ExternalAccountCredentialsTest.validateMetricsHeader(headers, "programmatic", true, false); 559 } 560 561 @Test refreshAccessToken_workforceWithServiceAccountImpersonation()562 public void refreshAccessToken_workforceWithServiceAccountImpersonation() throws IOException { 563 MockExternalAccountCredentialsTransportFactory transportFactory = 564 new MockExternalAccountCredentialsTransportFactory(); 565 566 transportFactory.transport.setExpireTime(TestUtils.getDefaultExpireTime()); 567 IdentityPoolCredentials credential = 568 IdentityPoolCredentials.newBuilder(FILE_SOURCED_CREDENTIAL) 569 .setAudience( 570 "//iam.googleapis.com/locations/global/workforcePools/pool/providers/provider") 571 .setTokenUrl(transportFactory.transport.getStsUrl()) 572 .setServiceAccountImpersonationUrl( 573 transportFactory.transport.getServiceAccountImpersonationUrl()) 574 .setHttpTransportFactory(transportFactory) 575 .setCredentialSource( 576 buildUrlBasedCredentialSource(transportFactory.transport.getMetadataUrl())) 577 .setWorkforcePoolUserProject("userProject") 578 .build(); 579 580 AccessToken accessToken = credential.refreshAccessToken(); 581 582 assertEquals( 583 transportFactory.transport.getServiceAccountAccessToken(), accessToken.getTokenValue()); 584 585 // Validate internal options set. 586 Map<String, String> query = TestUtils.parseQuery(transportFactory.transport.getStsContent()); 587 588 GenericJson expectedInternalOptions = new GenericJson(); 589 expectedInternalOptions.setFactory(OAuth2Utils.JSON_FACTORY); 590 expectedInternalOptions.put("userProject", "userProject"); 591 592 assertNotNull(query.get("options")); 593 assertEquals(expectedInternalOptions.toString(), query.get("options")); 594 } 595 596 @Test refreshAccessToken_workforceWithServiceAccountImpersonationOptions()597 public void refreshAccessToken_workforceWithServiceAccountImpersonationOptions() 598 throws IOException { 599 MockExternalAccountCredentialsTransportFactory transportFactory = 600 new MockExternalAccountCredentialsTransportFactory(); 601 602 transportFactory.transport.setExpireTime(TestUtils.getDefaultExpireTime()); 603 IdentityPoolCredentials credential = 604 IdentityPoolCredentials.newBuilder(FILE_SOURCED_CREDENTIAL) 605 .setAudience( 606 "//iam.googleapis.com/locations/global/workforcePools/pool/providers/provider") 607 .setTokenUrl(transportFactory.transport.getStsUrl()) 608 .setServiceAccountImpersonationUrl( 609 transportFactory.transport.getServiceAccountImpersonationUrl()) 610 .setHttpTransportFactory(transportFactory) 611 .setCredentialSource( 612 buildUrlBasedCredentialSource(transportFactory.transport.getMetadataUrl())) 613 .setWorkforcePoolUserProject("userProject") 614 .setServiceAccountImpersonationOptions( 615 ExternalAccountCredentialsTest.buildServiceAccountImpersonationOptions(2800)) 616 .build(); 617 618 AccessToken accessToken = credential.refreshAccessToken(); 619 620 // Validate that default lifetime was set correctly on the request. 621 assertEquals( 622 transportFactory.transport.getServiceAccountAccessToken(), accessToken.getTokenValue()); 623 624 GenericJson query = 625 OAuth2Utils.JSON_FACTORY 626 .createJsonParser(transportFactory.transport.getLastRequest().getContentAsString()) 627 .parseAndClose(GenericJson.class); 628 629 assertEquals("2800s", query.get("lifetime")); 630 } 631 632 @Test identityPoolCredentialSource_validFormats()633 public void identityPoolCredentialSource_validFormats() { 634 Map<String, Object> credentialSourceMapWithFileTextSource = new HashMap<>(); 635 Map<String, Object> credentialSourceMapWithFileJsonTextSource = new HashMap<>(); 636 Map<String, Object> credentialSourceMapWithUrlTextSource = new HashMap<>(); 637 Map<String, Object> credentialSourceMapWithUrlJsonTextSource = new HashMap<>(); 638 639 credentialSourceMapWithFileTextSource.put("file", "/path/to/file"); 640 credentialSourceMapWithFileJsonTextSource.put("file", "/path/to/file"); 641 642 credentialSourceMapWithUrlTextSource.put("url", "https://google.com"); 643 credentialSourceMapWithUrlJsonTextSource.put("url", "https://google.com"); 644 Map<String, String> headersMap = new HashMap<>(); 645 headersMap.put("header1", "value1"); 646 headersMap.put("header2", "value2"); 647 credentialSourceMapWithUrlTextSource.put("headers", headersMap); 648 credentialSourceMapWithUrlJsonTextSource.put("headers", headersMap); 649 650 Map<String, String> textFormat = new HashMap<>(); 651 textFormat.put("type", "text"); 652 653 Map<String, String> jsonTextFormat = new HashMap<>(); 654 jsonTextFormat.put("type", "json"); 655 jsonTextFormat.put("subject_token_field_name", "access_token"); 656 657 credentialSourceMapWithFileTextSource.put("format", textFormat); 658 credentialSourceMapWithFileJsonTextSource.put("format", jsonTextFormat); 659 660 credentialSourceMapWithUrlTextSource.put("format", textFormat); 661 credentialSourceMapWithUrlJsonTextSource.put("format", jsonTextFormat); 662 663 List<Map<String, Object>> sources = 664 Arrays.asList( 665 credentialSourceMapWithFileTextSource, 666 credentialSourceMapWithFileJsonTextSource, 667 credentialSourceMapWithUrlTextSource, 668 credentialSourceMapWithUrlJsonTextSource); 669 for (Map<String, Object> source : sources) { 670 // Should not throw. 671 new IdentityPoolCredentialSource(source); 672 } 673 } 674 675 @Test identityPoolCredentialSource_caseInsensitive()676 public void identityPoolCredentialSource_caseInsensitive() { 677 Map<String, Object> credentialSourceMapWithFileTextSource = new HashMap<>(); 678 Map<String, Object> credentialSourceMapWithFileJsonTextSource = new HashMap<>(); 679 Map<String, Object> credentialSourceMapWithUrlTextSource = new HashMap<>(); 680 Map<String, Object> credentialSourceMapWithUrlJsonTextSource = new HashMap<>(); 681 682 credentialSourceMapWithFileTextSource.put("file", "/path/to/file"); 683 credentialSourceMapWithFileJsonTextSource.put("file", "/path/to/file"); 684 685 credentialSourceMapWithUrlTextSource.put("url", "https://google.com"); 686 credentialSourceMapWithUrlJsonTextSource.put("url", "https://google.com"); 687 Map<String, String> headersMap = new HashMap<>(); 688 headersMap.put("HeaDer1", "Value1"); 689 headersMap.put("HeaDer2", "Value2"); 690 credentialSourceMapWithUrlTextSource.put("headers", headersMap); 691 credentialSourceMapWithUrlJsonTextSource.put("headers", headersMap); 692 693 Map<String, String> textFormat = new HashMap<>(); 694 textFormat.put("type", "TEXT"); 695 696 Map<String, String> jsonTextFormat = new HashMap<>(); 697 jsonTextFormat.put("type", "JSON"); 698 jsonTextFormat.put("subject_token_field_name", "access_token"); 699 700 credentialSourceMapWithFileTextSource.put("format", textFormat); 701 credentialSourceMapWithFileJsonTextSource.put("format", jsonTextFormat); 702 703 credentialSourceMapWithUrlTextSource.put("format", textFormat); 704 credentialSourceMapWithUrlJsonTextSource.put("format", jsonTextFormat); 705 706 List<Map<String, Object>> sources = 707 Arrays.asList( 708 credentialSourceMapWithFileTextSource, 709 credentialSourceMapWithFileJsonTextSource, 710 credentialSourceMapWithUrlTextSource, 711 credentialSourceMapWithUrlJsonTextSource); 712 for (Map<String, Object> source : sources) { 713 // Should not throw. 714 new IdentityPoolCredentialSource(source); 715 } 716 } 717 718 @Test identityPoolCredentialSource_invalidSourceType()719 public void identityPoolCredentialSource_invalidSourceType() { 720 try { 721 new IdentityPoolCredentialSource(new HashMap<>()); 722 fail("Should not be able to continue without exception."); 723 } catch (IllegalArgumentException exception) { 724 assertEquals( 725 "Missing credential source file location or URL. At least one must be specified.", 726 exception.getMessage()); 727 } 728 } 729 730 @Test identityPoolCredentialSource_invalidFormatType()731 public void identityPoolCredentialSource_invalidFormatType() { 732 Map<String, Object> credentialSourceMap = new HashMap<>(); 733 credentialSourceMap.put("url", "url"); 734 735 Map<String, String> format = new HashMap<>(); 736 format.put("type", "unsupportedType"); 737 credentialSourceMap.put("format", format); 738 739 try { 740 new IdentityPoolCredentialSource(credentialSourceMap); 741 fail("Exception should be thrown."); 742 } catch (IllegalArgumentException e) { 743 assertEquals("Invalid credential source format type: unsupportedType.", e.getMessage()); 744 } 745 } 746 747 @Test identityPoolCredentialSource_nullFormatType()748 public void identityPoolCredentialSource_nullFormatType() { 749 Map<String, Object> credentialSourceMap = new HashMap<>(); 750 credentialSourceMap.put("url", "url"); 751 752 Map<String, String> format = new HashMap<>(); 753 format.put("type", null); 754 credentialSourceMap.put("format", format); 755 756 try { 757 new IdentityPoolCredentialSource(credentialSourceMap); 758 fail("Exception should be thrown."); 759 } catch (IllegalArgumentException e) { 760 assertEquals("Invalid credential source format type: null.", e.getMessage()); 761 } 762 } 763 764 @Test identityPoolCredentialSource_subjectTokenFieldNameUnset()765 public void identityPoolCredentialSource_subjectTokenFieldNameUnset() { 766 Map<String, Object> credentialSourceMap = new HashMap<>(); 767 credentialSourceMap.put("url", "url"); 768 769 Map<String, String> format = new HashMap<>(); 770 format.put("type", "json"); 771 credentialSourceMap.put("format", format); 772 773 try { 774 new IdentityPoolCredentialSource(credentialSourceMap); 775 fail("Exception should be thrown."); 776 } catch (IllegalArgumentException e) { 777 assertEquals( 778 "When specifying a JSON credential type, the subject_token_field_name must be set.", 779 e.getMessage()); 780 } 781 } 782 783 @Test builder_allFields()784 public void builder_allFields() throws IOException { 785 List<String> scopes = Arrays.asList("scope1", "scope2"); 786 787 IdentityPoolCredentials credentials = 788 IdentityPoolCredentials.newBuilder() 789 .setHttpTransportFactory(OAuth2Utils.HTTP_TRANSPORT_FACTORY) 790 .setAudience("audience") 791 .setSubjectTokenType("subjectTokenType") 792 .setTokenUrl(STS_URL) 793 .setTokenInfoUrl("tokenInfoUrl") 794 .setCredentialSource(FILE_CREDENTIAL_SOURCE) 795 .setServiceAccountImpersonationUrl(SERVICE_ACCOUNT_IMPERSONATION_URL) 796 .setQuotaProjectId("quotaProjectId") 797 .setClientId("clientId") 798 .setClientSecret("clientSecret") 799 .setScopes(scopes) 800 .setUniverseDomain("universeDomain") 801 .build(); 802 803 assertEquals("audience", credentials.getAudience()); 804 assertEquals("subjectTokenType", credentials.getSubjectTokenType()); 805 assertEquals(STS_URL, credentials.getTokenUrl()); 806 assertEquals("tokenInfoUrl", credentials.getTokenInfoUrl()); 807 assertEquals( 808 SERVICE_ACCOUNT_IMPERSONATION_URL, credentials.getServiceAccountImpersonationUrl()); 809 assertEquals(FILE_CREDENTIAL_SOURCE, credentials.getCredentialSource()); 810 assertEquals("quotaProjectId", credentials.getQuotaProjectId()); 811 assertEquals("clientId", credentials.getClientId()); 812 assertEquals("clientSecret", credentials.getClientSecret()); 813 assertEquals(scopes, credentials.getScopes()); 814 assertEquals(SystemEnvironmentProvider.getInstance(), credentials.getEnvironmentProvider()); 815 assertEquals("universeDomain", credentials.getUniverseDomain()); 816 } 817 818 @Test builder_subjectTokenSupplier()819 public void builder_subjectTokenSupplier() { 820 List<String> scopes = Arrays.asList("scope1", "scope2"); 821 822 IdentityPoolCredentials credentials = 823 IdentityPoolCredentials.newBuilder() 824 .setSubjectTokenSupplier(testProvider) 825 .setHttpTransportFactory(OAuth2Utils.HTTP_TRANSPORT_FACTORY) 826 .setAudience("audience") 827 .setSubjectTokenType("subjectTokenType") 828 .setTokenUrl(STS_URL) 829 .setTokenInfoUrl("tokenInfoUrl") 830 .setServiceAccountImpersonationUrl(SERVICE_ACCOUNT_IMPERSONATION_URL) 831 .setQuotaProjectId("quotaProjectId") 832 .setClientId("clientId") 833 .setClientSecret("clientSecret") 834 .setScopes(scopes) 835 .build(); 836 837 assertEquals(testProvider, credentials.getIdentityPoolSubjectTokenSupplier()); 838 } 839 840 @Test builder_invalidWorkforceAudiences_throws()841 public void builder_invalidWorkforceAudiences_throws() { 842 List<String> invalidAudiences = 843 Arrays.asList( 844 "", 845 "//iam.googleapis.com/projects/x23/locations/global/workloadIdentityPools/pool/providers/provider", 846 "//iam.googleapis.com/locations/global/workforcepools/pool/providers/provider", 847 "//iam.googleapis.com/locations/global/workforcePools/providers/provider", 848 "//iam.googleapis.com/locations/global/workforcePools/providers", 849 "//iam.googleapis.com/locations/global/workforcePools/", 850 "//iam.googleapis.com/locations//workforcePools/providers", 851 "//iam.googleapis.com/notlocations/global/workforcePools/providers", 852 "//iam.googleapis.com/locations/global/workforce/providers"); 853 854 for (String audience : invalidAudiences) { 855 try { 856 IdentityPoolCredentials.newBuilder() 857 .setWorkforcePoolUserProject("workforcePoolUserProject") 858 .setHttpTransportFactory(OAuth2Utils.HTTP_TRANSPORT_FACTORY) 859 .setAudience(audience) 860 .setSubjectTokenType("subjectTokenType") 861 .setTokenUrl(STS_URL) 862 .setTokenInfoUrl("tokenInfoUrl") 863 .setCredentialSource(FILE_CREDENTIAL_SOURCE) 864 .setQuotaProjectId("quotaProjectId") 865 .build(); 866 fail("Exception should be thrown."); 867 } catch (IllegalArgumentException e) { 868 assertEquals( 869 "The workforce_pool_user_project parameter should only be provided for a Workforce Pool configuration.", 870 e.getMessage()); 871 } 872 } 873 } 874 875 @Test builder_emptyWorkforceUserProjectWithWorkforceAudience()876 public void builder_emptyWorkforceUserProjectWithWorkforceAudience() { 877 // No exception should be thrown. 878 IdentityPoolCredentials credentials = 879 IdentityPoolCredentials.newBuilder() 880 .setWorkforcePoolUserProject("") 881 .setHttpTransportFactory(OAuth2Utils.HTTP_TRANSPORT_FACTORY) 882 .setAudience( 883 "//iam.googleapis.com/locations/global/workforcePools/pool/providers/provider") 884 .setSubjectTokenType("subjectTokenType") 885 .setTokenUrl(STS_URL) 886 .setTokenInfoUrl("tokenInfoUrl") 887 .setCredentialSource(FILE_CREDENTIAL_SOURCE) 888 .setQuotaProjectId("quotaProjectId") 889 .build(); 890 891 assertTrue(credentials.isWorkforcePoolConfiguration()); 892 } 893 894 @Test builder_supplierAndCredSourceThrows()895 public void builder_supplierAndCredSourceThrows() throws IOException { 896 try { 897 IdentityPoolCredentials credentials = 898 IdentityPoolCredentials.newBuilder() 899 .setSubjectTokenSupplier(testProvider) 900 .setHttpTransportFactory(OAuth2Utils.HTTP_TRANSPORT_FACTORY) 901 .setAudience("audience") 902 .setSubjectTokenType("subjectTokenType") 903 .setTokenUrl(STS_URL) 904 .setCredentialSource(FILE_CREDENTIAL_SOURCE) 905 .build(); 906 fail("Should not be able to continue without exception."); 907 } catch (IllegalArgumentException exception) { 908 assertEquals( 909 "IdentityPoolCredentials cannot have both a subjectTokenSupplier and a credentialSource.", 910 exception.getMessage()); 911 } 912 } 913 914 @Test builder_noSupplierOrCredSourceThrows()915 public void builder_noSupplierOrCredSourceThrows() throws IOException { 916 917 try { 918 IdentityPoolCredentials credentials = 919 IdentityPoolCredentials.newBuilder() 920 .setHttpTransportFactory(OAuth2Utils.HTTP_TRANSPORT_FACTORY) 921 .setAudience("audience") 922 .setSubjectTokenType("subjectTokenType") 923 .setTokenUrl(STS_URL) 924 .build(); 925 fail("Should not be able to continue without exception."); 926 } catch (IllegalArgumentException exception) { 927 assertEquals( 928 "A subjectTokenSupplier or a credentialSource must be provided.", exception.getMessage()); 929 } 930 } 931 builder_missingUniverseDomain_defaults()932 public void builder_missingUniverseDomain_defaults() throws IOException { 933 List<String> scopes = Arrays.asList("scope1", "scope2"); 934 935 IdentityPoolCredentials credentials = 936 IdentityPoolCredentials.newBuilder() 937 .setHttpTransportFactory(OAuth2Utils.HTTP_TRANSPORT_FACTORY) 938 .setAudience("audience") 939 .setSubjectTokenType("subjectTokenType") 940 .setTokenUrl(STS_URL) 941 .setTokenInfoUrl("tokenInfoUrl") 942 .setCredentialSource(FILE_CREDENTIAL_SOURCE) 943 .setServiceAccountImpersonationUrl(SERVICE_ACCOUNT_IMPERSONATION_URL) 944 .setQuotaProjectId("quotaProjectId") 945 .setClientId("clientId") 946 .setClientSecret("clientSecret") 947 .setScopes(scopes) 948 .build(); 949 950 assertEquals("audience", credentials.getAudience()); 951 assertEquals("subjectTokenType", credentials.getSubjectTokenType()); 952 assertEquals(STS_URL, credentials.getTokenUrl()); 953 assertEquals("tokenInfoUrl", credentials.getTokenInfoUrl()); 954 assertEquals( 955 SERVICE_ACCOUNT_IMPERSONATION_URL, credentials.getServiceAccountImpersonationUrl()); 956 assertEquals(FILE_CREDENTIAL_SOURCE, credentials.getCredentialSource()); 957 assertEquals("quotaProjectId", credentials.getQuotaProjectId()); 958 assertEquals("clientId", credentials.getClientId()); 959 assertEquals("clientSecret", credentials.getClientSecret()); 960 assertEquals(scopes, credentials.getScopes()); 961 assertEquals(SystemEnvironmentProvider.getInstance(), credentials.getEnvironmentProvider()); 962 assertEquals(GOOGLE_DEFAULT_UNIVERSE, credentials.getUniverseDomain()); 963 } 964 965 @Test newBuilder_allFields()966 public void newBuilder_allFields() throws IOException { 967 List<String> scopes = Arrays.asList("scope1", "scope2"); 968 969 IdentityPoolCredentials credentials = 970 IdentityPoolCredentials.newBuilder() 971 .setHttpTransportFactory(OAuth2Utils.HTTP_TRANSPORT_FACTORY) 972 .setAudience( 973 "//iam.googleapis.com/locations/global/workforcePools/pool/providers/provider") 974 .setSubjectTokenType("subjectTokenType") 975 .setTokenUrl(STS_URL) 976 .setTokenInfoUrl("tokenInfoUrl") 977 .setCredentialSource(FILE_CREDENTIAL_SOURCE) 978 .setServiceAccountImpersonationUrl(SERVICE_ACCOUNT_IMPERSONATION_URL) 979 .setQuotaProjectId("quotaProjectId") 980 .setClientId("clientId") 981 .setClientSecret("clientSecret") 982 .setScopes(scopes) 983 .setWorkforcePoolUserProject("workforcePoolUserProject") 984 .setUniverseDomain("universeDomain") 985 .build(); 986 987 IdentityPoolCredentials newBuilderCreds = 988 IdentityPoolCredentials.newBuilder(credentials).build(); 989 assertEquals(credentials.getAudience(), newBuilderCreds.getAudience()); 990 assertEquals(credentials.getSubjectTokenType(), newBuilderCreds.getSubjectTokenType()); 991 assertEquals(credentials.getTokenUrl(), newBuilderCreds.getTokenUrl()); 992 assertEquals(credentials.getTokenInfoUrl(), newBuilderCreds.getTokenInfoUrl()); 993 assertEquals( 994 credentials.getServiceAccountImpersonationUrl(), 995 newBuilderCreds.getServiceAccountImpersonationUrl()); 996 assertEquals(credentials.getCredentialSource(), newBuilderCreds.getCredentialSource()); 997 assertEquals(credentials.getQuotaProjectId(), newBuilderCreds.getQuotaProjectId()); 998 assertEquals(credentials.getClientId(), newBuilderCreds.getClientId()); 999 assertEquals(credentials.getClientSecret(), newBuilderCreds.getClientSecret()); 1000 assertEquals(credentials.getScopes(), newBuilderCreds.getScopes()); 1001 assertEquals(credentials.getEnvironmentProvider(), newBuilderCreds.getEnvironmentProvider()); 1002 assertEquals( 1003 credentials.getWorkforcePoolUserProject(), newBuilderCreds.getWorkforcePoolUserProject()); 1004 assertEquals(credentials.getUniverseDomain(), newBuilderCreds.getUniverseDomain()); 1005 } 1006 1007 @Test newBuilder_noUniverseDomain_defaults()1008 public void newBuilder_noUniverseDomain_defaults() throws IOException { 1009 List<String> scopes = Arrays.asList("scope1", "scope2"); 1010 1011 IdentityPoolCredentials credentials = 1012 IdentityPoolCredentials.newBuilder() 1013 .setHttpTransportFactory(OAuth2Utils.HTTP_TRANSPORT_FACTORY) 1014 .setAudience( 1015 "//iam.googleapis.com/locations/global/workforcePools/pool/providers/provider") 1016 .setSubjectTokenType("subjectTokenType") 1017 .setTokenUrl(STS_URL) 1018 .setTokenInfoUrl("tokenInfoUrl") 1019 .setCredentialSource(FILE_CREDENTIAL_SOURCE) 1020 .setServiceAccountImpersonationUrl(SERVICE_ACCOUNT_IMPERSONATION_URL) 1021 .setQuotaProjectId("quotaProjectId") 1022 .setClientId("clientId") 1023 .setClientSecret("clientSecret") 1024 .setScopes(scopes) 1025 .setWorkforcePoolUserProject("workforcePoolUserProject") 1026 .build(); 1027 1028 IdentityPoolCredentials newBuilderCreds = 1029 IdentityPoolCredentials.newBuilder(credentials).build(); 1030 assertEquals(credentials.getAudience(), newBuilderCreds.getAudience()); 1031 assertEquals(credentials.getSubjectTokenType(), newBuilderCreds.getSubjectTokenType()); 1032 assertEquals(credentials.getTokenUrl(), newBuilderCreds.getTokenUrl()); 1033 assertEquals(credentials.getTokenInfoUrl(), newBuilderCreds.getTokenInfoUrl()); 1034 assertEquals( 1035 credentials.getServiceAccountImpersonationUrl(), 1036 newBuilderCreds.getServiceAccountImpersonationUrl()); 1037 assertEquals(credentials.getCredentialSource(), newBuilderCreds.getCredentialSource()); 1038 assertEquals(credentials.getQuotaProjectId(), newBuilderCreds.getQuotaProjectId()); 1039 assertEquals(credentials.getClientId(), newBuilderCreds.getClientId()); 1040 assertEquals(credentials.getClientSecret(), newBuilderCreds.getClientSecret()); 1041 assertEquals(credentials.getScopes(), newBuilderCreds.getScopes()); 1042 assertEquals(credentials.getEnvironmentProvider(), newBuilderCreds.getEnvironmentProvider()); 1043 assertEquals( 1044 credentials.getWorkforcePoolUserProject(), newBuilderCreds.getWorkforcePoolUserProject()); 1045 assertEquals(GOOGLE_DEFAULT_UNIVERSE, newBuilderCreds.getUniverseDomain()); 1046 } 1047 1048 @Test serialize()1049 public void serialize() throws IOException, ClassNotFoundException { 1050 IdentityPoolCredentials testCredentials = 1051 IdentityPoolCredentials.newBuilder(FILE_SOURCED_CREDENTIAL) 1052 .setServiceAccountImpersonationUrl(SERVICE_ACCOUNT_IMPERSONATION_URL) 1053 .setQuotaProjectId("quotaProjectId") 1054 .setClientId("clientId") 1055 .setClientSecret("clientSecret") 1056 .setUniverseDomain("universeDomain") 1057 .build(); 1058 1059 IdentityPoolCredentials deserializedCredentials = serializeAndDeserialize(testCredentials); 1060 assertEquals(testCredentials, deserializedCredentials); 1061 assertEquals(testCredentials.hashCode(), deserializedCredentials.hashCode()); 1062 assertEquals(testCredentials.toString(), deserializedCredentials.toString()); 1063 assertSame(deserializedCredentials.clock, Clock.SYSTEM); 1064 } 1065 writeIdentityPoolCredentialsStream( String tokenUrl, String url, @Nullable String serviceAccountImpersonationUrl, @Nullable Map<String, Object> serviceAccountImpersonationOptionsMap)1066 static InputStream writeIdentityPoolCredentialsStream( 1067 String tokenUrl, 1068 String url, 1069 @Nullable String serviceAccountImpersonationUrl, 1070 @Nullable Map<String, Object> serviceAccountImpersonationOptionsMap) 1071 throws IOException { 1072 GenericJson json = new GenericJson(); 1073 json.put("audience", "audience"); 1074 json.put("subject_token_type", "subjectTokenType"); 1075 json.put("token_url", tokenUrl); 1076 json.put("token_info_url", "tokenInfoUrl"); 1077 json.put("type", ExternalAccountCredentials.EXTERNAL_ACCOUNT_FILE_TYPE); 1078 1079 if (serviceAccountImpersonationUrl != null) { 1080 json.put("service_account_impersonation_url", serviceAccountImpersonationUrl); 1081 } 1082 1083 if (serviceAccountImpersonationOptionsMap != null) { 1084 json.put("service_account_impersonation", serviceAccountImpersonationOptionsMap); 1085 } 1086 1087 GenericJson credentialSource = new GenericJson(); 1088 GenericJson headers = new GenericJson(); 1089 headers.put("Metadata-Flavor", "Google"); 1090 credentialSource.put("url", url); 1091 credentialSource.put("headers", headers); 1092 1093 json.put("credential_source", credentialSource); 1094 return TestUtils.jsonToInputStream(json); 1095 } 1096 buildUrlBasedCredentialSource(String url)1097 private static IdentityPoolCredentialSource buildUrlBasedCredentialSource(String url) { 1098 return buildUrlBasedCredentialSource(url, /* formatMap= */ null); 1099 } 1100 buildUrlBasedCredentialSource( String url, Map<String, String> formatMap)1101 private static IdentityPoolCredentialSource buildUrlBasedCredentialSource( 1102 String url, Map<String, String> formatMap) { 1103 Map<String, Object> credentialSourceMap = new HashMap<>(); 1104 Map<String, String> headers = new HashMap<>(); 1105 headers.put("Metadata-Flavor", "Google"); 1106 credentialSourceMap.put("url", url); 1107 credentialSourceMap.put("headers", headers); 1108 credentialSourceMap.put("format", formatMap); 1109 1110 return new IdentityPoolCredentialSource(credentialSourceMap); 1111 } 1112 } 1113