Skip to content

Commit

Permalink
Merge branch 'main' into renovate/actions-checkout-4.x
Browse files Browse the repository at this point in the history
  • Loading branch information
bshaffer authored Dec 12, 2023
2 parents b0db1f1 + 7b03c82 commit 7ba3d8b
Show file tree
Hide file tree
Showing 16 changed files with 327 additions and 56 deletions.
33 changes: 33 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Release Pre-Check
on:
pull_request:
workflow_dispatch:
permissions:
contents: read
jobs:
release-suite:
runs-on: ubuntu-latest
name: Run googleapis/google-cloud-php tests against latest version
if: github.event.pull_request.user.login == 'release-please[bot]'
steps:
- uses: actions/checkout@v4
- name: Clone googleapis/google-cloud-php
uses: actions/checkout@master
with:
repository: googleapis/google-cloud-php
path: google-cloud-php
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.1'
extensions: grpc
- name: Configure google/auth to dev-main
run: |
cd google-cloud-php
composer install -q -d dev
dev/google-cloud update-deps google/auth 'dev-main as 1.200.0' --add=dev
- name: Run google/cloud package tests
run: |
cd google-cloud-php
bash .github/run-package-tests.sh
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
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,18 @@ print_r((string) $response->getBody());

[iap-proxy-header]: https://cloud.google.com/iap/docs/authentication-howto#authenticating_from_proxy-authorization_header

#### External credentials (Workload identity federation)

Using workload identity federation, your application can access Google Cloud resources from Amazon Web Services (AWS),
Microsoft Azure or any identity provider that supports OpenID Connect (OIDC).

Traditionally, applications running outside Google Cloud have used service account keys to access Google Cloud
resources. Using identity federation, you can allow your workload to impersonate a service account. This lets you access
Google Cloud resources directly, eliminating the maintenance and security burden associated with service account keys.

Follow the detailed instructions on how to
[Configure Workload Identity Federation](https://cloud.google.com/iam/docs/workload-identity-federation-with-other-clouds).

#### Verifying JWTs

If you are [using Google ID tokens to authenticate users][google-id-tokens], use
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
19 changes: 19 additions & 0 deletions src/Credentials/ServiceAccountCredentials.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ class ServiceAccountCredentials extends CredentialsLoader implements
*/
private $jwtAccessCredentials;

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

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

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

/**
Expand Down Expand Up @@ -328,6 +334,19 @@ public function getQuotaProject()
return $this->quotaProject;
}

/**
* Get the universe domain configured in the JSON credential.
*
* @return string
*/
public function getUniverseDomain(): string
{
if (null === $this->universeDomain) {
return self::DEFAULT_UNIVERSE_DOMAIN;
}
return $this->universeDomain;
}

/**
* @return bool
*/
Expand Down
12 changes: 12 additions & 0 deletions src/CredentialsLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
* credentials files on the file system.
*/
abstract class CredentialsLoader implements
GetUniverseDomainInterface,
FetchAuthTokenInterface,
UpdateMetadataInterface
{
Expand Down Expand Up @@ -273,4 +274,15 @@ private static function loadDefaultClientCertSourceFile()
}
return $clientCertSourceJson;
}

/**
* Get the universe domain from the credential. Defaults to "googleapis.com"
* for all credential types which do not support universe domain.
*
* @return string
*/
public function getUniverseDomain(): string
{
return self::DEFAULT_UNIVERSE_DOMAIN;
}
}
15 changes: 15 additions & 0 deletions src/FetchAuthTokenCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
class FetchAuthTokenCache implements
FetchAuthTokenInterface,
GetQuotaProjectInterface,
GetUniverseDomainInterface,
SignBlobInterface,
ProjectIdProviderInterface,
UpdateMetadataInterface
Expand Down Expand Up @@ -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.
*
Expand Down
35 changes: 35 additions & 0 deletions src/GetUniverseDomainInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php
/*
* Copyright 2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

namespace Google\Auth;

/**
* An interface implemented by objects that can get universe domain for Google Cloud APIs.
*/
interface GetUniverseDomainInterface
{
const DEFAULT_UNIVERSE_DOMAIN = 'googleapis.com';

/**
* Get the universe domain from the credential. This should always return
* a string, and default to "googleapis.com" if no universe domain is
* configured.
*
* @return string
*/
public function getUniverseDomain(): string;
}
47 changes: 27 additions & 20 deletions src/Middleware/AuthTokenMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@

