OXIESEC PANEL
- Current Dir:
/
/
var
/
www
/
firebase
/
vendor
/
google
/
auth
/
tests
Server IP: 139.59.38.164
Upload:
Create Dir:
Name
Size
Modified
Perms
📁
..
-
08/12/2024 10:33:10 AM
rwxr-xr-x
📄
AccessTokenTest.php
18.63 KB
08/12/2024 10:33:11 AM
rw-r--r--
📄
ApplicationDefaultCredentialsTest.php
29.48 KB
08/12/2024 10:33:11 AM
rw-r--r--
📄
BaseTest.php
1.08 KB
08/12/2024 10:33:11 AM
rw-r--r--
📁
Cache
-
08/12/2024 10:33:43 AM
rwxr-xr-x
📄
CacheTraitTest.php
6.01 KB
08/12/2024 10:33:11 AM
rw-r--r--
📁
CredentialSource
-
08/12/2024 10:33:44 AM
rwxr-xr-x
📁
Credentials
-
08/12/2024 10:33:43 AM
rwxr-xr-x
📄
CredentialsLoaderTest.php
5.17 KB
08/12/2024 10:33:11 AM
rw-r--r--
📁
ExecutableHandler
-
08/12/2024 10:33:44 AM
rwxr-xr-x
📄
FetchAuthTokenCacheTest.php
28.14 KB
08/12/2024 10:33:11 AM
rw-r--r--
📄
FetchAuthTokenTest.php
8.38 KB
08/12/2024 10:33:11 AM
rw-r--r--
📄
GCECacheTest.php
5.53 KB
08/12/2024 10:33:11 AM
rw-r--r--
📁
HttpHandler
-
08/12/2024 10:33:45 AM
rwxr-xr-x
📄
IamTest.php
2.97 KB
08/12/2024 10:33:11 AM
rw-r--r--
📄
MetricsTraitTest.php
1.79 KB
08/12/2024 10:33:11 AM
rw-r--r--
📁
Middleware
-
08/12/2024 10:33:45 AM
rwxr-xr-x
📄
OAuth2Test.php
44.78 KB
08/12/2024 10:33:11 AM
rw-r--r--
📄
ObservabilityMetricsTest.php
7.7 KB
08/12/2024 10:33:11 AM
rw-r--r--
📄
ServiceAccountSignerTraitTest.php
1.9 KB
08/12/2024 10:33:11 AM
rw-r--r--
📄
bootstrap.php
1.03 KB
08/12/2024 10:33:11 AM
rw-r--r--
📁
fixtures
-
08/12/2024 10:36:15 AM
rwxr-xr-x
📁
fixtures2
-
08/12/2024 10:36:15 AM
rwxr-xr-x
📁
fixtures3
-
08/12/2024 10:33:44 AM
rwxr-xr-x
📁
fixtures4
-
08/12/2024 10:36:16 AM
rwxr-xr-x
📁
fixtures5
-
08/12/2024 10:36:16 AM
rwxr-xr-x
📁
fixtures6
-
08/12/2024 10:33:45 AM
rwxr-xr-x
📁
mocks
-
08/12/2024 10:33:45 AM
rwxr-xr-x
📄
phpstan-autoload.php
433 bytes
08/12/2024 10:33:11 AM
rw-r--r--
Editing: OAuth2Test.php
Close
<?php /* * Copyright 2010 Google Inc. * * 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\Tests; use DomainException; use Firebase\JWT\JWT; use Firebase\JWT\Key; use Google\Auth\ExternalAccountCredentialSourceInterface; use Google\Auth\OAuth2; use GuzzleHttp\Psr7\Query; use GuzzleHttp\Psr7\Response; use GuzzleHttp\Psr7\Utils; use InvalidArgumentException; use PHPUnit\Framework\TestCase; use Prophecy\PhpUnit\ProphecyTrait; use UnexpectedValueException; class OAuth2Test extends TestCase { private $minimal = [ 'authorizationUri' => 'https://accounts.test.org/insecure/url', 'redirectUri' => 'https://accounts.test.org/redirect/url', 'clientId' => 'aClientID', ]; private $signingMinimal = [ 'signingKey' => 'example_key', 'signingAlgorithm' => 'HS256', 'scope' => 'https://www.googleapis.com/auth/userinfo.profile', 'issuer' => 'app@example.com', 'audience' => 'accounts.google.com', 'clientId' => 'aClientID', ]; private $tokenRequestMinimal = [ 'tokenCredentialUri' => 'https://tokens_r_us/test', 'scope' => 'https://www.googleapis.com/auth/userinfo.profile', 'issuer' => 'app@example.com', 'audience' => 'accounts.google.com', 'clientId' => 'aClientID', ]; private $fetchAuthTokenMinimal = [ 'tokenCredentialUri' => 'https://tokens_r_us/test', 'scope' => 'https://www.googleapis.com/auth/userinfo.profile', 'signingKey' => 'example_key', 'signingAlgorithm' => 'HS256', 'issuer' => 'app@example.com', 'audience' => 'accounts.google.com', 'clientId' => 'aClientID', ]; private $verifyIdTokenMinimal = [ 'scope' => 'https://www.googleapis.com/auth/userinfo.profile', 'audience' => 'myaccount.on.host.issuer.com', 'issuer' => 'an.issuer.com', 'clientId' => 'myaccount.on.host.issuer.com', ]; /** * @group oauth2-authorization-uri */ public function testIsNullIfAuthorizationUriIsNull() { $this->expectException(InvalidArgumentException::class); $o = new OAuth2([]); $this->assertNull($o->buildFullAuthorizationUri()); } /** * @group oauth2-authorization-uri */ public function testRequiresTheClientId() { $this->expectException(InvalidArgumentException::class); $o = new OAuth2([ 'authorizationUri' => 'https://accounts.test.org/auth/url', 'redirectUri' => 'https://accounts.test.org/redirect/url', ]); $o->buildFullAuthorizationUri(); } /** * @group oauth2-authorization-uri */ public function testRequiresTheRedirectUri() { $this->expectException(InvalidArgumentException::class); $o = new OAuth2([ 'authorizationUri' => 'https://accounts.test.org/auth/url', 'clientId' => 'aClientID', ]); $o->buildFullAuthorizationUri(); } /** * @group oauth2-authorization-uri */ public function testCannotHavePromptAndApprovalPrompt() { $this->expectException(InvalidArgumentException::class); $o = new OAuth2([ 'authorizationUri' => 'https://accounts.test.org/auth/url', 'clientId' => 'aClientID', ]); $o->buildFullAuthorizationUri([ 'approval_prompt' => 'an approval prompt', 'prompt' => 'a prompt', ]); } /** * @group oauth2-authorization-uri */ public function testCannotHaveInsecureAuthorizationUri() { $this->expectException(InvalidArgumentException::class); $o = new OAuth2([ 'authorizationUri' => 'http://accounts.test.org/insecure/url', 'redirectUri' => 'https://accounts.test.org/redirect/url', 'clientId' => 'aClientID', ]); $o->buildFullAuthorizationUri(); } /** * @group oauth2-authorization-uri */ public function testCannotHaveRelativeRedirectUri() { $this->expectException(InvalidArgumentException::class); $o = new OAuth2([ 'authorizationUri' => 'http://accounts.test.org/insecure/url', 'redirectUri' => '/redirect/url', 'clientId' => 'aClientID', ]); $o->buildFullAuthorizationUri(); } /** * @group oauth2-authorization-uri */ public function testAudOrScopeIsRequiredForJwt() { $this->expectException(DomainException::class); $this->expectExceptionMessage('one of scope or aud should not be null'); $o = new OAuth2([]); $o->setSigningKey('a key'); $o->setSigningAlgorithm('RS256'); $o->setIssuer('an issuer'); $o->toJwt(); } /** * @group oauth2-authorization-uri */ public function testHasDefaultXXXTypeParams() { $o = new OAuth2($this->minimal); $q = Query::parse($o->buildFullAuthorizationUri()->getQuery()); $this->assertEquals('code', $q['response_type']); $this->assertEquals('offline', $q['access_type']); } /** * @group oauth2-authorization-uri */ public function testCanBeUrlObject() { $config = array_merge($this->minimal, [ 'authorizationUri' => Utils::uriFor('https://another/uri'), ]); $o = new OAuth2($config); $this->assertEquals('/uri', $o->buildFullAuthorizationUri()->getPath()); } /** * @group oauth2-authorization-uri */ public function testCanOverrideParams() { $overrides = [ 'access_type' => 'o_access_type', 'client_id' => 'o_client_id', 'redirect_uri' => 'o_redirect_uri', 'response_type' => 'o_response_type', 'state' => 'o_state', ]; $config = array_merge($this->minimal, ['state' => 'the_state']); $o = new OAuth2($config); $q = Query::parse($o->buildFullAuthorizationUri($overrides)->getQuery()); $this->assertEquals('o_access_type', $q['access_type']); $this->assertEquals('o_client_id', $q['client_id']); $this->assertEquals('o_redirect_uri', $q['redirect_uri']); $this->assertEquals('o_response_type', $q['response_type']); $this->assertEquals('o_state', $q['state']); } /** * @group oauth2-authorization-uri */ public function testAuthorizationUriWithCodeVerifier() { $codeVerifier = 'my_code_verifier'; $expectedCodeChallenge = 'DLIjHQaEUYlb3dD1s35ERX1uDg0eu3_9ggFsQayed5c'; // test in constructor $config = array_merge($this->minimal, ['codeVerifier' => $codeVerifier]); $o = new OAuth2($config); $q = Query::parse($o->buildFullAuthorizationUri()->getQuery()); $this->assertArrayNotHasKey('code_verifier', $q); $this->assertArrayHasKey('code_challenge', $q); $this->assertEquals($expectedCodeChallenge, $q['code_challenge']); $this->assertEquals('S256', $q['code_challenge_method']); // test in settter $o = new OAuth2($this->minimal); $o->setCodeVerifier($codeVerifier); $q = Query::parse($o->buildFullAuthorizationUri()->getQuery()); $this->assertArrayNotHasKey('code_verifier', $q); $this->assertArrayHasKey('code_challenge', $q); $this->assertEquals($expectedCodeChallenge, $q['code_challenge']); $this->assertEquals('S256', $q['code_challenge_method']); } /** * @group oauth2-authorization-uri */ public function testGenerateCodeVerifier() { $o = new OAuth2($this->minimal); $codeVerifier = $o->generateCodeVerifier(); $this->assertEquals(128, strlen($codeVerifier)); // The generated code verifier is set on the object $this->assertEquals($o->getCodeVerifier(), $codeVerifier); // When it's called again, it generates a new one $this->assertNotEquals($codeVerifier, $o->generateCodeVerifier()); // The new code verifier is set on the object $this->assertNotEquals($codeVerifier, $o->getCodeVerifier()); } /** * @group oauth2-authorization-uri */ public function testIncludesTheScope() { $with_strings = array_merge($this->minimal, ['scope' => 'scope1 scope2']); $o = new OAuth2($with_strings); $q = Query::parse($o->buildFullAuthorizationUri()->getQuery()); $this->assertEquals('scope1 scope2', $q['scope']); $with_array = array_merge($this->minimal, [ 'scope' => ['scope1', 'scope2'], ]); $o = new OAuth2($with_array); $q = Query::parse($o->buildFullAuthorizationUri()->getQuery()); $this->assertEquals('scope1 scope2', $q['scope']); } /** * @group oauth2-authorization-uri */ public function testRedirectUriPostmessageIsAllowed() { $o = new OAuth2([ 'authorizationUri' => 'https://accounts.test.org/insecure/url', 'redirectUri' => 'postmessage', 'clientId' => 'aClientID', ]); $this->assertEquals('postmessage', $o->getRedirectUri()); $url = $o->buildFullAuthorizationUri(); $parts = parse_url((string)$url); parse_str($parts['query'], $query); $this->assertArrayHasKey('redirect_uri', $query); $this->assertEquals('postmessage', $query['redirect_uri']); } /** * @group oauth2-grant-type */ public function testReturnsNullIfCannotBeInferred() { $o = new OAuth2($this->minimal); $this->assertNull($o->getGrantType()); } /** * @group oauth2-grant-type */ public function testInfersAuthorizationCode() { $o = new OAuth2($this->minimal); $o->setCode('an auth code'); $this->assertEquals('authorization_code', $o->getGrantType()); } /** * @group oauth2-grant-type */ public function testInfersRefreshToken() { $o = new OAuth2($this->minimal); $o->setRefreshToken('a refresh token'); $this->assertEquals('refresh_token', $o->getGrantType()); } /** * @group oauth2-grant-type */ public function testInfersPassword() { $o = new OAuth2($this->minimal); $o->setPassword('a password'); $o->setUsername('a username'); $this->assertEquals('password', $o->getGrantType()); } /** * @group oauth2-grant-type */ public function testInfersJwtBearer() { $o = new OAuth2($this->minimal); $o->setIssuer('an issuer'); $o->setSigningKey('a key'); $this->assertEquals( 'urn:ietf:params:oauth:grant-type:jwt-bearer', $o->getGrantType() ); } /** * @group oauth2-grant-type */ public function testSetsKnownTypes() { $o = new OAuth2($this->minimal); foreach (OAuth2::$knownGrantTypes as $t) { $o->setGrantType($t); $this->assertEquals($t, $o->getGrantType()); } } /** * @group oauth2-grant-type */ public function testSetsUrlAsGrantType() { $o = new OAuth2($this->minimal); $o->setGrantType('http://a/grant/url'); $this->assertEquals('http://a/grant/url', $o->getGrantType()); } /** * @group oauth2-cache-key */ public function testIsNullWithNoScopesOrAudience() { $o = new OAuth2($this->minimal); $this->assertNull($o->getCacheKey()); } /** * @group oauth2-cache-key */ public function testIsScopeIfSingleScope() { $o = new OAuth2($this->minimal); $o->setScope('test/scope/1'); $this->assertEquals('test/scope/1', $o->getCacheKey()); } /** * @group oauth2-cache-key */ public function testIsAllScopesWhenScopeIsArray() { $o = new OAuth2($this->minimal); $o->setScope(['test/scope/1', 'test/scope/2']); $this->assertEquals('test/scope/1:test/scope/2', $o->getCacheKey()); } /** * @group oauth2-cache-key */ public function testIsAudienceWhenScopeIsNull() { $aud = 'https://drive.googleapis.com'; $o = new OAuth2($this->minimal); $o->setAudience($aud); $this->assertEquals($aud, $o->getCacheKey()); } /** * @group oauth2-timing */ public function testIssuedAtDefaultsToNull() { $o = new OAuth2($this->minimal); $this->assertNull($o->getIssuedAt()); } /** * @group oauth2-timing */ public function testExpiresAtDefaultsToNull() { $o = new OAuth2($this->minimal); $this->assertNull($o->getExpiresAt()); } /** * @group oauth2-timing */ public function testExpiresInDefaultsToNull() { $o = new OAuth2($this->minimal); $this->assertNull($o->getExpiresIn()); } /** * @group oauth2-timing */ public function testSettingExpiresInSetsIssuedAt() { $o = new OAuth2($this->minimal); $this->assertNull($o->getIssuedAt()); $aShortWhile = 5; $o->setExpiresIn($aShortWhile); $this->assertEquals($aShortWhile, $o->getExpiresIn()); $this->assertNotNull($o->getIssuedAt()); } /** * @group oauth2-timing */ public function testSettingExpiresInSetsExpireAt() { $o = new OAuth2($this->minimal); $this->assertNull($o->getExpiresAt()); $aShortWhile = 5; $o->setExpiresIn($aShortWhile); $this->assertNotNull($o->getExpiresAt()); $this->assertEquals($aShortWhile, $o->getExpiresAt() - $o->getIssuedAt()); } /** * @group oauth2-timing */ public function testIsNotExpiredByDefault() { $o = new OAuth2($this->minimal); $this->assertFalse($o->isExpired()); } /** * @group oauth2-timing */ public function testIsNotExpiredIfExpiresAtIsOld() { $o = new OAuth2($this->minimal); $o->setExpiresAt(time() - 2); $this->assertTrue($o->isExpired()); } /** * @group oauth2-general */ public function testFailsOnUnknownSigningAlgorithm() { $this->expectException(InvalidArgumentException::class); $o = new OAuth2($this->minimal); $o->setSigningAlgorithm('this is definitely not an algorithm name'); } /** * @group oauth2-general */ public function testAllowsKnownSigningAlgorithms() { $o = new OAuth2($this->minimal); foreach (OAuth2::$knownSigningAlgorithms as $a) { $o->setSigningAlgorithm($a); $this->assertEquals($a, $o->getSigningAlgorithm()); } } /** * @group oauth2-general */ public function testFailsOnRelativeRedirectUri() { $this->expectException(InvalidArgumentException::class); $o = new OAuth2($this->minimal); $o->setRedirectUri('/relative/url'); } /** * @group oauth2-general */ public function testAllowsUrnRedirectUri() { $urn = 'urn:ietf:wg:oauth:2.0:oob'; $o = new OAuth2($this->minimal); $o->setRedirectUri($urn); $this->assertEquals($urn, $o->getRedirectUri()); } /** * @group oauth2-jwt */ public function testFailsWithMissingAudience() { $this->expectException(DomainException::class); $testConfig = $this->signingMinimal; unset($testConfig['audience']); unset($testConfig['scope']); $o = new OAuth2($testConfig); $o->toJwt(); } /** * @group oauth2-jwt */ public function testFailsWithMissingIssuer() { $this->expectException(DomainException::class); $testConfig = $this->signingMinimal; unset($testConfig['issuer']); $o = new OAuth2($testConfig); $o->toJwt(); } /** * @group oauth2-jwt */ public function testCanHaveNoScope() { $testConfig = $this->signingMinimal; unset($testConfig['scope']); $o = new OAuth2($testConfig); $jwt = $o->toJwt(); $this->assertTrue(is_string($jwt)); } /** * @group oauth2-jwt */ public function testFailsWithMissingSigningKey() { $this->expectException(DomainException::class); $testConfig = $this->signingMinimal; unset($testConfig['signingKey']); $o = new OAuth2($testConfig); $o->toJwt(); } /** * @group oauth2-jwt */ public function testFailsWithMissingSigningAlgorithm() { $this->expectException(DomainException::class); $testConfig = $this->signingMinimal; unset($testConfig['signingAlgorithm']); $o = new OAuth2($testConfig); $o->toJwt(); } /** * @group oauth2-jwt */ public function testCanHS256EncodeAValidPayloadWithSigningKeyId() { $testConfig = $this->signingMinimal; $keys = [ 'example_key_id1' => new Key('example_key1', 'HS256'), 'example_key_id2' => new Key('example_key2', 'HS256'), ]; $testConfig['signingKey'] = $keys['example_key_id2']->getKeyMaterial(); $testConfig['signingKeyId'] = 'example_key_id2'; $o = new OAuth2($testConfig); $payload = $o->toJwt(); $roundTrip = JWT::decode($payload, $keys); $this->assertEquals($roundTrip->iss, $testConfig['issuer']); $this->assertEquals($roundTrip->aud, $testConfig['audience']); $this->assertEquals($roundTrip->scope, $testConfig['scope']); } /** * @group oauth2-jwt */ public function testFailDecodeWithoutSigningKeyId() { $testConfig = $this->signingMinimal; $keys = [ 'example_key_id1' => new Key('example_key1', 'HS256'), 'example_key_id2' => new Key('example_key2', 'HS256'), ]; $testConfig['signingKey'] = $keys['example_key_id2']->getKeyMaterial(); $o = new OAuth2($testConfig); $payload = $o->toJwt(); try { JWT::decode($payload, $keys); } catch (\Exception $e) { // Workaround: In old JWT versions throws DomainException $this->assertTrue( ($e instanceof \DomainException || $e instanceof \UnexpectedValueException) && $e->getMessage() === '"kid" empty, unable to lookup correct key' ); return; } $this->fail('Expected exception about problem with decode'); } /** * @group oauth2-jwt */ public function testCanHS256EncodeAValidPayload() { $testConfig = $this->signingMinimal; $o = new OAuth2($testConfig); $payload = $o->toJwt(); $roundTrip = JWT::decode($payload, new Key($testConfig['signingKey'], 'HS256')); $this->assertEquals($roundTrip->iss, $testConfig['issuer']); $this->assertEquals($roundTrip->aud, $testConfig['audience']); $this->assertEquals($roundTrip->scope, $testConfig['scope']); } /** * @group oauth2-jwt */ public function testCanRS256EncodeAValidPayload() { $publicKey = file_get_contents(__DIR__ . '/fixtures' . '/public.pem'); $privateKey = file_get_contents(__DIR__ . '/fixtures' . '/private.pem'); $testConfig = $this->signingMinimal; $o = new OAuth2($testConfig); $o->setSigningAlgorithm('RS256'); $o->setSigningKey($privateKey); $payload = $o->toJwt(); $roundTrip = JWT::decode($payload, new Key($publicKey, 'RS256')); $this->assertEquals($roundTrip->iss, $testConfig['issuer']); $this->assertEquals($roundTrip->aud, $testConfig['audience']); $this->assertEquals($roundTrip->scope, $testConfig['scope']); } /** * @group oauth2-jwt */ public function testCanHaveAdditionalClaims() { $publicKey = file_get_contents(__DIR__ . '/fixtures' . '/public.pem'); $privateKey = file_get_contents(__DIR__ . '/fixtures' . '/private.pem'); $testConfig = $this->signingMinimal; $targetAud = '123@456.com'; $testConfig['additionalClaims'] = ['target_audience' => $targetAud]; $o = new OAuth2($testConfig); $o->setSigningAlgorithm('RS256'); $o->setSigningKey($privateKey); $payload = $o->toJwt(); $roundTrip = JWT::decode($payload, new Key($publicKey, 'RS256')); $this->assertEquals($roundTrip->target_audience, $targetAud); } /** * @group oauth2-generate-access-token */ public function testFailsIfNoTokenCredentialUri() { $this->expectException(DomainException::class); $testConfig = $this->tokenRequestMinimal; unset($testConfig['tokenCredentialUri']); $o = new OAuth2($testConfig); $o->generateCredentialsRequest(); } /** * @group oauth2-generate-access-token */ public function testFailsIfAuthorizationCodeIsMissing() { $this->expectException(DomainException::class); $testConfig = $this->tokenRequestMinimal; $testConfig['redirectUri'] = 'https://has/redirect/uri'; $o = new OAuth2($testConfig); $o->generateCredentialsRequest(); } /** * @group oauth2-generate-access-token */ public function testGeneratesAuthorizationCodeRequests() { $testConfig = $this->tokenRequestMinimal; $testConfig['redirectUri'] = 'https://has/redirect/uri'; $o = new OAuth2($testConfig); $o->setCode('an_auth_code'); // Generate the request and confirm that it's correct. $req = $o->generateCredentialsRequest(); $this->assertInstanceOf('Psr\Http\Message\RequestInterface', $req); $this->assertEquals('POST', $req->getMethod()); $fields = Query::parse((string)$req->getBody()); $this->assertEquals('authorization_code', $fields['grant_type']); $this->assertEquals('an_auth_code', $fields['code']); } /** * @group oauth2-generate-access-token */ public function testGeneratesPasswordRequests() { $testConfig = $this->tokenRequestMinimal; $o = new OAuth2($testConfig); $o->setUsername('a_username'); $o->setPassword('a_password'); // Generate the request and confirm that it's correct. $req = $o->generateCredentialsRequest(); $this->assertInstanceOf('Psr\Http\Message\RequestInterface', $req); $this->assertEquals('POST', $req->getMethod()); $fields = Query::parse((string)$req->getBody()); $this->assertEquals('password', $fields['grant_type']); $this->assertEquals('a_password', $fields['password']); $this->assertEquals('a_username', $fields['username']); } /** * @group oauth2-generate-access-token */ public function testGeneratesRefreshTokenRequests() { $testConfig = $this->tokenRequestMinimal; $o = new OAuth2($testConfig); $o->setRefreshToken('a_refresh_token'); // Generate the request and confirm that it's correct. $req = $o->generateCredentialsRequest(); $this->assertInstanceOf('Psr\Http\Message\RequestInterface', $req); $this->assertEquals('POST', $req->getMethod()); $fields = Query::parse((string)$req->getBody()); $this->assertEquals('refresh_token', $fields['grant_type']); $this->assertEquals('a_refresh_token', $fields['refresh_token']); } /** * @group oauth2-generate-access-token */ public function testClientSecretAddedIfSetForAuthorizationCodeRequests() { $testConfig = $this->tokenRequestMinimal; $testConfig['clientSecret'] = 'a_client_secret'; $testConfig['redirectUri'] = 'https://has/redirect/uri'; $o = new OAuth2($testConfig); $o->setCode('an_auth_code'); $request = $o->generateCredentialsRequest(); $fields = Query::parse((string)$request->getBody()); $this->assertEquals('a_client_secret', $fields['client_secret']); } /** * @group oauth2-generate-access-token */ public function testClientSecretAddedIfSetForRefreshTokenRequests() { $testConfig = $this->tokenRequestMinimal; $testConfig['clientSecret'] = 'a_client_secret'; $o = new OAuth2($testConfig); $o->setRefreshToken('a_refresh_token'); $request = $o->generateCredentialsRequest(); $fields = Query::parse((string)$request->getBody()); $this->assertEquals('a_client_secret', $fields['client_secret']); } /** * @group oauth2-generate-access-token */ public function testClientSecretAddedIfSetForPasswordRequests() { $testConfig = $this->tokenRequestMinimal; $testConfig['clientSecret'] = 'a_client_secret'; $o = new OAuth2($testConfig); $o->setUsername('a_username'); $o->setPassword('a_password'); $request = $o->generateCredentialsRequest(); $fields = Query::parse((string)$request->getBody()); $this->assertEquals('a_client_secret', $fields['client_secret']); } /** * @group oauth2-generate-access-token */ public function testGeneratesAssertionRequests() { $testConfig = $this->tokenRequestMinimal; $o = new OAuth2($testConfig); $o->setSigningKey('a_key'); $o->setSigningAlgorithm('HS256'); // Generate the request and confirm that it's correct. $req = $o->generateCredentialsRequest(); $this->assertInstanceOf('Psr\Http\Message\RequestInterface', $req); $this->assertEquals('POST', $req->getMethod()); $fields = Query::parse((string)$req->getBody()); $this->assertEquals(OAuth2::JWT_URN, $fields['grant_type']); $this->assertArrayHasKey('assertion', $fields); } /** * @group oauth2-generate-access-token */ public function testGeneratesExtendedRequests() { $testConfig = $this->tokenRequestMinimal; $o = new OAuth2($testConfig); $o->setGrantType('urn:my_test_grant_type'); $o->setExtensionParams(['my_param' => 'my_value']); // Generate the request and confirm that it's correct. $req = $o->generateCredentialsRequest(); $this->assertInstanceOf('Psr\Http\Message\RequestInterface', $req); $this->assertEquals('POST', $req->getMethod()); $fields = Query::parse((string)$req->getBody()); $this->assertEquals('my_value', $fields['my_param']); $this->assertEquals('urn:my_test_grant_type', $fields['grant_type']); } /** * @group oauth2-generate-access-token */ public function testTokenUriWithCodeVerifier() { $codeVerifier = 'my_code_verifier'; // test in constructor $config = array_merge($this->tokenRequestMinimal, [ 'codeVerifier' => $codeVerifier, ]); $o = new OAuth2($config); $o->setCode('abc123'); $req = $o->generateCredentialsRequest(); $fields = Query::parse((string) $req->getBody()); $this->assertArrayHasKey('code_verifier', $fields); $this->assertEquals($codeVerifier, $fields['code_verifier']); // test in settter $o = new OAuth2($this->tokenRequestMinimal); $o->setCode('abc123'); $o->setCodeVerifier($codeVerifier); $req = $o->generateCredentialsRequest(); $q = Query::parse((string) $req->getBody()); $this->assertArrayHasKey('code_verifier', $q); $this->assertEquals($codeVerifier, $q['code_verifier']); } /** * @group oauth2-fetch-auth-token */ public function testFailsOn400() { $this->expectException(\GuzzleHttp\Exception\ClientException::class); $testConfig = $this->fetchAuthTokenMinimal; $httpHandler = getHandler([ new Response(400), ]); $o = new OAuth2($testConfig); $o->fetchAuthToken($httpHandler); } /** * @group oauth2-fetch-auth-token */ public function testFailsOn500() { $this->expectException(\GuzzleHttp\Exception\ServerException::class); $testConfig = $this->fetchAuthTokenMinimal; $httpHandler = getHandler([ new Response(500), ]); $o = new OAuth2($testConfig); $o->fetchAuthToken($httpHandler); } /** * @group oauth2-fetch-auth-token */ public function testFailsOnNoContentTypeIfResponseIsNotJSON() { $this->expectException(\Exception::class); $this->expectExceptionMessage('Invalid JSON response'); $testConfig = $this->fetchAuthTokenMinimal; $notJson = '{"foo": , this is cannot be passed as json" "bar"}'; $httpHandler = getHandler([ new Response(200, [], Utils::streamFor($notJson)), ]); $o = new OAuth2($testConfig); $o->fetchAuthToken($httpHandler); } /** * @group oauth2-fetch-auth-token */ public function testFetchesJsonResponseOnNoContentTypeOK() { $testConfig = $this->fetchAuthTokenMinimal; $json = '{"foo": "bar"}'; $httpHandler = getHandler([ new Response(200, [], Utils::streamFor($json)), ]); $o = new OAuth2($testConfig); $tokens = $o->fetchAuthToken($httpHandler); $this->assertEquals($tokens['foo'], 'bar'); } /** * @group oauth2-fetch-auth-token */ public function testFetchesFromFormEncodedResponseOK() { $testConfig = $this->fetchAuthTokenMinimal; $json = 'foo=bar&spice=nice'; $httpHandler = getHandler([ new Response( 200, ['Content-Type' => 'application/x-www-form-urlencoded'], Utils::streamFor($json) ), ]); $o = new OAuth2($testConfig); $tokens = $o->fetchAuthToken($httpHandler); $this->assertEquals($tokens['foo'], 'bar'); $this->assertEquals($tokens['spice'], 'nice'); } /** * @group oauth2-fetch-auth-token */ public function testUpdatesTokenFieldsOnFetch() { $testConfig = $this->fetchAuthTokenMinimal; $wanted_updates = [ 'expires_at' => '1', 'expires_in' => '57', 'issued_at' => '2', 'access_token' => 'an_access_token', 'id_token' => 'an_id_token', 'refresh_token' => 'a_refresh_token', 'scope' => 'scope1 scope2', ]; $json = json_encode($wanted_updates); $httpHandler = getHandler([ new Response(200, [], Utils::streamFor($json)), ]); $o = new OAuth2($testConfig); $this->assertNull($o->getExpiresAt()); $this->assertNull($o->getExpiresIn()); $this->assertNull($o->getIssuedAt()); $this->assertNull($o->getAccessToken()); $this->assertNull($o->getIdToken()); $this->assertNull($o->getRefreshToken()); $tokens = $o->fetchAuthToken($httpHandler); $this->assertEquals(1, $o->getExpiresAt()); $this->assertEquals(57, $o->getExpiresIn()); $this->assertEquals(2, $o->getIssuedAt()); $this->assertEquals('an_access_token', $o->getAccessToken()); $this->assertEquals('an_id_token', $o->getIdToken()); $this->assertEquals('a_refresh_token', $o->getRefreshToken()); $this->assertEquals('scope1 scope2', $o->getGrantedScope()); } /** * @group oauth2-fetch-auth-token */ public function testUpdatesTokenFieldsOnFetchMissingRefreshToken() { $testConfig = $this->fetchAuthTokenMinimal; $testConfig['refresh_token'] = 'a_refresh_token'; $wanted_updates = [ 'expires_at' => '1', 'expires_in' => '57', 'issued_at' => '2', 'access_token' => 'an_access_token', 'id_token' => 'an_id_token', ]; $json = json_encode($wanted_updates); $httpHandler = getHandler([ new Response(200, [], Utils::streamFor($json)), ]); $o = new OAuth2($testConfig); $this->assertNull($o->getExpiresAt()); $this->assertNull($o->getExpiresIn()); $this->assertNull($o->getIssuedAt()); $this->assertNull($o->getAccessToken()); $this->assertNull($o->getIdToken()); $this->assertEquals('a_refresh_token', $o->getRefreshToken()); $tokens = $o->fetchAuthToken($httpHandler); $this->assertEquals(1, $o->getExpiresAt()); $this->assertEquals(57, $o->getExpiresIn()); $this->assertEquals(2, $o->getIssuedAt()); $this->assertEquals('an_access_token', $o->getAccessToken()); $this->assertEquals('an_id_token', $o->getIdToken()); $this->assertEquals('a_refresh_token', $o->getRefreshToken()); } /** * @dataProvider provideGetLastReceivedToken * @group oauth2-fetch-auth-token */ public function testGetLastReceivedToken( $updateToken, $expectedToken = null ) { $testConfig = $this->fetchAuthTokenMinimal; $o = new OAuth2($testConfig); $o->updateToken($updateToken); $this->assertEquals( $expectedToken ?: $updateToken, $o->getLastReceivedToken() ); } public function provideGetLastReceivedToken() { $time = time(); return [ [ ['access_token' => 'abc'], ['access_token' => 'abc', 'expires_at' => null], ], [ ['access_token' => 'abc', 'invalid-field' => 'foo'], ['access_token' => 'abc', 'expires_at' => null], ], [ ['access_token' => 'abc', 'expires_at' => 1234567890], ['access_token' => 'abc', 'expires_at' => 1234567890], ], [ ['id_token' => 'def'], ['id_token' => 'def', 'expires_at' => null], ], [ ['id_token' => 'def', 'expires_at' => 1234567890], ['id_token' => 'def', 'expires_at' => 1234567890], ], [ [ 'access_token' => 'abc', 'expires_in' => 3600, 'issued_at' => $time ], [ 'access_token' => 'abc', 'expires_at' => $time + 3600, 'expires_in' => 3600, 'issued_at' => $time ], ], [ ['access_token' => 'abc', 'issued_at' => 1234567890], [ 'access_token' => 'abc', 'expires_at' => null, 'issued_at' => 1234567890 ], ], [ ['access_token' => 'abc', 'refresh_token' => 'xyz'], [ 'access_token' => 'abc', 'expires_at' => null, 'refresh_token' => 'xyz' ], ], ]; } /** * @group oauth2-verify-id-token */ public function testFailsIfIdTokenIsInvalid() { $this->expectException(UnexpectedValueException::class); $publicKey = file_get_contents(__DIR__ . '/fixtures' . '/public.pem'); $testConfig = $this->verifyIdTokenMinimal; $not_a_jwt = 'not a jot'; $o = new OAuth2($testConfig); $o->setIdToken($not_a_jwt); $o->verifyIdToken($publicKey, ['RS256']); } /** * @group oauth2-verify-id-token */ public function testFailsIfAudienceIsMissing() { $this->expectException(DomainException::class); $publicKey = file_get_contents(__DIR__ . '/fixtures' . '/public.pem'); $privateKey = file_get_contents(__DIR__ . '/fixtures' . '/private.pem'); $testConfig = $this->verifyIdTokenMinimal; $now = time(); $origIdToken = [ 'issuer' => $testConfig['issuer'], 'exp' => $now + 65, // arbitrary 'iat' => $now, ]; $o = new OAuth2($testConfig); $jwtIdToken = JWT::encode($origIdToken, $privateKey, 'RS256'); $o->setIdToken($jwtIdToken); $o->verifyIdToken($publicKey, ['RS256']); } /** * @group oauth2-verify-id-token */ public function testFailsIfAudienceIsWrong() { $this->expectException(DomainException::class); $publicKey = file_get_contents(__DIR__ . '/fixtures' . '/public.pem'); $privateKey = file_get_contents(__DIR__ . '/fixtures' . '/private.pem'); $now = time(); $testConfig = $this->verifyIdTokenMinimal; $origIdToken = [ 'aud' => 'a different audience', 'iss' => $testConfig['issuer'], 'exp' => $now + 65, // arbitrary 'iat' => $now, ]; $o = new OAuth2($testConfig); $jwtIdToken = JWT::encode($origIdToken, $privateKey, 'RS256'); $o->setIdToken($jwtIdToken); $o->verifyIdToken($publicKey, ['RS256']); } /** * @group oauth2-verify-id-token */ public function testFailsWithStringPublicKeyAndAllowedAlgsGreaterThanOne() { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('To have multiple allowed algorithms'); $publicKey = file_get_contents(__DIR__ . '/fixtures' . '/public.pem'); $testConfig = $this->verifyIdTokenMinimal; $not_a_jwt = 'not a jot'; $o = new OAuth2($testConfig); $o->setIdToken($not_a_jwt); $o->verifyIdToken($publicKey, ['RS256', 'ES256']); } /** * @group oauth2-verify-id-token */ public function testFailsWithStringPublicKeyAndNoAllowedAlgs() { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('When allowed algorithms is empty'); $publicKey = file_get_contents(__DIR__ . '/fixtures' . '/public.pem'); $testConfig = $this->verifyIdTokenMinimal; $not_a_jwt = 'not a jot'; $o = new OAuth2($testConfig); $o->setIdToken($not_a_jwt); $o->verifyIdToken($publicKey, []); } /** * @group oauth2-verify-id-token */ public function testFailsWithStringInPublicKeyArrayAndNoAllowedAlgs() { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('When allowed algorithms is empty'); $publicKey = file_get_contents(__DIR__ . '/fixtures' . '/public.pem'); $testConfig = $this->verifyIdTokenMinimal; $not_a_jwt = 'not a jot'; $o = new OAuth2($testConfig); $o->setIdToken($not_a_jwt); $o->verifyIdToken([ new Key($publicKey, 'RS256'), $publicKey, ], []); } /** * @group oauth2-verify-id-token */ public function testFailsWithInvalidTypeForAllowedAlgs() { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('allowed algorithms must be a string or array'); $publicKey = file_get_contents(__DIR__ . '/fixtures' . '/public.pem'); $testConfig = $this->verifyIdTokenMinimal; $not_a_jwt = 'not a jot'; $o = new OAuth2($testConfig); $o->setIdToken($not_a_jwt); $o->verifyIdToken($publicKey, 123); } /** * @group oauth2-verify-id-token */ public function testShouldReturnAValidIdToken() { $publicKey = file_get_contents(__DIR__ . '/fixtures' . '/public.pem'); $privateKey = file_get_contents(__DIR__ . '/fixtures' . '/private.pem'); $testConfig = $this->verifyIdTokenMinimal; $now = time(); $origIdToken = [ 'aud' => $testConfig['audience'], 'iss' => $testConfig['issuer'], 'exp' => $now + 65, // arbitrary 'iat' => $now, ]; $o = new OAuth2($testConfig); $alg = 'RS256'; $jwtIdToken = JWT::encode($origIdToken, $privateKey, $alg); $o->setIdToken($jwtIdToken); // Test with array alg $roundTrip = $o->verifyIdToken($publicKey, [$alg]); $this->assertEquals($origIdToken['aud'], $roundTrip->aud); // Test with string alg $roundTrip2 = $o->verifyIdToken($publicKey, $alg); $this->assertEquals($origIdToken['aud'], $roundTrip2->aud); } } class OAuth2StsTest extends TestCase { use ProphecyTrait; private $publicKey; private $privateKey; private $stsMinimal = [ 'tokenCredentialUri' => 'https://tokens_r_us/test', 'subjectTokenType' => 'urn:ietf:params:aws:token-type:aws4_request', ]; public function testStsGrantType() { $credentialSource = $this->prophesize(ExternalAccountCredentialSourceInterface::class); $o = new OAuth2($this->stsMinimal + ['subjectTokenFetcher' => $credentialSource->reveal()]); $this->assertEquals(OAuth2::STS_URN, $o->getGrantType()); } public function testStsCredentialsRequestMinimal() { $credentialSource = $this->prophesize(ExternalAccountCredentialSourceInterface::class); $credentialSource->fetchSubjectToken(null) ->shouldBeCalledOnce() ->willReturn('xyz'); $o = new OAuth2($this->stsMinimal + ['subjectTokenFetcher' => $credentialSource->reveal()]); $request = $o->generateCredentialsRequest(); $this->assertEquals('POST', $request->getMethod()); $this->assertEquals($this->stsMinimal['tokenCredentialUri'], (string) $request->getUri()); parse_str((string)$request->getBody(), $requestParams); $this->assertCount(4, $requestParams); $this->assertEquals(OAuth2::STS_URN, $requestParams['grant_type']); $this->assertEquals('xyz', $requestParams['subject_token']); $this->assertEquals($this->stsMinimal['subjectTokenType'], $requestParams['subject_token_type']); } public function testStsCredentialsRequestFull() { $credentialSource = $this->prophesize(ExternalAccountCredentialSourceInterface::class); $credentialSource->fetchSubjectToken(null) ->shouldBeCalledOnce() ->willReturn('xyz'); $stsMinimal = $this->stsMinimal + [ 'subjectTokenFetcher' => $credentialSource->reveal(), 'resource' => 'abc', 'scope' => ['scope1', 'scope2'], 'audience' => 'def', 'actorToken' => '123', 'actorTokenType' => 'urn:ietf:params:oauth:token-type:access_token', ]; $o = new OAuth2($stsMinimal); $request = $o->generateCredentialsRequest(); $this->assertEquals('POST', $request->getMethod()); $this->assertEquals($this->stsMinimal['tokenCredentialUri'], (string) $request->getUri()); parse_str((string)$request->getBody(), $requestParams); $this->assertCount(9, $requestParams); $this->assertEquals(OAuth2::STS_URN, $requestParams['grant_type']); $this->assertEquals('xyz', $requestParams['subject_token']); $this->assertEquals($stsMinimal['subjectTokenType'], $requestParams['subject_token_type']); $this->assertEquals($stsMinimal['resource'], $requestParams['resource']); $this->assertEquals('scope1 scope2', $requestParams['scope']); $this->assertEquals($stsMinimal['audience'], $requestParams['audience']); $this->assertEquals($stsMinimal['actorToken'], $requestParams['actor_token']); $this->assertEquals($stsMinimal['actorTokenType'], $requestParams['actor_token_type']); } }