1 /* 2 * Copyright 2015, 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.http.HttpTransport; 43 import com.google.api.client.http.LowLevelHttpRequest; 44 import com.google.api.client.http.LowLevelHttpResponse; 45 import com.google.api.client.testing.http.MockHttpTransport; 46 import com.google.api.client.testing.http.MockLowLevelHttpRequest; 47 import com.google.auth.TestUtils; 48 import com.google.auth.http.HttpTransportFactory; 49 import com.google.auth.oauth2.ComputeEngineCredentialsTest.MockMetadataServerTransportFactory; 50 import java.io.BufferedReader; 51 import java.io.ByteArrayInputStream; 52 import java.io.File; 53 import java.io.FileNotFoundException; 54 import java.io.IOException; 55 import java.io.InputStream; 56 import java.io.StringReader; 57 import java.net.URI; 58 import java.nio.file.Paths; 59 import java.security.AccessControlException; 60 import java.util.Collection; 61 import java.util.Collections; 62 import java.util.HashMap; 63 import java.util.List; 64 import java.util.Map; 65 import java.util.logging.Handler; 66 import java.util.logging.Level; 67 import java.util.logging.LogRecord; 68 import java.util.logging.Logger; 69 import org.junit.Test; 70 import org.junit.runner.RunWith; 71 import org.junit.runners.JUnit4; 72 73 /** Test case for {@link DefaultCredentialsProvider}. */ 74 @RunWith(JUnit4.class) 75 public class DefaultCredentialsProviderTest { 76 77 private static final String USER_CLIENT_SECRET = "jakuaL9YyieakhECKL2SwZcu"; 78 private static final String USER_CLIENT_ID = "ya29.1.AADtN_UtlxN3PuGAxrN2XQnZTVRvDyVWnYq4I6dws"; 79 private static final String GCLOUDSDK_CLIENT_ID = 80 "764086051850-6qr4p6gpi6hn506pt8ejuq83di341hur.apps.googleusercontent.com"; 81 private static final String REFRESH_TOKEN = "1/Tl6awhpFjkMkSJoj1xsli0H2eL5YsMgU_NKPY2TyGWY"; 82 private static final String ACCESS_TOKEN = "1/MkSJoj1xsli0AccessToken_NKPY2"; 83 private static final String SA_CLIENT_EMAIL = 84 "36680232662-vrd7ji19qe3nelgchd0ah2csanun6bnr@developer.gserviceaccount.com"; 85 private static final String SA_CLIENT_ID = 86 "36680232662-vrd7ji19qe3nelgchd0ah2csanun6bnr.apps.googleusercontent.com"; 87 private static final String SA_PRIVATE_KEY_ID = "d84a4fefcf50791d4a90f2d7af17469d6282df9d"; 88 private static final String SA_PRIVATE_KEY_PKCS8 = 89 ServiceAccountCredentialsTest.PRIVATE_KEY_PKCS8; 90 private static final String GDCH_SA_FORMAT_VERSION = GdchCredentials.SUPPORTED_FORMAT_VERSION; 91 private static final String GDCH_SA_PROJECT_ID = "gdch-service-account-project-id"; 92 private static final String GDCH_SA_PRIVATE_KEY_ID = "d84a4fefcf50791d4a90f2d7af17469d6282df9d"; 93 private static final String GDCH_SA_PRIVATE_KEY_PKC8 = GdchCredentialsTest.PRIVATE_KEY_PKCS8; 94 private static final String GDCH_SA_SERVICE_IDENTITY_NAME = 95 "gdch-service-account-service-identity-name"; 96 private static final URI GDCH_SA_TOKEN_SERVER_URI = 97 URI.create("https://service-identity.domain/authenticate"); 98 private static final String GDCH_SA_CA_CERT_FILE_NAME = "cert.pem"; 99 private static final String GDCH_SA_CA_CERT_PATH = 100 GdchCredentialsTest.class.getClassLoader().getResource(GDCH_SA_CA_CERT_FILE_NAME).getPath(); 101 private static final URI GDCH_SA_API_AUDIENCE = URI.create("https://gdch-api-audience"); 102 private static final Collection<String> SCOPES = Collections.singletonList("dummy.scope"); 103 private static final URI CALL_URI = URI.create("http://googleapis.com/testapi/v1/foo"); 104 private static final String QUOTA_PROJECT = "sample-quota-project-id"; 105 private static final String QUOTA_PROJECT_FROM_ENVIRONMENT = "environment-quota-project-id"; 106 private static final String QUOTA_PROJECT_EXPLICIT = "explicit-quota-project-id"; 107 private static final String SMBIOS_PATH_LINUX = "/sys/class/dmi/id/product_name"; 108 109 @Test getDefaultCredentials_noCredentials_throws()110 public void getDefaultCredentials_noCredentials_throws() { 111 MockHttpTransportFactory transportFactory = new MockHttpTransportFactory(); 112 TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider(); 113 114 try { 115 testProvider.getDefaultCredentials(transportFactory); 116 fail("No credential expected."); 117 } catch (IOException e) { 118 String message = e.getMessage(); 119 assertTrue(message.equals(DefaultCredentialsProvider.CLOUDSDK_MISSING_CREDENTIALS)); 120 } 121 } 122 123 @Test getDefaultCredentials_noCredentialsSandbox_throwsNonSecurity()124 public void getDefaultCredentials_noCredentialsSandbox_throwsNonSecurity() { 125 MockHttpTransportFactory transportFactory = new MockHttpTransportFactory(); 126 TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider(); 127 testProvider.setFileSandbox(true); 128 129 try { 130 testProvider.getDefaultCredentials(transportFactory); 131 fail("No credential expected."); 132 } catch (IOException e) { 133 String message = e.getMessage(); 134 assertTrue(message.equals(DefaultCredentialsProvider.CLOUDSDK_MISSING_CREDENTIALS)); 135 } 136 } 137 138 @Test getDefaultCredentials_envValidSandbox_throwsNonSecurity()139 public void getDefaultCredentials_envValidSandbox_throwsNonSecurity() throws Exception { 140 MockHttpTransportFactory transportFactory = new MockHttpTransportFactory(); 141 InputStream userStream = 142 UserCredentialsTest.writeUserStream( 143 USER_CLIENT_ID, USER_CLIENT_SECRET, REFRESH_TOKEN, QUOTA_PROJECT); 144 TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider(); 145 testProvider.setFileSandbox(true); 146 String userPath = tempFilePath("user.json"); 147 testProvider.addFile(userPath, userStream); 148 testProvider.setEnv(DefaultCredentialsProvider.CREDENTIAL_ENV_VAR, userPath); 149 150 try { 151 testProvider.getDefaultCredentials(transportFactory); 152 fail("No credential expected."); 153 } catch (IOException e) { 154 String message = e.getMessage(); 155 assertTrue(message.equals(DefaultCredentialsProvider.CLOUDSDK_MISSING_CREDENTIALS)); 156 } 157 } 158 159 @Test getDefaultCredentials_noCredentials_singleGceTestRequest()160 public void getDefaultCredentials_noCredentials_singleGceTestRequest() { 161 MockRequestCountingTransportFactory transportFactory = 162 new MockRequestCountingTransportFactory(); 163 TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider(); 164 165 try { 166 testProvider.getDefaultCredentials(transportFactory); 167 fail("No credential expected."); 168 } catch (IOException expected) { 169 String message = expected.getMessage(); 170 assertTrue(message.equals(DefaultCredentialsProvider.CLOUDSDK_MISSING_CREDENTIALS)); 171 } 172 assertEquals( 173 transportFactory.transport.getRequestCount(), 174 ComputeEngineCredentials.MAX_COMPUTE_PING_TRIES); 175 try { 176 testProvider.getDefaultCredentials(transportFactory); 177 fail("No credential expected."); 178 } catch (IOException expected) { 179 // Expected 180 } 181 assertEquals( 182 transportFactory.transport.getRequestCount(), 183 ComputeEngineCredentials.MAX_COMPUTE_PING_TRIES); 184 } 185 186 @Test getDefaultCredentials_noCredentials_linuxNotGce()187 public void getDefaultCredentials_noCredentials_linuxNotGce() throws IOException { 188 TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider(); 189 testProvider.setProperty("os.name", "Linux"); 190 String productFilePath = SMBIOS_PATH_LINUX; 191 InputStream productStream = new ByteArrayInputStream("test".getBytes()); 192 testProvider.addFile(productFilePath, productStream); 193 194 assertFalse(ComputeEngineCredentials.checkStaticGceDetection(testProvider)); 195 } 196 197 @Test getDefaultCredentials_static_linux()198 public void getDefaultCredentials_static_linux() throws IOException { 199 TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider(); 200 testProvider.setProperty("os.name", "Linux"); 201 String productFilePath = SMBIOS_PATH_LINUX; 202 File productFile = new File(productFilePath); 203 InputStream productStream = new ByteArrayInputStream("Googlekdjsfhg".getBytes()); 204 testProvider.addFile(productFile.getAbsolutePath(), productStream); 205 206 assertTrue(ComputeEngineCredentials.checkStaticGceDetection(testProvider)); 207 } 208 209 @Test getDefaultCredentials_static_windows_configuredAsLinux_notGce()210 public void getDefaultCredentials_static_windows_configuredAsLinux_notGce() throws IOException { 211 TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider(); 212 testProvider.setProperty("os.name", "windows"); 213 String productFilePath = SMBIOS_PATH_LINUX; 214 InputStream productStream = new ByteArrayInputStream("Googlekdjsfhg".getBytes()); 215 testProvider.addFile(productFilePath, productStream); 216 217 assertFalse(ComputeEngineCredentials.checkStaticGceDetection(testProvider)); 218 } 219 220 @Test getDefaultCredentials_static_unsupportedPlatform_notGce()221 public void getDefaultCredentials_static_unsupportedPlatform_notGce() throws IOException { 222 TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider(); 223 testProvider.setProperty("os.name", "macos"); 224 String productFilePath = SMBIOS_PATH_LINUX; 225 InputStream productStream = new ByteArrayInputStream("Googlekdjsfhg".getBytes()); 226 testProvider.addFile(productFilePath, productStream); 227 228 assertFalse(ComputeEngineCredentials.checkStaticGceDetection(testProvider)); 229 } 230 231 @Test checkGcpLinuxPlatformData()232 public void checkGcpLinuxPlatformData() throws Exception { 233 BufferedReader reader; 234 reader = new BufferedReader(new StringReader("HP Z440 Workstation")); 235 assertFalse(ComputeEngineCredentials.checkProductNameOnLinux(reader)); 236 reader = new BufferedReader(new StringReader("Google")); 237 assertTrue(ComputeEngineCredentials.checkProductNameOnLinux(reader)); 238 reader = new BufferedReader(new StringReader("Google Compute Engine")); 239 assertTrue(ComputeEngineCredentials.checkProductNameOnLinux(reader)); 240 reader = new BufferedReader(new StringReader("Google Compute Engine ")); 241 assertTrue(ComputeEngineCredentials.checkProductNameOnLinux(reader)); 242 } 243 244 @Test getDefaultCredentials_caches()245 public void getDefaultCredentials_caches() throws IOException { 246 MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); 247 TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider(); 248 249 GoogleCredentials firstCall = testProvider.getDefaultCredentials(transportFactory); 250 GoogleCredentials secondCall = testProvider.getDefaultCredentials(transportFactory); 251 252 assertNotNull(firstCall); 253 assertSame(firstCall, secondCall); 254 } 255 256 @Test getDefaultCredentials_appEngineClassWithoutRuntime_NotFoundError()257 public void getDefaultCredentials_appEngineClassWithoutRuntime_NotFoundError() { 258 MockHttpTransportFactory transportFactory = new MockHttpTransportFactory(); 259 TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider(); 260 testProvider.addType( 261 DefaultCredentialsProvider.APP_ENGINE_SIGNAL_CLASS, MockOffAppEngineSystemProperty.class); 262 testProvider.setProperty("isOnGAEStandard7", "true"); 263 264 try { 265 testProvider.getDefaultCredentials(transportFactory); 266 fail("No credential expected when not on App Engine."); 267 } catch (IOException e) { 268 String message = e.getMessage(); 269 assertTrue(message.equals(DefaultCredentialsProvider.CLOUDSDK_MISSING_CREDENTIALS)); 270 } 271 } 272 273 @Test getDefaultCredentials_appEngineRuntimeWithoutClass_throwsHelpfulLoadError()274 public void getDefaultCredentials_appEngineRuntimeWithoutClass_throwsHelpfulLoadError() { 275 MockHttpTransportFactory transportFactory = new MockHttpTransportFactory(); 276 TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider(); 277 testProvider.addType( 278 DefaultCredentialsProvider.APP_ENGINE_SIGNAL_CLASS, MockAppEngineSystemProperty.class); 279 testProvider.setProperty("isOnGAEStandard7", "true"); 280 281 try { 282 testProvider.getDefaultCredentials(transportFactory); 283 fail("Credential expected to fail to load if credential class not present."); 284 } catch (IOException e) { 285 String message = e.getMessage(); 286 assertFalse(message.equals(DefaultCredentialsProvider.CLOUDSDK_MISSING_CREDENTIALS)); 287 assertTrue(message.contains("Check that the App Engine SDK is deployed.")); 288 } 289 } 290 291 @Test getDefaultCredentials_appEngineSkipWorks_retrievesCloudShellCredential()292 public void getDefaultCredentials_appEngineSkipWorks_retrievesCloudShellCredential() 293 throws IOException { 294 MockHttpTransportFactory transportFactory = new MockHttpTransportFactory(); 295 TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider(); 296 testProvider.addType( 297 DefaultCredentialsProvider.APP_ENGINE_SIGNAL_CLASS, MockOffAppEngineSystemProperty.class); 298 testProvider.setEnv(DefaultCredentialsProvider.CLOUD_SHELL_ENV_VAR, "9090"); 299 testProvider.setEnv(DefaultCredentialsProvider.SKIP_APP_ENGINE_ENV_VAR, "true"); 300 testProvider.setProperty("isOnGAEStanadard7", "true"); 301 GoogleCredentials credentials = testProvider.getDefaultCredentials(transportFactory); 302 assertNotNull(credentials); 303 assertTrue(credentials instanceof CloudShellCredentials); 304 } 305 306 @Test getDefaultCredentials_compute_providesToken()307 public void getDefaultCredentials_compute_providesToken() throws IOException { 308 MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); 309 transportFactory.transport.setAccessToken(ACCESS_TOKEN); 310 TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider(); 311 312 GoogleCredentials defaultCredentials = testProvider.getDefaultCredentials(transportFactory); 313 314 assertNotNull(defaultCredentials); 315 Map<String, List<String>> metadata = defaultCredentials.getRequestMetadata(CALL_URI); 316 TestUtils.assertContainsBearerToken(metadata, ACCESS_TOKEN); 317 } 318 319 @Test getDefaultCredentials_cloudshell()320 public void getDefaultCredentials_cloudshell() throws IOException { 321 MockHttpTransportFactory transportFactory = new MockHttpTransportFactory(); 322 TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider(); 323 testProvider.setEnv(DefaultCredentialsProvider.CLOUD_SHELL_ENV_VAR, "4"); 324 325 GoogleCredentials defaultCredentials = testProvider.getDefaultCredentials(transportFactory); 326 327 assertTrue(defaultCredentials instanceof CloudShellCredentials); 328 assertEquals(((CloudShellCredentials) defaultCredentials).getAuthPort(), 4); 329 } 330 331 @Test getDefaultCredentials_cloudshell_withComputCredentialsPresent()332 public void getDefaultCredentials_cloudshell_withComputCredentialsPresent() throws IOException { 333 MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); 334 transportFactory.transport.setAccessToken(ACCESS_TOKEN); 335 TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider(); 336 testProvider.setEnv(DefaultCredentialsProvider.CLOUD_SHELL_ENV_VAR, "4"); 337 338 GoogleCredentials defaultCredentials = testProvider.getDefaultCredentials(transportFactory); 339 340 assertTrue(defaultCredentials instanceof CloudShellCredentials); 341 assertEquals(((CloudShellCredentials) defaultCredentials).getAuthPort(), 4); 342 } 343 344 @Test getDefaultCredentials_envMissingFile_throws()345 public void getDefaultCredentials_envMissingFile_throws() { 346 final String invalidPath = "/invalid/path"; 347 MockHttpTransportFactory transportFactory = new MockHttpTransportFactory(); 348 TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider(); 349 testProvider.setEnv(DefaultCredentialsProvider.CREDENTIAL_ENV_VAR, invalidPath); 350 351 try { 352 testProvider.getDefaultCredentials(transportFactory); 353 fail("Non existent credential should throw exception"); 354 } catch (IOException e) { 355 String message = e.getMessage(); 356 assertTrue(message.contains(DefaultCredentialsProvider.CREDENTIAL_ENV_VAR)); 357 assertTrue(message.contains(invalidPath)); 358 } 359 } 360 361 @Test getDefaultCredentials_envServiceAccount_providesToken()362 public void getDefaultCredentials_envServiceAccount_providesToken() throws IOException { 363 MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); 364 transportFactory.transport.addServiceAccount(SA_CLIENT_EMAIL, ACCESS_TOKEN); 365 InputStream serviceAccountStream = 366 ServiceAccountCredentialsTest.writeServiceAccountStream( 367 SA_CLIENT_ID, SA_CLIENT_EMAIL, SA_PRIVATE_KEY_PKCS8, SA_PRIVATE_KEY_ID); 368 TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider(); 369 String serviceAccountPath = tempFilePath("service_account.json"); 370 testProvider.addFile(serviceAccountPath, serviceAccountStream); 371 testProvider.setEnv(DefaultCredentialsProvider.CREDENTIAL_ENV_VAR, serviceAccountPath); 372 373 GoogleCredentials defaultCredentials = testProvider.getDefaultCredentials(transportFactory); 374 375 assertNotNull(defaultCredentials); 376 defaultCredentials = defaultCredentials.createScoped(SCOPES); 377 Map<String, List<String>> metadata = defaultCredentials.getRequestMetadata(CALL_URI); 378 TestUtils.assertContainsBearerToken(metadata, ACCESS_TOKEN); 379 } 380 381 @Test getDefaultCredentials_envUser_providesToken()382 public void getDefaultCredentials_envUser_providesToken() throws IOException { 383 InputStream userStream = 384 UserCredentialsTest.writeUserStream( 385 USER_CLIENT_ID, USER_CLIENT_SECRET, REFRESH_TOKEN, QUOTA_PROJECT); 386 TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider(); 387 String userPath = tempFilePath("user.json"); 388 testProvider.addFile(userPath, userStream); 389 testProvider.setEnv(DefaultCredentialsProvider.CREDENTIAL_ENV_VAR, userPath); 390 391 testUserProvidesToken(testProvider, USER_CLIENT_ID, USER_CLIENT_SECRET, REFRESH_TOKEN); 392 } 393 394 @Test getDefaultCredentials_GdchServiceAccount()395 public void getDefaultCredentials_GdchServiceAccount() throws IOException { 396 MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); 397 InputStream gdchServiceAccountStream = 398 GdchCredentialsTest.writeGdchServiceAccountStream( 399 GDCH_SA_FORMAT_VERSION, 400 GDCH_SA_PROJECT_ID, 401 GDCH_SA_PRIVATE_KEY_ID, 402 GDCH_SA_PRIVATE_KEY_PKC8, 403 GDCH_SA_SERVICE_IDENTITY_NAME, 404 GDCH_SA_CA_CERT_PATH, 405 GDCH_SA_TOKEN_SERVER_URI); 406 TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider(); 407 String gdchServiceAccountPath = tempFilePath("gdch_service_account.json"); 408 testProvider.addFile(gdchServiceAccountPath, gdchServiceAccountStream); 409 testProvider.setEnv(DefaultCredentialsProvider.CREDENTIAL_ENV_VAR, gdchServiceAccountPath); 410 411 GoogleCredentials defaultCredentials = testProvider.getDefaultCredentials(transportFactory); 412 413 assertNotNull(defaultCredentials); 414 assertTrue(defaultCredentials instanceof GdchCredentials); 415 assertEquals(GDCH_SA_PROJECT_ID, ((GdchCredentials) defaultCredentials).getProjectId()); 416 assertEquals( 417 GDCH_SA_SERVICE_IDENTITY_NAME, 418 ((GdchCredentials) defaultCredentials).getServiceIdentityName()); 419 assertEquals( 420 GDCH_SA_TOKEN_SERVER_URI, ((GdchCredentials) defaultCredentials).getTokenServerUri()); 421 assertEquals(GDCH_SA_CA_CERT_PATH, ((GdchCredentials) defaultCredentials).getCaCertPath()); 422 assertNull(((GdchCredentials) defaultCredentials).getApiAudience()); 423 424 defaultCredentials = 425 ((GdchCredentials) defaultCredentials).createWithGdchAudience(GDCH_SA_API_AUDIENCE); 426 assertNotNull(defaultCredentials); 427 assertTrue(defaultCredentials instanceof GdchCredentials); 428 assertEquals(GDCH_SA_PROJECT_ID, ((GdchCredentials) defaultCredentials).getProjectId()); 429 assertEquals( 430 GDCH_SA_SERVICE_IDENTITY_NAME, 431 ((GdchCredentials) defaultCredentials).getServiceIdentityName()); 432 assertEquals( 433 GDCH_SA_TOKEN_SERVER_URI, ((GdchCredentials) defaultCredentials).getTokenServerUri()); 434 assertEquals(GDCH_SA_CA_CERT_PATH, ((GdchCredentials) defaultCredentials).getCaCertPath()); 435 assertNotNull(((GdchCredentials) defaultCredentials).getApiAudience()); 436 } 437 getDefaultCredentials_quota_project()438 public void getDefaultCredentials_quota_project() throws IOException { 439 InputStream userStream = 440 UserCredentialsTest.writeUserStream( 441 USER_CLIENT_ID, USER_CLIENT_SECRET, REFRESH_TOKEN, QUOTA_PROJECT); 442 TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider(); 443 String userPath = tempFilePath("user.json"); 444 testProvider.addFile(userPath, userStream); 445 testProvider.setEnv(DefaultCredentialsProvider.CREDENTIAL_ENV_VAR, userPath); 446 MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); 447 transportFactory.transport.addClient(USER_CLIENT_ID, USER_CLIENT_SECRET); 448 transportFactory.transport.addRefreshToken(REFRESH_TOKEN, ACCESS_TOKEN); 449 450 // Validate that quota from env overrides the value from json 451 testProvider.setEnv( 452 DefaultCredentialsProvider.QUOTA_PROJECT_ENV_VAR, QUOTA_PROJECT_FROM_ENVIRONMENT); 453 GoogleCredentials credentials = testProvider.getDefaultCredentials(transportFactory); 454 assertEquals(QUOTA_PROJECT_FROM_ENVIRONMENT, credentials.getQuotaProjectId()); 455 456 // Validate that if user sets quota, env and json value not used 457 credentials = credentials.toBuilder().setQuotaProjectId(QUOTA_PROJECT_EXPLICIT).build(); 458 assertEquals(QUOTA_PROJECT_EXPLICIT, credentials.getQuotaProjectId()); 459 460 testUserProvidesToken(testProvider, USER_CLIENT_ID, USER_CLIENT_SECRET, REFRESH_TOKEN); 461 } 462 463 @Test getDefaultCredentials_compute_quotaProject()464 public void getDefaultCredentials_compute_quotaProject() throws IOException { 465 MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); 466 transportFactory.transport.setAccessToken(ACCESS_TOKEN); 467 TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider(); 468 testProvider.setEnv( 469 DefaultCredentialsProvider.QUOTA_PROJECT_ENV_VAR, QUOTA_PROJECT_FROM_ENVIRONMENT); 470 471 GoogleCredentials defaultCredentials = testProvider.getDefaultCredentials(transportFactory); 472 473 assertTrue(defaultCredentials instanceof ComputeEngineCredentials); 474 assertEquals(QUOTA_PROJECT_FROM_ENVIRONMENT, defaultCredentials.getQuotaProjectId()); 475 } 476 477 @Test getDefaultCredentials_cloudshell_quotaProject()478 public void getDefaultCredentials_cloudshell_quotaProject() throws IOException { 479 MockHttpTransportFactory transportFactory = new MockHttpTransportFactory(); 480 TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider(); 481 testProvider.setEnv(DefaultCredentialsProvider.CLOUD_SHELL_ENV_VAR, "4"); 482 testProvider.setEnv( 483 DefaultCredentialsProvider.QUOTA_PROJECT_ENV_VAR, QUOTA_PROJECT_FROM_ENVIRONMENT); 484 485 GoogleCredentials defaultCredentials = testProvider.getDefaultCredentials(transportFactory); 486 487 assertTrue(defaultCredentials instanceof CloudShellCredentials); 488 assertEquals(QUOTA_PROJECT_FROM_ENVIRONMENT, defaultCredentials.getQuotaProjectId()); 489 } 490 491 @Test getDefaultCredentials_envNoGceCheck_noGceRequest()492 public void getDefaultCredentials_envNoGceCheck_noGceRequest() throws IOException { 493 MockRequestCountingTransportFactory transportFactory = 494 new MockRequestCountingTransportFactory(); 495 TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider(); 496 testProvider.setEnv(DefaultCredentialsProvider.NO_GCE_CHECK_ENV_VAR, "true"); 497 498 try { 499 testProvider.getDefaultCredentials(transportFactory); 500 fail("No credential expected."); 501 } catch (IOException expected) { 502 // Expected 503 } 504 assertEquals(transportFactory.transport.getRequestCount(), 0); 505 } 506 507 @Test getDefaultCredentials_linuxSetup_envNoGceCheck_noGce()508 public void getDefaultCredentials_linuxSetup_envNoGceCheck_noGce() throws IOException { 509 MockRequestCountingTransportFactory transportFactory = 510 new MockRequestCountingTransportFactory(); 511 TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider(); 512 testProvider.setEnv(DefaultCredentialsProvider.NO_GCE_CHECK_ENV_VAR, "true"); 513 testProvider.setProperty("os.name", "Linux"); 514 String productFilePath = SMBIOS_PATH_LINUX; 515 File productFile = new File(productFilePath); 516 InputStream productStream = new ByteArrayInputStream("Googlekdjsfhg".getBytes()); 517 testProvider.addFile(productFile.getAbsolutePath(), productStream); 518 try { 519 testProvider.getDefaultCredentials(transportFactory); 520 fail("No credential expected."); 521 } catch (IOException expected) { 522 // Expected 523 } 524 assertEquals(transportFactory.transport.getRequestCount(), 0); 525 } 526 527 @Test getDefaultCredentials_envGceMetadataHost_setsMetadataServerUrl()528 public void getDefaultCredentials_envGceMetadataHost_setsMetadataServerUrl() { 529 String testUrl = "192.0.2.0"; 530 TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider(); 531 testProvider.setEnv(DefaultCredentialsProvider.GCE_METADATA_HOST_ENV_VAR, testUrl); 532 assertEquals(ComputeEngineCredentials.getMetadataServerUrl(testProvider), "http://" + testUrl); 533 } 534 535 @Test getDefaultCredentials_envGceMetadataHost_setsTokenServerUrl()536 public void getDefaultCredentials_envGceMetadataHost_setsTokenServerUrl() { 537 String testUrl = "192.0.2.0"; 538 TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider(); 539 testProvider.setEnv(DefaultCredentialsProvider.GCE_METADATA_HOST_ENV_VAR, testUrl); 540 assertEquals( 541 ComputeEngineCredentials.getTokenServerEncodedUrl(testProvider), 542 "http://" + testUrl + "/computeMetadata/v1/instance/service-accounts/default/token"); 543 } 544 545 @Test getDefaultCredentials_wellKnownFileEnv_providesToken()546 public void getDefaultCredentials_wellKnownFileEnv_providesToken() throws IOException { 547 File cloudConfigDir = getTempDirectory(); 548 InputStream userStream = 549 UserCredentialsTest.writeUserStream( 550 USER_CLIENT_ID, USER_CLIENT_SECRET, REFRESH_TOKEN, QUOTA_PROJECT); 551 File wellKnownFile = 552 new File(cloudConfigDir, DefaultCredentialsProvider.WELL_KNOWN_CREDENTIALS_FILE); 553 TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider(); 554 testProvider.setEnv("CLOUDSDK_CONFIG", cloudConfigDir.getAbsolutePath()); 555 testProvider.addFile(wellKnownFile.getAbsolutePath(), userStream); 556 557 testUserProvidesToken(testProvider, USER_CLIENT_ID, USER_CLIENT_SECRET, REFRESH_TOKEN); 558 } 559 560 @Test getDefaultCredentials_wellKnownFileNonWindows_providesToken()561 public void getDefaultCredentials_wellKnownFileNonWindows_providesToken() throws IOException { 562 File homeDir = getTempDirectory(); 563 File configDir = new File(homeDir, ".config"); 564 File cloudConfigDir = new File(configDir, DefaultCredentialsProvider.CLOUDSDK_CONFIG_DIRECTORY); 565 InputStream userStream = 566 UserCredentialsTest.writeUserStream( 567 USER_CLIENT_ID, USER_CLIENT_SECRET, REFRESH_TOKEN, QUOTA_PROJECT); 568 File wellKnownFile = 569 new File(cloudConfigDir, DefaultCredentialsProvider.WELL_KNOWN_CREDENTIALS_FILE); 570 TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider(); 571 testProvider.setProperty("os.name", "linux"); 572 testProvider.setProperty("user.home", homeDir.getAbsolutePath()); 573 testProvider.addFile(wellKnownFile.getAbsolutePath(), userStream); 574 575 testUserProvidesToken(testProvider, USER_CLIENT_ID, USER_CLIENT_SECRET, REFRESH_TOKEN); 576 } 577 578 @Test getDefaultCredentials_wellKnownFileWindows_providesToken()579 public void getDefaultCredentials_wellKnownFileWindows_providesToken() throws IOException { 580 File homeDir = getTempDirectory(); 581 File cloudConfigDir = new File(homeDir, DefaultCredentialsProvider.CLOUDSDK_CONFIG_DIRECTORY); 582 InputStream userStream = 583 UserCredentialsTest.writeUserStream( 584 USER_CLIENT_ID, USER_CLIENT_SECRET, REFRESH_TOKEN, QUOTA_PROJECT); 585 File wellKnownFile = 586 new File(cloudConfigDir, DefaultCredentialsProvider.WELL_KNOWN_CREDENTIALS_FILE); 587 TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider(); 588 testProvider.setProperty("os.name", "windows"); 589 testProvider.setEnv("APPDATA", homeDir.getAbsolutePath()); 590 testProvider.addFile(wellKnownFile.getAbsolutePath(), userStream); 591 592 testUserProvidesToken(testProvider, USER_CLIENT_ID, USER_CLIENT_SECRET, REFRESH_TOKEN); 593 } 594 595 @Test getDefaultCredentials_envAndWellKnownFile_envPrecedence()596 public void getDefaultCredentials_envAndWellKnownFile_envPrecedence() throws IOException { 597 final String refreshTokenEnv = "2/Tl6awhpFjkMkSJoj1xsli0H2eL5YsMgU_NKPY2TyGWY"; 598 final String accessTokenEnv = "2/MkSJoj1xsli0AccessToken_NKPY2"; 599 final String refreshTokenWkf = "3/Tl6awhpFjkMkSJoj1xsli0H2eL5YsMgU_NKPY2TyGWY"; 600 final String accessTokenWkf = "3/MkSJoj1xsli0AccessToken_NKPY2"; 601 TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider(); 602 603 InputStream envStream = 604 UserCredentialsTest.writeUserStream( 605 USER_CLIENT_ID, USER_CLIENT_SECRET, refreshTokenEnv, QUOTA_PROJECT); 606 String envPath = tempFilePath("env.json"); 607 testProvider.setEnv(DefaultCredentialsProvider.CREDENTIAL_ENV_VAR, envPath); 608 testProvider.addFile(envPath, envStream); 609 610 File homeDir = getTempDirectory(); 611 File configDir = new File(homeDir, ".config"); 612 File cloudConfigDir = new File(configDir, DefaultCredentialsProvider.CLOUDSDK_CONFIG_DIRECTORY); 613 InputStream wkfStream = 614 UserCredentialsTest.writeUserStream( 615 USER_CLIENT_ID, USER_CLIENT_SECRET, refreshTokenWkf, QUOTA_PROJECT); 616 File wellKnownFile = 617 new File(cloudConfigDir, DefaultCredentialsProvider.WELL_KNOWN_CREDENTIALS_FILE); 618 testProvider.setProperty("os.name", "linux"); 619 testProvider.setProperty("user.home", homeDir.getAbsolutePath()); 620 testProvider.addFile(wellKnownFile.getAbsolutePath(), wkfStream); 621 622 MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); 623 transportFactory.transport.addClient(USER_CLIENT_ID, USER_CLIENT_SECRET); 624 transportFactory.transport.addRefreshToken(refreshTokenWkf, accessTokenWkf); 625 transportFactory.transport.addRefreshToken(refreshTokenEnv, accessTokenEnv); 626 627 testUserProvidesToken(testProvider, transportFactory, accessTokenEnv); 628 } 629 tempFilePath(String filename)630 private String tempFilePath(String filename) { 631 return Paths.get(System.getProperty("java.io.tmpdir"), filename).toString(); 632 } 633 634 private class LogHandler extends Handler { 635 LogRecord lastRecord; 636 637 @Override publish(LogRecord record)638 public void publish(LogRecord record) { 639 lastRecord = record; 640 } 641 getRecord()642 public LogRecord getRecord() { 643 return lastRecord; 644 } 645 646 @Override close()647 public void close() {} 648 649 @Override flush()650 public void flush() {} 651 } 652 653 @Test getDefaultCredentials_wellKnownFile_logsGcloudWarning()654 public void getDefaultCredentials_wellKnownFile_logsGcloudWarning() throws IOException { 655 LogRecord message = getCredentialsAndReturnLogMessage(false, true); 656 assertNotNull(message); 657 assertEquals(Level.WARNING, message.getLevel()); 658 assertTrue( 659 message.getMessage().equals(DefaultCredentialsProvider.CLOUDSDK_CREDENTIALS_WARNING)); 660 } 661 662 @Test getDefaultCredentials_wellKnownFile_noGcloudWarning()663 public void getDefaultCredentials_wellKnownFile_noGcloudWarning() throws IOException { 664 LogRecord message = getCredentialsAndReturnLogMessage(false, false); 665 assertNull(message); 666 } 667 668 @Test getDefaultCredentials_wellKnownFile_suppressGcloudWarning()669 public void getDefaultCredentials_wellKnownFile_suppressGcloudWarning() throws IOException { 670 LogRecord message = getCredentialsAndReturnLogMessage(true, true); 671 assertNull(message); 672 } 673 getCredentialsAndReturnLogMessage(boolean suppressWarning, boolean isGce)674 private LogRecord getCredentialsAndReturnLogMessage(boolean suppressWarning, boolean isGce) 675 throws IOException { 676 Logger logger = Logger.getLogger(DefaultCredentialsProvider.class.getName()); 677 LogHandler handler = new LogHandler(); 678 logger.addHandler(handler); 679 680 File homeDir = getTempDirectory(); 681 File configDir = new File(homeDir, ".config"); 682 File cloudConfigDir = new File(configDir, DefaultCredentialsProvider.CLOUDSDK_CONFIG_DIRECTORY); 683 InputStream userStream = 684 UserCredentialsTest.writeUserStream( 685 GCLOUDSDK_CLIENT_ID, USER_CLIENT_SECRET, REFRESH_TOKEN, QUOTA_PROJECT); 686 File wellKnownFile = 687 new File(cloudConfigDir, DefaultCredentialsProvider.WELL_KNOWN_CREDENTIALS_FILE); 688 TestDefaultCredentialsProvider testProvider = new TestDefaultCredentialsProvider(); 689 testProvider.setEnv( 690 DefaultCredentialsProvider.SUPPRESS_GCLOUD_CREDS_WARNING_ENV_VAR, 691 Boolean.toString(suppressWarning)); 692 testProvider.setProperty("os.name", "linux"); 693 testProvider.setProperty("user.home", homeDir.getAbsolutePath()); 694 if (isGce) { 695 String productFilePath = SMBIOS_PATH_LINUX; 696 File productFile = new File(productFilePath); 697 InputStream productStream = new ByteArrayInputStream("Googlekdjsfhg".getBytes()); 698 testProvider.addFile(productFile.getAbsolutePath(), productStream); 699 } 700 testProvider.addFile(wellKnownFile.getAbsolutePath(), userStream); 701 testUserProvidesToken(testProvider, GCLOUDSDK_CLIENT_ID, USER_CLIENT_SECRET, REFRESH_TOKEN); 702 return handler.getRecord(); 703 } 704 getTempDirectory()705 private static File getTempDirectory() { 706 return new File(System.getProperty("java.io.tmpdir")); 707 } 708 testUserProvidesToken( TestDefaultCredentialsProvider testProvider, String clientId, String clientSecret, String refreshToken)709 private void testUserProvidesToken( 710 TestDefaultCredentialsProvider testProvider, 711 String clientId, 712 String clientSecret, 713 String refreshToken) 714 throws IOException { 715 MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); 716 transportFactory.transport.addClient(clientId, clientSecret); 717 transportFactory.transport.addRefreshToken(refreshToken, ACCESS_TOKEN); 718 testUserProvidesToken(testProvider, transportFactory, ACCESS_TOKEN); 719 } 720 testUserProvidesToken( TestDefaultCredentialsProvider testProvider, HttpTransportFactory transportFactory, String accessToken)721 private void testUserProvidesToken( 722 TestDefaultCredentialsProvider testProvider, 723 HttpTransportFactory transportFactory, 724 String accessToken) 725 throws IOException { 726 GoogleCredentials defaultCredentials = testProvider.getDefaultCredentials(transportFactory); 727 728 assertNotNull(defaultCredentials); 729 Map<String, List<String>> metadata = defaultCredentials.getRequestMetadata(CALL_URI); 730 TestUtils.assertContainsBearerToken(metadata, accessToken); 731 } 732 733 public static class MockAppEngineCredentials extends GoogleCredentials { 734 private static final long serialVersionUID = 2695173591854484322L; 735 MockAppEngineCredentials(Collection<String> scopes)736 public MockAppEngineCredentials(Collection<String> scopes) {} 737 738 @Override refreshAccessToken()739 public AccessToken refreshAccessToken() throws IOException { 740 return null; 741 } 742 } 743 744 /* 745 * App Engine is detected by calling SystemProperty.environment.value() via Reflection. 746 * The following mock types simulate the shape and behavior of that call sequence. 747 */ 748 749 private static class MockAppEngineSystemProperty { 750 751 @SuppressWarnings("unused") 752 public static final MockEnvironment environment = 753 new MockEnvironment(MockEnvironmentEnum.Production); 754 } 755 756 private static class MockOffAppEngineSystemProperty { 757 758 @SuppressWarnings("unused") 759 public static final MockEnvironment environment = new MockEnvironment(null); 760 } 761 762 private enum MockEnvironmentEnum { 763 Production, 764 Development; 765 } 766 767 public static class MockEnvironment { 768 769 private MockEnvironmentEnum innerValue; 770 MockEnvironment(MockEnvironmentEnum value)771 MockEnvironment(MockEnvironmentEnum value) { 772 this.innerValue = value; 773 } 774 value()775 public MockEnvironmentEnum value() { 776 return innerValue; 777 } 778 } 779 780 /* 781 * End of types simulating SystemProperty.environment.value() to detect App Engine. 782 */ 783 784 static class MockRequestCountingTransport extends MockHttpTransport { 785 int requestCount = 0; 786 MockRequestCountingTransport()787 MockRequestCountingTransport() {} 788 getRequestCount()789 int getRequestCount() { 790 return requestCount; 791 } 792 793 @Override buildRequest(String method, String url)794 public LowLevelHttpRequest buildRequest(String method, String url) { 795 return new MockLowLevelHttpRequest(url) { 796 @Override 797 public LowLevelHttpResponse execute() throws IOException { 798 requestCount++; 799 throw new IOException("MockRequestCountingTransport request failed."); 800 } 801 }; 802 } 803 } 804 805 static class TestDefaultCredentialsProvider extends DefaultCredentialsProvider { 806 807 private final Map<String, Class<?>> types = new HashMap<>(); 808 private final Map<String, String> variables = new HashMap<>(); 809 private final Map<String, String> properties = new HashMap<>(); 810 private final Map<String, InputStream> files = new HashMap<>(); 811 private boolean fileSandbox = false; 812 813 TestDefaultCredentialsProvider() {} 814 815 void addFile(String file, InputStream stream) { 816 files.put(file, stream); 817 } 818 819 void addType(String className, Class<?> type) { 820 types.put(className, type); 821 } 822 823 @Override 824 String getEnv(String name) { 825 return variables.get(name); 826 } 827 828 void setEnv(String name, String value) { 829 variables.put(name, value); 830 } 831 832 @Override 833 String getProperty(String property, String def) { 834 String value = properties.get(property); 835 return value == null ? def : value; 836 } 837 838 void setProperty(String property, String value) { 839 properties.put(property, value); 840 } 841 842 @Override 843 Class<?> forName(String className) throws ClassNotFoundException { 844 Class<?> lookup = types.get(className); 845 if (lookup != null) { 846 return lookup; 847 } 848 throw new ClassNotFoundException("TestDefaultCredentialProvider: Class not found."); 849 } 850 851 @Override 852 protected boolean isOnGAEStandard7() { 853 return getProperty("isOnGAEStandard7", "false").equals("true"); 854 } 855 856 @Override 857 boolean isFile(File file) { 858 if (fileSandbox) { 859 throw new AccessControlException("No file permission."); 860 } 861 return files.containsKey(file.getAbsolutePath()); 862 } 863 864 @Override 865 InputStream readStream(File file) throws FileNotFoundException { 866 if (fileSandbox) { 867 throw new AccessControlException("No file permission."); 868 } 869 InputStream stream = files.get(file.getAbsolutePath()); 870 if (stream == null) { 871 throw new FileNotFoundException(file.getAbsolutePath()); 872 } 873 return stream; 874 } 875 876 void setFileSandbox(boolean fileSandbox) { 877 this.fileSandbox = fileSandbox; 878 } 879 } 880 881 static class MockRequestCountingTransportFactory implements HttpTransportFactory { 882 883 MockRequestCountingTransport transport = new MockRequestCountingTransport(); 884 885 @Override 886 public HttpTransport create() { 887 return transport; 888 } 889 } 890 } 891