namespace Google\Auth\Middleware;

use Google\Auth\FetchAuthTokenCache;
use Google\Auth\FetchAuthTokenInterface;
use Google\Auth\GetQuotaProjectInterface;
use Google\Auth\UpdateMetadataInterface;
use GuzzleHttp\Psr7\Utils;
use Psr\Http\Message\RequestInterface;

/**
Expand All @@ -40,6 +43,9 @@ class AuthTokenMiddleware
private $httpHandler;

/**
* It must be an implementation of FetchAuthTokenInterface.
* It may also implement UpdateMetadataInterface allowing direct
* retrieval of auth related headers
* @var FetchAuthTokenInterface
*/
private $fetcher;
Expand Down Expand Up @@ -99,7 +105,7 @@ public function __invoke(callable $handler)
return $handler($request, $options);
}

$request = $request->withHeader('authorization', 'Bearer ' . $this->fetchToken());
$request = $this->addAuthHeaders($request);

if ($quotaProject = $this->getQuotaProject()) {
$request = $request->withHeader(
Expand All @@ -113,32 +119,33 @@ public function __invoke(callable $handler)
}

/**
* Call fetcher to fetch the token.
* Adds auth related headers to the request.
*
* @return string|null
* @param RequestInterface $request
* @return RequestInterface
*/
private function fetchToken()
private function addAuthHeaders(RequestInterface $request)
{
$auth_tokens = (array) $this->fetcher->fetchAuthToken($this->httpHandler);

if (array_key_exists('access_token', $auth_tokens)) {
// notify the callback if applicable
if ($this->tokenCallback) {
call_user_func(
$this->tokenCallback,
$this->fetcher->getCacheKey(),
$auth_tokens['access_token']
);
}

return $auth_tokens['access_token'];
if (!$this->fetcher instanceof UpdateMetadataInterface ||
($this->fetcher instanceof FetchAuthTokenCache &&
!$this->fetcher->getFetcher() instanceof UpdateMetadataInterface)
) {
$token = $this->fetcher->fetchAuthToken();
$request = $request->withHeader(
'authorization', 'Bearer ' . ($token['access_token'] ?? $token['id_token'])
);
} else {
$headers = $this->fetcher->updateMetadata($request->getHeaders(), null, $this->httpHandler);
$request = Utils::modifyRequest($request, ['set_headers' => $headers]);
}

if (array_key_exists('id_token', $auth_tokens)) {
return $auth_tokens['id_token'];
if ($this->tokenCallback && ($token = $this->fetcher->getLastReceivedToken())) {
if (array_key_exists('access_token', $token)) {
call_user_func($this->tokenCallback, $this->fetcher->getCacheKey(), $token['access_token']);
}
}

return null;
return $request;
}

/**
Expand Down
22 changes: 22 additions & 0 deletions tests/ApplicationDefaultCredentialsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -783,4 +783,26 @@ public function provideExternalAccountCredentials()
['aws_credentials.json', CredentialSource\AwsNativeSource::class],
];
}

/** @runInSeparateProcess */
public function testUniverseDomainInKeyFile()
{
// Test no universe domain in keyfile defaults to "googleapis.com"
$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 in "service_account" keyfile
$keyFile = __DIR__ . '/fixtures/private.json';
putenv(ServiceAccountCredentials::ENV_VAR . '=' . $keyFile);
$creds = ApplicationDefaultCredentials::getCredentials();
$this->assertEquals('example-universe.com', $creds->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());
}
}
8 changes: 8 additions & 0 deletions tests/Credentials/GCECredentialsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -512,4 +512,12 @@ public function testGetClientNameWithServiceAccountIdentity()
$creds = new GCECredentials(null, null, null, null, 'foo');
$this->assertEquals($expected, $creds->getClientName($httpHandler));
}

public function testGetUniverseDomain()
{
$creds = new GCECredentials();

// Universe domain should always be the default
$this->assertEquals(GCECredentials::DEFAULT_UNIVERSE_DOMAIN, $creds->getUniverseDomain());
}
}
36 changes: 36 additions & 0 deletions tests/FetchAuthTokenCacheTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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')
Expand Down
Loading

0 comments on commit 7ba3d8b

Please sign in to comment.