1 /* 2 * Copyright 2022, Google Inc. All rights reserved. 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 Inc. 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 org.junit.Assert.assertEquals; 35 import static org.junit.Assert.assertFalse; 36 import static org.junit.Assert.assertNotNull; 37 import static org.junit.Assert.assertNull; 38 import static org.junit.Assert.assertSame; 39 import static org.junit.Assert.assertTrue; 40 import static org.junit.Assert.fail; 41 42 import com.google.api.client.json.GenericJson; 43 import com.google.api.client.json.JsonFactory; 44 import com.google.api.client.json.webtoken.JsonWebSignature; 45 import com.google.api.client.json.webtoken.JsonWebToken; 46 import com.google.api.client.testing.http.FixedClock; 47 import com.google.api.client.util.Clock; 48 import com.google.auth.TestUtils; 49 import java.io.File; 50 import java.io.IOException; 51 import java.io.InputStream; 52 import java.net.URI; 53 import java.nio.file.Files; 54 import java.util.List; 55 import java.util.Map; 56 import org.junit.Test; 57 import org.junit.runner.RunWith; 58 import org.junit.runners.JUnit4; 59 60 /** Test case for {@link GdchCredentials}. */ 61 @RunWith(JUnit4.class) 62 public class GdchCredentialsTest extends BaseSerializationTest { 63 private static final String FORMAT_VERSION = GdchCredentials.SUPPORTED_FORMAT_VERSION; 64 private static final String PRIVATE_KEY_ID = "d84a4fefcf50791d4a90f2d7af17469d6282df9d"; 65 static final String PRIVATE_KEY_PKCS8 = 66 "-----BEGIN PRIVATE KEY-----\n" 67 + "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALX0PQoe1igW12i" 68 + "kv1bN/r9lN749y2ijmbc/mFHPyS3hNTyOCjDvBbXYbDhQJzWVUikh4mvGBA07qTj79Xc3yBDfKP2IeyYQIFe0t0" 69 + "zkd7R9Zdn98Y2rIQC47aAbDfubtkU1U72t4zL11kHvoa0/RuFZjncvlr42X7be7lYh4p3NAgMBAAECgYASk5wDw" 70 + "4Az2ZkmeuN6Fk/y9H+Lcb2pskJIXjrL533vrDWGOC48LrsThMQPv8cxBky8HFSEklPpkfTF95tpD43iVwJRB/Gr" 71 + "CtGTw65IfJ4/tI09h6zGc4yqvIo1cHX/LQ+SxKLGyir/dQM925rGt/VojxY5ryJR7GLbCzxPnJm/oQJBANwOCO6" 72 + "D2hy1LQYJhXh7O+RLtA/tSnT1xyMQsGT+uUCMiKS2bSKx2wxo9k7h3OegNJIu1q6nZ6AbxDK8H3+d0dUCQQDTrP" 73 + "SXagBxzp8PecbaCHjzNRSQE2in81qYnrAFNB4o3DpHyMMY6s5ALLeHKscEWnqP8Ur6X4PvzZecCWU9BKAZAkAut" 74 + "LPknAuxSCsUOvUfS1i87ex77Ot+w6POp34pEX+UWb+u5iFn2cQacDTHLV1LtE80L8jVLSbrbrlH43H0DjU5AkEA" 75 + "gidhycxS86dxpEljnOMCw8CKoUBd5I880IUahEiUltk7OLJYS/Ts1wbn3kPOVX3wyJs8WBDtBkFrDHW2ezth2QJ" 76 + "ADj3e1YhMVdjJW5jqwlD/VNddGjgzyunmiZg0uOXsHXbytYmsA545S8KRQFaJKFXYYFo2kOjqOiC1T2cAzMDjCQ" 77 + "==\n-----END PRIVATE KEY-----\n"; 78 private static final String PROJECT_ID = "project-id"; 79 private static final String SERVICE_IDENTITY_NAME = "service-identity-name"; 80 private static final String ACCESS_TOKEN = "1/MkSJoj1xsli0AccessToken_NKPY2"; 81 private static final URI TOKEN_SERVER_URI = 82 URI.create("https://service-identity.domain/authenticate"); 83 private static final String CA_CERT_FILE_NAME = "cert.pem"; 84 private static final String CA_CERT_PATH = 85 GdchCredentialsTest.class.getClassLoader().getResource(CA_CERT_FILE_NAME).getPath(); 86 private static final URI API_AUDIENCE = URI.create("https://gdch-api-audience"); 87 private static final URI CALL_URI = URI.create("http://googleapis.com/testapi/v1/foo"); 88 89 @Test fromJSON_getProjectId()90 public void fromJSON_getProjectId() throws IOException { 91 GenericJson json = 92 writeGdchServiceAccountJson( 93 FORMAT_VERSION, 94 PROJECT_ID, 95 PRIVATE_KEY_ID, 96 PRIVATE_KEY_PKCS8, 97 SERVICE_IDENTITY_NAME, 98 CA_CERT_PATH, 99 TOKEN_SERVER_URI); 100 GdchCredentials credentials = GdchCredentials.fromJson(json); 101 102 assertEquals(PROJECT_ID, credentials.getProjectId()); 103 } 104 105 @Test fromJSON_getServiceIdentityName()106 public void fromJSON_getServiceIdentityName() throws IOException { 107 GenericJson json = 108 writeGdchServiceAccountJson( 109 FORMAT_VERSION, 110 PROJECT_ID, 111 PRIVATE_KEY_ID, 112 PRIVATE_KEY_PKCS8, 113 SERVICE_IDENTITY_NAME, 114 CA_CERT_PATH, 115 TOKEN_SERVER_URI); 116 GdchCredentials credentials = GdchCredentials.fromJson(json); 117 118 assertEquals(SERVICE_IDENTITY_NAME, credentials.getServiceIdentityName()); 119 } 120 121 @Test fromJSON_getCaCertPath()122 public void fromJSON_getCaCertPath() throws IOException { 123 GenericJson json = 124 writeGdchServiceAccountJson( 125 FORMAT_VERSION, 126 PROJECT_ID, 127 PRIVATE_KEY_ID, 128 PRIVATE_KEY_PKCS8, 129 SERVICE_IDENTITY_NAME, 130 CA_CERT_PATH, 131 TOKEN_SERVER_URI); 132 GdchCredentials credentials = GdchCredentials.fromJson(json); 133 134 assertEquals(CA_CERT_PATH, credentials.getCaCertPath()); 135 } 136 137 @Test fromJSON_getTokenServerUri()138 public void fromJSON_getTokenServerUri() throws IOException { 139 GenericJson json = 140 writeGdchServiceAccountJson( 141 FORMAT_VERSION, 142 PROJECT_ID, 143 PRIVATE_KEY_ID, 144 PRIVATE_KEY_PKCS8, 145 SERVICE_IDENTITY_NAME, 146 CA_CERT_PATH, 147 TOKEN_SERVER_URI); 148 GdchCredentials credentials = GdchCredentials.fromJson(json); 149 150 assertEquals(TOKEN_SERVER_URI, credentials.getTokenServerUri()); 151 } 152 153 @Test fromJSON_nullFormatVersion()154 public void fromJSON_nullFormatVersion() throws IOException { 155 GenericJson json = 156 writeGdchServiceAccountJson( 157 null, 158 PROJECT_ID, 159 PRIVATE_KEY_ID, 160 PRIVATE_KEY_PKCS8, 161 SERVICE_IDENTITY_NAME, 162 CA_CERT_PATH, 163 TOKEN_SERVER_URI); 164 165 try { 166 GdchCredentials credentials = GdchCredentials.fromJson(json); 167 fail("Should not be able to create GDCH credential without exception."); 168 } catch (IOException ex) { 169 assertTrue( 170 ex.getMessage() 171 .contains( 172 String.format( 173 "Error reading GDCH service account credential from JSON, " 174 + "%s is misconfigured.", 175 "format_version"))); 176 } 177 } 178 179 @Test fromJSON_nullProjectId()180 public void fromJSON_nullProjectId() throws IOException { 181 GenericJson json = 182 writeGdchServiceAccountJson( 183 FORMAT_VERSION, 184 null, 185 PRIVATE_KEY_ID, 186 PRIVATE_KEY_PKCS8, 187 SERVICE_IDENTITY_NAME, 188 CA_CERT_PATH, 189 TOKEN_SERVER_URI); 190 191 try { 192 GdchCredentials credentials = GdchCredentials.fromJson(json); 193 fail("Should not be able to create GDCH credential without exception."); 194 } catch (IOException ex) { 195 assertTrue( 196 ex.getMessage() 197 .contains( 198 String.format( 199 "Error reading GDCH service account credential from JSON, " 200 + "%s is misconfigured.", 201 "project"))); 202 } 203 } 204 205 @Test fromJSON_nullPrivateKeyId()206 public void fromJSON_nullPrivateKeyId() throws IOException { 207 GenericJson json = 208 writeGdchServiceAccountJson( 209 FORMAT_VERSION, 210 PROJECT_ID, 211 null, 212 PRIVATE_KEY_PKCS8, 213 SERVICE_IDENTITY_NAME, 214 CA_CERT_PATH, 215 TOKEN_SERVER_URI); 216 217 try { 218 GdchCredentials credentials = GdchCredentials.fromJson(json); 219 fail("Should not be able to create GDCH credential without exception."); 220 } catch (IOException ex) { 221 assertTrue( 222 ex.getMessage() 223 .contains( 224 String.format( 225 "Error reading GDCH service account credential from JSON, " 226 + "%s is misconfigured.", 227 "private_key_id"))); 228 } 229 } 230 231 @Test fromJSON_nullPrivateKey()232 public void fromJSON_nullPrivateKey() throws IOException { 233 GenericJson json = 234 writeGdchServiceAccountJson( 235 FORMAT_VERSION, 236 PROJECT_ID, 237 PRIVATE_KEY_ID, 238 null, 239 SERVICE_IDENTITY_NAME, 240 CA_CERT_PATH, 241 TOKEN_SERVER_URI); 242 243 try { 244 GdchCredentials credentials = GdchCredentials.fromJson(json); 245 fail("Should not be able to create GDCH credential without exception."); 246 } catch (IOException ex) { 247 assertTrue( 248 ex.getMessage() 249 .contains( 250 String.format( 251 "Error reading GDCH service account credential from JSON, " 252 + "%s is misconfigured.", 253 "private_key"))); 254 } 255 } 256 257 @Test fromJSON_nullServiceIdentityName()258 public void fromJSON_nullServiceIdentityName() throws IOException { 259 GenericJson json = 260 writeGdchServiceAccountJson( 261 FORMAT_VERSION, 262 PROJECT_ID, 263 PRIVATE_KEY_ID, 264 PRIVATE_KEY_PKCS8, 265 null, 266 CA_CERT_PATH, 267 TOKEN_SERVER_URI); 268 269 try { 270 GdchCredentials credentials = GdchCredentials.fromJson(json); 271 fail("Should not be able to create GDCH credential without exception."); 272 } catch (IOException ex) { 273 assertTrue( 274 ex.getMessage() 275 .contains( 276 String.format( 277 "Error reading GDCH service account credential from JSON, " 278 + "%s is misconfigured.", 279 "name"))); 280 } 281 } 282 283 @Test fromJSON_nullCaCertPath()284 public void fromJSON_nullCaCertPath() throws IOException { 285 GenericJson json = 286 writeGdchServiceAccountJson( 287 FORMAT_VERSION, 288 PROJECT_ID, 289 PRIVATE_KEY_ID, 290 PRIVATE_KEY_PKCS8, 291 SERVICE_IDENTITY_NAME, 292 null, 293 TOKEN_SERVER_URI); 294 GdchCredentials credentials = GdchCredentials.fromJson(json); 295 assertNull(credentials.getCaCertPath()); 296 } 297 298 @Test fromJSON_nullTokenServerUri()299 public void fromJSON_nullTokenServerUri() throws IOException { 300 GenericJson json = 301 writeGdchServiceAccountJson( 302 FORMAT_VERSION, 303 PROJECT_ID, 304 PRIVATE_KEY_ID, 305 PRIVATE_KEY_PKCS8, 306 SERVICE_IDENTITY_NAME, 307 CA_CERT_PATH, 308 null); 309 310 try { 311 GdchCredentials credentials = GdchCredentials.fromJson(json); 312 fail("Should not be able to create GDCH credential without exception."); 313 } catch (IOException ex) { 314 assertTrue( 315 ex.getMessage() 316 .contains( 317 String.format( 318 "Error reading GDCH service account credential from JSON, " 319 + "%s is misconfigured.", 320 "token_uri"))); 321 } 322 } 323 324 @Test fromJSON_invalidFormatVersion()325 public void fromJSON_invalidFormatVersion() throws IOException { 326 GenericJson json = 327 writeGdchServiceAccountJson( 328 "100", 329 PROJECT_ID, 330 PRIVATE_KEY_ID, 331 PRIVATE_KEY_PKCS8, 332 SERVICE_IDENTITY_NAME, 333 CA_CERT_PATH, 334 TOKEN_SERVER_URI); 335 336 try { 337 GdchCredentials credentials = GdchCredentials.fromJson(json); 338 fail("Should not be able to create GDCH credential without exception."); 339 } catch (IOException ex) { 340 assertTrue( 341 ex.getMessage() 342 .contains(String.format("Only format version %s is supported", FORMAT_VERSION))); 343 } 344 } 345 346 @Test fromJSON_invalidCaCertPath()347 public void fromJSON_invalidCaCertPath() throws IOException { 348 GenericJson json = 349 writeGdchServiceAccountJson( 350 FORMAT_VERSION, 351 PROJECT_ID, 352 PRIVATE_KEY_ID, 353 PRIVATE_KEY_PKCS8, 354 SERVICE_IDENTITY_NAME, 355 "/path/to/missing/file", 356 TOKEN_SERVER_URI); 357 358 try { 359 GdchCredentials credentials = GdchCredentials.fromJson(json); 360 fail("Should not be able to create GDCH credential without exception."); 361 } catch (IOException ex) { 362 assertTrue(ex.getMessage().contains("Error reading certificate file from CA cert path")); 363 } 364 } 365 366 @Test fromJSON_emptyCaCertPath()367 public void fromJSON_emptyCaCertPath() throws IOException { 368 GenericJson json = 369 writeGdchServiceAccountJson( 370 FORMAT_VERSION, 371 PROJECT_ID, 372 PRIVATE_KEY_ID, 373 PRIVATE_KEY_PKCS8, 374 SERVICE_IDENTITY_NAME, 375 "", 376 TOKEN_SERVER_URI); 377 GdchCredentials credentials = GdchCredentials.fromJson(json); 378 assertEquals("", credentials.getCaCertPath()); 379 } 380 381 @Test fromJSON_transportFactoryForGdch()382 public void fromJSON_transportFactoryForGdch() throws IOException { 383 GenericJson json = 384 writeGdchServiceAccountJson( 385 FORMAT_VERSION, 386 PROJECT_ID, 387 PRIVATE_KEY_ID, 388 PRIVATE_KEY_PKCS8, 389 SERVICE_IDENTITY_NAME, 390 CA_CERT_PATH, 391 TOKEN_SERVER_URI); 392 GdchCredentials credentials = GdchCredentials.fromJson(json); 393 assertEquals( 394 GdchCredentials.TransportFactoryForGdch.class, 395 credentials.getTransportFactory().getClass()); 396 } 397 398 @Test fromJSON_hasAccessToken()399 public void fromJSON_hasAccessToken() throws IOException { 400 MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); 401 GenericJson json = 402 writeGdchServiceAccountJson( 403 FORMAT_VERSION, 404 PROJECT_ID, 405 PRIVATE_KEY_ID, 406 PRIVATE_KEY_PKCS8, 407 SERVICE_IDENTITY_NAME, 408 CA_CERT_PATH, 409 TOKEN_SERVER_URI); 410 GdchCredentials credentials = GdchCredentials.fromJson(json, transportFactory); 411 GdchCredentials gdchWithAudience = credentials.createWithGdchAudience(API_AUDIENCE); 412 transportFactory.transport.addGdchServiceAccount( 413 GdchCredentials.getIssuerSubjectValue(PROJECT_ID, SERVICE_IDENTITY_NAME), ACCESS_TOKEN); 414 transportFactory.transport.setTokenServerUri(TOKEN_SERVER_URI); 415 Map<String, List<String>> metadata = gdchWithAudience.getRequestMetadata(CALL_URI); 416 TestUtils.assertContainsBearerToken(metadata, ACCESS_TOKEN); 417 } 418 419 @Test createWithGdchAudience_correct()420 public void createWithGdchAudience_correct() throws IOException { 421 GenericJson json = 422 writeGdchServiceAccountJson( 423 FORMAT_VERSION, 424 PROJECT_ID, 425 PRIVATE_KEY_ID, 426 PRIVATE_KEY_PKCS8, 427 SERVICE_IDENTITY_NAME, 428 CA_CERT_PATH, 429 TOKEN_SERVER_URI); 430 GdchCredentials credentials = GdchCredentials.fromJson(json); 431 432 assertEquals(PROJECT_ID, credentials.getProjectId()); 433 assertEquals(SERVICE_IDENTITY_NAME, credentials.getServiceIdentityName()); 434 assertEquals(TOKEN_SERVER_URI, credentials.getTokenServerUri()); 435 assertEquals(CA_CERT_PATH, credentials.getCaCertPath()); 436 assertNull(credentials.getApiAudience()); 437 438 GdchCredentials gdchWithAudience = credentials.createWithGdchAudience(API_AUDIENCE); 439 440 assertEquals(PROJECT_ID, gdchWithAudience.getProjectId()); 441 assertEquals(SERVICE_IDENTITY_NAME, gdchWithAudience.getServiceIdentityName()); 442 assertEquals(TOKEN_SERVER_URI, gdchWithAudience.getTokenServerUri()); 443 assertEquals(CA_CERT_PATH, credentials.getCaCertPath()); 444 assertEquals(API_AUDIENCE, gdchWithAudience.getApiAudience()); 445 } 446 447 @Test createWithGdchAudience_nullApiAudience()448 public void createWithGdchAudience_nullApiAudience() throws IOException { 449 GenericJson json = 450 writeGdchServiceAccountJson( 451 FORMAT_VERSION, 452 PROJECT_ID, 453 PRIVATE_KEY_ID, 454 PRIVATE_KEY_PKCS8, 455 SERVICE_IDENTITY_NAME, 456 CA_CERT_PATH, 457 TOKEN_SERVER_URI); 458 GdchCredentials credentials = GdchCredentials.fromJson(json); 459 460 try { 461 GdchCredentials gdchWithAudience = credentials.createWithGdchAudience(null); 462 fail("Should not be able to create GDCH credential without exception."); 463 } catch (NullPointerException ex) { 464 assertTrue(ex.getMessage().contains("Audience are not configured for GDCH service account")); 465 } 466 } 467 468 @Test createAssertion_correct()469 public void createAssertion_correct() throws IOException { 470 GenericJson json = 471 writeGdchServiceAccountJson( 472 FORMAT_VERSION, 473 PROJECT_ID, 474 PRIVATE_KEY_ID, 475 PRIVATE_KEY_PKCS8, 476 SERVICE_IDENTITY_NAME, 477 CA_CERT_PATH, 478 TOKEN_SERVER_URI); 479 GdchCredentials credentials = GdchCredentials.fromJson(json); 480 JsonFactory jsonFactory = OAuth2Utils.JSON_FACTORY; 481 long currentTimeMillis = Clock.SYSTEM.currentTimeMillis(); 482 String assertion = credentials.createAssertion(jsonFactory, currentTimeMillis, API_AUDIENCE); 483 484 JsonWebSignature signature = JsonWebSignature.parse(jsonFactory, assertion); 485 JsonWebToken.Payload payload = signature.getPayload(); 486 487 String expectedIssSubValue = 488 GdchCredentials.getIssuerSubjectValue(PROJECT_ID, SERVICE_IDENTITY_NAME); 489 assertEquals(expectedIssSubValue, payload.getIssuer()); 490 assertEquals(expectedIssSubValue, payload.getSubject()); 491 assertEquals(TOKEN_SERVER_URI.toString(), payload.getAudience()); 492 assertEquals(currentTimeMillis / 1000, (long) payload.getIssuedAtTimeSeconds()); 493 assertEquals(currentTimeMillis / 1000 + 3600, (long) payload.getExpirationTimeSeconds()); 494 } 495 496 @Test refreshAccessToken_correct()497 public void refreshAccessToken_correct() throws IOException { 498 final String tokenString = "1/MkSJoj1xsli0AccessToken_NKPY2"; 499 MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); 500 GenericJson json = 501 writeGdchServiceAccountJson( 502 FORMAT_VERSION, 503 PROJECT_ID, 504 PRIVATE_KEY_ID, 505 PRIVATE_KEY_PKCS8, 506 SERVICE_IDENTITY_NAME, 507 CA_CERT_PATH, 508 TOKEN_SERVER_URI); 509 GdchCredentials credentials = GdchCredentials.fromJson(json, transportFactory); 510 GdchCredentials gdchWithAudience = credentials.createWithGdchAudience(API_AUDIENCE); 511 512 GdchCredentialsTestUtil.registerGdchCredentialWithMockTransport( 513 gdchWithAudience, 514 transportFactory.transport, 515 PROJECT_ID, 516 SERVICE_IDENTITY_NAME, 517 tokenString, 518 TOKEN_SERVER_URI); 519 520 AccessToken accessToken = gdchWithAudience.refreshAccessToken(); 521 assertNotNull(accessToken); 522 assertEquals(tokenString, accessToken.getTokenValue()); 523 assertEquals(3600 * 1000L, accessToken.getExpirationTimeMillis().longValue()); 524 525 // Test for large expires_in values (should not overflow). 526 transportFactory.transport.setExpiresInSeconds(3600 * 1000); 527 accessToken = gdchWithAudience.refreshAccessToken(); 528 assertNotNull(accessToken); 529 assertEquals(tokenString, accessToken.getTokenValue()); 530 assertEquals(3600 * 1000 * 1000L, accessToken.getExpirationTimeMillis().longValue()); 531 } 532 533 @Test refreshAccessToken_nullApiAudience()534 public void refreshAccessToken_nullApiAudience() throws IOException { 535 final String tokenString = "1/MkSJoj1xsli0AccessToken_NKPY2"; 536 MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); 537 GenericJson json = 538 writeGdchServiceAccountJson( 539 FORMAT_VERSION, 540 PROJECT_ID, 541 PRIVATE_KEY_ID, 542 PRIVATE_KEY_PKCS8, 543 SERVICE_IDENTITY_NAME, 544 CA_CERT_PATH, 545 TOKEN_SERVER_URI); 546 GdchCredentials credentials = GdchCredentials.fromJson(json, transportFactory); 547 548 credentials.clock = new FixedClock(0L); 549 550 transportFactory.transport.addGdchServiceAccount( 551 GdchCredentials.getIssuerSubjectValue(PROJECT_ID, SERVICE_IDENTITY_NAME), tokenString); 552 transportFactory.transport.setTokenServerUri(TOKEN_SERVER_URI); 553 try { 554 AccessToken accessToken = credentials.refreshAccessToken(); 555 fail("Should not be able to refresh access token without exception."); 556 } catch (NullPointerException ex) { 557 assertTrue( 558 ex.getMessage() 559 .contains( 560 "Audience are not configured for GDCH service account. Specify the " 561 + "audience by calling createWithGDCHAudience")); 562 } 563 } 564 565 @Test getIssuerSubjectValue_correct()566 public void getIssuerSubjectValue_correct() throws IOException { 567 GenericJson json = 568 writeGdchServiceAccountJson( 569 FORMAT_VERSION, 570 PROJECT_ID, 571 PRIVATE_KEY_ID, 572 PRIVATE_KEY_PKCS8, 573 SERVICE_IDENTITY_NAME, 574 CA_CERT_PATH, 575 TOKEN_SERVER_URI); 576 GdchCredentials credentials = GdchCredentials.fromJson(json); 577 Object expectedIssSubValue = 578 String.format("system:serviceaccount:%s:%s", PROJECT_ID, SERVICE_IDENTITY_NAME); 579 assertEquals( 580 expectedIssSubValue, 581 GdchCredentials.getIssuerSubjectValue(PROJECT_ID, SERVICE_IDENTITY_NAME)); 582 } 583 584 @Test equals_same()585 public void equals_same() throws IOException { 586 GenericJson json = 587 writeGdchServiceAccountJson( 588 FORMAT_VERSION, 589 PROJECT_ID, 590 PRIVATE_KEY_ID, 591 PRIVATE_KEY_PKCS8, 592 SERVICE_IDENTITY_NAME, 593 CA_CERT_PATH, 594 TOKEN_SERVER_URI); 595 OAuth2Credentials credentials = GdchCredentials.fromJson(json); 596 GenericJson otherJson = 597 writeGdchServiceAccountJson( 598 FORMAT_VERSION, 599 PROJECT_ID, 600 PRIVATE_KEY_ID, 601 PRIVATE_KEY_PKCS8, 602 SERVICE_IDENTITY_NAME, 603 CA_CERT_PATH, 604 TOKEN_SERVER_URI); 605 OAuth2Credentials otherCredentials = GdchCredentials.fromJson(otherJson); 606 assertTrue(credentials.equals(otherCredentials)); 607 assertTrue(otherCredentials.equals(credentials)); 608 609 credentials = ((GdchCredentials) credentials).createWithGdchAudience(API_AUDIENCE); 610 otherCredentials = ((GdchCredentials) otherCredentials).createWithGdchAudience(API_AUDIENCE); 611 assertTrue(credentials.equals(otherCredentials)); 612 assertTrue(otherCredentials.equals(credentials)); 613 } 614 615 @Test equals_false_projectId()616 public void equals_false_projectId() throws IOException { 617 GenericJson json = 618 writeGdchServiceAccountJson( 619 FORMAT_VERSION, 620 PROJECT_ID, 621 PRIVATE_KEY_ID, 622 PRIVATE_KEY_PKCS8, 623 SERVICE_IDENTITY_NAME, 624 CA_CERT_PATH, 625 TOKEN_SERVER_URI); 626 OAuth2Credentials credentials = GdchCredentials.fromJson(json); 627 GenericJson otherJson = 628 writeGdchServiceAccountJson( 629 FORMAT_VERSION, 630 "otherProjectId", 631 PRIVATE_KEY_ID, 632 PRIVATE_KEY_PKCS8, 633 SERVICE_IDENTITY_NAME, 634 CA_CERT_PATH, 635 TOKEN_SERVER_URI); 636 OAuth2Credentials otherCredentials = GdchCredentials.fromJson(otherJson); 637 assertFalse(credentials.equals(otherCredentials)); 638 assertFalse(otherCredentials.equals(credentials)); 639 640 credentials = ((GdchCredentials) credentials).createWithGdchAudience(API_AUDIENCE); 641 otherCredentials = ((GdchCredentials) otherCredentials).createWithGdchAudience(API_AUDIENCE); 642 assertFalse(credentials.equals(otherCredentials)); 643 assertFalse(otherCredentials.equals(credentials)); 644 } 645 646 @Test equals_false_keyId()647 public void equals_false_keyId() throws IOException { 648 GenericJson json = 649 writeGdchServiceAccountJson( 650 FORMAT_VERSION, 651 PROJECT_ID, 652 PRIVATE_KEY_ID, 653 PRIVATE_KEY_PKCS8, 654 SERVICE_IDENTITY_NAME, 655 CA_CERT_PATH, 656 TOKEN_SERVER_URI); 657 OAuth2Credentials credentials = GdchCredentials.fromJson(json); 658 GenericJson otherJson = 659 writeGdchServiceAccountJson( 660 FORMAT_VERSION, 661 PROJECT_ID, 662 "otherId", 663 PRIVATE_KEY_PKCS8, 664 SERVICE_IDENTITY_NAME, 665 CA_CERT_PATH, 666 TOKEN_SERVER_URI); 667 OAuth2Credentials otherCredentials = GdchCredentials.fromJson(otherJson); 668 assertFalse(credentials.equals(otherCredentials)); 669 assertFalse(otherCredentials.equals(credentials)); 670 671 credentials = ((GdchCredentials) credentials).createWithGdchAudience(API_AUDIENCE); 672 otherCredentials = ((GdchCredentials) otherCredentials).createWithGdchAudience(API_AUDIENCE); 673 assertFalse(credentials.equals(otherCredentials)); 674 assertFalse(otherCredentials.equals(credentials)); 675 } 676 677 @Test equals_false_serviceIdentityName()678 public void equals_false_serviceIdentityName() throws IOException { 679 GenericJson json = 680 writeGdchServiceAccountJson( 681 FORMAT_VERSION, 682 PROJECT_ID, 683 PRIVATE_KEY_ID, 684 PRIVATE_KEY_PKCS8, 685 SERVICE_IDENTITY_NAME, 686 CA_CERT_PATH, 687 TOKEN_SERVER_URI); 688 OAuth2Credentials credentials = GdchCredentials.fromJson(json); 689 GenericJson otherJson = 690 writeGdchServiceAccountJson( 691 FORMAT_VERSION, 692 PROJECT_ID, 693 PRIVATE_KEY_ID, 694 PRIVATE_KEY_PKCS8, 695 "otherServiceIdentityName", 696 CA_CERT_PATH, 697 TOKEN_SERVER_URI); 698 OAuth2Credentials otherCredentials = GdchCredentials.fromJson(otherJson); 699 assertFalse(credentials.equals(otherCredentials)); 700 assertFalse(otherCredentials.equals(credentials)); 701 702 credentials = ((GdchCredentials) credentials).createWithGdchAudience(API_AUDIENCE); 703 otherCredentials = ((GdchCredentials) otherCredentials).createWithGdchAudience(API_AUDIENCE); 704 assertFalse(credentials.equals(otherCredentials)); 705 assertFalse(otherCredentials.equals(credentials)); 706 } 707 708 @Test equals_false_caCertPath()709 public void equals_false_caCertPath() throws IOException { 710 File tmpDirectory = Files.createTempDirectory("tmpDirectory").toFile(); 711 File testCaCertFile = File.createTempFile("testCert", ".pem", tmpDirectory); 712 GenericJson json = 713 writeGdchServiceAccountJson( 714 FORMAT_VERSION, 715 PROJECT_ID, 716 PRIVATE_KEY_ID, 717 PRIVATE_KEY_PKCS8, 718 SERVICE_IDENTITY_NAME, 719 CA_CERT_PATH, 720 TOKEN_SERVER_URI); 721 OAuth2Credentials credentials = GdchCredentials.fromJson(json); 722 GenericJson otherJson = 723 writeGdchServiceAccountJson( 724 FORMAT_VERSION, 725 PROJECT_ID, 726 PRIVATE_KEY_ID, 727 PRIVATE_KEY_PKCS8, 728 SERVICE_IDENTITY_NAME, 729 testCaCertFile.getPath(), 730 TOKEN_SERVER_URI); 731 OAuth2Credentials otherCredentials = GdchCredentials.fromJson(otherJson); 732 assertFalse(credentials.equals(otherCredentials)); 733 assertFalse(otherCredentials.equals(credentials)); 734 735 credentials = ((GdchCredentials) credentials).createWithGdchAudience(API_AUDIENCE); 736 otherCredentials = ((GdchCredentials) otherCredentials).createWithGdchAudience(API_AUDIENCE); 737 assertFalse(credentials.equals(otherCredentials)); 738 assertFalse(otherCredentials.equals(credentials)); 739 740 testCaCertFile.delete(); 741 } 742 743 @Test equals_false_tokenServer()744 public void equals_false_tokenServer() throws IOException { 745 GenericJson json = 746 writeGdchServiceAccountJson( 747 FORMAT_VERSION, 748 PROJECT_ID, 749 PRIVATE_KEY_ID, 750 PRIVATE_KEY_PKCS8, 751 SERVICE_IDENTITY_NAME, 752 CA_CERT_PATH, 753 TOKEN_SERVER_URI); 754 OAuth2Credentials credentials = GdchCredentials.fromJson(json); 755 GenericJson otherJson = 756 writeGdchServiceAccountJson( 757 FORMAT_VERSION, 758 PROJECT_ID, 759 PRIVATE_KEY_ID, 760 PRIVATE_KEY_PKCS8, 761 SERVICE_IDENTITY_NAME, 762 CA_CERT_PATH, 763 URI.create("https://foo1.com/bar")); 764 OAuth2Credentials otherCredentials = GdchCredentials.fromJson(otherJson); 765 assertFalse(credentials.equals(otherCredentials)); 766 assertFalse(otherCredentials.equals(credentials)); 767 768 credentials = ((GdchCredentials) credentials).createWithGdchAudience(API_AUDIENCE); 769 otherCredentials = ((GdchCredentials) otherCredentials).createWithGdchAudience(API_AUDIENCE); 770 assertFalse(credentials.equals(otherCredentials)); 771 assertFalse(otherCredentials.equals(credentials)); 772 } 773 774 @Test equals_false_apiAudience()775 public void equals_false_apiAudience() throws IOException { 776 URI otherApiAudience = URI.create("https://foo1.com/bar"); 777 778 GenericJson json = 779 writeGdchServiceAccountJson( 780 FORMAT_VERSION, 781 PROJECT_ID, 782 PRIVATE_KEY_ID, 783 PRIVATE_KEY_PKCS8, 784 SERVICE_IDENTITY_NAME, 785 CA_CERT_PATH, 786 TOKEN_SERVER_URI); 787 OAuth2Credentials credentials = GdchCredentials.fromJson(json); 788 GenericJson otherJson = 789 writeGdchServiceAccountJson( 790 FORMAT_VERSION, 791 PROJECT_ID, 792 PRIVATE_KEY_ID, 793 PRIVATE_KEY_PKCS8, 794 SERVICE_IDENTITY_NAME, 795 CA_CERT_PATH, 796 TOKEN_SERVER_URI); 797 OAuth2Credentials otherCredentials = GdchCredentials.fromJson(otherJson); 798 799 credentials = ((GdchCredentials) credentials).createWithGdchAudience(API_AUDIENCE); 800 otherCredentials = 801 ((GdchCredentials) otherCredentials).createWithGdchAudience(otherApiAudience); 802 assertFalse(credentials.equals(otherCredentials)); 803 assertFalse(otherCredentials.equals(credentials)); 804 } 805 806 @Test toString_containsFields()807 public void toString_containsFields() throws IOException { 808 GenericJson json = 809 writeGdchServiceAccountJson( 810 FORMAT_VERSION, 811 PROJECT_ID, 812 PRIVATE_KEY_ID, 813 PRIVATE_KEY_PKCS8, 814 SERVICE_IDENTITY_NAME, 815 CA_CERT_PATH, 816 TOKEN_SERVER_URI); 817 OAuth2Credentials credentials = GdchCredentials.fromJson(json); 818 credentials = ((GdchCredentials) credentials).createWithGdchAudience(API_AUDIENCE); 819 String expectedToString = 820 String.format( 821 "GdchCredentials{projectId=%s, privateKeyId=%s, serviceIdentityName=%s, " 822 + "tokenServerUri=%s, transportFactoryClassName=%s, caCertPath=%s, apiAudience=%s, lifetime=3600}", 823 PROJECT_ID, 824 PRIVATE_KEY_ID, 825 SERVICE_IDENTITY_NAME, 826 TOKEN_SERVER_URI, 827 GdchCredentials.TransportFactoryForGdch.class.getName(), 828 CA_CERT_PATH, 829 API_AUDIENCE); 830 assertEquals(expectedToString, credentials.toString()); 831 } 832 833 @Test hashCode_equals()834 public void hashCode_equals() throws IOException { 835 GenericJson json = 836 writeGdchServiceAccountJson( 837 FORMAT_VERSION, 838 PROJECT_ID, 839 PRIVATE_KEY_ID, 840 PRIVATE_KEY_PKCS8, 841 SERVICE_IDENTITY_NAME, 842 CA_CERT_PATH, 843 TOKEN_SERVER_URI); 844 OAuth2Credentials credentials = GdchCredentials.fromJson(json); 845 GenericJson otherJson = 846 writeGdchServiceAccountJson( 847 FORMAT_VERSION, 848 PROJECT_ID, 849 PRIVATE_KEY_ID, 850 PRIVATE_KEY_PKCS8, 851 SERVICE_IDENTITY_NAME, 852 CA_CERT_PATH, 853 TOKEN_SERVER_URI); 854 OAuth2Credentials otherCredentials = GdchCredentials.fromJson(otherJson); 855 assertEquals(credentials.hashCode(), otherCredentials.hashCode()); 856 857 credentials = ((GdchCredentials) credentials).createWithGdchAudience(API_AUDIENCE); 858 otherCredentials = ((GdchCredentials) otherCredentials).createWithGdchAudience(API_AUDIENCE); 859 assertEquals(credentials.hashCode(), otherCredentials.hashCode()); 860 } 861 862 @Test serialize_correct()863 public void serialize_correct() throws IOException, ClassNotFoundException { 864 MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); 865 GenericJson json = 866 writeGdchServiceAccountJson( 867 FORMAT_VERSION, 868 PROJECT_ID, 869 PRIVATE_KEY_ID, 870 PRIVATE_KEY_PKCS8, 871 SERVICE_IDENTITY_NAME, 872 CA_CERT_PATH, 873 TOKEN_SERVER_URI); 874 GdchCredentials credentials = GdchCredentials.fromJson(json, transportFactory); 875 credentials = credentials.createWithGdchAudience(API_AUDIENCE); 876 877 GdchCredentials deserializedCredentials = serializeAndDeserialize(credentials); 878 assertEquals(credentials, deserializedCredentials); 879 assertEquals(credentials.hashCode(), deserializedCredentials.hashCode()); 880 assertEquals(credentials.toString(), deserializedCredentials.toString()); 881 assertSame(deserializedCredentials.clock, Clock.SYSTEM); 882 assertEquals( 883 MockTokenServerTransportFactory.class, 884 deserializedCredentials.toBuilder().getHttpTransportFactory().getClass()); 885 } 886 writeGdchServiceAccountJson( String formatVersion, String project, String privateKeyId, String privateKeyPkcs8, String serviceIdentityName, String caCertPath, URI tokenServerUri)887 static GenericJson writeGdchServiceAccountJson( 888 String formatVersion, 889 String project, 890 String privateKeyId, 891 String privateKeyPkcs8, 892 String serviceIdentityName, 893 String caCertPath, 894 URI tokenServerUri) { 895 GenericJson json = new GenericJson(); 896 897 if (formatVersion != null) { 898 json.put("format_version", formatVersion); 899 } 900 if (project != null) { 901 json.put("project", project); 902 } 903 if (privateKeyId != null) { 904 json.put("private_key_id", privateKeyId); 905 } 906 if (privateKeyPkcs8 != null) { 907 json.put("private_key", privateKeyPkcs8); 908 } 909 if (serviceIdentityName != null) { 910 json.put("name", serviceIdentityName); 911 } 912 if (caCertPath != null) { 913 json.put("ca_cert_path", caCertPath); 914 } 915 if (tokenServerUri != null) { 916 json.put("token_uri", tokenServerUri.toString()); 917 } 918 json.put("type", GoogleCredentials.GDCH_SERVICE_ACCOUNT_FILE_TYPE); 919 return json; 920 } 921 writeGdchServiceAccountStream( String formatVersion, String project, String privateKeyId, String privateKeyPkcs8, String serviceIdentityName, String caCertPath, URI tokenServerUri)922 static InputStream writeGdchServiceAccountStream( 923 String formatVersion, 924 String project, 925 String privateKeyId, 926 String privateKeyPkcs8, 927 String serviceIdentityName, 928 String caCertPath, 929 URI tokenServerUri) 930 throws IOException { 931 GenericJson json = 932 writeGdchServiceAccountJson( 933 formatVersion, 934 project, 935 privateKeyId, 936 privateKeyPkcs8, 937 serviceIdentityName, 938 caCertPath, 939 tokenServerUri); 940 return TestUtils.jsonToInputStream(json); 941 } 942 } 943