Skip to content

Commit

Permalink
Merge branch 'main' into php8.3
Browse files Browse the repository at this point in the history
  • Loading branch information
bshaffer authored Dec 19, 2023
2 parents 54d97da + 0c563b5 commit 3a69694
Show file tree
Hide file tree
Showing 14 changed files with 316 additions and 18 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- run: git fetch --depth=1 origin +refs/tags/*:refs/tags/*
- name: Setup PHP
uses: shivammathur/setup-php@v2
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
php: [ "7.4", "8.0", "8.1", "8.2", "8.3" ]
name: PHP ${{matrix.php }} Unit Test
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
Expand All @@ -31,7 +31,7 @@ jobs:
runs-on: ubuntu-latest
name: Test Prefer Lowest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
Expand All @@ -49,7 +49,7 @@ jobs:
runs-on: ubuntu-latest
name: PHP Style Check
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
Expand All @@ -64,7 +64,7 @@ jobs:
runs-on: ubuntu-latest
name: PHPStan Static Analysis
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
Expand Down
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@

* [feat]: add support for Firebase v6.0 (#391)

## [1.33.0](https://github.com/googleapis/google-auth-library-php/compare/v1.32.1...v1.33.0) (2023-11-29)


### Features

* Add and implement universe domain interface ([#477](https://github.com/googleapis/google-auth-library-php/issues/477)) ([35781ed](https://github.com/googleapis/google-auth-library-php/commit/35781ed573aa9d831d38452eefbac790559dfb97))

### Miscellaneous

* Refactor `AuthTokenMiddleware` ([#492](https://github.com/googleapis/google-auth-library-php/pull/492))

## [1.32.1](https://github.com/googleapis/google-auth-library-php/compare/v1.32.0...v1.32.1) (2023-10-17)


Expand Down
1 change: 1 addition & 0 deletions VERSION
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1.33.0
2 changes: 1 addition & 1 deletion phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="tests/bootstrap.php" colors="true" convertWarningsToExceptions="false" convertNoticesToExceptions="false" convertErrorsToExceptions="false" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="tests/bootstrap.php" colors="true" convertWarningsToExceptions="true" convertNoticesToExceptions="false" convertErrorsToExceptions="true" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
<coverage>
<include>
<directory suffix=".php">src</directory>
Expand Down
10 changes: 8 additions & 2 deletions src/ApplicationDefaultCredentials.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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()
Expand All @@ -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,
Expand All @@ -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
}

Expand Down
78 changes: 77 additions & 1 deletion src/Credentials/GCECredentials.php
Original file line number Diff line number Diff line change
Expand Up @@ -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/universe_domain';

/**
* The header whose presence indicates GCE presence.
*/
Expand Down Expand Up @@ -169,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,
Expand All @@ -178,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,
string $universeDomain = null
) {
$this->iam = $iam;

Expand Down Expand Up @@ -212,6 +225,7 @@ public function __construct(
$this->tokenUri = $tokenUri;
$this->quotaProject = $quotaProject;
$this->serviceAccountIdentity = $serviceAccountIdentity;
$this->universeDomain = $universeDomain;
}

/**
Expand Down Expand Up @@ -294,6 +308,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.
Expand Down Expand Up @@ -500,6 +526,56 @@ 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 (null !== $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.
*
Expand Down
29 changes: 23 additions & 6 deletions src/Credentials/ServiceAccountCredentials.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,9 @@ class ServiceAccountCredentials extends CredentialsLoader implements
private $jwtAccessCredentials;

/**
* @var string|null
* @var string
*/
private ?string $universeDomain;
private string $universeDomain;

/**
* Create a new ServiceAccountCredentials.
Expand Down Expand Up @@ -164,7 +164,7 @@ public function __construct(
]);

$this->projectId = $jsonKey['project_id'] ?? null;
$this->universeDomain = $jsonKey['universe_domain'] ?? null;
$this->universeDomain = $jsonKey['universe_domain'] ?? self::DEFAULT_UNIVERSE_DOMAIN;
}

/**
Expand Down Expand Up @@ -341,9 +341,6 @@ public function getQuotaProject()
*/
public function getUniverseDomain(): string
{
if (null === $this->universeDomain) {
return self::DEFAULT_UNIVERSE_DOMAIN;
}
return $this->universeDomain;
}

Expand All @@ -352,6 +349,20 @@ public function getUniverseDomain(): string
*/
private function useSelfSignedJwt()
{
// When a sub is supplied, the user is using domain-wide delegation, which not available
// with self-signed JWTs
if (null !== $this->auth->getSub()) {
// If we are outside the GDU, we can't use domain-wide delegation
if ($this->getUniverseDomain() !== self::DEFAULT_UNIVERSE_DOMAIN) {
throw new \LogicException(sprintf(
'Service Account subject is configured for the credential. Domain-wide ' .
'delegation is not supported in universes other than %s.',
self::DEFAULT_UNIVERSE_DOMAIN
));
}
return false;
}

// If claims are set, this call is for "id_tokens"
if ($this->auth->getAdditionalClaims()) {
return false;
Expand All @@ -361,6 +372,12 @@ private function useSelfSignedJwt()
if ($this->useJwtAccessWithScope) {
return true;
}

// If the universe domain is outside the GDU, use JwtAccess for access tokens
if ($this->getUniverseDomain() !== self::DEFAULT_UNIVERSE_DOMAIN) {
return true;
}

return is_null($this->auth->getScope());
}
}
2 changes: 1 addition & 1 deletion src/Middleware/AuthTokenMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ private function addAuthHeaders(RequestInterface $request)
) {
$token = $this->fetcher->fetchAuthToken();
$request = $request->withHeader(
'authorization', 'Bearer ' . ($token['access_token'] ?? $token['id_token'])
'authorization', 'Bearer ' . ($token['access_token'] ?? $token['id_token'] ?? '')
);
} else {
$headers = $this->fetcher->updateMetadata($request->getHeaders(), null, $this->httpHandler);
Expand Down
52 changes: 52 additions & 0 deletions tests/ApplicationDefaultCredentialsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -804,5 +804,57 @@ public function testUniverseDomainInKeyFile()
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 */
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));
}
}
Loading

0 comments on commit 3a69694

Please sign in to comment.