Skip to content

Commit

Permalink
add universe domain to credentials wrapper
Browse files Browse the repository at this point in the history
  • Loading branch information
bshaffer committed Nov 14, 2023
1 parent c66d5ef commit 73b1877
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 40 deletions.
41 changes: 27 additions & 14 deletions src/CredentialsWrapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
/**
* The CredentialsWrapper object provides a wrapper around a FetchAuthTokenInterface.
*/
class CredentialsWrapper implements GetUniverseDomainInterface
class CredentialsWrapper
{
use ValidationTrait;

Expand All @@ -59,6 +59,9 @@ class CredentialsWrapper implements GetUniverseDomainInterface
/** @var callable $authHttpHandle */
private $authHttpHandler;

private ?string $universeDomain;
private bool $hasCheckedUniverse = false;

/** @var int */
private static int $eagerRefreshThresholdSeconds = 10;

Expand All @@ -71,10 +74,14 @@ class CredentialsWrapper implements GetUniverseDomainInterface
* `function (RequestInterface $request, array $options) : ResponseInterface`.
* @throws ValidationException
*/
public function __construct(FetchAuthTokenInterface $credentialsFetcher, callable $authHttpHandler = null)
{
public function __construct(
FetchAuthTokenInterface $credentialsFetcher,
callable $authHttpHandler = null,
?string $universeDomain = null
) {
$this->credentialsFetcher = $credentialsFetcher;
$this->authHttpHandler = $authHttpHandler ?: self::buildHttpHandlerFactory();
$this->universeDomain = $universeDomain;
}

/**
Expand Down Expand Up @@ -108,10 +115,12 @@ public function __construct(FetchAuthTokenInterface $credentialsFetcher, callabl
* Ensures service account credentials use JWT Access (also known as self-signed
* JWTs), even when user-defined scopes are supplied.
* }
* @param string $universeDomain The expected universe of the credentials. If empty, the
* credentials wrapper will bypass checking that the credentials universe matches this one.
* @return CredentialsWrapper
* @throws ValidationException
*/
public static function build(array $args = [])
public static function build(array $args = [], string $universeDomain = null)
{
$args += [
'keyFile' => null,
Expand Down Expand Up @@ -174,7 +183,7 @@ public static function build(array $args = [])
);
}

return new CredentialsWrapper($loader, $authHttpHandler);
return new CredentialsWrapper($loader, $authHttpHandler, $universeDomain);
}

/**
Expand Down Expand Up @@ -213,6 +222,19 @@ public function getAuthorizationHeaderCallback($audience = null)
return function () use ($credentialsFetcher, $authHttpHandler, $audience) {
$token = $credentialsFetcher->getLastReceivedToken();
if (self::isExpired($token)) {
if (false === $this->hasCheckedUniverse
&& null !== $this->universeDomain
&& $credentialsFetcher instanceof GetUniverseDomainInterface
) {
if ($credentialsFetcher->getUniverseDomain() !== $this->universeDomain) {
throw new ValidationException(sprintf(
'The configured universe domain (%s) does not match the credential universe domain (%s)',
$this->universeDomain,
$credentialsFetcher->getUniverseDomain()
));
}
$this->hasCheckedUniverseDomain = true;

Check failure on line 236 in src/CredentialsWrapper.php

View workflow job for this annotation

GitHub Actions / PHPStan Static Analysis

Access to an undefined property Google\ApiCore\CredentialsWrapper::$hasCheckedUniverseDomain.
}
// Call updateMetadata to take advantage of self-signed JWTs
if ($credentialsFetcher instanceof UpdateMetadataInterface) {
return $credentialsFetcher->updateMetadata([], $audience);
Expand Down Expand Up @@ -308,13 +330,4 @@ private static function isExpired($token)
&& array_key_exists('expires_at', $token)
&& $token['expires_at'] > time() + self::$eagerRefreshThresholdSeconds);
}

public function getUniverseDomain(): string
{
if ($this->credentialsFetcher instanceof GetUniverseDomainInterface) {
return $this->credentialsFetcher->getUniverseDomain();
}

return GetUniverseDomainInterface::DEFAULT_UNIVERSE_DOMAIN;
}
}
44 changes: 18 additions & 26 deletions src/GapicClientTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -241,9 +241,19 @@ private function buildClientOptions(array $options)
// if the universe domain hasn't been explicitly set, assume GDU ("googleapis.com")
$options['universeDomain'] ??= GetUniverseDomainInterface::DEFAULT_UNIVERSE_DOMAIN;

// Build the apiEndpoint from the universe domain if it hasn't been explicitly provided
if (is_null($apiEndpoint)) {
$apiEndpoint = self::determineApiEndpoint($options['universeDomain'], $defaultOptions['apiEndpoint']);
if (defined('self::SERVICE_ADDRESS_TEMPLATE')) {
// Derive the endpoint from the service address template and the universe domain
$apiEndpoint = str_replace(
'UNIVERSE_DOMAIN',
$universeDomain,
self::SERVICE_ADDRESS_TEMPLATE
);
} else {
// For older clients, the service address template does not exist. Use the default
// endpoint instead.
$apiEndpoint = $defaultOptions['apiEndpoint'];
}
}

if (extension_loaded('sysvshm')
Expand Down Expand Up @@ -274,25 +284,6 @@ private function buildClientOptions(array $options)
return $options;
}

/**
* @internal
* @throws ValidationException
*/
private static function determineApiEndpoint(string $universeDomain, string $legacyApiEndpoint): string
{
// If no API endpoint is set, derive the endpoint from the service address template and the
// universe domain
if (defined('self::SERVICE_ADDRESS_TEMPLATE')) {
return str_replace(
'UNIVERSE_DOMAIN',
$universeDomain,
self::SERVICE_ADDRESS_TEMPLATE
);
}
// If no serviceAddressTemplate exsts, this is an older client. Use the default endpoint
return $legacyApiEndpoint;
}

private function shouldUseMtlsEndpoint(array $options)
{
$mtlsEndpointEnvVar = getenv('GOOGLE_API_USE_MTLS_ENDPOINT');
Expand Down Expand Up @@ -449,7 +440,8 @@ private function setClientOptions(array $options)

$this->credentialsWrapper = $this->createCredentialsWrapper(
$options['credentials'],
$options['credentialsConfig']
$options['credentialsConfig'],
$options['universeDomain']
);

$transport = $options['transport'] ?: self::defaultTransport();
Expand All @@ -469,15 +461,15 @@ private function setClientOptions(array $options)
* @return CredentialsWrapper
* @throws ValidationException
*/
private function createCredentialsWrapper($credentials, array $credentialsConfig)
private function createCredentialsWrapper($credentials, array $credentialsConfig, string $universeDomain)
{
if (is_null($credentials)) {
return CredentialsWrapper::build($credentialsConfig);
return CredentialsWrapper::build($credentialsConfig, $universeDomain);
} elseif (is_string($credentials) || is_array($credentials)) {
return CredentialsWrapper::build(['keyFile' => $credentials] + $credentialsConfig);
return CredentialsWrapper::build(['keyFile' => $credentials] + $credentialsConfig, $universeDomain);
} elseif ($credentials instanceof FetchAuthTokenInterface) {
$authHttpHandler = $credentialsConfig['authHttpHandler'] ?? null;
return new CredentialsWrapper($credentials, $authHttpHandler);
return new CredentialsWrapper($credentials, $authHttpHandler, $universeDomain);
} elseif ($credentials instanceof CredentialsWrapper) {
return $credentials;
} else {
Expand Down
3 changes: 3 additions & 0 deletions tests/Tests/Unit/GapicClientTraitTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,7 @@ public function testCreateCredentialsWrapper($auth, $authConfig, $expectedCreden
$actualCredentialsWrapper = $client->createCredentialsWrapper(
$auth,
$authConfig,
''
);

$this->assertEquals($expectedCredentialsWrapper, $actualCredentialsWrapper);
Expand Down Expand Up @@ -656,6 +657,7 @@ public function testCreateCredentialsWrapperValidationException($auth, $authConf
$client->createCredentialsWrapper(
$auth,
$authConfig,
''
);
}

Expand All @@ -679,6 +681,7 @@ public function testCreateCredentialsWrapperInvalidArgumentException($auth, $aut
$client->createCredentialsWrapper(
$auth,
$authConfig,
''
);
}

Expand Down

0 comments on commit 73b1877

Please sign in to comment.