Skip to content

Commit

Permalink
add testing for service account URL and integration tests for file/ur…
Browse files Browse the repository at this point in the history
…l creds
  • Loading branch information
bshaffer committed Oct 5, 2023
1 parent e076b11 commit 1a51a52
Show file tree
Hide file tree
Showing 2 changed files with 140 additions and 3 deletions.
6 changes: 3 additions & 3 deletions src/Credentials/ExternalAccountCredentials.php
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ private static function buildCredentialSource(array $jsonKey): ExternalAccountCr
*/
private function getImpersonatedAccessToken(string $stsToken, callable $httpHandler = null): array
{
if (is_null($this->serviceAccountImpersonationUrl)) {
if (!isset($this->serviceAccountImpersonationUrl)) {
throw new InvalidArgumentException(
'service_account_impersonation_url must be set in JSON credentials.'
);
Expand All @@ -175,7 +175,7 @@ private function getImpersonatedAccessToken(string $stsToken, callable $httpHand
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . $stsToken,
],
json_encode([
(string) json_encode([
'lifetime' => sprintf('%ss', OAuth2::DEFAULT_EXPIRY_SECONDS),
'scope' => $this->auth->getScope(),
]),
Expand Down Expand Up @@ -208,7 +208,7 @@ public function fetchAuthToken(callable $httpHandler = null)
{
$stsToken = $this->auth->fetchAuthToken($httpHandler);

if ($this->serviceAccountImpersonationUrl) {
if (isset($this->serviceAccountImpersonationUrl)) {
return $this->getImpersonatedAccessToken($stsToken['access_token'], $httpHandler);
}

Expand Down
137 changes: 137 additions & 0 deletions tests/Credentials/ExternalAccountCredentialsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,20 @@
use Google\Auth\CredentialSource\UrlSource;
use Google\Auth\OAuth2;
use InvalidArgumentException;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;
use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait;

/**
* @group credentials
* @group credentials-external
*/
class ExternalAccountCredentialsTest extends TestCase
{
use ProphecyTrait;

/**
* @dataProvider provideCredentialSourceFromCredentials
*/
Expand Down Expand Up @@ -186,4 +192,135 @@ public function provideInvalidCredentialsJson()
],
];
}

public function testFetchAuthTokenFileCredentials()
{
$tmpFile = tempnam(sys_get_temp_dir(), 'test');
file_put_contents($tmpFile, 'abc');

$jsonCreds = [
'type' => 'external_account',
'token_url' => 'token-url.com',
'audience' => '',
'subject_token_type' => '',
'credential_source' => ['file' => $tmpFile],
];

$creds = new ExternalAccountCredentials('a-scope', $jsonCreds);

$httpHandler = function (RequestInterface $request) {
$this->assertEquals('token-url.com', (string) $request->getUri());
parse_str((string) $request->getBody(), $requestBody);
$this->assertEquals('abc', $requestBody['subject_token']);

$responseBody = $this->prophesize(StreamInterface::class);
$responseBody->__toString()->willReturn(json_encode(['access_token' => 'def', 'expires_in' => 1000]));

$response = $this->prophesize(ResponseInterface::class);
$response->getBody()->willReturn($responseBody->reveal());
$response->hasHeader('Content-Type')->willReturn(false);

return $response->reveal();
};

$authToken = $creds->fetchAuthToken($httpHandler);
$this->assertArrayHasKey('access_token', $authToken);
$this->assertEquals('def', $authToken['access_token']);
}

public function testFetchAuthTokenUrlCredentials()
{
$url = 'sts-url.com';
$jsonCreds = [
'type' => 'external_account',
'token_url' => 'token-url.com',
'audience' => '',
'subject_token_type' => '',
'credential_source' => ['url' => $url],
];

$creds = new ExternalAccountCredentials('a-scope', $jsonCreds);

$requestCount = 0;
$httpHandler = function (RequestInterface $request) use (&$requestCount) {
switch (++$requestCount) {
case 1:
$this->assertEquals('sts-url.com', (string) $request->getUri());
$responseBody = 'abc';
break;

case 2:
$this->assertEquals('token-url.com', (string) $request->getUri());
parse_str((string) $request->getBody(), $requestBody);
$this->assertEquals('abc', $requestBody['subject_token']);
$responseBody = '{"access_token": "def"}';
break;
}

$body = $this->prophesize(StreamInterface::class);
$body->__toString()->willReturn($responseBody);

$response = $this->prophesize(ResponseInterface::class);
$response->getBody()->willReturn($body->reveal());
if ($requestCount === 2) {
$response->hasHeader('Content-Type')->willReturn(false);
}

return $response->reveal();
};

$authToken = $creds->fetchAuthToken($httpHandler);
$this->assertArrayHasKey('access_token', $authToken);
$this->assertEquals('def', $authToken['access_token']);
}

public function testFetchAuthTokenWithImpersonation()
{
$tmpFile = tempnam(sys_get_temp_dir(), 'test');
file_put_contents($tmpFile, 'abc');

$jsonCreds = [
'type' => 'external_account',
'token_url' => 'token-url.com',
'audience' => '',
'subject_token_type' => '',
'credential_source' => ['file' => $tmpFile],
'service_account_impersonation_url' => 'service-account-impersonation-url.com',
];

$creds = new ExternalAccountCredentials('a-scope', $jsonCreds);

$requestCount = 0;
$expiry = '2023-10-05T18:00:01Z';
$httpHandler = function (RequestInterface $request) use (&$requestCount, $expiry) {
switch (++$requestCount) {
case 1:
$this->assertEquals('token-url.com', (string) $request->getUri());
parse_str((string) $request->getBody(), $requestBody);
$this->assertEquals('abc', $requestBody['subject_token']);
$responseBody = '{"access_token": "def"}';
break;
case 2:
$this->assertEquals('service-account-impersonation-url.com', (string) $request->getUri());
$responseBody = json_encode(['accessToken' => 'def', 'expireTime' => $expiry]);
break;
}

$body = $this->prophesize(StreamInterface::class);
$body->__toString()->willReturn($responseBody);

$response = $this->prophesize(ResponseInterface::class);
$response->getBody()->willReturn($body->reveal());
if ($requestCount === 1) {
$response->hasHeader('Content-Type')->willReturn(false);
}

return $response->reveal();
};

$authToken = $creds->fetchAuthToken($httpHandler);
$this->assertArrayHasKey('access_token', $authToken);
$this->assertEquals('def', $authToken['access_token']);
$this->assertEquals(strtotime($expiry), $authToken['expires_at']);
}
}

0 comments on commit 1a51a52

Please sign in to comment.