1 /* 2 * Copyright 2022 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.ExternalAccountAuthorizedUserCredentials.EXTERNAL_ACCOUNT_AUTHORIZED_USER_FILE_TYPE; 36 import static org.junit.Assert.assertEquals; 37 import static org.junit.Assert.assertFalse; 38 import static org.junit.Assert.assertNotEquals; 39 import static org.junit.Assert.assertNull; 40 import static org.junit.Assert.assertSame; 41 import static org.junit.Assert.assertTrue; 42 import static org.junit.Assert.fail; 43 44 import com.google.api.client.http.HttpTransport; 45 import com.google.api.client.json.GenericJson; 46 import com.google.api.client.testing.http.MockLowLevelHttpRequest; 47 import com.google.api.client.util.Clock; 48 import com.google.auth.TestUtils; 49 import com.google.auth.http.AuthHttpConstants; 50 import com.google.auth.http.HttpTransportFactory; 51 import com.google.common.collect.ImmutableList; 52 import com.google.common.collect.ImmutableMap; 53 import com.google.common.io.BaseEncoding; 54 import java.io.IOException; 55 import java.net.URI; 56 import java.nio.charset.StandardCharsets; 57 import java.util.Arrays; 58 import java.util.Collection; 59 import java.util.Collections; 60 import java.util.Date; 61 import java.util.HashMap; 62 import java.util.List; 63 import java.util.Map; 64 import org.junit.Before; 65 import org.junit.Test; 66 import org.junit.runner.RunWith; 67 import org.junit.runners.JUnit4; 68 69 /** Test case for {@link ExternalAccountAuthorizedUserCredentials}. */ 70 @RunWith(JUnit4.class) 71 public class ExternalAccountAuthorizedUserCredentialsTest extends BaseSerializationTest { 72 73 private static final String AUDIENCE = 74 "//iam.googleapis.com/locations/global/workforcePools/$WORKFORCE_POOL_ID/providers/$PROVIDER_ID"; 75 private static final String CLIENT_SECRET = "jakuaL9YyieakhECKL2SwZcu"; 76 private static final String CLIENT_ID = "ya29.1.AADtN_UtlxN3PuGAxrN2XQnZTVRvDyVWnYq4I6dws"; 77 private static final String REFRESH_TOKEN = "1/Tl6awhpFjkMkSJoj1xsli0H2eL5YsMgU_NKPY2TyGWY"; 78 private static final String ACCESS_TOKEN = "1/MkSJoj1xsli0AccessToken_NKPY2"; 79 private static final String TOKEN_URL = "https://sts.googleapis.com/v1/oauthtoken"; 80 private static final String TOKEN_INFO_URL = "https://sts.googleapis.com/v1/introspect"; 81 private static final String REVOKE_URL = "https://sts.googleapis.com/v1/revoke"; 82 private static final String QUOTA_PROJECT = "sample-quota-project-id"; 83 private static final String UNIVERSE_DOMAIN = "foo.bar"; 84 85 private static final String BASIC_AUTH = 86 String.format( 87 "Basic %s", 88 BaseEncoding.base64() 89 .encode( 90 String.format("%s:%s", CLIENT_ID, CLIENT_SECRET) 91 .getBytes(StandardCharsets.UTF_8))); 92 93 private static final Collection<String> SCOPES = Collections.singletonList("dummy.scope"); 94 private static final URI CALL_URI = URI.create("http://googleapis.com/testapi/v1/foo"); 95 96 private MockExternalAccountAuthorizedUserCredentialsTransportFactory transportFactory; 97 98 static class MockExternalAccountAuthorizedUserCredentialsTransportFactory 99 implements HttpTransportFactory { 100 101 MockStsTransport transport = new MockStsTransport(); 102 103 @Override create()104 public HttpTransport create() { 105 return transport; 106 } 107 } 108 109 @Before setup()110 public void setup() { 111 transportFactory = new MockExternalAccountAuthorizedUserCredentialsTransportFactory(); 112 } 113 114 @Test builder_allFields()115 public void builder_allFields() throws IOException { 116 ExternalAccountAuthorizedUserCredentials credentials = 117 ExternalAccountAuthorizedUserCredentials.newBuilder() 118 .setAudience(AUDIENCE) 119 .setClientId(CLIENT_ID) 120 .setClientSecret(CLIENT_SECRET) 121 .setRefreshToken(REFRESH_TOKEN) 122 .setTokenUrl(TOKEN_URL) 123 .setTokenInfoUrl(TOKEN_INFO_URL) 124 .setRevokeUrl(REVOKE_URL) 125 .setAccessToken(new AccessToken(ACCESS_TOKEN, /* expirationTime= */ null)) 126 .setQuotaProjectId(QUOTA_PROJECT) 127 .setUniverseDomain(UNIVERSE_DOMAIN) 128 .build(); 129 130 assertEquals(AUDIENCE, credentials.getAudience()); 131 assertEquals(CLIENT_ID, credentials.getClientId()); 132 assertEquals(CLIENT_SECRET, credentials.getClientSecret()); 133 assertEquals(REFRESH_TOKEN, credentials.getRefreshToken()); 134 assertEquals(TOKEN_URL, credentials.getTokenUrl()); 135 assertEquals(TOKEN_INFO_URL, credentials.getTokenInfoUrl()); 136 assertEquals(REVOKE_URL, credentials.getRevokeUrl()); 137 assertEquals(ACCESS_TOKEN, credentials.getAccessToken().getTokenValue()); 138 assertEquals(QUOTA_PROJECT, credentials.getQuotaProjectId()); 139 assertEquals(UNIVERSE_DOMAIN, credentials.getUniverseDomain()); 140 } 141 142 @Test builder_minimumRequiredFieldsForRefresh()143 public void builder_minimumRequiredFieldsForRefresh() { 144 ExternalAccountAuthorizedUserCredentials credentials = 145 ExternalAccountAuthorizedUserCredentials.newBuilder() 146 .setClientId(CLIENT_ID) 147 .setClientSecret(CLIENT_SECRET) 148 .setRefreshToken(REFRESH_TOKEN) 149 .setTokenUrl(TOKEN_URL) 150 .build(); 151 152 assertEquals(CLIENT_ID, credentials.getClientId()); 153 assertEquals(CLIENT_SECRET, credentials.getClientSecret()); 154 assertEquals(REFRESH_TOKEN, credentials.getRefreshToken()); 155 assertEquals(TOKEN_URL, credentials.getTokenUrl()); 156 assertNull(credentials.getAudience()); 157 assertNull(credentials.getTokenInfoUrl()); 158 assertNull(credentials.getRevokeUrl()); 159 assertNull(credentials.getAccessToken()); 160 assertNull(credentials.getQuotaProjectId()); 161 } 162 163 @Test builder_accessTokenOnly()164 public void builder_accessTokenOnly() { 165 ExternalAccountAuthorizedUserCredentials credentials = 166 ExternalAccountAuthorizedUserCredentials.newBuilder() 167 .setAccessToken(AccessToken.newBuilder().setTokenValue(ACCESS_TOKEN).build()) 168 .build(); 169 170 assertEquals(ACCESS_TOKEN, credentials.getAccessToken().getTokenValue()); 171 assertNull(credentials.getAudience()); 172 assertNull(credentials.getTokenUrl()); 173 assertNull(credentials.getTokenInfoUrl()); 174 assertNull(credentials.getRevokeUrl()); 175 assertNull(credentials.getClientId()); 176 assertNull(credentials.getClientSecret()); 177 assertNull(credentials.getRefreshToken()); 178 assertNull(credentials.getQuotaProjectId()); 179 } 180 181 @Test builder_credentialConstructor()182 public void builder_credentialConstructor() { 183 ExternalAccountAuthorizedUserCredentials credentials = 184 ExternalAccountAuthorizedUserCredentials.newBuilder() 185 .setAudience(AUDIENCE) 186 .setClientId(CLIENT_ID) 187 .setClientSecret(CLIENT_SECRET) 188 .setRefreshToken(REFRESH_TOKEN) 189 .setTokenUrl(TOKEN_URL) 190 .setTokenInfoUrl(TOKEN_INFO_URL) 191 .setRevokeUrl(REVOKE_URL) 192 .setQuotaProjectId(QUOTA_PROJECT) 193 .build(); 194 195 ExternalAccountAuthorizedUserCredentials otherCredentials = credentials.toBuilder().build(); 196 197 assertEquals(AUDIENCE, otherCredentials.getAudience()); 198 assertEquals(CLIENT_ID, otherCredentials.getClientId()); 199 assertEquals(CLIENT_SECRET, otherCredentials.getClientSecret()); 200 assertEquals(REFRESH_TOKEN, otherCredentials.getRefreshToken()); 201 assertEquals(TOKEN_URL, otherCredentials.getTokenUrl()); 202 assertEquals(TOKEN_INFO_URL, otherCredentials.getTokenInfoUrl()); 203 assertEquals(REVOKE_URL, otherCredentials.getRevokeUrl()); 204 assertEquals(QUOTA_PROJECT, otherCredentials.getQuotaProjectId()); 205 } 206 207 @Test builder_accessTokenWithMissingRefreshFields()208 public void builder_accessTokenWithMissingRefreshFields() { 209 ExternalAccountAuthorizedUserCredentials credentials = 210 ExternalAccountAuthorizedUserCredentials.newBuilder() 211 .setAccessToken(AccessToken.newBuilder().setTokenValue(ACCESS_TOKEN).build()) 212 .setRefreshToken(REFRESH_TOKEN) 213 .setTokenUrl(TOKEN_URL) 214 .setClientId(CLIENT_ID) 215 .build(); 216 217 assertEquals(ACCESS_TOKEN, credentials.getAccessToken().getTokenValue()); 218 assertEquals(REFRESH_TOKEN, credentials.getRefreshToken()); 219 assertEquals(TOKEN_URL, credentials.getTokenUrl()); 220 assertEquals(CLIENT_ID, credentials.getClientId()); 221 assertNull(credentials.getAudience()); 222 assertNull(credentials.getTokenInfoUrl()); 223 assertNull(credentials.getRevokeUrl()); 224 assertNull(credentials.getClientSecret()); 225 assertNull(credentials.getQuotaProjectId()); 226 } 227 228 @Test builder_accessAndRefreshTokenNull_throws()229 public void builder_accessAndRefreshTokenNull_throws() { 230 try { 231 ExternalAccountAuthorizedUserCredentials.newBuilder().build(); 232 fail("Should not be able to continue without exception."); 233 } catch (IllegalStateException exception) { 234 assertEquals( 235 "ExternalAccountAuthorizedUserCredentials must be initialized with " 236 + "an access token or fields to enable refresh: " 237 + "('refresh_token', 'token_url', 'client_id', 'client_secret').", 238 exception.getMessage()); 239 } 240 } 241 242 @Test builder_missingTokenUrl_throws()243 public void builder_missingTokenUrl_throws() { 244 try { 245 ExternalAccountAuthorizedUserCredentials.newBuilder() 246 .setRefreshToken(REFRESH_TOKEN) 247 .setClientId(CLIENT_ID) 248 .setClientSecret(CLIENT_SECRET) 249 .build(); 250 fail("Should not be able to continue without exception."); 251 } catch (IllegalStateException exception) { 252 assertEquals( 253 "ExternalAccountAuthorizedUserCredentials must be initialized with " 254 + "an access token or fields to enable refresh: " 255 + "('refresh_token', 'token_url', 'client_id', 'client_secret').", 256 exception.getMessage()); 257 } 258 } 259 260 @Test builder_missingClientId_throws()261 public void builder_missingClientId_throws() { 262 try { 263 ExternalAccountAuthorizedUserCredentials.newBuilder() 264 .setRefreshToken(REFRESH_TOKEN) 265 .setTokenUrl(TOKEN_URL) 266 .setClientSecret(CLIENT_SECRET) 267 .build(); 268 fail("Should not be able to continue without exception."); 269 } catch (IllegalStateException exception) { 270 assertEquals( 271 "ExternalAccountAuthorizedUserCredentials must be initialized with " 272 + "an access token or fields to enable refresh: " 273 + "('refresh_token', 'token_url', 'client_id', 'client_secret').", 274 exception.getMessage()); 275 } 276 } 277 278 @Test builder_missingClientSecret_throws()279 public void builder_missingClientSecret_throws() { 280 try { 281 ExternalAccountAuthorizedUserCredentials.newBuilder() 282 .setRefreshToken(REFRESH_TOKEN) 283 .setTokenUrl(TOKEN_URL) 284 .setClientId(CLIENT_ID) 285 .build(); 286 fail("Should not be able to continue without exception."); 287 } catch (IllegalStateException exception) { 288 assertEquals( 289 "ExternalAccountAuthorizedUserCredentials must be initialized with " 290 + "an access token or fields to enable refresh: " 291 + "('refresh_token', 'token_url', 'client_id', 'client_secret').", 292 exception.getMessage()); 293 } 294 } 295 296 @Test builder_missingUniverseDomain_defaults()297 public void builder_missingUniverseDomain_defaults() throws IOException { 298 ExternalAccountAuthorizedUserCredentials credentials = 299 ExternalAccountAuthorizedUserCredentials.newBuilder() 300 .setAudience(AUDIENCE) 301 .setClientId(CLIENT_ID) 302 .setClientSecret(CLIENT_SECRET) 303 .setRefreshToken(REFRESH_TOKEN) 304 .setTokenUrl(TOKEN_URL) 305 .setTokenInfoUrl(TOKEN_INFO_URL) 306 .setRevokeUrl(REVOKE_URL) 307 .setAccessToken(new AccessToken(ACCESS_TOKEN, /* expirationTime= */ null)) 308 .setQuotaProjectId(QUOTA_PROJECT) 309 .build(); 310 311 assertEquals(AUDIENCE, credentials.getAudience()); 312 assertEquals(CLIENT_ID, credentials.getClientId()); 313 assertEquals(CLIENT_SECRET, credentials.getClientSecret()); 314 assertEquals(REFRESH_TOKEN, credentials.getRefreshToken()); 315 assertEquals(TOKEN_URL, credentials.getTokenUrl()); 316 assertEquals(TOKEN_INFO_URL, credentials.getTokenInfoUrl()); 317 assertEquals(REVOKE_URL, credentials.getRevokeUrl()); 318 assertEquals(ACCESS_TOKEN, credentials.getAccessToken().getTokenValue()); 319 assertEquals(QUOTA_PROJECT, credentials.getQuotaProjectId()); 320 assertEquals(GOOGLE_DEFAULT_UNIVERSE, credentials.getUniverseDomain()); 321 } 322 323 @Test toBuilder_allFields()324 public void toBuilder_allFields() { 325 ExternalAccountAuthorizedUserCredentials credentials = 326 ExternalAccountAuthorizedUserCredentials.newBuilder() 327 .setAudience(AUDIENCE) 328 .setClientId(CLIENT_ID) 329 .setClientSecret(CLIENT_SECRET) 330 .setRefreshToken(REFRESH_TOKEN) 331 .setTokenUrl(TOKEN_URL) 332 .setTokenInfoUrl(TOKEN_INFO_URL) 333 .setRevokeUrl(REVOKE_URL) 334 .setAccessToken(new AccessToken(ACCESS_TOKEN, new Date())) 335 .setQuotaProjectId(QUOTA_PROJECT) 336 .setUniverseDomain(UNIVERSE_DOMAIN) 337 .build(); 338 339 ExternalAccountAuthorizedUserCredentials secondCredentials = credentials.toBuilder().build(); 340 341 assertEquals(credentials, secondCredentials); 342 } 343 344 @Test toBuilder_missingUniverseDomain_defaults()345 public void toBuilder_missingUniverseDomain_defaults() throws IOException { 346 ExternalAccountAuthorizedUserCredentials credentials = 347 ExternalAccountAuthorizedUserCredentials.newBuilder() 348 .setAudience(AUDIENCE) 349 .setClientId(CLIENT_ID) 350 .setClientSecret(CLIENT_SECRET) 351 .setRefreshToken(REFRESH_TOKEN) 352 .setTokenUrl(TOKEN_URL) 353 .setTokenInfoUrl(TOKEN_INFO_URL) 354 .setRevokeUrl(REVOKE_URL) 355 .setAccessToken(new AccessToken(ACCESS_TOKEN, new Date())) 356 .setQuotaProjectId(QUOTA_PROJECT) 357 .build(); 358 359 ExternalAccountAuthorizedUserCredentials secondCredentials = credentials.toBuilder().build(); 360 361 assertEquals(credentials, secondCredentials); 362 assertEquals(GOOGLE_DEFAULT_UNIVERSE, secondCredentials.getUniverseDomain()); 363 } 364 365 @Test fromJson_allFields()366 public void fromJson_allFields() throws IOException { 367 ExternalAccountAuthorizedUserCredentials credentials = 368 ExternalAccountAuthorizedUserCredentials.fromJson( 369 buildJsonCredentials(), OAuth2Utils.HTTP_TRANSPORT_FACTORY); 370 371 assertEquals(AUDIENCE, credentials.getAudience()); 372 assertEquals(CLIENT_ID, credentials.getClientId()); 373 assertEquals(CLIENT_SECRET, credentials.getClientSecret()); 374 assertEquals(REFRESH_TOKEN, credentials.getRefreshToken()); 375 assertEquals(TOKEN_URL, credentials.getTokenUrl()); 376 assertEquals(TOKEN_INFO_URL, credentials.getTokenInfoUrl()); 377 assertEquals(REVOKE_URL, credentials.getRevokeUrl()); 378 assertEquals(QUOTA_PROJECT, credentials.getQuotaProjectId()); 379 assertEquals(UNIVERSE_DOMAIN, credentials.getUniverseDomain()); 380 } 381 382 @Test fromJson_minimumRequiredFieldsForRefresh()383 public void fromJson_minimumRequiredFieldsForRefresh() throws IOException { 384 GenericJson json = new GenericJson(); 385 json.put("client_id", CLIENT_ID); 386 json.put("client_secret", CLIENT_SECRET); 387 json.put("refresh_token", REFRESH_TOKEN); 388 json.put("token_url", TOKEN_URL); 389 390 ExternalAccountAuthorizedUserCredentials credentials = 391 ExternalAccountAuthorizedUserCredentials.fromJson(json, OAuth2Utils.HTTP_TRANSPORT_FACTORY); 392 393 assertEquals(CLIENT_ID, credentials.getClientId()); 394 assertEquals(CLIENT_SECRET, credentials.getClientSecret()); 395 assertEquals(REFRESH_TOKEN, credentials.getRefreshToken()); 396 assertEquals(TOKEN_URL, credentials.getTokenUrl()); 397 assertNull(credentials.getAudience()); 398 assertNull(credentials.getTokenInfoUrl()); 399 assertNull(credentials.getRevokeUrl()); 400 assertNull(credentials.getAccessToken()); 401 assertNull(credentials.getQuotaProjectId()); 402 } 403 404 @Test fromJson_accessTokenOnly_notSupported()405 public void fromJson_accessTokenOnly_notSupported() throws IOException { 406 GenericJson json = new GenericJson(); 407 json.put("access_token", ACCESS_TOKEN); 408 409 try { 410 ExternalAccountAuthorizedUserCredentials.fromJson(json, OAuth2Utils.HTTP_TRANSPORT_FACTORY); 411 fail("Should not be able to continue without exception."); 412 } catch (IllegalStateException exception) { 413 assertEquals( 414 "ExternalAccountAuthorizedUserCredentials must be initialized with " 415 + "an access token or fields to enable refresh: " 416 + "('refresh_token', 'token_url', 'client_id', 'client_secret').", 417 exception.getMessage()); 418 } 419 } 420 421 @Test fromJson_missingRefreshToken_throws()422 public void fromJson_missingRefreshToken_throws() throws IOException { 423 try { 424 GenericJson json = buildJsonCredentials(); 425 json.remove("refresh_token"); 426 ExternalAccountAuthorizedUserCredentials.fromJson(json, OAuth2Utils.HTTP_TRANSPORT_FACTORY); 427 fail("Should not be able to continue without exception."); 428 } catch (IllegalStateException exception) { 429 assertEquals( 430 "ExternalAccountAuthorizedUserCredentials must be initialized with " 431 + "an access token or fields to enable refresh: " 432 + "('refresh_token', 'token_url', 'client_id', 'client_secret').", 433 exception.getMessage()); 434 } 435 } 436 437 @Test fromJson_missingTokenUrl_throws()438 public void fromJson_missingTokenUrl_throws() throws IOException { 439 try { 440 GenericJson json = buildJsonCredentials(); 441 json.remove("token_url"); 442 ExternalAccountAuthorizedUserCredentials.fromJson(json, OAuth2Utils.HTTP_TRANSPORT_FACTORY); 443 fail("Should not be able to continue without exception."); 444 } catch (IllegalStateException exception) { 445 assertEquals( 446 "ExternalAccountAuthorizedUserCredentials must be initialized with " 447 + "an access token or fields to enable refresh: " 448 + "('refresh_token', 'token_url', 'client_id', 'client_secret').", 449 exception.getMessage()); 450 } 451 } 452 453 @Test fromJson_missingClientId_throws()454 public void fromJson_missingClientId_throws() throws IOException { 455 try { 456 GenericJson json = buildJsonCredentials(); 457 json.remove("client_id"); 458 ExternalAccountAuthorizedUserCredentials.fromJson(json, OAuth2Utils.HTTP_TRANSPORT_FACTORY); 459 fail("Should not be able to continue without exception."); 460 } catch (IllegalStateException exception) { 461 assertEquals( 462 "ExternalAccountAuthorizedUserCredentials must be initialized with " 463 + "an access token or fields to enable refresh: " 464 + "('refresh_token', 'token_url', 'client_id', 'client_secret').", 465 exception.getMessage()); 466 } 467 } 468 469 @Test fromJson_missingClientSecret_throws()470 public void fromJson_missingClientSecret_throws() throws IOException { 471 try { 472 GenericJson json = buildJsonCredentials(); 473 json.remove("client_secret"); 474 ExternalAccountAuthorizedUserCredentials.fromJson(json, OAuth2Utils.HTTP_TRANSPORT_FACTORY); 475 fail("Should not be able to continue without exception."); 476 } catch (IllegalStateException exception) { 477 assertEquals( 478 "ExternalAccountAuthorizedUserCredentials must be initialized with " 479 + "an access token or fields to enable refresh: " 480 + "('refresh_token', 'token_url', 'client_id', 'client_secret').", 481 exception.getMessage()); 482 } 483 } 484 485 @Test fromJson_missingUniverseDomain_defaults()486 public void fromJson_missingUniverseDomain_defaults() throws IOException { 487 GenericJson json = buildJsonCredentials(); 488 json.remove("universe_domain"); 489 490 ExternalAccountAuthorizedUserCredentials credentials = 491 ExternalAccountAuthorizedUserCredentials.fromJson(json, OAuth2Utils.HTTP_TRANSPORT_FACTORY); 492 493 assertEquals(AUDIENCE, credentials.getAudience()); 494 assertEquals(CLIENT_ID, credentials.getClientId()); 495 assertEquals(CLIENT_SECRET, credentials.getClientSecret()); 496 assertEquals(REFRESH_TOKEN, credentials.getRefreshToken()); 497 assertEquals(TOKEN_URL, credentials.getTokenUrl()); 498 assertEquals(TOKEN_INFO_URL, credentials.getTokenInfoUrl()); 499 assertEquals(REVOKE_URL, credentials.getRevokeUrl()); 500 assertEquals(QUOTA_PROJECT, credentials.getQuotaProjectId()); 501 assertEquals(GOOGLE_DEFAULT_UNIVERSE, credentials.getUniverseDomain()); 502 } 503 504 @Test fromStream_allFields()505 public void fromStream_allFields() throws IOException { 506 GenericJson json = buildJsonCredentials(); 507 508 ExternalAccountAuthorizedUserCredentials credentials = 509 ExternalAccountAuthorizedUserCredentials.fromStream(TestUtils.jsonToInputStream(json)); 510 511 assertEquals(AUDIENCE, credentials.getAudience()); 512 assertEquals(CLIENT_ID, credentials.getClientId()); 513 assertEquals(CLIENT_SECRET, credentials.getClientSecret()); 514 assertEquals(REFRESH_TOKEN, credentials.getRefreshToken()); 515 assertEquals(TOKEN_URL, credentials.getTokenUrl()); 516 assertEquals(TOKEN_INFO_URL, credentials.getTokenInfoUrl()); 517 assertEquals(REVOKE_URL, credentials.getRevokeUrl()); 518 assertEquals(QUOTA_PROJECT, credentials.getQuotaProjectId()); 519 } 520 521 @Test fromStream_minimumRequiredFieldsForRefresh()522 public void fromStream_minimumRequiredFieldsForRefresh() throws IOException { 523 GenericJson json = new GenericJson(); 524 json.put("client_id", CLIENT_ID); 525 json.put("client_secret", CLIENT_SECRET); 526 json.put("refresh_token", REFRESH_TOKEN); 527 json.put("token_url", TOKEN_URL); 528 529 ExternalAccountAuthorizedUserCredentials credentials = 530 ExternalAccountAuthorizedUserCredentials.fromStream(TestUtils.jsonToInputStream(json)); 531 532 assertEquals(CLIENT_ID, credentials.getClientId()); 533 assertEquals(CLIENT_SECRET, credentials.getClientSecret()); 534 assertEquals(REFRESH_TOKEN, credentials.getRefreshToken()); 535 assertEquals(TOKEN_URL, credentials.getTokenUrl()); 536 assertNull(credentials.getAudience()); 537 assertNull(credentials.getTokenInfoUrl()); 538 assertNull(credentials.getRevokeUrl()); 539 assertNull(credentials.getAccessToken()); 540 assertNull(credentials.getQuotaProjectId()); 541 } 542 543 @Test fromStream_accessTokenOnly_notSupported()544 public void fromStream_accessTokenOnly_notSupported() throws IOException { 545 GenericJson json = new GenericJson(); 546 json.put("access_token", ACCESS_TOKEN); 547 try { 548 ExternalAccountAuthorizedUserCredentials.fromStream(TestUtils.jsonToInputStream(json)); 549 fail("Should not be able to continue without exception."); 550 } catch (IllegalStateException exception) { 551 assertEquals( 552 "ExternalAccountAuthorizedUserCredentials must be initialized with " 553 + "an access token or fields to enable refresh: " 554 + "('refresh_token', 'token_url', 'client_id', 'client_secret').", 555 exception.getMessage()); 556 } 557 } 558 559 @Test fromStream_missingRefreshToken_throws()560 public void fromStream_missingRefreshToken_throws() throws IOException { 561 try { 562 GenericJson json = buildJsonCredentials(); 563 json.remove("refresh_token"); 564 ExternalAccountAuthorizedUserCredentials.fromStream(TestUtils.jsonToInputStream(json)); 565 fail("Should not be able to continue without exception."); 566 } catch (IllegalStateException exception) { 567 assertEquals( 568 "ExternalAccountAuthorizedUserCredentials must be initialized with " 569 + "an access token or fields to enable refresh: " 570 + "('refresh_token', 'token_url', 'client_id', 'client_secret').", 571 exception.getMessage()); 572 } 573 } 574 575 @Test fromStream_missingTokenUrl_throws()576 public void fromStream_missingTokenUrl_throws() throws IOException { 577 try { 578 GenericJson json = buildJsonCredentials(); 579 json.remove("token_url"); 580 ExternalAccountAuthorizedUserCredentials.fromStream(TestUtils.jsonToInputStream(json)); 581 fail("Should not be able to continue without exception."); 582 } catch (IllegalStateException exception) { 583 assertEquals( 584 "ExternalAccountAuthorizedUserCredentials must be initialized with " 585 + "an access token or fields to enable refresh: " 586 + "('refresh_token', 'token_url', 'client_id', 'client_secret').", 587 exception.getMessage()); 588 } 589 } 590 591 @Test fromStream_missingClientId_throws()592 public void fromStream_missingClientId_throws() throws IOException { 593 try { 594 GenericJson json = buildJsonCredentials(); 595 json.remove("client_id"); 596 ExternalAccountAuthorizedUserCredentials.fromStream(TestUtils.jsonToInputStream(json)); 597 fail("Should not be able to continue without exception."); 598 } catch (IllegalStateException exception) { 599 assertEquals( 600 "ExternalAccountAuthorizedUserCredentials must be initialized with " 601 + "an access token or fields to enable refresh: " 602 + "('refresh_token', 'token_url', 'client_id', 'client_secret').", 603 exception.getMessage()); 604 } 605 } 606 607 @Test fromStream_missingClientSecret_throws()608 public void fromStream_missingClientSecret_throws() throws IOException { 609 try { 610 GenericJson json = buildJsonCredentials(); 611 json.remove("client_secret"); 612 ExternalAccountAuthorizedUserCredentials.fromStream(TestUtils.jsonToInputStream(json)); 613 fail("Should not be able to continue without exception."); 614 } catch (IllegalStateException exception) { 615 assertEquals( 616 "ExternalAccountAuthorizedUserCredentials must be initialized with " 617 + "an access token or fields to enable refresh: " 618 + "('refresh_token', 'token_url', 'client_id', 'client_secret').", 619 exception.getMessage()); 620 } 621 } 622 623 @Test fromStream_missingUniverseDomain_defaults()624 public void fromStream_missingUniverseDomain_defaults() throws IOException { 625 GenericJson json = buildJsonCredentials(); 626 json.remove("universe_domain"); 627 628 ExternalAccountAuthorizedUserCredentials credentials = 629 ExternalAccountAuthorizedUserCredentials.fromStream(TestUtils.jsonToInputStream(json)); 630 631 assertEquals(AUDIENCE, credentials.getAudience()); 632 assertEquals(CLIENT_ID, credentials.getClientId()); 633 assertEquals(CLIENT_SECRET, credentials.getClientSecret()); 634 assertEquals(REFRESH_TOKEN, credentials.getRefreshToken()); 635 assertEquals(TOKEN_URL, credentials.getTokenUrl()); 636 assertEquals(TOKEN_INFO_URL, credentials.getTokenInfoUrl()); 637 assertEquals(REVOKE_URL, credentials.getRevokeUrl()); 638 assertEquals(QUOTA_PROJECT, credentials.getQuotaProjectId()); 639 assertEquals(GOOGLE_DEFAULT_UNIVERSE, credentials.getUniverseDomain()); 640 } 641 642 @Test fromStream_invalidInputStream_throws()643 public void fromStream_invalidInputStream_throws() throws IOException { 644 try { 645 GenericJson json = buildJsonCredentials(); 646 json.put("audience", new HashMap<>()); 647 ExternalAccountAuthorizedUserCredentials.fromStream(TestUtils.jsonToInputStream(json)); 648 fail("Should not be able to continue without exception."); 649 } catch (CredentialFormatException e) { 650 assertEquals("Invalid input stream provided.", e.getMessage()); 651 } 652 } 653 654 @Test createScoped_noChange()655 public void createScoped_noChange() { 656 ExternalAccountAuthorizedUserCredentials externalAccountAuthorizedUserCredentials = 657 ExternalAccountAuthorizedUserCredentials.newBuilder() 658 .setTokenUrl(TOKEN_URL) 659 .setClientId(CLIENT_ID) 660 .setClientSecret(CLIENT_SECRET) 661 .setRefreshToken(REFRESH_TOKEN) 662 .build(); 663 assertSame( 664 externalAccountAuthorizedUserCredentials, 665 externalAccountAuthorizedUserCredentials.createScoped(SCOPES)); 666 } 667 668 @Test createScopedRequired_false()669 public void createScopedRequired_false() { 670 ExternalAccountAuthorizedUserCredentials externalAccountAuthorizedUserCredentials = 671 ExternalAccountAuthorizedUserCredentials.newBuilder() 672 .setTokenUrl(TOKEN_URL) 673 .setClientId(CLIENT_ID) 674 .setClientSecret(CLIENT_SECRET) 675 .setRefreshToken(REFRESH_TOKEN) 676 .build(); 677 assertFalse(externalAccountAuthorizedUserCredentials.createScopedRequired()); 678 } 679 680 @Test getRequestMetadata()681 public void getRequestMetadata() throws IOException { 682 GoogleCredentials credentials = 683 ExternalAccountAuthorizedUserCredentials.fromJson(buildJsonCredentials(), transportFactory); 684 685 Map<String, List<String>> metadata = credentials.getRequestMetadata(CALL_URI); 686 687 TestUtils.assertContainsBearerToken(metadata, transportFactory.transport.getAccessToken()); 688 validateAuthHeader(transportFactory.transport.getRequest()); 689 } 690 691 @Test getRequestMetadata_withQuotaProjectId()692 public void getRequestMetadata_withQuotaProjectId() throws IOException { 693 GoogleCredentials credentials = 694 ExternalAccountAuthorizedUserCredentials.fromJson(buildJsonCredentials(), transportFactory); 695 696 Map<String, List<String>> metadata = credentials.getRequestMetadata(CALL_URI); 697 698 assertTrue(metadata.containsKey(GoogleCredentials.QUOTA_PROJECT_ID_HEADER_KEY)); 699 assertEquals( 700 metadata.get(GoogleCredentials.QUOTA_PROJECT_ID_HEADER_KEY), 701 Collections.singletonList(QUOTA_PROJECT)); 702 703 validateAuthHeader(transportFactory.transport.getRequest()); 704 } 705 706 @Test getRequestMetadata_withAccessToken()707 public void getRequestMetadata_withAccessToken() throws IOException { 708 ExternalAccountAuthorizedUserCredentials credentials = 709 ExternalAccountAuthorizedUserCredentials.newBuilder() 710 .setHttpTransportFactory(transportFactory) 711 .setAccessToken(new AccessToken(ACCESS_TOKEN, /* expirationTime= */ null)) 712 .build(); 713 714 Map<String, List<String>> metadata = credentials.getRequestMetadata(CALL_URI); 715 716 TestUtils.assertContainsBearerToken(metadata, ACCESS_TOKEN); 717 } 718 719 @Test refreshAccessToken()720 public void refreshAccessToken() throws IOException { 721 ExternalAccountAuthorizedUserCredentials credentials = 722 ExternalAccountAuthorizedUserCredentials.fromJson(buildJsonCredentials(), transportFactory); 723 724 AccessToken accessToken = credentials.refreshAccessToken(); 725 726 assertEquals(transportFactory.transport.getAccessToken(), accessToken.getTokenValue()); 727 validateAuthHeader(transportFactory.transport.getRequest()); 728 } 729 730 @Test refreshAccessToken_withRefreshTokenRotation()731 public void refreshAccessToken_withRefreshTokenRotation() throws IOException { 732 ExternalAccountAuthorizedUserCredentials credentials = 733 ExternalAccountAuthorizedUserCredentials.fromJson(buildJsonCredentials(), transportFactory); 734 735 transportFactory.transport.addRefreshTokenSequence("aNewRefreshToken"); 736 737 AccessToken accessToken = credentials.refreshAccessToken(); 738 739 assertEquals(transportFactory.transport.getAccessToken(), accessToken.getTokenValue()); 740 // Validate new refresh token was set. 741 assertEquals("aNewRefreshToken", credentials.getRefreshToken()); 742 assertNotEquals(REFRESH_TOKEN, credentials.getRefreshToken()); 743 validateAuthHeader(transportFactory.transport.getRequest()); 744 } 745 746 @Test refreshAccessToken_genericAuthError_throws()747 public void refreshAccessToken_genericAuthError_throws() throws IOException { 748 transportFactory.transport.addResponseErrorSequence( 749 TestUtils.buildHttpResponseException( 750 "invalid_request", "Invalid request.", /* errorUri= */ null)); 751 752 ExternalAccountAuthorizedUserCredentials credentials = 753 ExternalAccountAuthorizedUserCredentials.fromJson(buildJsonCredentials(), transportFactory); 754 755 try { 756 credentials.refreshAccessToken(); 757 fail(""); 758 } catch (OAuthException e) { 759 assertEquals("invalid_request", e.getErrorCode()); 760 assertEquals("Invalid request.", e.getErrorDescription()); 761 } 762 } 763 764 @Test(expected = IOException.class) refreshAccessToken_genericIOError_throws()765 public void refreshAccessToken_genericIOError_throws() throws IOException { 766 transportFactory.transport.addResponseErrorSequence(new IOException("")); 767 768 ExternalAccountAuthorizedUserCredentials credentials = 769 ExternalAccountAuthorizedUserCredentials.fromJson(buildJsonCredentials(), transportFactory); 770 771 credentials.refreshAccessToken(); 772 } 773 774 @Test(expected = IllegalStateException.class) refreshAccessToken_missingRefreshFields_throws()775 public void refreshAccessToken_missingRefreshFields_throws() throws IOException { 776 ExternalAccountAuthorizedUserCredentials credentials = 777 ExternalAccountAuthorizedUserCredentials.newBuilder() 778 .setClientId(CLIENT_ID) 779 .setClientSecret(CLIENT_SECRET) 780 .setTokenUrl(TOKEN_URL) 781 .setAccessToken(new AccessToken(ACCESS_TOKEN, /* expirationTime= */ null)) 782 .setHttpTransportFactory(transportFactory) 783 .build(); 784 785 credentials.refreshAccessToken(); 786 } 787 788 @Test hashCode_sameCredentials()789 public void hashCode_sameCredentials() { 790 ExternalAccountAuthorizedUserCredentials credentials = 791 ExternalAccountAuthorizedUserCredentials.newBuilder() 792 .setAudience(AUDIENCE) 793 .setClientId(CLIENT_ID) 794 .setClientSecret(CLIENT_SECRET) 795 .setRefreshToken(REFRESH_TOKEN) 796 .setTokenUrl(TOKEN_URL) 797 .setTokenInfoUrl(TOKEN_INFO_URL) 798 .setRevokeUrl(REVOKE_URL) 799 .setAccessToken(new AccessToken(ACCESS_TOKEN, /* expirationTime= */ null)) 800 .setQuotaProjectId(QUOTA_PROJECT) 801 .build(); 802 803 ExternalAccountAuthorizedUserCredentials secondCredentials = 804 ExternalAccountAuthorizedUserCredentials.newBuilder() 805 .setAudience(AUDIENCE) 806 .setClientId(CLIENT_ID) 807 .setClientSecret(CLIENT_SECRET) 808 .setRefreshToken(REFRESH_TOKEN) 809 .setTokenUrl(TOKEN_URL) 810 .setTokenInfoUrl(TOKEN_INFO_URL) 811 .setRevokeUrl(REVOKE_URL) 812 .setAccessToken(new AccessToken(ACCESS_TOKEN, /* expirationTime= */ null)) 813 .setQuotaProjectId(QUOTA_PROJECT) 814 .build(); 815 816 assertEquals(credentials, secondCredentials); 817 assertEquals(secondCredentials, credentials); 818 assertEquals(credentials.hashCode(), secondCredentials.hashCode()); 819 } 820 821 @Test hashCode_differentCredentials()822 public void hashCode_differentCredentials() { 823 ExternalAccountAuthorizedUserCredentials credentials = 824 ExternalAccountAuthorizedUserCredentials.newBuilder() 825 .setAudience(AUDIENCE) 826 .setClientId(CLIENT_ID) 827 .setClientSecret(CLIENT_SECRET) 828 .setRefreshToken(REFRESH_TOKEN) 829 .setTokenUrl(TOKEN_URL) 830 .setTokenInfoUrl(TOKEN_INFO_URL) 831 .setRevokeUrl(REVOKE_URL) 832 .build(); 833 834 // Second credentials have an access token set. 835 ExternalAccountAuthorizedUserCredentials secondCredentials = 836 ExternalAccountAuthorizedUserCredentials.newBuilder() 837 .setAudience(AUDIENCE) 838 .setClientId(CLIENT_ID) 839 .setClientSecret(CLIENT_SECRET) 840 .setRefreshToken(REFRESH_TOKEN) 841 .setTokenUrl(TOKEN_URL) 842 .setTokenInfoUrl(TOKEN_INFO_URL) 843 .setRevokeUrl(REVOKE_URL) 844 .setAccessToken(new AccessToken(ACCESS_TOKEN, /* expirationTime= */ null)) 845 .setQuotaProjectId(QUOTA_PROJECT) 846 .build(); 847 848 assertNotEquals(secondCredentials, credentials); 849 assertNotEquals(credentials, secondCredentials); 850 assertNotEquals(credentials.hashCode(), secondCredentials.hashCode()); 851 } 852 853 @Test hashCode_differentCredentialsWithCredentialsFile()854 public void hashCode_differentCredentialsWithCredentialsFile() throws IOException { 855 // Optional fields that can be specified in the credentials file. 856 List<String> fields = Arrays.asList("audience", "revoke_url", "quota_project_id"); 857 858 // Credential initialized with all fields. 859 ExternalAccountAuthorizedUserCredentials credentials = 860 ExternalAccountAuthorizedUserCredentials.fromJson(buildJsonCredentials(), transportFactory); 861 862 for (String field : fields) { 863 // Build credential with one of these fields missing. 864 GenericJson json = buildJsonCredentials(); 865 json.remove(field); 866 867 ExternalAccountAuthorizedUserCredentials secondCredentials = 868 ExternalAccountAuthorizedUserCredentials.fromJson(json, transportFactory); 869 assertNotEquals(secondCredentials, credentials); 870 assertNotEquals(credentials, secondCredentials); 871 assertNotEquals(credentials.hashCode(), secondCredentials.hashCode()); 872 } 873 } 874 875 @Test equals_differentCredentials()876 public void equals_differentCredentials() throws IOException { 877 UserCredentials userCredentials = 878 UserCredentials.newBuilder() 879 .setClientId(CLIENT_ID) 880 .setClientSecret(CLIENT_SECRET) 881 .setRefreshToken(REFRESH_TOKEN) 882 .setHttpTransportFactory(transportFactory) 883 .setTokenServerUri(URI.create(TOKEN_URL)) 884 .setQuotaProjectId(QUOTA_PROJECT) 885 .build(); 886 887 ExternalAccountAuthorizedUserCredentials credentials = 888 ExternalAccountAuthorizedUserCredentials.fromJson(buildJsonCredentials(), transportFactory); 889 890 assertNotEquals(userCredentials, credentials); 891 assertNotEquals(credentials, userCredentials); 892 } 893 894 @Test equals_differentAudience()895 public void equals_differentAudience() { 896 ExternalAccountAuthorizedUserCredentials credentials = 897 ExternalAccountAuthorizedUserCredentials.newBuilder() 898 .setAudience(AUDIENCE) 899 .setClientId(CLIENT_ID) 900 .setClientSecret(CLIENT_SECRET) 901 .setRefreshToken(REFRESH_TOKEN) 902 .setTokenUrl(TOKEN_URL) 903 .setTokenInfoUrl(TOKEN_INFO_URL) 904 .setRevokeUrl(REVOKE_URL) 905 .setAccessToken(new AccessToken(ACCESS_TOKEN, /* expirationTime= */ null)) 906 .setQuotaProjectId(QUOTA_PROJECT) 907 .setHttpTransportFactory(transportFactory) 908 .build(); 909 910 ExternalAccountAuthorizedUserCredentials secondCredentials = 911 credentials.toBuilder().setAudience("different").build(); 912 913 assertNotEquals(secondCredentials, credentials); 914 assertNotEquals(credentials, secondCredentials); 915 assertNotEquals(credentials.hashCode(), secondCredentials.hashCode()); 916 } 917 918 @Test equals_differentClientId()919 public void equals_differentClientId() { 920 ExternalAccountAuthorizedUserCredentials credentials = 921 ExternalAccountAuthorizedUserCredentials.newBuilder() 922 .setAudience(AUDIENCE) 923 .setClientId(CLIENT_ID) 924 .setClientSecret(CLIENT_SECRET) 925 .setRefreshToken(REFRESH_TOKEN) 926 .setTokenUrl(TOKEN_URL) 927 .setTokenInfoUrl(TOKEN_INFO_URL) 928 .setRevokeUrl(REVOKE_URL) 929 .setAccessToken(new AccessToken(ACCESS_TOKEN, /* expirationTime= */ null)) 930 .setQuotaProjectId(QUOTA_PROJECT) 931 .setHttpTransportFactory(transportFactory) 932 .build(); 933 934 ExternalAccountAuthorizedUserCredentials secondCredentials = 935 credentials.toBuilder().setClientId("different").build(); 936 937 assertNotEquals(secondCredentials, credentials); 938 assertNotEquals(credentials, secondCredentials); 939 assertNotEquals(credentials.hashCode(), secondCredentials.hashCode()); 940 } 941 942 @Test equals_differentClientSecret()943 public void equals_differentClientSecret() { 944 ExternalAccountAuthorizedUserCredentials credentials = 945 ExternalAccountAuthorizedUserCredentials.newBuilder() 946 .setAudience(AUDIENCE) 947 .setClientId(CLIENT_ID) 948 .setClientSecret(CLIENT_SECRET) 949 .setRefreshToken(REFRESH_TOKEN) 950 .setTokenUrl(TOKEN_URL) 951 .setTokenInfoUrl(TOKEN_INFO_URL) 952 .setRevokeUrl(REVOKE_URL) 953 .setAccessToken(new AccessToken(ACCESS_TOKEN, /* expirationTime= */ null)) 954 .setQuotaProjectId(QUOTA_PROJECT) 955 .setHttpTransportFactory(transportFactory) 956 .build(); 957 958 ExternalAccountAuthorizedUserCredentials secondCredentials = 959 credentials.toBuilder().setClientSecret("different").build(); 960 961 assertNotEquals(secondCredentials, credentials); 962 assertNotEquals(credentials, secondCredentials); 963 assertNotEquals(credentials.hashCode(), secondCredentials.hashCode()); 964 } 965 966 @Test equals_differentRefreshToken()967 public void equals_differentRefreshToken() { 968 ExternalAccountAuthorizedUserCredentials credentials = 969 ExternalAccountAuthorizedUserCredentials.newBuilder() 970 .setAudience(AUDIENCE) 971 .setClientId(CLIENT_ID) 972 .setClientSecret(CLIENT_SECRET) 973 .setRefreshToken(REFRESH_TOKEN) 974 .setTokenUrl(TOKEN_URL) 975 .setTokenInfoUrl(TOKEN_INFO_URL) 976 .setRevokeUrl(REVOKE_URL) 977 .setAccessToken(new AccessToken(ACCESS_TOKEN, /* expirationTime= */ null)) 978 .setQuotaProjectId(QUOTA_PROJECT) 979 .setHttpTransportFactory(transportFactory) 980 .build(); 981 982 ExternalAccountAuthorizedUserCredentials secondCredentials = 983 credentials.toBuilder().setRefreshToken("different").build(); 984 985 assertNotEquals(secondCredentials, credentials); 986 assertNotEquals(credentials, secondCredentials); 987 assertNotEquals(credentials.hashCode(), secondCredentials.hashCode()); 988 } 989 990 @Test equals_differentTokenUrl()991 public void equals_differentTokenUrl() { 992 ExternalAccountAuthorizedUserCredentials credentials = 993 ExternalAccountAuthorizedUserCredentials.newBuilder() 994 .setAudience(AUDIENCE) 995 .setClientId(CLIENT_ID) 996 .setClientSecret(CLIENT_SECRET) 997 .setRefreshToken(REFRESH_TOKEN) 998 .setTokenUrl(TOKEN_URL) 999 .setTokenInfoUrl(TOKEN_INFO_URL) 1000 .setRevokeUrl(REVOKE_URL) 1001 .setAccessToken(new AccessToken(ACCESS_TOKEN, /* expirationTime= */ null)) 1002 .setQuotaProjectId(QUOTA_PROJECT) 1003 .setHttpTransportFactory(transportFactory) 1004 .build(); 1005 1006 ExternalAccountAuthorizedUserCredentials secondCredentials = 1007 credentials.toBuilder().setTokenUrl("different").build(); 1008 1009 assertNotEquals(secondCredentials, credentials); 1010 assertNotEquals(credentials, secondCredentials); 1011 assertNotEquals(credentials.hashCode(), secondCredentials.hashCode()); 1012 } 1013 1014 @Test equals_differentTokenInfoUrl()1015 public void equals_differentTokenInfoUrl() { 1016 ExternalAccountAuthorizedUserCredentials credentials = 1017 ExternalAccountAuthorizedUserCredentials.newBuilder() 1018 .setAudience(AUDIENCE) 1019 .setClientId(CLIENT_ID) 1020 .setClientSecret(CLIENT_SECRET) 1021 .setRefreshToken(REFRESH_TOKEN) 1022 .setTokenUrl(TOKEN_URL) 1023 .setTokenInfoUrl(TOKEN_INFO_URL) 1024 .setRevokeUrl(REVOKE_URL) 1025 .setAccessToken(new AccessToken(ACCESS_TOKEN, /* expirationTime= */ null)) 1026 .setQuotaProjectId(QUOTA_PROJECT) 1027 .setHttpTransportFactory(transportFactory) 1028 .build(); 1029 1030 ExternalAccountAuthorizedUserCredentials secondCredentials = 1031 credentials.toBuilder().setTokenInfoUrl("different").build(); 1032 1033 assertNotEquals(secondCredentials, credentials); 1034 assertNotEquals(credentials, secondCredentials); 1035 assertNotEquals(credentials.hashCode(), secondCredentials.hashCode()); 1036 } 1037 1038 @Test equals_differentRevokeUrl()1039 public void equals_differentRevokeUrl() { 1040 ExternalAccountAuthorizedUserCredentials credentials = 1041 ExternalAccountAuthorizedUserCredentials.newBuilder() 1042 .setAudience(AUDIENCE) 1043 .setClientId(CLIENT_ID) 1044 .setClientSecret(CLIENT_SECRET) 1045 .setRefreshToken(REFRESH_TOKEN) 1046 .setTokenUrl(TOKEN_URL) 1047 .setTokenInfoUrl(TOKEN_INFO_URL) 1048 .setRevokeUrl(REVOKE_URL) 1049 .setAccessToken(new AccessToken(ACCESS_TOKEN, /* expirationTime= */ null)) 1050 .setQuotaProjectId(QUOTA_PROJECT) 1051 .setHttpTransportFactory(transportFactory) 1052 .build(); 1053 1054 ExternalAccountAuthorizedUserCredentials secondCredentials = 1055 credentials.toBuilder().setRevokeUrl("different").build(); 1056 1057 assertNotEquals(secondCredentials, credentials); 1058 assertNotEquals(credentials, secondCredentials); 1059 assertNotEquals(credentials.hashCode(), secondCredentials.hashCode()); 1060 } 1061 1062 @Test equals_differentAccessToken()1063 public void equals_differentAccessToken() { 1064 ExternalAccountAuthorizedUserCredentials credentials = 1065 ExternalAccountAuthorizedUserCredentials.newBuilder() 1066 .setAudience(AUDIENCE) 1067 .setClientId(CLIENT_ID) 1068 .setClientSecret(CLIENT_SECRET) 1069 .setRefreshToken(REFRESH_TOKEN) 1070 .setTokenUrl(TOKEN_URL) 1071 .setTokenInfoUrl(TOKEN_INFO_URL) 1072 .setRevokeUrl(REVOKE_URL) 1073 .setAccessToken(new AccessToken(ACCESS_TOKEN, new Date())) 1074 .setQuotaProjectId(QUOTA_PROJECT) 1075 .setHttpTransportFactory(transportFactory) 1076 .build(); 1077 1078 ExternalAccountAuthorizedUserCredentials secondCredentials = 1079 credentials.toBuilder().setAccessToken(new AccessToken("different", new Date())).build(); 1080 1081 assertNotEquals(secondCredentials, credentials); 1082 assertNotEquals(credentials, secondCredentials); 1083 assertNotEquals(credentials.hashCode(), secondCredentials.hashCode()); 1084 } 1085 1086 @Test equals_differentQuotaProjectId()1087 public void equals_differentQuotaProjectId() { 1088 ExternalAccountAuthorizedUserCredentials credentials = 1089 ExternalAccountAuthorizedUserCredentials.newBuilder() 1090 .setAudience(AUDIENCE) 1091 .setClientId(CLIENT_ID) 1092 .setClientSecret(CLIENT_SECRET) 1093 .setRefreshToken(REFRESH_TOKEN) 1094 .setTokenUrl(TOKEN_URL) 1095 .setTokenInfoUrl(TOKEN_INFO_URL) 1096 .setRevokeUrl(REVOKE_URL) 1097 .setAccessToken(new AccessToken(ACCESS_TOKEN, /* expirationTime= */ null)) 1098 .setQuotaProjectId(QUOTA_PROJECT) 1099 .setHttpTransportFactory(transportFactory) 1100 .build(); 1101 1102 ExternalAccountAuthorizedUserCredentials secondCredentials = 1103 credentials.toBuilder().setQuotaProjectId("different").build(); 1104 1105 assertNotEquals(secondCredentials, credentials); 1106 assertNotEquals(credentials, secondCredentials); 1107 assertNotEquals(credentials.hashCode(), secondCredentials.hashCode()); 1108 } 1109 1110 @Test equals_differentTransportFactory()1111 public void equals_differentTransportFactory() { 1112 ExternalAccountAuthorizedUserCredentials credentials = 1113 ExternalAccountAuthorizedUserCredentials.newBuilder() 1114 .setAudience(AUDIENCE) 1115 .setClientId(CLIENT_ID) 1116 .setClientSecret(CLIENT_SECRET) 1117 .setRefreshToken(REFRESH_TOKEN) 1118 .setTokenUrl(TOKEN_URL) 1119 .setTokenInfoUrl(TOKEN_INFO_URL) 1120 .setRevokeUrl(REVOKE_URL) 1121 .setAccessToken(new AccessToken(ACCESS_TOKEN, /* expirationTime= */ null)) 1122 .setQuotaProjectId(QUOTA_PROJECT) 1123 .setHttpTransportFactory(transportFactory) 1124 .build(); 1125 1126 ExternalAccountAuthorizedUserCredentials secondCredentials = 1127 credentials.toBuilder().setHttpTransportFactory(OAuth2Utils.HTTP_TRANSPORT_FACTORY).build(); 1128 1129 assertNotEquals(secondCredentials, credentials); 1130 assertNotEquals(credentials, secondCredentials); 1131 assertNotEquals(credentials.hashCode(), secondCredentials.hashCode()); 1132 } 1133 1134 @Test equals_differentUniverseDomain()1135 public void equals_differentUniverseDomain() { 1136 ExternalAccountAuthorizedUserCredentials credentials = 1137 ExternalAccountAuthorizedUserCredentials.newBuilder() 1138 .setAudience(AUDIENCE) 1139 .setClientId(CLIENT_ID) 1140 .setClientSecret(CLIENT_SECRET) 1141 .setRefreshToken(REFRESH_TOKEN) 1142 .setTokenUrl(TOKEN_URL) 1143 .setTokenInfoUrl(TOKEN_INFO_URL) 1144 .setRevokeUrl(REVOKE_URL) 1145 .setAccessToken(new AccessToken(ACCESS_TOKEN, /* expirationTime= */ null)) 1146 .setQuotaProjectId(QUOTA_PROJECT) 1147 .setHttpTransportFactory(transportFactory) 1148 .setUniverseDomain(UNIVERSE_DOMAIN) 1149 .build(); 1150 1151 ExternalAccountAuthorizedUserCredentials secondCredentials = 1152 credentials.toBuilder().setUniverseDomain("different").build(); 1153 1154 assertNotEquals(secondCredentials, credentials); 1155 assertNotEquals(credentials, secondCredentials); 1156 assertNotEquals(credentials.hashCode(), secondCredentials.hashCode()); 1157 } 1158 1159 @Test toString_expectedFormat()1160 public void toString_expectedFormat() { 1161 AccessToken accessToken = new AccessToken(ACCESS_TOKEN, new Date()); 1162 ExternalAccountAuthorizedUserCredentials credentials = 1163 ExternalAccountAuthorizedUserCredentials.newBuilder() 1164 .setAudience(AUDIENCE) 1165 .setClientId(CLIENT_ID) 1166 .setClientSecret(CLIENT_SECRET) 1167 .setRefreshToken(REFRESH_TOKEN) 1168 .setTokenUrl(TOKEN_URL) 1169 .setTokenInfoUrl(TOKEN_INFO_URL) 1170 .setRevokeUrl(REVOKE_URL) 1171 .setAccessToken(accessToken) 1172 .setQuotaProjectId(QUOTA_PROJECT) 1173 .setHttpTransportFactory(transportFactory) 1174 .build(); 1175 1176 String expectedToString = 1177 String.format( 1178 "ExternalAccountAuthorizedUserCredentials{requestMetadata=%s, temporaryAccess=%s, " 1179 + "clientId=%s, clientSecret=%s, refreshToken=%s, tokenUrl=%s, tokenInfoUrl=%s, " 1180 + "revokeUrl=%s, audience=%s, transportFactoryClassName=%s, quotaProjectId=%s}", 1181 ImmutableMap.of( 1182 AuthHttpConstants.AUTHORIZATION, 1183 ImmutableList.of(OAuth2Utils.BEARER_PREFIX + accessToken.getTokenValue())), 1184 accessToken, 1185 CLIENT_ID, 1186 CLIENT_SECRET, 1187 REFRESH_TOKEN, 1188 TOKEN_URL, 1189 TOKEN_INFO_URL, 1190 REVOKE_URL, 1191 AUDIENCE, 1192 transportFactory.getClass().getName(), 1193 QUOTA_PROJECT); 1194 1195 assertEquals(expectedToString, credentials.toString()); 1196 } 1197 1198 @Test serialize()1199 public void serialize() throws IOException, ClassNotFoundException { 1200 ExternalAccountAuthorizedUserCredentials credentials = 1201 ExternalAccountAuthorizedUserCredentials.newBuilder() 1202 .setAudience(AUDIENCE) 1203 .setClientId(CLIENT_ID) 1204 .setClientSecret(CLIENT_SECRET) 1205 .setRefreshToken(REFRESH_TOKEN) 1206 .setTokenUrl(TOKEN_URL) 1207 .setTokenInfoUrl(TOKEN_INFO_URL) 1208 .setRevokeUrl(REVOKE_URL) 1209 .setAccessToken(new AccessToken(ACCESS_TOKEN, /* expirationTime= */ null)) 1210 .setQuotaProjectId(QUOTA_PROJECT) 1211 .build(); 1212 1213 ExternalAccountAuthorizedUserCredentials deserializedCredentials = 1214 serializeAndDeserialize(credentials); 1215 assertEquals(credentials, deserializedCredentials); 1216 assertEquals(credentials.hashCode(), deserializedCredentials.hashCode()); 1217 assertEquals(credentials.toString(), deserializedCredentials.toString()); 1218 assertSame(deserializedCredentials.clock, Clock.SYSTEM); 1219 } 1220 buildJsonCredentials()1221 static GenericJson buildJsonCredentials() { 1222 GenericJson json = new GenericJson(); 1223 json.put("type", EXTERNAL_ACCOUNT_AUTHORIZED_USER_FILE_TYPE); 1224 json.put("audience", AUDIENCE); 1225 json.put("refresh_token", REFRESH_TOKEN); 1226 json.put("client_id", CLIENT_ID); 1227 json.put("client_secret", CLIENT_SECRET); 1228 json.put("token_url", TOKEN_URL); 1229 json.put("token_info_url", TOKEN_INFO_URL); 1230 json.put("revoke_url", REVOKE_URL); 1231 json.put("quota_project_id", QUOTA_PROJECT); 1232 json.put("universe_domain", UNIVERSE_DOMAIN); 1233 return json; 1234 } 1235 validateAuthHeader(MockLowLevelHttpRequest request)1236 private static void validateAuthHeader(MockLowLevelHttpRequest request) { 1237 Map<String, List<String>> headers = request.getHeaders(); 1238 List<String> authHeader = headers.get("authorization"); 1239 1240 assertEquals(BASIC_AUTH, authHeader.iterator().next()); 1241 assertEquals(1, authHeader.size()); 1242 } 1243 } 1244