From dc60bd7706ec1f49379719b0edc50c6eea00ec88 Mon Sep 17 00:00:00 2001 From: Brent Shaffer Date: Wed, 6 Sep 2023 13:54:27 -0700 Subject: [PATCH 01/16] feat: add universe domain support --- src/Credentials/GCECredentials.php | 43 +++++++++++++++++++ src/Credentials/ServiceAccountCredentials.php | 16 +++++++ src/Credentials/UserRefreshCredentials.php | 16 +++++++ src/CredentialsLoader.php | 12 ++++++ src/GetUniverseDomainInterface.php | 35 +++++++++++++++ 5 files changed, 122 insertions(+) create mode 100644 src/GetUniverseDomainInterface.php diff --git a/src/Credentials/GCECredentials.php b/src/Credentials/GCECredentials.php index 991589b52..2a3959024 100644 --- a/src/Credentials/GCECredentials.php +++ b/src/Credentials/GCECredentials.php @@ -95,6 +95,11 @@ class GCECredentials extends CredentialsLoader implements */ const PROJECT_ID_URI_PATH = 'v1/project/project-id'; + /** + * The metadata path of the project ID. + */ + const UNIVERSE_DOMAIN_URI_PATH = 'v1/universe'; + /** * The header whose presence indicates GCE presence. */ @@ -294,6 +299,18 @@ private static function getProjectIdUri() return $base . self::PROJECT_ID_URI_PATH; } + /** + * The full uri for accessing the default universe domain. + * + * @return string + */ + private static function getUniverseDomainUri() + { + $base = 'http://' . self::METADATA_IP . '/computeMetadata/'; + + return $base . self::UNIVERSE_DOMAIN_URI_PATH; + } + /** * Determines if this an App Engine Flexible instance, by accessing the * GAE_INSTANCE environment variable. @@ -500,6 +517,32 @@ public function getProjectId(callable $httpHandler = null) return $this->projectId; } + /** + * Fetch the default universe domain from the metadata server. + * + * Returns null if called outside GCE. + * + * @param callable $httpHandler Callback which delivers psr7 request + * @return string|null + */ + public function getUniverseDomain(): string + { + $httpHandler = $httpHandler + ?: HttpHandlerFactory::build(HttpClientCache::getHttpClient()); + + if (!$this->hasCheckedOnGce) { + $this->isOnGce = self::onGce($httpHandler); + $this->hasCheckedOnGce = true; + } + + if (!$this->isOnGce) { + return null; + } + + $this->projectId = $this->getFromMetadata($httpHandler, self::getProjectIdUri()); + return $this->projectId; + } + /** * Fetch the value of a GCE metadata server URI. * diff --git a/src/Credentials/ServiceAccountCredentials.php b/src/Credentials/ServiceAccountCredentials.php index 76aa0fc99..a3874d7be 100644 --- a/src/Credentials/ServiceAccountCredentials.php +++ b/src/Credentials/ServiceAccountCredentials.php @@ -99,6 +99,11 @@ class ServiceAccountCredentials extends CredentialsLoader implements */ private $jwtAccessCredentials; + /** + * @var string + */ + private $universeDomain; + /** * Create a new ServiceAccountCredentials. * @@ -159,6 +164,7 @@ public function __construct( ]); $this->projectId = $jsonKey['project_id'] ?? null; + $this->universeDomain = $jsonKey['universedomain'] ?? self::DEFAULT_UNIVERSE_DOMAIN; } /** @@ -328,6 +334,16 @@ public function getQuotaProject() return $this->quotaProject; } + /** + * Get the universe domain configured in the JSON credential. + * + * @return string + */ + public function getUniverseDomain(): string + { + return $this->universeDomain; + } + /** * @return bool */ diff --git a/src/Credentials/UserRefreshCredentials.php b/src/Credentials/UserRefreshCredentials.php index e2f32d87f..08614be78 100644 --- a/src/Credentials/UserRefreshCredentials.php +++ b/src/Credentials/UserRefreshCredentials.php @@ -48,6 +48,11 @@ class UserRefreshCredentials extends CredentialsLoader implements GetQuotaProjec */ protected $quotaProject; + /** + * @var string + */ + private $universeDomain; + /** * Create a new UserRefreshCredentials. * @@ -94,6 +99,7 @@ public function __construct( if (array_key_exists('quota_project_id', $jsonKey)) { $this->quotaProject = (string) $jsonKey['quota_project_id']; } + $this->universeDomain = $jsonKey['universedomain'] ?? self::DEFAULT_UNIVERSE_DOMAIN; } /** @@ -140,6 +146,16 @@ public function getQuotaProject() return $this->quotaProject; } + /** + * Get the universe domain configured in the JSON credential. + * + * @return string + */ + public function getUniverseDomain(): string + { + return $this->universeDomain; + } + /** * Get the granted scopes (if they exist) for the last fetched token. * diff --git a/src/CredentialsLoader.php b/src/CredentialsLoader.php index ada8e759c..aace498f8 100644 --- a/src/CredentialsLoader.php +++ b/src/CredentialsLoader.php @@ -29,6 +29,7 @@ * credentials files on the file system. */ abstract class CredentialsLoader implements + GetUniverseDomainInterface, FetchAuthTokenInterface, UpdateMetadataInterface { @@ -303,4 +304,15 @@ private static function loadDefaultClientCertSourceFile() } return $clientCertSourceJson; } + + /** + * Get the universe domain from the credential. Defaults to + * "googleapis.com" for all credential types. + * + * @return string + */ + public function getUniverseDomain(): string + { + return self::DEFAULT_UNIVERSE_DOMAIN; + } } diff --git a/src/GetUniverseDomainInterface.php b/src/GetUniverseDomainInterface.php new file mode 100644 index 000000000..2b6b8763f --- /dev/null +++ b/src/GetUniverseDomainInterface.php @@ -0,0 +1,35 @@ + Date: Thu, 7 Sep 2023 10:06:33 -0700 Subject: [PATCH 02/16] fix GCE creds, misc cleanup --- src/Credentials/GCECredentials.php | 23 +++++++++++++++---- src/Credentials/ServiceAccountCredentials.php | 8 +++---- src/Credentials/UserRefreshCredentials.php | 8 +++---- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/src/Credentials/GCECredentials.php b/src/Credentials/GCECredentials.php index 2a3959024..580a3a39f 100644 --- a/src/Credentials/GCECredentials.php +++ b/src/Credentials/GCECredentials.php @@ -98,7 +98,7 @@ class GCECredentials extends CredentialsLoader implements /** * The metadata path of the project ID. */ - const UNIVERSE_DOMAIN_URI_PATH = 'v1/universe'; + const UNIVERSE_DOMAIN_URI_PATH = 'v1/universe/universe_domain'; /** * The header whose presence indicates GCE presence. @@ -174,6 +174,11 @@ class GCECredentials extends CredentialsLoader implements */ private $serviceAccountIdentity; + /** + * @var string + */ + private ?string $universeDomain; + /** * @param Iam $iam [optional] An IAM instance. * @param string|string[] $scope [optional] the scope of the access request, @@ -183,13 +188,16 @@ class GCECredentials extends CredentialsLoader implements * charges associated with the request. * @param string $serviceAccountIdentity [optional] Specify a service * account identity name to use instead of "default". + * @param string $universeDomain [optional] Specify a universe domain to use + * instead of fetching one from the metadata server. */ public function __construct( Iam $iam = null, $scope = null, $targetAudience = null, $quotaProject = null, - $serviceAccountIdentity = null + $serviceAccountIdentity = null, + $universeDomain = null ) { $this->iam = $iam; @@ -217,6 +225,7 @@ public function __construct( $this->tokenUri = $tokenUri; $this->quotaProject = $quotaProject; $this->serviceAccountIdentity = $serviceAccountIdentity; + $this->universeDomain = $universeDomain; } /** @@ -527,6 +536,10 @@ public function getProjectId(callable $httpHandler = null) */ public function getUniverseDomain(): string { + if ($this->universeDomain) { + return $this->universeDomain; + } + $httpHandler = $httpHandler ?: HttpHandlerFactory::build(HttpClientCache::getHttpClient()); @@ -536,11 +549,11 @@ public function getUniverseDomain(): string } if (!$this->isOnGce) { - return null; + return self::DEFAULT_UNIVERSE_DOMAIN; } - $this->projectId = $this->getFromMetadata($httpHandler, self::getProjectIdUri()); - return $this->projectId; + $this->universeDomain = $this->getFromMetadata($httpHandler, self::getUniverseDomainUri()); + return $this->universeDomain; } /** diff --git a/src/Credentials/ServiceAccountCredentials.php b/src/Credentials/ServiceAccountCredentials.php index a3874d7be..c7a7a2dd0 100644 --- a/src/Credentials/ServiceAccountCredentials.php +++ b/src/Credentials/ServiceAccountCredentials.php @@ -100,9 +100,9 @@ class ServiceAccountCredentials extends CredentialsLoader implements private $jwtAccessCredentials; /** - * @var string + * @var string|null */ - private $universeDomain; + private ?string $universeDomain; /** * Create a new ServiceAccountCredentials. @@ -164,7 +164,7 @@ public function __construct( ]); $this->projectId = $jsonKey['project_id'] ?? null; - $this->universeDomain = $jsonKey['universedomain'] ?? self::DEFAULT_UNIVERSE_DOMAIN; + $this->universeDomain = $jsonKey['universe_domain'] ?? null; } /** @@ -341,7 +341,7 @@ public function getQuotaProject() */ public function getUniverseDomain(): string { - return $this->universeDomain; + return $this->universeDomain ?: self::DEFAULT_UNIVERSE_DOMAIN; } /** diff --git a/src/Credentials/UserRefreshCredentials.php b/src/Credentials/UserRefreshCredentials.php index 08614be78..5031c3e08 100644 --- a/src/Credentials/UserRefreshCredentials.php +++ b/src/Credentials/UserRefreshCredentials.php @@ -49,9 +49,9 @@ class UserRefreshCredentials extends CredentialsLoader implements GetQuotaProjec protected $quotaProject; /** - * @var string + * @var string|null */ - private $universeDomain; + private ?string $universeDomain; /** * Create a new UserRefreshCredentials. @@ -99,7 +99,7 @@ public function __construct( if (array_key_exists('quota_project_id', $jsonKey)) { $this->quotaProject = (string) $jsonKey['quota_project_id']; } - $this->universeDomain = $jsonKey['universedomain'] ?? self::DEFAULT_UNIVERSE_DOMAIN; + $this->universeDomain = $jsonKey['universe_domain'] ?? null; } /** @@ -153,7 +153,7 @@ public function getQuotaProject() */ public function getUniverseDomain(): string { - return $this->universeDomain; + return $this->universeDomain ?: self::DEFAULT_UNIVERSE_DOMAIN; } /** From f5b53a8b2b51018240ef89564ad56c76d4954cd1 Mon Sep 17 00:00:00 2001 From: Brent Shaffer Date: Thu, 7 Sep 2023 12:17:51 -0700 Subject: [PATCH 03/16] fix phpstan --- src/Credentials/GCECredentials.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Credentials/GCECredentials.php b/src/Credentials/GCECredentials.php index 580a3a39f..63a82b8e0 100644 --- a/src/Credentials/GCECredentials.php +++ b/src/Credentials/GCECredentials.php @@ -532,9 +532,9 @@ public function getProjectId(callable $httpHandler = null) * Returns null if called outside GCE. * * @param callable $httpHandler Callback which delivers psr7 request - * @return string|null + * @return string */ - public function getUniverseDomain(): string + public function getUniverseDomain(callable $httpHandler = null): string { if ($this->universeDomain) { return $this->universeDomain; From ca7fb2d0cafe457df0b4e042601fc51028030b80 Mon Sep 17 00:00:00 2001 From: Brent Shaffer Date: Thu, 7 Sep 2023 12:58:37 -0700 Subject: [PATCH 04/16] add universe domain to ADC --- src/ApplicationDefaultCredentials.php | 10 ++- src/Credentials/GCECredentials.php | 13 +++- tests/ApplicationDefaultCredentialsTest.php | 68 +++++++++++++++++++++ tests/Credentials/GCECredentialsTest.php | 40 ++++++++++++ tests/fixtures2/private.json | 3 +- 5 files changed, 129 insertions(+), 5 deletions(-) diff --git a/src/ApplicationDefaultCredentials.php b/src/ApplicationDefaultCredentials.php index d556fac4e..80437c8c9 100644 --- a/src/ApplicationDefaultCredentials.php +++ b/src/ApplicationDefaultCredentials.php @@ -144,6 +144,8 @@ public static function getMiddleware( * @param string|string[] $defaultScope The default scope to use if no * user-defined scopes exist, expressed either as an Array or as a * space-delimited string. + * @param string $universeDomain Specifies a universe domain to use for the + * calling client library * * @return FetchAuthTokenInterface * @throws DomainException if no implementation can be obtained. @@ -154,7 +156,8 @@ public static function getCredentials( array $cacheConfig = null, CacheItemPoolInterface $cache = null, $quotaProject = null, - $defaultScope = null + $defaultScope = null, + string $universeDomain = null ) { $creds = null; $jsonKey = CredentialsLoader::fromEnv() @@ -179,6 +182,9 @@ public static function getCredentials( if ($quotaProject) { $jsonKey['quota_project_id'] = $quotaProject; } + if ($universeDomain) { + $jsonKey['universe_domain'] = $universeDomain; + } $creds = CredentialsLoader::makeCredentials( $scope, $jsonKey, @@ -187,7 +193,7 @@ public static function getCredentials( } elseif (AppIdentityCredentials::onAppEngine() && !GCECredentials::onAppEngineFlexible()) { $creds = new AppIdentityCredentials($anyScope); } elseif (self::onGce($httpHandler, $cacheConfig, $cache)) { - $creds = new GCECredentials(null, $anyScope, null, $quotaProject); + $creds = new GCECredentials(null, $anyScope, null, $quotaProject, null, $universeDomain); $creds->setIsOnGce(true); // save the credentials a trip to the metadata server } diff --git a/src/Credentials/GCECredentials.php b/src/Credentials/GCECredentials.php index 63a82b8e0..562e7fd59 100644 --- a/src/Credentials/GCECredentials.php +++ b/src/Credentials/GCECredentials.php @@ -197,7 +197,7 @@ public function __construct( $targetAudience = null, $quotaProject = null, $serviceAccountIdentity = null, - $universeDomain = null + string $universeDomain = null ) { $this->iam = $iam; @@ -552,7 +552,16 @@ public function getUniverseDomain(callable $httpHandler = null): string return self::DEFAULT_UNIVERSE_DOMAIN; } - $this->universeDomain = $this->getFromMetadata($httpHandler, self::getUniverseDomainUri()); + // In the case of 404, we return the default universe domain. + try { + $this->universeDomain = $this->getFromMetadata( + $httpHandler, + self::getUniverseDomainUri() + ); + } catch (ClientException $e) { + return self::DEFAULT_UNIVERSE_DOMAIN; + } + return $this->universeDomain; } diff --git a/tests/ApplicationDefaultCredentialsTest.php b/tests/ApplicationDefaultCredentialsTest.php index e3d7a8dcc..70225fea4 100644 --- a/tests/ApplicationDefaultCredentialsTest.php +++ b/tests/ApplicationDefaultCredentialsTest.php @@ -782,4 +782,72 @@ public function provideExternalAccountCredentials() ['url_credentials.json', CredentialSource\UrlSource::class], ]; } + + /** @runInSeparateProcess */ + public function testUniverseDomainInKeyFile() + { + // Test no universe domain in keyfile defaults to "googleapis.com" + $keyFile = __DIR__ . '/fixtures/private.json'; + putenv(ServiceAccountCredentials::ENV_VAR . '=' . $keyFile); + $creds = ApplicationDefaultCredentials::getCredentials(); + $this->assertEquals(CredentialsLoader::DEFAULT_UNIVERSE_DOMAIN, $creds->getUniverseDomain()); + + // Test universe domain from keyfile + $keyFile = __DIR__ . '/fixtures2/private.json'; + putenv(ServiceAccountCredentials::ENV_VAR . '=' . $keyFile); + $creds2 = ApplicationDefaultCredentials::getCredentials(); + $this->assertEquals('example-universe.com', $creds2->getUniverseDomain()); + + // test passing in a different universe domain overrides keyfile + $creds3 = ApplicationDefaultCredentials::getCredentials( + null, + null, + null, + null, + null, + null, + 'example-universe2.com' + ); + $this->assertEquals('example-universe2.com', $creds3->getUniverseDomain()); + } + + /** @runInSeparateProcess */ + public function testUniverseDomainInGceCredentials() + { + putenv('HOME'); + + $expectedUniverseDomain = 'example-universe.com'; + $creds = ApplicationDefaultCredentials::getCredentials( + null, // $scope + $httpHandler = getHandler([ + new Response(200, [GCECredentials::FLAVOR_HEADER => 'Google']), + new Response(200, [], Utils::streamFor($expectedUniverseDomain)), + ]) // $httpHandler + ); + $this->assertEquals('example-universe.com', $creds->getUniverseDomain($httpHandler)); + + // test passing in a different universe domain overrides metadata server + $creds2 = ApplicationDefaultCredentials::getCredentials( + null, // $scope + $httpHandler = getHandler([ + new Response(200, [GCECredentials::FLAVOR_HEADER => 'Google']), + ]), // $httpHandler + null, // $cacheConfig + null, // $cache + null, // $quotaProject + null, // $defaultScope + 'example-universe2.com' // $universeDomain + ); + $this->assertEquals('example-universe2.com', $creds2->getUniverseDomain($httpHandler)); + + // test error response returns default universe domain + $creds2 = ApplicationDefaultCredentials::getCredentials( + null, // $scope + $httpHandler = getHandler([ + new Response(200, [GCECredentials::FLAVOR_HEADER => 'Google']), + new Response(404), + ]), // $httpHandler + ); + $this->assertEquals(CredentialsLoader::DEFAULT_UNIVERSE_DOMAIN, $creds2->getUniverseDomain($httpHandler)); + } } diff --git a/tests/Credentials/GCECredentialsTest.php b/tests/Credentials/GCECredentialsTest.php index 0d36e6771..088b16325 100644 --- a/tests/Credentials/GCECredentialsTest.php +++ b/tests/Credentials/GCECredentialsTest.php @@ -512,4 +512,44 @@ public function testGetClientNameWithServiceAccountIdentity() $creds = new GCECredentials(null, null, null, null, 'foo'); $this->assertEquals($expected, $creds->getClientName($httpHandler)); } + + public function testGetUniverseDomain() + { + $creds = new GCECredentials(); + + // If we are not on GCE, this should return the default + $creds->setIsOnGce(false); + $this->assertEquals( + GCECredentials::DEFAULT_UNIVERSE_DOMAIN, + $creds->getUniverseDomain() + ); + + // Pretend we are on GCE and mock the http handler. + $expected = 'example-universe.com'; + $timesCalled = 0; + $httpHandler = function ($request) use (&$timesCalled, $expected) { + $timesCalled++; + $this->assertEquals( + '/computeMetadata/v1/universe/universe_domain', + $request->getUri()->getPath() + ); + $this->assertEquals(1, $timesCalled, 'should only be called once'); + return new Psr7\Response(200, [], Utils::streamFor($expected)); + }; + + $creds->setIsOnGce(true); + + // Assert correct universe domain. + $this->assertEquals($expected, $creds->getUniverseDomain($httpHandler)); + + // Assert the result is cached for subsequent calls. + $this->assertEquals($expected, $creds->getUniverseDomain($httpHandler)); + } + + public function testExplicitUniverseDomain() + { + $expected = 'example-universe.com'; + $creds = new GCECredentials(null, null, null, null, null, $expected); + $this->assertEquals($expected, $creds->getUniverseDomain()); + } } diff --git a/tests/fixtures2/private.json b/tests/fixtures2/private.json index 20bb61793..9ae0aae96 100644 --- a/tests/fixtures2/private.json +++ b/tests/fixtures2/private.json @@ -3,5 +3,6 @@ "client_secret": "clientSecret123", "refresh_token": "refreshToken123", "type": "authorized_user", - "quota_project_id": "test_quota_project" + "quota_project_id": "test_quota_project", + "universe_domain": "example-universe.com" } From 6a89d349e5d10c3935e5c61164335384870223d9 Mon Sep 17 00:00:00 2001 From: Brent Shaffer Date: Mon, 11 Sep 2023 14:02:38 -0700 Subject: [PATCH 05/16] Update src/Credentials/GCECredentials.php --- src/Credentials/GCECredentials.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Credentials/GCECredentials.php b/src/Credentials/GCECredentials.php index 562e7fd59..e5da0d79f 100644 --- a/src/Credentials/GCECredentials.php +++ b/src/Credentials/GCECredentials.php @@ -559,7 +559,10 @@ public function getUniverseDomain(callable $httpHandler = null): string self::getUniverseDomainUri() ); } catch (ClientException $e) { - return self::DEFAULT_UNIVERSE_DOMAIN; + if ($e->hasResponse() && 404 == $e->getResponse()->getStatusCode()) { + return self::DEFAULT_UNIVERSE_DOMAIN; + } + throw $e; } return $this->universeDomain; From 602e2fe12cbdaa07dadf9a693520b5e03bdf6a34 Mon Sep 17 00:00:00 2001 From: Brent Shaffer Date: Tue, 12 Sep 2023 11:39:15 -0700 Subject: [PATCH 06/16] add comment regarding 404 on GCE --- src/Credentials/GCECredentials.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Credentials/GCECredentials.php b/src/Credentials/GCECredentials.php index e5da0d79f..5cb484906 100644 --- a/src/Credentials/GCECredentials.php +++ b/src/Credentials/GCECredentials.php @@ -552,7 +552,9 @@ public function getUniverseDomain(callable $httpHandler = null): string return self::DEFAULT_UNIVERSE_DOMAIN; } - // In the case of 404, we return the default universe domain. + // If we know the metadata server exists, but it returns a 404 for the universe domain, we + // can safely assume this is an older metadata server running in GCU, and so we can return + // the default universe domain. try { $this->universeDomain = $this->getFromMetadata( $httpHandler, From 961e021f621120496d70a8af49a351e787bfe809 Mon Sep 17 00:00:00 2001 From: Brent Shaffer Date: Tue, 12 Sep 2023 12:50:51 -0700 Subject: [PATCH 07/16] return default universe domain when MDS returns empty string --- src/Credentials/GCECredentials.php | 18 ++++++++++++------ tests/Credentials/GCECredentialsTest.php | 21 +++++++++++++++++++++ 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/src/Credentials/GCECredentials.php b/src/Credentials/GCECredentials.php index 5cb484906..2a6304bb9 100644 --- a/src/Credentials/GCECredentials.php +++ b/src/Credentials/GCECredentials.php @@ -552,19 +552,25 @@ public function getUniverseDomain(callable $httpHandler = null): string return self::DEFAULT_UNIVERSE_DOMAIN; } - // If we know the metadata server exists, but it returns a 404 for the universe domain, we - // can safely assume this is an older metadata server running in GCU, and so we can return - // the default universe domain. try { $this->universeDomain = $this->getFromMetadata( $httpHandler, self::getUniverseDomainUri() ); } catch (ClientException $e) { - if ($e->hasResponse() && 404 == $e->getResponse()->getStatusCode()) { - return self::DEFAULT_UNIVERSE_DOMAIN; + // If the metadata server exists, but returns a 404 for the universe domain, the auth + // libraries should safely assume this is an older metadata server running in GCU, and + // should return the default universe domain. + if (!$e->hasResponse() || 404 != $e->getResponse()->getStatusCode()) { + throw $e; } - throw $e; + $this->universeDomain = self::DEFAULT_UNIVERSE_DOMAIN; + } + + // We expect in some cases the metadata server will return an empty string for the universe + // domain. In this case, the auth library MUST return the default universe domain. + if ('' === $this->universeDomain) { + $this->universeDomain = self::DEFAULT_UNIVERSE_DOMAIN; } return $this->universeDomain; diff --git a/tests/Credentials/GCECredentialsTest.php b/tests/Credentials/GCECredentialsTest.php index 088b16325..695ba0195 100644 --- a/tests/Credentials/GCECredentialsTest.php +++ b/tests/Credentials/GCECredentialsTest.php @@ -546,6 +546,27 @@ public function testGetUniverseDomain() $this->assertEquals($expected, $creds->getUniverseDomain($httpHandler)); } + public function testGetUniverseDomainEmptyStringReturnsDefault() + { + $creds = new GCECredentials(); + $creds->setIsOnGce(true); + + // Pretend we are on GCE and mock the MDS returning an empty string for the universe domain. + $httpHandler = function ($request) { + $this->assertEquals( + '/computeMetadata/v1/universe/universe_domain', + $request->getUri()->getPath() + ); + return new Psr7\Response(200, [], Utils::streamFor('')); + }; + + // Assert the default universe domain is returned instead of the empty string. + $this->assertEquals( + GCECredentials::DEFAULT_UNIVERSE_DOMAIN, + $creds->getUniverseDomain($httpHandler) + ); + } + public function testExplicitUniverseDomain() { $expected = 'example-universe.com'; From dd75d5b790b4a305ca99c7bb699086113ed9f84e Mon Sep 17 00:00:00 2001 From: Brent Shaffer Date: Tue, 12 Sep 2023 16:20:53 -0700 Subject: [PATCH 08/16] add validation for user-configured universe domain --- src/ApplicationDefaultCredentials.php | 16 ++++- src/Credentials/GCECredentials.php | 49 +++++++++---- tests/ApplicationDefaultCredentialsTest.php | 78 +++++++++++++++++---- tests/Credentials/GCECredentialsTest.php | 29 +++++++- 4 files changed, 140 insertions(+), 32 deletions(-) diff --git a/src/ApplicationDefaultCredentials.php b/src/ApplicationDefaultCredentials.php index 80437c8c9..741a24552 100644 --- a/src/ApplicationDefaultCredentials.php +++ b/src/ApplicationDefaultCredentials.php @@ -29,6 +29,7 @@ use GuzzleHttp\Client; use InvalidArgumentException; use Psr\Cache\CacheItemPoolInterface; +use UnexpectedValueException; /** * ApplicationDefaultCredentials obtains the default credentials for @@ -144,11 +145,14 @@ public static function getMiddleware( * @param string|string[] $defaultScope The default scope to use if no * user-defined scopes exist, expressed either as an Array or as a * space-delimited string. - * @param string $universeDomain Specifies a universe domain to use for the - * calling client library + * @param string $universeDomain A universe domain to use when none is detected + * from the credentials. If the credentains do contain a universe domain, an + * exception is thrown if it does not match this value. * * @return FetchAuthTokenInterface * @throws DomainException if no implementation can be obtained. + * @throws UnexpectedValueException if the configured universe domain differs from + * the credentials */ public static function getCredentials( $scope = null, @@ -183,6 +187,14 @@ public static function getCredentials( $jsonKey['quota_project_id'] = $quotaProject; } if ($universeDomain) { + if ( + isset($jsonKey['universe_domain']) + && $jsonKey['universe_domain'] != $universeDomain + ) { + throw new UnexpectedValueException( + 'Universe information from credentials is different from configured' + ); + } $jsonKey['universe_domain'] = $universeDomain; } $creds = CredentialsLoader::makeCredentials( diff --git a/src/Credentials/GCECredentials.php b/src/Credentials/GCECredentials.php index 2a6304bb9..47767312d 100644 --- a/src/Credentials/GCECredentials.php +++ b/src/Credentials/GCECredentials.php @@ -31,6 +31,7 @@ use GuzzleHttp\Exception\ServerException; use GuzzleHttp\Psr7\Request; use InvalidArgumentException; +use UnexpectedValueException; /** * GCECredentials supports authorization on Google Compute Engine. @@ -179,6 +180,11 @@ class GCECredentials extends CredentialsLoader implements */ private ?string $universeDomain; + /** + * @var bool + */ + private ?string $expectedUniverseDomain; + /** * @param Iam $iam [optional] An IAM instance. * @param string|string[] $scope [optional] the scope of the access request, @@ -188,8 +194,9 @@ class GCECredentials extends CredentialsLoader implements * charges associated with the request. * @param string $serviceAccountIdentity [optional] Specify a service * account identity name to use instead of "default". - * @param string $universeDomain [optional] Specify a universe domain to use - * instead of fetching one from the metadata server. + * @param string $expectedUniverseDomain [optional] Specify a universe + * domain which will be checked against the one returned by the metadata + * server, and throw an exception on mismatch. */ public function __construct( Iam $iam = null, @@ -197,7 +204,7 @@ public function __construct( $targetAudience = null, $quotaProject = null, $serviceAccountIdentity = null, - string $universeDomain = null + string $expectedUniverseDomain = null ) { $this->iam = $iam; @@ -225,7 +232,7 @@ public function __construct( $this->tokenUri = $tokenUri; $this->quotaProject = $quotaProject; $this->serviceAccountIdentity = $serviceAccountIdentity; - $this->universeDomain = $universeDomain; + $this->expectedUniverseDomain = $expectedUniverseDomain; } /** @@ -533,13 +540,28 @@ public function getProjectId(callable $httpHandler = null) * * @param callable $httpHandler Callback which delivers psr7 request * @return string + * @throws UnexpectedValueException if the detected universe domain differs from + * the expected one. */ public function getUniverseDomain(callable $httpHandler = null): string { - if ($this->universeDomain) { + if (isset($this->universeDomain)) { return $this->universeDomain; } + $universeDomain = $this->detectUniverseDomain($httpHandler); + + if ($this->expectedUniverseDomain && $this->expectedUniverseDomain != $universeDomain) { + throw new UnexpectedValueException( + 'Universe information from credentials is different from configured' + ); + } + + return $this->universeDomain = $universeDomain; + } + + private function detectUniverseDomain(callable $httpHandler = null): string + { $httpHandler = $httpHandler ?: HttpHandlerFactory::build(HttpClientCache::getHttpClient()); @@ -553,27 +575,24 @@ public function getUniverseDomain(callable $httpHandler = null): string } try { - $this->universeDomain = $this->getFromMetadata( - $httpHandler, - self::getUniverseDomainUri() - ); + $universeDomain = $this->getFromMetadata($httpHandler, self::getUniverseDomainUri()); } catch (ClientException $e) { // If the metadata server exists, but returns a 404 for the universe domain, the auth // libraries should safely assume this is an older metadata server running in GCU, and // should return the default universe domain. - if (!$e->hasResponse() || 404 != $e->getResponse()->getStatusCode()) { - throw $e; + if ($e->hasResponse() && 404 == $e->getResponse()->getStatusCode()) { + return self::DEFAULT_UNIVERSE_DOMAIN;; } - $this->universeDomain = self::DEFAULT_UNIVERSE_DOMAIN; + throw $e; } // We expect in some cases the metadata server will return an empty string for the universe // domain. In this case, the auth library MUST return the default universe domain. - if ('' === $this->universeDomain) { - $this->universeDomain = self::DEFAULT_UNIVERSE_DOMAIN; + if ('' === $universeDomain) { + return self::DEFAULT_UNIVERSE_DOMAIN; } - return $this->universeDomain; + return $universeDomain; } /** diff --git a/tests/ApplicationDefaultCredentialsTest.php b/tests/ApplicationDefaultCredentialsTest.php index 70225fea4..e120b91d1 100644 --- a/tests/ApplicationDefaultCredentialsTest.php +++ b/tests/ApplicationDefaultCredentialsTest.php @@ -31,6 +31,7 @@ use PHPUnit\Framework\TestCase; use Prophecy\PhpUnit\ProphecyTrait; use ReflectionClass; +use UnexpectedValueException; /** * @runTestsInSeparateProcesses @@ -798,8 +799,42 @@ public function testUniverseDomainInKeyFile() $creds2 = ApplicationDefaultCredentials::getCredentials(); $this->assertEquals('example-universe.com', $creds2->getUniverseDomain()); + } + + /** @runInSeparateProcess */ + public function testUserConfiguredUniverseDomain() + { + // Test no universe domain in keyfile defaults to "googleapis.com" + $keyFile = __DIR__ . '/fixtures/private.json'; + putenv(ServiceAccountCredentials::ENV_VAR . '=' . $keyFile); + $creds = ApplicationDefaultCredentials::getCredentials(); + $this->assertEquals(CredentialsLoader::DEFAULT_UNIVERSE_DOMAIN, $creds->getUniverseDomain()); + + // test passing in a different universe domain overrides keyfile + $creds2 = ApplicationDefaultCredentials::getCredentials( + null, + null, + null, + null, + null, + null, + 'example-universe2.com' + ); + $this->assertEquals('example-universe2.com', $creds2->getUniverseDomain()); + } + + /** @runInSeparateProcess */ + public function testPassingInDifferentUniverseDomainFromKeyFileThrowsException() + { + $this->expectException(UnexpectedValueException::class); + $this->expectExceptionMessage('Universe information from credentials is different from configured'); + + // Test universe domain from keyfile + $keyFile = __DIR__ . '/fixtures2/private.json'; + putenv(ServiceAccountCredentials::ENV_VAR . '=' . $keyFile); + // test passing in a different universe domain overrides keyfile - $creds3 = ApplicationDefaultCredentials::getCredentials( + ApplicationDefaultCredentials::getCredentials( null, null, null, @@ -808,7 +843,6 @@ public function testUniverseDomainInKeyFile() null, 'example-universe2.com' ); - $this->assertEquals('example-universe2.com', $creds3->getUniverseDomain()); } /** @runInSeparateProcess */ @@ -826,28 +860,48 @@ public function testUniverseDomainInGceCredentials() ); $this->assertEquals('example-universe.com', $creds->getUniverseDomain($httpHandler)); - // test passing in a different universe domain overrides metadata server + // test error response returns default universe domain $creds2 = ApplicationDefaultCredentials::getCredentials( null, // $scope $httpHandler = getHandler([ new Response(200, [GCECredentials::FLAVOR_HEADER => 'Google']), + new Response(404), ]), // $httpHandler - null, // $cacheConfig - null, // $cache - null, // $quotaProject - null, // $defaultScope - 'example-universe2.com' // $universeDomain ); - $this->assertEquals('example-universe2.com', $creds2->getUniverseDomain($httpHandler)); + $this->assertEquals(CredentialsLoader::DEFAULT_UNIVERSE_DOMAIN, $creds2->getUniverseDomain($httpHandler)); + } - // test error response returns default universe domain + /** @runInSeparateProcess */ + public function testPassingInDifferentUniverseDomainInGceCredentialsThrowsException() + { + $this->expectException(UnexpectedValueException::class); + $this->expectExceptionMessage('Universe information from credentials is different from configured'); + + putenv('HOME'); + + $expectedUniverseDomain = 'example-universe.com'; + $creds = ApplicationDefaultCredentials::getCredentials( + null, // $scope + $httpHandler = getHandler([ + new Response(200, [GCECredentials::FLAVOR_HEADER => 'Google']), + new Response(200, [], Utils::streamFor($expectedUniverseDomain)), + ]) // $httpHandler + ); + $this->assertEquals('example-universe.com', $creds->getUniverseDomain($httpHandler)); + + // test passing in a different universe domain throws exception $creds2 = ApplicationDefaultCredentials::getCredentials( null, // $scope $httpHandler = getHandler([ new Response(200, [GCECredentials::FLAVOR_HEADER => 'Google']), - new Response(404), + new Response(200, [], Utils::streamFor($expectedUniverseDomain)), ]), // $httpHandler + null, // $cacheConfig + null, // $cache + null, // $quotaProject + null, // $defaultScope + 'example-universe2.com' // $universeDomain ); - $this->assertEquals(CredentialsLoader::DEFAULT_UNIVERSE_DOMAIN, $creds2->getUniverseDomain($httpHandler)); + $this->assertEquals('example-universe2.com', $creds2->getUniverseDomain($httpHandler)); } } diff --git a/tests/Credentials/GCECredentialsTest.php b/tests/Credentials/GCECredentialsTest.php index 695ba0195..02d611fcd 100644 --- a/tests/Credentials/GCECredentialsTest.php +++ b/tests/Credentials/GCECredentialsTest.php @@ -28,6 +28,7 @@ use InvalidArgumentException; use Prophecy\Argument; use Prophecy\PhpUnit\ProphecyTrait; +use UnexpectedValueException; /** * @group credentials @@ -537,6 +538,7 @@ public function testGetUniverseDomain() return new Psr7\Response(200, [], Utils::streamFor($expected)); }; + $creds = new GCECredentials(); $creds->setIsOnGce(true); // Assert correct universe domain. @@ -544,6 +546,12 @@ public function testGetUniverseDomain() // Assert the result is cached for subsequent calls. $this->assertEquals($expected, $creds->getUniverseDomain($httpHandler)); + + // Assert expected universe domain does not throw exception + $creds2 = new GCECredentials(null, null, null, null, null, $expected); + $creds2->setIsOnGce(true); + $timesCalled = 0; + $this->assertEquals($expected, $creds2->getUniverseDomain($httpHandler)); } public function testGetUniverseDomainEmptyStringReturnsDefault() @@ -567,10 +575,25 @@ public function testGetUniverseDomainEmptyStringReturnsDefault() ); } - public function testExplicitUniverseDomain() + public function testExpectedUniverseDomainThrowsExceptionOnMismatch() { - $expected = 'example-universe.com'; + $this->expectException(UnexpectedValueException::class); + $this->expectExceptionMessage('Universe information from credentials is different from configured'); + + $expected = 'example-universe1.com'; + $actual = 'example-universe2.com'; + + // Pretend we are on GCE and mock the MDS returning a different universe domain. + $httpHandler = function ($request) use ($actual) { + $this->assertEquals( + '/computeMetadata/v1/universe/universe_domain', + $request->getUri()->getPath() + ); + return new Psr7\Response(200, [], Utils::streamFor($actual)); + }; + $creds = new GCECredentials(null, null, null, null, null, $expected); - $this->assertEquals($expected, $creds->getUniverseDomain()); + $creds->setIsOnGce(true); + $this->assertEquals($expected, $creds->getUniverseDomain($httpHandler)); } } From 90cb62e0cca1fccc920f0f8fdcebb263f9eef2a9 Mon Sep 17 00:00:00 2001 From: Brent Shaffer Date: Wed, 13 Sep 2023 14:29:15 -0700 Subject: [PATCH 09/16] Revert "add validation for user-configured universe domain" This reverts commit dd75d5b790b4a305ca99c7bb699086113ed9f84e. --- src/ApplicationDefaultCredentials.php | 16 +---- src/Credentials/GCECredentials.php | 49 ++++--------- tests/ApplicationDefaultCredentialsTest.php | 78 ++++----------------- tests/Credentials/GCECredentialsTest.php | 29 +------- 4 files changed, 32 insertions(+), 140 deletions(-) diff --git a/src/ApplicationDefaultCredentials.php b/src/ApplicationDefaultCredentials.php index 741a24552..80437c8c9 100644 --- a/src/ApplicationDefaultCredentials.php +++ b/src/ApplicationDefaultCredentials.php @@ -29,7 +29,6 @@ use GuzzleHttp\Client; use InvalidArgumentException; use Psr\Cache\CacheItemPoolInterface; -use UnexpectedValueException; /** * ApplicationDefaultCredentials obtains the default credentials for @@ -145,14 +144,11 @@ public static function getMiddleware( * @param string|string[] $defaultScope The default scope to use if no * user-defined scopes exist, expressed either as an Array or as a * space-delimited string. - * @param string $universeDomain A universe domain to use when none is detected - * from the credentials. If the credentains do contain a universe domain, an - * exception is thrown if it does not match this value. + * @param string $universeDomain Specifies a universe domain to use for the + * calling client library * * @return FetchAuthTokenInterface * @throws DomainException if no implementation can be obtained. - * @throws UnexpectedValueException if the configured universe domain differs from - * the credentials */ public static function getCredentials( $scope = null, @@ -187,14 +183,6 @@ public static function getCredentials( $jsonKey['quota_project_id'] = $quotaProject; } if ($universeDomain) { - if ( - isset($jsonKey['universe_domain']) - && $jsonKey['universe_domain'] != $universeDomain - ) { - throw new UnexpectedValueException( - 'Universe information from credentials is different from configured' - ); - } $jsonKey['universe_domain'] = $universeDomain; } $creds = CredentialsLoader::makeCredentials( diff --git a/src/Credentials/GCECredentials.php b/src/Credentials/GCECredentials.php index 47767312d..2a6304bb9 100644 --- a/src/Credentials/GCECredentials.php +++ b/src/Credentials/GCECredentials.php @@ -31,7 +31,6 @@ use GuzzleHttp\Exception\ServerException; use GuzzleHttp\Psr7\Request; use InvalidArgumentException; -use UnexpectedValueException; /** * GCECredentials supports authorization on Google Compute Engine. @@ -180,11 +179,6 @@ class GCECredentials extends CredentialsLoader implements */ private ?string $universeDomain; - /** - * @var bool - */ - private ?string $expectedUniverseDomain; - /** * @param Iam $iam [optional] An IAM instance. * @param string|string[] $scope [optional] the scope of the access request, @@ -194,9 +188,8 @@ class GCECredentials extends CredentialsLoader implements * charges associated with the request. * @param string $serviceAccountIdentity [optional] Specify a service * account identity name to use instead of "default". - * @param string $expectedUniverseDomain [optional] Specify a universe - * domain which will be checked against the one returned by the metadata - * server, and throw an exception on mismatch. + * @param string $universeDomain [optional] Specify a universe domain to use + * instead of fetching one from the metadata server. */ public function __construct( Iam $iam = null, @@ -204,7 +197,7 @@ public function __construct( $targetAudience = null, $quotaProject = null, $serviceAccountIdentity = null, - string $expectedUniverseDomain = null + string $universeDomain = null ) { $this->iam = $iam; @@ -232,7 +225,7 @@ public function __construct( $this->tokenUri = $tokenUri; $this->quotaProject = $quotaProject; $this->serviceAccountIdentity = $serviceAccountIdentity; - $this->expectedUniverseDomain = $expectedUniverseDomain; + $this->universeDomain = $universeDomain; } /** @@ -540,28 +533,13 @@ public function getProjectId(callable $httpHandler = null) * * @param callable $httpHandler Callback which delivers psr7 request * @return string - * @throws UnexpectedValueException if the detected universe domain differs from - * the expected one. */ public function getUniverseDomain(callable $httpHandler = null): string { - if (isset($this->universeDomain)) { + if ($this->universeDomain) { return $this->universeDomain; } - $universeDomain = $this->detectUniverseDomain($httpHandler); - - if ($this->expectedUniverseDomain && $this->expectedUniverseDomain != $universeDomain) { - throw new UnexpectedValueException( - 'Universe information from credentials is different from configured' - ); - } - - return $this->universeDomain = $universeDomain; - } - - private function detectUniverseDomain(callable $httpHandler = null): string - { $httpHandler = $httpHandler ?: HttpHandlerFactory::build(HttpClientCache::getHttpClient()); @@ -575,24 +553,27 @@ private function detectUniverseDomain(callable $httpHandler = null): string } try { - $universeDomain = $this->getFromMetadata($httpHandler, self::getUniverseDomainUri()); + $this->universeDomain = $this->getFromMetadata( + $httpHandler, + self::getUniverseDomainUri() + ); } catch (ClientException $e) { // If the metadata server exists, but returns a 404 for the universe domain, the auth // libraries should safely assume this is an older metadata server running in GCU, and // should return the default universe domain. - if ($e->hasResponse() && 404 == $e->getResponse()->getStatusCode()) { - return self::DEFAULT_UNIVERSE_DOMAIN;; + if (!$e->hasResponse() || 404 != $e->getResponse()->getStatusCode()) { + throw $e; } - throw $e; + $this->universeDomain = self::DEFAULT_UNIVERSE_DOMAIN; } // We expect in some cases the metadata server will return an empty string for the universe // domain. In this case, the auth library MUST return the default universe domain. - if ('' === $universeDomain) { - return self::DEFAULT_UNIVERSE_DOMAIN; + if ('' === $this->universeDomain) { + $this->universeDomain = self::DEFAULT_UNIVERSE_DOMAIN; } - return $universeDomain; + return $this->universeDomain; } /** diff --git a/tests/ApplicationDefaultCredentialsTest.php b/tests/ApplicationDefaultCredentialsTest.php index e120b91d1..70225fea4 100644 --- a/tests/ApplicationDefaultCredentialsTest.php +++ b/tests/ApplicationDefaultCredentialsTest.php @@ -31,7 +31,6 @@ use PHPUnit\Framework\TestCase; use Prophecy\PhpUnit\ProphecyTrait; use ReflectionClass; -use UnexpectedValueException; /** * @runTestsInSeparateProcesses @@ -799,42 +798,8 @@ public function testUniverseDomainInKeyFile() $creds2 = ApplicationDefaultCredentials::getCredentials(); $this->assertEquals('example-universe.com', $creds2->getUniverseDomain()); - } - - /** @runInSeparateProcess */ - public function testUserConfiguredUniverseDomain() - { - // Test no universe domain in keyfile defaults to "googleapis.com" - $keyFile = __DIR__ . '/fixtures/private.json'; - putenv(ServiceAccountCredentials::ENV_VAR . '=' . $keyFile); - $creds = ApplicationDefaultCredentials::getCredentials(); - $this->assertEquals(CredentialsLoader::DEFAULT_UNIVERSE_DOMAIN, $creds->getUniverseDomain()); - - // test passing in a different universe domain overrides keyfile - $creds2 = ApplicationDefaultCredentials::getCredentials( - null, - null, - null, - null, - null, - null, - 'example-universe2.com' - ); - $this->assertEquals('example-universe2.com', $creds2->getUniverseDomain()); - } - - /** @runInSeparateProcess */ - public function testPassingInDifferentUniverseDomainFromKeyFileThrowsException() - { - $this->expectException(UnexpectedValueException::class); - $this->expectExceptionMessage('Universe information from credentials is different from configured'); - - // Test universe domain from keyfile - $keyFile = __DIR__ . '/fixtures2/private.json'; - putenv(ServiceAccountCredentials::ENV_VAR . '=' . $keyFile); - // test passing in a different universe domain overrides keyfile - ApplicationDefaultCredentials::getCredentials( + $creds3 = ApplicationDefaultCredentials::getCredentials( null, null, null, @@ -843,6 +808,7 @@ public function testPassingInDifferentUniverseDomainFromKeyFileThrowsException() null, 'example-universe2.com' ); + $this->assertEquals('example-universe2.com', $creds3->getUniverseDomain()); } /** @runInSeparateProcess */ @@ -860,48 +826,28 @@ public function testUniverseDomainInGceCredentials() ); $this->assertEquals('example-universe.com', $creds->getUniverseDomain($httpHandler)); - // test error response returns default universe domain + // test passing in a different universe domain overrides metadata server $creds2 = ApplicationDefaultCredentials::getCredentials( null, // $scope $httpHandler = getHandler([ new Response(200, [GCECredentials::FLAVOR_HEADER => 'Google']), - new Response(404), ]), // $httpHandler + null, // $cacheConfig + null, // $cache + null, // $quotaProject + null, // $defaultScope + 'example-universe2.com' // $universeDomain ); - $this->assertEquals(CredentialsLoader::DEFAULT_UNIVERSE_DOMAIN, $creds2->getUniverseDomain($httpHandler)); - } - - /** @runInSeparateProcess */ - public function testPassingInDifferentUniverseDomainInGceCredentialsThrowsException() - { - $this->expectException(UnexpectedValueException::class); - $this->expectExceptionMessage('Universe information from credentials is different from configured'); - - putenv('HOME'); - - $expectedUniverseDomain = 'example-universe.com'; - $creds = ApplicationDefaultCredentials::getCredentials( - null, // $scope - $httpHandler = getHandler([ - new Response(200, [GCECredentials::FLAVOR_HEADER => 'Google']), - new Response(200, [], Utils::streamFor($expectedUniverseDomain)), - ]) // $httpHandler - ); - $this->assertEquals('example-universe.com', $creds->getUniverseDomain($httpHandler)); + $this->assertEquals('example-universe2.com', $creds2->getUniverseDomain($httpHandler)); - // test passing in a different universe domain throws exception + // test error response returns default universe domain $creds2 = ApplicationDefaultCredentials::getCredentials( null, // $scope $httpHandler = getHandler([ new Response(200, [GCECredentials::FLAVOR_HEADER => 'Google']), - new Response(200, [], Utils::streamFor($expectedUniverseDomain)), + new Response(404), ]), // $httpHandler - null, // $cacheConfig - null, // $cache - null, // $quotaProject - null, // $defaultScope - 'example-universe2.com' // $universeDomain ); - $this->assertEquals('example-universe2.com', $creds2->getUniverseDomain($httpHandler)); + $this->assertEquals(CredentialsLoader::DEFAULT_UNIVERSE_DOMAIN, $creds2->getUniverseDomain($httpHandler)); } } diff --git a/tests/Credentials/GCECredentialsTest.php b/tests/Credentials/GCECredentialsTest.php index 02d611fcd..695ba0195 100644 --- a/tests/Credentials/GCECredentialsTest.php +++ b/tests/Credentials/GCECredentialsTest.php @@ -28,7 +28,6 @@ use InvalidArgumentException; use Prophecy\Argument; use Prophecy\PhpUnit\ProphecyTrait; -use UnexpectedValueException; /** * @group credentials @@ -538,7 +537,6 @@ public function testGetUniverseDomain() return new Psr7\Response(200, [], Utils::streamFor($expected)); }; - $creds = new GCECredentials(); $creds->setIsOnGce(true); // Assert correct universe domain. @@ -546,12 +544,6 @@ public function testGetUniverseDomain() // Assert the result is cached for subsequent calls. $this->assertEquals($expected, $creds->getUniverseDomain($httpHandler)); - - // Assert expected universe domain does not throw exception - $creds2 = new GCECredentials(null, null, null, null, null, $expected); - $creds2->setIsOnGce(true); - $timesCalled = 0; - $this->assertEquals($expected, $creds2->getUniverseDomain($httpHandler)); } public function testGetUniverseDomainEmptyStringReturnsDefault() @@ -575,25 +567,10 @@ public function testGetUniverseDomainEmptyStringReturnsDefault() ); } - public function testExpectedUniverseDomainThrowsExceptionOnMismatch() + public function testExplicitUniverseDomain() { - $this->expectException(UnexpectedValueException::class); - $this->expectExceptionMessage('Universe information from credentials is different from configured'); - - $expected = 'example-universe1.com'; - $actual = 'example-universe2.com'; - - // Pretend we are on GCE and mock the MDS returning a different universe domain. - $httpHandler = function ($request) use ($actual) { - $this->assertEquals( - '/computeMetadata/v1/universe/universe_domain', - $request->getUri()->getPath() - ); - return new Psr7\Response(200, [], Utils::streamFor($actual)); - }; - + $expected = 'example-universe.com'; $creds = new GCECredentials(null, null, null, null, null, $expected); - $creds->setIsOnGce(true); - $this->assertEquals($expected, $creds->getUniverseDomain($httpHandler)); + $this->assertEquals($expected, $creds->getUniverseDomain()); } } From a068736a669bf4725bbe5a1b3ef41fd994d55f7d Mon Sep 17 00:00:00 2001 From: Brent Shaffer Date: Wed, 13 Sep 2023 14:38:16 -0700 Subject: [PATCH 10/16] remove support for universe_domain in user credentials --- src/Credentials/UserRefreshCredentials.php | 11 +++----- tests/ApplicationDefaultCredentialsTest.php | 28 +++++++++++++++++---- tests/fixtures/private.json | 3 ++- 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/Credentials/UserRefreshCredentials.php b/src/Credentials/UserRefreshCredentials.php index 5031c3e08..075e57811 100644 --- a/src/Credentials/UserRefreshCredentials.php +++ b/src/Credentials/UserRefreshCredentials.php @@ -48,11 +48,6 @@ class UserRefreshCredentials extends CredentialsLoader implements GetQuotaProjec */ protected $quotaProject; - /** - * @var string|null - */ - private ?string $universeDomain; - /** * Create a new UserRefreshCredentials. * @@ -99,7 +94,6 @@ public function __construct( if (array_key_exists('quota_project_id', $jsonKey)) { $this->quotaProject = (string) $jsonKey['quota_project_id']; } - $this->universeDomain = $jsonKey['universe_domain'] ?? null; } /** @@ -147,13 +141,14 @@ public function getQuotaProject() } /** - * Get the universe domain configured in the JSON credential. + * Universe domain is not supported in User Refresh credentials - they should + * always return the default universe domain. * * @return string */ public function getUniverseDomain(): string { - return $this->universeDomain ?: self::DEFAULT_UNIVERSE_DOMAIN; + return self::DEFAULT_UNIVERSE_DOMAIN; } /** diff --git a/tests/ApplicationDefaultCredentialsTest.php b/tests/ApplicationDefaultCredentialsTest.php index 70225fea4..9af669357 100644 --- a/tests/ApplicationDefaultCredentialsTest.php +++ b/tests/ApplicationDefaultCredentialsTest.php @@ -787,16 +787,16 @@ public function provideExternalAccountCredentials() public function testUniverseDomainInKeyFile() { // Test no universe domain in keyfile defaults to "googleapis.com" - $keyFile = __DIR__ . '/fixtures/private.json'; + $keyFile = __DIR__ . '/fixtures3/service_account_credentials.json'; putenv(ServiceAccountCredentials::ENV_VAR . '=' . $keyFile); $creds = ApplicationDefaultCredentials::getCredentials(); $this->assertEquals(CredentialsLoader::DEFAULT_UNIVERSE_DOMAIN, $creds->getUniverseDomain()); - // Test universe domain from keyfile - $keyFile = __DIR__ . '/fixtures2/private.json'; + // Test universe domain in "service_account" keyfile + $keyFile = __DIR__ . '/fixtures/private.json'; putenv(ServiceAccountCredentials::ENV_VAR . '=' . $keyFile); - $creds2 = ApplicationDefaultCredentials::getCredentials(); - $this->assertEquals('example-universe.com', $creds2->getUniverseDomain()); + $creds = ApplicationDefaultCredentials::getCredentials(); + $this->assertEquals('example-universe.com', $creds->getUniverseDomain()); // test passing in a different universe domain overrides keyfile $creds3 = ApplicationDefaultCredentials::getCredentials( @@ -809,6 +809,24 @@ public function testUniverseDomainInKeyFile() 'example-universe2.com' ); $this->assertEquals('example-universe2.com', $creds3->getUniverseDomain()); + + // Test universe domain in "authenticated_user" keyfile is not read. + $keyFile = __DIR__ . '/fixtures2/private.json'; + putenv(ServiceAccountCredentials::ENV_VAR . '=' . $keyFile); + $creds2 = ApplicationDefaultCredentials::getCredentials(); + $this->assertEquals(CredentialsLoader::DEFAULT_UNIVERSE_DOMAIN, $creds2->getUniverseDomain()); + + // test passing in a different universe domain for "authenticated_user" has no effect. + $creds3 = ApplicationDefaultCredentials::getCredentials( + null, + null, + null, + null, + null, + null, + 'example-universe2.com' + ); + $this->assertEquals(CredentialsLoader::DEFAULT_UNIVERSE_DOMAIN, $creds3->getUniverseDomain()); } /** @runInSeparateProcess */ diff --git a/tests/fixtures/private.json b/tests/fixtures/private.json index 5d6d1ea64..ef1d49507 100644 --- a/tests/fixtures/private.json +++ b/tests/fixtures/private.json @@ -4,5 +4,6 @@ "client_email": "hello@youarecool.com", "client_id": "client123", "type": "service_account", - "quota_project_id": "test_quota_project" + "quota_project_id": "test_quota_project", + "universe_domain": "example-universe.com" } From 569c4feadee5f3a6e2c43b21cd888463db2759a1 Mon Sep 17 00:00:00 2001 From: Brent Shaffer Date: Wed, 13 Sep 2023 14:44:00 -0700 Subject: [PATCH 11/16] simplify user refresh --- src/Credentials/UserRefreshCredentials.php | 11 ----------- src/CredentialsLoader.php | 4 ++-- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/src/Credentials/UserRefreshCredentials.php b/src/Credentials/UserRefreshCredentials.php index 075e57811..e2f32d87f 100644 --- a/src/Credentials/UserRefreshCredentials.php +++ b/src/Credentials/UserRefreshCredentials.php @@ -140,17 +140,6 @@ public function getQuotaProject() return $this->quotaProject; } - /** - * Universe domain is not supported in User Refresh credentials - they should - * always return the default universe domain. - * - * @return string - */ - public function getUniverseDomain(): string - { - return self::DEFAULT_UNIVERSE_DOMAIN; - } - /** * Get the granted scopes (if they exist) for the last fetched token. * diff --git a/src/CredentialsLoader.php b/src/CredentialsLoader.php index 689dfdf15..746b957a9 100644 --- a/src/CredentialsLoader.php +++ b/src/CredentialsLoader.php @@ -276,8 +276,8 @@ private static function loadDefaultClientCertSourceFile() } /** - * Get the universe domain from the credential. Defaults to - * "googleapis.com" for all credential types. + * Get the universe domain from the credential. Defaults to "googleapis.com" + * for all credential types which do not support universe domain. * * @return string */ From 1d3ec0171a4ec2db9abb8adcb75b1db9347dc988 Mon Sep 17 00:00:00 2001 From: Brent Shaffer Date: Wed, 20 Sep 2023 14:38:31 -0700 Subject: [PATCH 12/16] remove universe domain support in GCECredentials --- src/Credentials/GCECredentials.php | 50 ------------------ tests/ApplicationDefaultCredentialsTest.php | 40 --------------- tests/Credentials/GCECredentialsTest.php | 57 +-------------------- 3 files changed, 2 insertions(+), 145 deletions(-) diff --git a/src/Credentials/GCECredentials.php b/src/Credentials/GCECredentials.php index 2a6304bb9..ed79dbb37 100644 --- a/src/Credentials/GCECredentials.php +++ b/src/Credentials/GCECredentials.php @@ -526,56 +526,6 @@ public function getProjectId(callable $httpHandler = null) return $this->projectId; } - /** - * Fetch the default universe domain from the metadata server. - * - * Returns null if called outside GCE. - * - * @param callable $httpHandler Callback which delivers psr7 request - * @return string - */ - public function getUniverseDomain(callable $httpHandler = null): string - { - if ($this->universeDomain) { - return $this->universeDomain; - } - - $httpHandler = $httpHandler - ?: HttpHandlerFactory::build(HttpClientCache::getHttpClient()); - - if (!$this->hasCheckedOnGce) { - $this->isOnGce = self::onGce($httpHandler); - $this->hasCheckedOnGce = true; - } - - if (!$this->isOnGce) { - return self::DEFAULT_UNIVERSE_DOMAIN; - } - - try { - $this->universeDomain = $this->getFromMetadata( - $httpHandler, - self::getUniverseDomainUri() - ); - } catch (ClientException $e) { - // If the metadata server exists, but returns a 404 for the universe domain, the auth - // libraries should safely assume this is an older metadata server running in GCU, and - // should return the default universe domain. - if (!$e->hasResponse() || 404 != $e->getResponse()->getStatusCode()) { - throw $e; - } - $this->universeDomain = self::DEFAULT_UNIVERSE_DOMAIN; - } - - // We expect in some cases the metadata server will return an empty string for the universe - // domain. In this case, the auth library MUST return the default universe domain. - if ('' === $this->universeDomain) { - $this->universeDomain = self::DEFAULT_UNIVERSE_DOMAIN; - } - - return $this->universeDomain; - } - /** * Fetch the value of a GCE metadata server URI. * diff --git a/tests/ApplicationDefaultCredentialsTest.php b/tests/ApplicationDefaultCredentialsTest.php index 9af669357..f80372473 100644 --- a/tests/ApplicationDefaultCredentialsTest.php +++ b/tests/ApplicationDefaultCredentialsTest.php @@ -828,44 +828,4 @@ public function testUniverseDomainInKeyFile() ); $this->assertEquals(CredentialsLoader::DEFAULT_UNIVERSE_DOMAIN, $creds3->getUniverseDomain()); } - - /** @runInSeparateProcess */ - public function testUniverseDomainInGceCredentials() - { - putenv('HOME'); - - $expectedUniverseDomain = 'example-universe.com'; - $creds = ApplicationDefaultCredentials::getCredentials( - null, // $scope - $httpHandler = getHandler([ - new Response(200, [GCECredentials::FLAVOR_HEADER => 'Google']), - new Response(200, [], Utils::streamFor($expectedUniverseDomain)), - ]) // $httpHandler - ); - $this->assertEquals('example-universe.com', $creds->getUniverseDomain($httpHandler)); - - // test passing in a different universe domain overrides metadata server - $creds2 = ApplicationDefaultCredentials::getCredentials( - null, // $scope - $httpHandler = getHandler([ - new Response(200, [GCECredentials::FLAVOR_HEADER => 'Google']), - ]), // $httpHandler - null, // $cacheConfig - null, // $cache - null, // $quotaProject - null, // $defaultScope - 'example-universe2.com' // $universeDomain - ); - $this->assertEquals('example-universe2.com', $creds2->getUniverseDomain($httpHandler)); - - // test error response returns default universe domain - $creds2 = ApplicationDefaultCredentials::getCredentials( - null, // $scope - $httpHandler = getHandler([ - new Response(200, [GCECredentials::FLAVOR_HEADER => 'Google']), - new Response(404), - ]), // $httpHandler - ); - $this->assertEquals(CredentialsLoader::DEFAULT_UNIVERSE_DOMAIN, $creds2->getUniverseDomain($httpHandler)); - } } diff --git a/tests/Credentials/GCECredentialsTest.php b/tests/Credentials/GCECredentialsTest.php index 695ba0195..9369e40ac 100644 --- a/tests/Credentials/GCECredentialsTest.php +++ b/tests/Credentials/GCECredentialsTest.php @@ -517,60 +517,7 @@ public function testGetUniverseDomain() { $creds = new GCECredentials(); - // If we are not on GCE, this should return the default - $creds->setIsOnGce(false); - $this->assertEquals( - GCECredentials::DEFAULT_UNIVERSE_DOMAIN, - $creds->getUniverseDomain() - ); - - // Pretend we are on GCE and mock the http handler. - $expected = 'example-universe.com'; - $timesCalled = 0; - $httpHandler = function ($request) use (&$timesCalled, $expected) { - $timesCalled++; - $this->assertEquals( - '/computeMetadata/v1/universe/universe_domain', - $request->getUri()->getPath() - ); - $this->assertEquals(1, $timesCalled, 'should only be called once'); - return new Psr7\Response(200, [], Utils::streamFor($expected)); - }; - - $creds->setIsOnGce(true); - - // Assert correct universe domain. - $this->assertEquals($expected, $creds->getUniverseDomain($httpHandler)); - - // Assert the result is cached for subsequent calls. - $this->assertEquals($expected, $creds->getUniverseDomain($httpHandler)); - } - - public function testGetUniverseDomainEmptyStringReturnsDefault() - { - $creds = new GCECredentials(); - $creds->setIsOnGce(true); - - // Pretend we are on GCE and mock the MDS returning an empty string for the universe domain. - $httpHandler = function ($request) { - $this->assertEquals( - '/computeMetadata/v1/universe/universe_domain', - $request->getUri()->getPath() - ); - return new Psr7\Response(200, [], Utils::streamFor('')); - }; - - // Assert the default universe domain is returned instead of the empty string. - $this->assertEquals( - GCECredentials::DEFAULT_UNIVERSE_DOMAIN, - $creds->getUniverseDomain($httpHandler) - ); - } - - public function testExplicitUniverseDomain() - { - $expected = 'example-universe.com'; - $creds = new GCECredentials(null, null, null, null, null, $expected); - $this->assertEquals($expected, $creds->getUniverseDomain()); + // Universe domain should always be the default + $this->assertEquals(GCECredentials::DEFAULT_UNIVERSE_DOMAIN, $creds->getUniverseDomain()); } } From ca9192a8784a1dc607d27c49343af9c049c41e84 Mon Sep 17 00:00:00 2001 From: Brent Shaffer Date: Wed, 20 Sep 2023 14:50:58 -0700 Subject: [PATCH 13/16] remove logic for passing of universeDomain --- src/ApplicationDefaultCredentials.php | 10 ++------ src/Credentials/GCECredentials.php | 13 ---------- src/Credentials/ServiceAccountCredentials.php | 5 +++- tests/ApplicationDefaultCredentialsTest.php | 24 ------------------- 4 files changed, 6 insertions(+), 46 deletions(-) diff --git a/src/ApplicationDefaultCredentials.php b/src/ApplicationDefaultCredentials.php index 80437c8c9..d556fac4e 100644 --- a/src/ApplicationDefaultCredentials.php +++ b/src/ApplicationDefaultCredentials.php @@ -144,8 +144,6 @@ public static function getMiddleware( * @param string|string[] $defaultScope The default scope to use if no * user-defined scopes exist, expressed either as an Array or as a * space-delimited string. - * @param string $universeDomain Specifies a universe domain to use for the - * calling client library * * @return FetchAuthTokenInterface * @throws DomainException if no implementation can be obtained. @@ -156,8 +154,7 @@ public static function getCredentials( array $cacheConfig = null, CacheItemPoolInterface $cache = null, $quotaProject = null, - $defaultScope = null, - string $universeDomain = null + $defaultScope = null ) { $creds = null; $jsonKey = CredentialsLoader::fromEnv() @@ -182,9 +179,6 @@ public static function getCredentials( if ($quotaProject) { $jsonKey['quota_project_id'] = $quotaProject; } - if ($universeDomain) { - $jsonKey['universe_domain'] = $universeDomain; - } $creds = CredentialsLoader::makeCredentials( $scope, $jsonKey, @@ -193,7 +187,7 @@ public static function getCredentials( } elseif (AppIdentityCredentials::onAppEngine() && !GCECredentials::onAppEngineFlexible()) { $creds = new AppIdentityCredentials($anyScope); } elseif (self::onGce($httpHandler, $cacheConfig, $cache)) { - $creds = new GCECredentials(null, $anyScope, null, $quotaProject, null, $universeDomain); + $creds = new GCECredentials(null, $anyScope, null, $quotaProject); $creds->setIsOnGce(true); // save the credentials a trip to the metadata server } diff --git a/src/Credentials/GCECredentials.php b/src/Credentials/GCECredentials.php index ed79dbb37..9453088a3 100644 --- a/src/Credentials/GCECredentials.php +++ b/src/Credentials/GCECredentials.php @@ -95,11 +95,6 @@ class GCECredentials extends CredentialsLoader implements */ const PROJECT_ID_URI_PATH = 'v1/project/project-id'; - /** - * The metadata path of the project ID. - */ - const UNIVERSE_DOMAIN_URI_PATH = 'v1/universe/universe_domain'; - /** * The header whose presence indicates GCE presence. */ @@ -174,11 +169,6 @@ class GCECredentials extends CredentialsLoader implements */ private $serviceAccountIdentity; - /** - * @var string - */ - private ?string $universeDomain; - /** * @param Iam $iam [optional] An IAM instance. * @param string|string[] $scope [optional] the scope of the access request, @@ -188,8 +178,6 @@ class GCECredentials extends CredentialsLoader implements * charges associated with the request. * @param string $serviceAccountIdentity [optional] Specify a service * account identity name to use instead of "default". - * @param string $universeDomain [optional] Specify a universe domain to use - * instead of fetching one from the metadata server. */ public function __construct( Iam $iam = null, @@ -225,7 +213,6 @@ public function __construct( $this->tokenUri = $tokenUri; $this->quotaProject = $quotaProject; $this->serviceAccountIdentity = $serviceAccountIdentity; - $this->universeDomain = $universeDomain; } /** diff --git a/src/Credentials/ServiceAccountCredentials.php b/src/Credentials/ServiceAccountCredentials.php index c7a7a2dd0..086417c07 100644 --- a/src/Credentials/ServiceAccountCredentials.php +++ b/src/Credentials/ServiceAccountCredentials.php @@ -341,7 +341,10 @@ public function getQuotaProject() */ public function getUniverseDomain(): string { - return $this->universeDomain ?: self::DEFAULT_UNIVERSE_DOMAIN; + if (null === $this->universeDomain) { + return self::DEFAULT_UNIVERSE_DOMAIN; + } + return $this->universeDomain; } /** diff --git a/tests/ApplicationDefaultCredentialsTest.php b/tests/ApplicationDefaultCredentialsTest.php index f80372473..d7c2074ad 100644 --- a/tests/ApplicationDefaultCredentialsTest.php +++ b/tests/ApplicationDefaultCredentialsTest.php @@ -798,34 +798,10 @@ public function testUniverseDomainInKeyFile() $creds = ApplicationDefaultCredentials::getCredentials(); $this->assertEquals('example-universe.com', $creds->getUniverseDomain()); - // test passing in a different universe domain overrides keyfile - $creds3 = ApplicationDefaultCredentials::getCredentials( - null, - null, - null, - null, - null, - null, - 'example-universe2.com' - ); - $this->assertEquals('example-universe2.com', $creds3->getUniverseDomain()); - // Test universe domain in "authenticated_user" keyfile is not read. $keyFile = __DIR__ . '/fixtures2/private.json'; putenv(ServiceAccountCredentials::ENV_VAR . '=' . $keyFile); $creds2 = ApplicationDefaultCredentials::getCredentials(); $this->assertEquals(CredentialsLoader::DEFAULT_UNIVERSE_DOMAIN, $creds2->getUniverseDomain()); - - // test passing in a different universe domain for "authenticated_user" has no effect. - $creds3 = ApplicationDefaultCredentials::getCredentials( - null, - null, - null, - null, - null, - null, - 'example-universe2.com' - ); - $this->assertEquals(CredentialsLoader::DEFAULT_UNIVERSE_DOMAIN, $creds3->getUniverseDomain()); } } From f5ece95361d2a1c1315ae4896de2773760d31547 Mon Sep 17 00:00:00 2001 From: Brent Shaffer Date: Wed, 20 Sep 2023 14:54:44 -0700 Subject: [PATCH 14/16] remove unused methods --- src/Credentials/GCECredentials.php | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/Credentials/GCECredentials.php b/src/Credentials/GCECredentials.php index 9453088a3..991589b52 100644 --- a/src/Credentials/GCECredentials.php +++ b/src/Credentials/GCECredentials.php @@ -184,8 +184,7 @@ public function __construct( $scope = null, $targetAudience = null, $quotaProject = null, - $serviceAccountIdentity = null, - string $universeDomain = null + $serviceAccountIdentity = null ) { $this->iam = $iam; @@ -295,18 +294,6 @@ private static function getProjectIdUri() return $base . self::PROJECT_ID_URI_PATH; } - /** - * The full uri for accessing the default universe domain. - * - * @return string - */ - private static function getUniverseDomainUri() - { - $base = 'http://' . self::METADATA_IP . '/computeMetadata/'; - - return $base . self::UNIVERSE_DOMAIN_URI_PATH; - } - /** * Determines if this an App Engine Flexible instance, by accessing the * GAE_INSTANCE environment variable. From 0c47f37c4513a3eae300f086823b224b2a852d05 Mon Sep 17 00:00:00 2001 From: Brent Shaffer Date: Wed, 25 Oct 2023 15:02:25 -0700 Subject: [PATCH 15/16] implement GetUniverseDomainInterface for credentials cache --- src/FetchAuthTokenCache.php | 15 +++++++++++++ tests/FetchAuthTokenCacheTest.php | 36 +++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/src/FetchAuthTokenCache.php b/src/FetchAuthTokenCache.php index 47174a1b7..cac1984ab 100644 --- a/src/FetchAuthTokenCache.php +++ b/src/FetchAuthTokenCache.php @@ -26,6 +26,7 @@ class FetchAuthTokenCache implements FetchAuthTokenInterface, GetQuotaProjectInterface, + GetUniverseDomainInterface, SignBlobInterface, ProjectIdProviderInterface, UpdateMetadataInterface @@ -191,6 +192,20 @@ public function getProjectId(callable $httpHandler = null) return $this->fetcher->getProjectId($httpHandler); } + /* + * Get the Universe Domain from the fetcher. + * + * @return string + */ + public function getUniverseDomain(): string + { + if ($this->fetcher instanceof GetUniverseDomainInterface) { + return $this->fetcher->getUniverseDomain(); + } + + return GetUniverseDomainInterface::DEFAULT_UNIVERSE_DOMAIN; + } + /** * Updates metadata with the authorization token. * diff --git a/tests/FetchAuthTokenCacheTest.php b/tests/FetchAuthTokenCacheTest.php index f59c9295a..21a68e702 100644 --- a/tests/FetchAuthTokenCacheTest.php +++ b/tests/FetchAuthTokenCacheTest.php @@ -21,6 +21,7 @@ use Google\Auth\Credentials\ServiceAccountCredentials; use Google\Auth\CredentialsLoader; use Google\Auth\FetchAuthTokenCache; +use Google\Auth\GetUniverseDomainInterface; use Prophecy\Argument; use Prophecy\PhpUnit\ProphecyTrait; use RuntimeException; @@ -603,6 +604,41 @@ public function testGetProjectIdInvalidFetcher() $fetcher->getProjectId(); } + public function testGetUniverseDomain() + { + $universeDomain = 'foobar'; + + $mockFetcher = $this->prophesize('Google\Auth\GetUniverseDomainInterface'); + $mockFetcher->willImplement('Google\Auth\FetchAuthTokenInterface'); + $mockFetcher->getUniverseDomain() + ->shouldBeCalled() + ->willReturn($universeDomain); + + $fetcher = new FetchAuthTokenCache( + $mockFetcher->reveal(), + [], + $this->mockCache->reveal() + ); + + $this->assertEquals($universeDomain, $fetcher->getUniverseDomain()); + } + + public function testGetUniverseDomainInvalidFetcher() + { + $mockFetcher = $this->prophesize('Google\Auth\FetchAuthTokenInterface'); + + $fetcher = new FetchAuthTokenCache( + $mockFetcher->reveal(), + [], + $this->mockCache->reveal() + ); + + $this->assertEquals( + GetUniverseDomainInterface::DEFAULT_UNIVERSE_DOMAIN, + $fetcher->getUniverseDomain() + ); + } + public function testGetFetcher() { $mockFetcher = $this->prophesize('Google\Auth\FetchAuthTokenInterface') From 76e6149ec2482128455e9f2d7ab002899f288b29 Mon Sep 17 00:00:00 2001 From: Brent Shaffer Date: Tue, 28 Nov 2023 07:46:20 -0800 Subject: [PATCH 16/16] Update src/GetUniverseDomainInterface.php Co-authored-by: Vishwaraj Anand --- src/GetUniverseDomainInterface.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GetUniverseDomainInterface.php b/src/GetUniverseDomainInterface.php index 2b6b8763f..1656ddc2e 100644 --- a/src/GetUniverseDomainInterface.php +++ b/src/GetUniverseDomainInterface.php @@ -18,7 +18,7 @@ namespace Google\Auth; /** - * An interface implemented by objects that can get quota projects. + * An interface implemented by objects that can get universe domain for Google Cloud APIs. */ interface GetUniverseDomainInterface {