From 64d4c4a38ac8de2dd3d5b8d7c1a64c21907e0abe Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 15:44:34 +0000 Subject: [PATCH 01/49] Removed old tests --- tests/unit/AbstractServerTest.php | 26 - tests/unit/AuthorizationServerTest.php | 82 --- tests/unit/Entity/AbstractTokenEntityTest.php | 116 --- tests/unit/Entity/AccessTokenEntityTest.php | 59 -- tests/unit/Entity/AuthCodeEntityTest.php | 73 -- tests/unit/Entity/ClientEntityTest.php | 25 - tests/unit/Entity/RefreshTokenEntityTest.php | 94 --- tests/unit/Entity/ScopeEntityTest.php | 23 - tests/unit/Entity/SessionEntityTest.php | 154 ---- tests/unit/Exception/OAuthExceptionTest.php | 34 - tests/unit/Grant/AbstractGrantTest.php | 160 ---- tests/unit/Grant/AuthCodeGrantTest.php | 696 ------------------ .../unit/Grant/ClientCredentialsGrantTest.php | 251 ------- tests/unit/Grant/PasswordGrantTest.php | 479 ------------ tests/unit/Grant/RefreshTokenGrantTest.php | 501 ------------- tests/unit/ResourceServerTest.php | 226 ------ tests/unit/Storage/AbstractStorageTest.php | 23 - tests/unit/Stubs/StubAbstractGrant.php | 18 - tests/unit/Stubs/StubAbstractServer.php | 8 - tests/unit/Stubs/StubAbstractStorage.php | 8 - tests/unit/Stubs/StubAbstractTokenEntity.php | 18 - tests/unit/TokenType/MacTest.php | 165 ----- tests/unit/util/RedirectUriTest.php | 19 - tests/unit/util/SecureKeyTest.php | 35 - 24 files changed, 3293 deletions(-) delete mode 100644 tests/unit/AbstractServerTest.php delete mode 100644 tests/unit/AuthorizationServerTest.php delete mode 100644 tests/unit/Entity/AbstractTokenEntityTest.php delete mode 100644 tests/unit/Entity/AccessTokenEntityTest.php delete mode 100644 tests/unit/Entity/AuthCodeEntityTest.php delete mode 100644 tests/unit/Entity/ClientEntityTest.php delete mode 100644 tests/unit/Entity/RefreshTokenEntityTest.php delete mode 100644 tests/unit/Entity/ScopeEntityTest.php delete mode 100644 tests/unit/Entity/SessionEntityTest.php delete mode 100644 tests/unit/Exception/OAuthExceptionTest.php delete mode 100644 tests/unit/Grant/AbstractGrantTest.php delete mode 100644 tests/unit/Grant/AuthCodeGrantTest.php delete mode 100644 tests/unit/Grant/ClientCredentialsGrantTest.php delete mode 100644 tests/unit/Grant/PasswordGrantTest.php delete mode 100644 tests/unit/Grant/RefreshTokenGrantTest.php delete mode 100644 tests/unit/ResourceServerTest.php delete mode 100644 tests/unit/Storage/AbstractStorageTest.php delete mode 100644 tests/unit/Stubs/StubAbstractGrant.php delete mode 100644 tests/unit/Stubs/StubAbstractServer.php delete mode 100644 tests/unit/Stubs/StubAbstractStorage.php delete mode 100644 tests/unit/Stubs/StubAbstractTokenEntity.php delete mode 100644 tests/unit/TokenType/MacTest.php delete mode 100644 tests/unit/util/RedirectUriTest.php delete mode 100644 tests/unit/util/SecureKeyTest.php diff --git a/tests/unit/AbstractServerTest.php b/tests/unit/AbstractServerTest.php deleted file mode 100644 index 074f363c..00000000 --- a/tests/unit/AbstractServerTest.php +++ /dev/null @@ -1,26 +0,0 @@ -addEventListener('event.name', function () use ($var) { - $var++; - $this->assertSame(1, $var); - }); - $server->getEventEmitter()->emit('event.name'); - $this->assertTrue($server->getRequest() instanceof \Symfony\Component\HttpFoundation\Request); - $this->assertTrue($server->getEventEmitter() instanceof \League\Event\Emitter); - - $server2 = new StubAbstractServer(); - $server2->setRequest((new \Symfony\Component\HttpFoundation\Request())); - $server2->setEventEmitter(1); - $this->assertTrue($server2->getRequest() instanceof \Symfony\Component\HttpFoundation\Request); - } -} diff --git a/tests/unit/AuthorizationServerTest.php b/tests/unit/AuthorizationServerTest.php deleted file mode 100644 index 10a21686..00000000 --- a/tests/unit/AuthorizationServerTest.php +++ /dev/null @@ -1,82 +0,0 @@ -requireScopeParam(true); - $server->requireStateParam(true); - $server->setDefaultScope('foobar'); - $server->setScopeDelimiter(','); - $server->setAccessTokenTTL(1); - - $grant = M::mock('League\OAuth2\Server\Grant\GrantTypeInterface'); - $grant->shouldReceive('getIdentifier')->andReturn('foobar'); - $grant->shouldReceive('getResponseType')->andReturn('foobar'); - $grant->shouldReceive('setAuthorizationServer'); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - - $server->addGrantType($grant); - $server->setScopeStorage($scopeStorage); - - $this->assertTrue($server->hasGrantType('foobar')); - $this->assertTrue($server->getGrantType('foobar') instanceof GrantTypeInterface); - $this->assertSame($server->getResponseTypes(), ['foobar']); - $this->assertTrue($server->scopeParamRequired()); - $this->assertTrue($server->stateParamRequired()); - $this->assertTrue($server->getScopeStorage() instanceof ScopeInterface); - $this->assertEquals('foobar', $server->getDefaultScope()); - $this->assertEquals(',', $server->getScopeDelimiter()); - $this->assertEquals(1, $server->getAccessTokenTTL()); - } - - public function testInvalidGrantType() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidGrantException'); - $server = new AuthorizationServer(); - $server->getGrantType('foobar'); - } - - public function testIssueAccessToken() - { - $grant = M::mock('League\OAuth2\Server\Grant\GrantTypeInterface'); - $grant->shouldReceive('getIdentifier')->andReturn('foobar'); - $grant->shouldReceive('getResponseType')->andReturn('foobar'); - $grant->shouldReceive('setAuthorizationServer'); - $grant->shouldReceive('completeFlow')->andReturn(true); - - $_POST['grant_type'] = 'foobar'; - - $server = new AuthorizationServer(); - $server->addGrantType($grant); - - $this->assertTrue($server->issueAccessToken()); - } - - public function testIssueAccessTokenEmptyGrantType() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - $server = new AuthorizationServer(); - $this->assertTrue($server->issueAccessToken()); - } - - public function testIssueAccessTokenInvalidGrantType() - { - $this->setExpectedException('League\OAuth2\Server\Exception\UnsupportedGrantTypeException'); - - $_POST['grant_type'] = 'foobar'; - - $server = new AuthorizationServer(); - $this->assertTrue($server->issueAccessToken()); - } -} diff --git a/tests/unit/Entity/AbstractTokenEntityTest.php b/tests/unit/Entity/AbstractTokenEntityTest.php deleted file mode 100644 index 24428085..00000000 --- a/tests/unit/Entity/AbstractTokenEntityTest.php +++ /dev/null @@ -1,116 +0,0 @@ -setId('foobar'); - $entity->setExpireTime($time); - $entity->setSession((new SessionEntity($server))); - $entity->associateScope((new ScopeEntity($server))->hydrate(['id' => 'foo'])); - - $this->assertEquals('foobar', $entity->getId()); - $this->assertEquals($time, $entity->getExpireTime()); - // $this->assertTrue($entity->getSession() instanceof SessionEntity); - // $this->assertTrue($entity->hasScope('foo')); - - // $result = $entity->getScopes(); - // $this->assertTrue(isset($result['foo'])); - } - - /*public function testGetSession() - { - $server = M::mock('League\OAuth2\Server\AuthorizationServer'); - $server->shouldReceive('setSessionStorage'); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('getByAccessToken')->andReturn( - (new SessionEntity($server)) - ); - $sessionStorage->shouldReceive('setServer'); - - $server->shouldReceive('getStorage')->andReturn($sessionStorage); - - $server->setSessionStorage($sessionStorage); - - $entity = new StubAbstractTokenEntity($server); - $this->assertTrue($entity->getSession() instanceof SessionEntity); - }*/ - - /*public function testGetScopes() - { - $server = M::mock('League\OAuth2\Server\AuthorizationServer'); - $server->shouldReceive('setAccessTokenStorage'); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn( - [] - ); - $accessTokenStorage->shouldReceive('setServer'); - - $server->setAccessTokenStorage($accessTokenStorage); - - $entity = new StubAbstractTokenEntity($server); - $this->assertEquals($entity->getScopes(), []); - }*/ - - /*public function testHasScopes() - { - $server = M::mock('League\OAuth2\Server\AuthorizationServer'); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn( - [] - ); - $accessTokenStorage''>shouldReceive('setServer'); - - $server->setAccessTokenStorage($accessTokenStorage); - - $entity = new StubAbstractTokenEntity($server); - $this->assertFalse($entity->hasScope('foo')); - }*/ - - public function testFormatScopes() - { - $server = M::mock('League\OAuth2\Server\AbstractServer'); - - $entity = new StubAbstractTokenEntity($server); - $reflectedEntity = new \ReflectionClass('LeagueTests\Stubs\StubAbstractTokenEntity'); - $method = $reflectedEntity->getMethod('formatScopes'); - $method->setAccessible(true); - - $scopes = [ - (new ScopeEntity($server))->hydrate(['id' => 'scope1', 'description' => 'foo']), - (new ScopeEntity($server))->hydrate(['id' => 'scope2', 'description' => 'bar']), - ]; - - $result = $method->invokeArgs($entity, [$scopes]); - - $this->assertTrue(isset($result['scope1'])); - $this->assertTrue(isset($result['scope2'])); - $this->assertTrue($result['scope1'] instanceof ScopeEntity); - $this->assertTrue($result['scope2'] instanceof ScopeEntity); - } - - public function test__toString() - { - $server = M::mock('League\OAuth2\Server\AbstractServer'); - - $entity = new StubAbstractTokenEntity($server); - $this->assertEquals('', (string) $entity); - $entity->setId('foobar'); - $this->assertEquals('foobar', (string) $entity); - } -} diff --git a/tests/unit/Entity/AccessTokenEntityTest.php b/tests/unit/Entity/AccessTokenEntityTest.php deleted file mode 100644 index 6f2a617e..00000000 --- a/tests/unit/Entity/AccessTokenEntityTest.php +++ /dev/null @@ -1,59 +0,0 @@ -shouldReceive('setAccessTokenStorage'); - $server->shouldReceive('setSessionStorage'); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('associateScope'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('getByAccessToken')->andReturn( - (new SessionEntity($server)) - ); - $sessionStorage->shouldReceive('setServer'); - - $server->shouldReceive('getSessionStorage')->andReturn($sessionStorage); - $server->shouldReceive('getAccessTokenStorage')->andReturn($accessTokenStorage); - - $server->setAccessTokenStorage($accessTokenStorage); - $server->setSessionStorage($sessionStorage); - - $entity = new AccessTokenEntity($server); - $this->assertTrue($entity->save() instanceof AccessTokenEntity); - } - - public function testExpire() - { - $server = M::mock('League\OAuth2\Server\AbstractServer'); - - $server->shouldReceive('setAccessTokenStorage'); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('delete'); - $accessTokenStorage->shouldReceive('setServer'); - - $server->shouldReceive('getAccessTokenStorage')->andReturn($accessTokenStorage); - - $server->setAccessTokenStorage($accessTokenStorage); - - $entity = new AccessTokenEntity($server); - $this->assertSame($entity->expire(), null); - } -} diff --git a/tests/unit/Entity/AuthCodeEntityTest.php b/tests/unit/Entity/AuthCodeEntityTest.php deleted file mode 100644 index 5b7fc089..00000000 --- a/tests/unit/Entity/AuthCodeEntityTest.php +++ /dev/null @@ -1,73 +0,0 @@ -setRedirectUri('http://foo/bar'); - $code->setId('foobar'); - $code->setSession($session); - - $this->assertEquals('http://foo/bar', $code->getRedirectUri()); - $this->assertEquals('http://foo/bar?code=foobar', $code->generateRedirectUri()); - $this->assertTrue($code->getSession() instanceof \League\OAuth2\Server\Entity\SessionEntity); - } - - public function testSave() - { - $server = M::mock('League\OAuth2\Server\AbstractServer'); - $server->shouldReceive('setAuthCodeStorage'); - $server->shouldReceive('setSessionStorage'); - - $authCodeStorage = M::mock('League\OAuth2\Server\Storage\AuthCodeInterface'); - $authCodeStorage->shouldReceive('create'); - $authCodeStorage->shouldReceive('associateScope'); - $authCodeStorage->shouldReceive('setServer'); - $authCodeStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - - $server->shouldReceive('getAuthCodeStorage')->andReturn($authCodeStorage); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('getByAuthCode')->andReturn( - (new SessionEntity($server)) - ); - $sessionStorage->shouldReceive('setServer'); - - $server->shouldReceive('getSessionStorage')->andReturn($sessionStorage); - - $server->setAuthCodeStorage($authCodeStorage); - $server->setSessionStorage($sessionStorage); - - $entity = new AuthCodeEntity($server); - $this->assertTrue($entity->save() instanceof AuthCodeEntity); - } - - public function testExpire() - { - $server = new AuthorizationServer(); - - $authCodeStorage = M::mock('League\OAuth2\Server\Storage\AuthCodeInterface'); - $authCodeStorage->shouldReceive('delete'); - $authCodeStorage->shouldReceive('setServer'); - - $server->setAuthCodeStorage($authCodeStorage); - - $entity = new AuthCodeEntity($server); - $this->assertSame($entity->expire(), null); - } -} diff --git a/tests/unit/Entity/ClientEntityTest.php b/tests/unit/Entity/ClientEntityTest.php deleted file mode 100644 index 9bb13c7d..00000000 --- a/tests/unit/Entity/ClientEntityTest.php +++ /dev/null @@ -1,25 +0,0 @@ -hydrate([ - 'id' => 'foobar', - 'secret' => 'barfoo', - 'name' => 'Test Client', - 'redirectUri' => 'http://foo/bar', - ]); - - $this->assertEquals('foobar', $client->getId()); - $this->assertEquals('barfoo', $client->getSecret()); - $this->assertEquals('Test Client', $client->getName()); - $this->assertEquals('http://foo/bar', $client->getRedirectUri()); - } -} diff --git a/tests/unit/Entity/RefreshTokenEntityTest.php b/tests/unit/Entity/RefreshTokenEntityTest.php deleted file mode 100644 index f2b05cf7..00000000 --- a/tests/unit/Entity/RefreshTokenEntityTest.php +++ /dev/null @@ -1,94 +0,0 @@ -setAccessTokenId('foobar'); - - $reflector = new \ReflectionClass($entity); - $accessTokenProperty = $reflector->getProperty('accessTokenId'); - $accessTokenProperty->setAccessible(true); - - $this->assertSame($accessTokenProperty->getValue($entity), 'foobar'); - } - - public function testSetAccessToken() - { - $server = M::mock('League\OAuth2\Server\AbstractServer'); - $entity = new RefreshTokenEntity($server); - $entity->setAccessToken((new AccessTokenEntity($server))); - - $reflector = new \ReflectionClass($entity); - $accessTokenProperty = $reflector->getProperty('accessTokenEntity'); - $accessTokenProperty->setAccessible(true); - - $this->assertTrue($accessTokenProperty->getValue($entity) instanceof AccessTokenEntity); - } - - public function testSave() - { - $server = M::mock('League\OAuth2\Server\AbstractServer'); - $server->shouldReceive('setAccessTokenStorage'); - $server->shouldReceive('setRefreshTokenStorage'); - - $refreshTokenStorage = M::mock('League\OAuth2\Server\Storage\RefreshTokenInterface'); - $refreshTokenStorage->shouldReceive('create'); - $refreshTokenStorage->shouldReceive('setServer'); - $refreshTokenStorage->shouldReceive('associateScope'); - - $server->shouldReceive('getRefreshTokenStorage')->andReturn($refreshTokenStorage); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('get')->andReturn( - (new AccessTokenEntity($server))->setId('foobar') - ); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - - $server->shouldReceive('getAccessTokenStorage')->andReturn($accessTokenStorage); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('getByAccessToken')->andReturn( - (new SessionEntity($server)) - ); - $sessionStorage->shouldReceive('setServer'); - - $server->shouldReceive('getSessionStorage')->andReturn($sessionStorage); - - $server->setAccessTokenStorage($accessTokenStorage); - $server->setRefreshTokenStorage($refreshTokenStorage); - - $entity = new RefreshTokenEntity($server); - $this->assertSame(null, $entity->save()); - } - - public function testExpire() - { - $server = M::mock('League\OAuth2\Server\AbstractServer'); - $server->shouldReceive('setRefreshTokenStorage'); - - $refreshTokenStorage = M::mock('League\OAuth2\Server\Storage\RefreshTokenInterface'); - $refreshTokenStorage->shouldReceive('delete'); - $refreshTokenStorage->shouldReceive('setServer'); - - $server->shouldReceive('getRefreshTokenStorage')->andReturn($refreshTokenStorage); - - $server->setRefreshTokenStorage($refreshTokenStorage); - - $entity = new RefreshTokenEntity($server); - $this->assertSame($entity->expire(), null); - } -} diff --git a/tests/unit/Entity/ScopeEntityTest.php b/tests/unit/Entity/ScopeEntityTest.php deleted file mode 100644 index 3fec4fe1..00000000 --- a/tests/unit/Entity/ScopeEntityTest.php +++ /dev/null @@ -1,23 +0,0 @@ -hydrate([ - 'id' => 'foobar', - 'description' => 'barfoo', - ]); - - $this->assertEquals('foobar', $scope->getId()); - $this->assertEquals('barfoo', $scope->getDescription()); - - $this->assertTrue(is_array($scope->jsonSerialize())); - } -} diff --git a/tests/unit/Entity/SessionEntityTest.php b/tests/unit/Entity/SessionEntityTest.php deleted file mode 100644 index 5ca26a75..00000000 --- a/tests/unit/Entity/SessionEntityTest.php +++ /dev/null @@ -1,154 +0,0 @@ -shouldReceive('emit'); - $server = M::mock('League\OAuth2\Server\AbstractServer'); - $server->shouldReceive('setEventEmitter'); - $server->shouldReceive('getEventEmitter')->andReturn($emitter); - $server->setEventEmitter($emitter); - - $entity = new SessionEntity($server); - $entity->setId('foobar'); - $entity->setOwner('user', 123); - $entity->associateAccessToken((new AccessTokenEntity($server))); - $entity->associateRefreshToken((new RefreshTokenEntity($server))); - $entity->associateClient((new ClientEntity($server))); - $entity->associateScope( - (new ScopeEntity($server))->hydrate(['id' => 'foo']) - ); - // $entity->associateAuthCode((new AuthCode($server))); - - $this->assertEquals('foobar', $entity->getId()); - $this->assertEquals('user', $entity->getOwnerType()); - $this->assertEquals(123, $entity->getOwnerId()); - $this->assertTrue($entity->getClient() instanceof ClientEntity); - $this->assertTrue($entity->hasScope('foo')); - - $reflector = new \ReflectionClass($entity); - $accessTokenProperty = $reflector->getProperty('accessToken'); - $accessTokenProperty->setAccessible(true); - $refreshTokenProperty = $reflector->getProperty('refreshToken'); - $refreshTokenProperty->setAccessible(true); - - $this->assertTrue($accessTokenProperty->getValue($entity) instanceof AccessTokenEntity); - $this->assertTrue($refreshTokenProperty->getValue($entity) instanceof RefreshTokenEntity); - // $this->assertTrue($reader($entity, 'authCode') instanceof AuthCode); - } - - public function testFormatScopes() - { - $server = M::mock('League\OAuth2\Server\AbstractServer'); - - $entity = new SessionEntity($server); - $reflectedEntity = new \ReflectionClass('League\OAuth2\Server\Entity\SessionEntity'); - $method = $reflectedEntity->getMethod('formatScopes'); - $method->setAccessible(true); - - $scopes = [ - (new ScopeEntity($server))->hydrate(['id' => 'scope1']), - (new ScopeEntity($server))->hydrate(['id' => 'scope2']), - ]; - - $result = $method->invokeArgs($entity, [$scopes]); - - $this->assertTrue(isset($result['scope1'])); - $this->assertTrue(isset($result['scope2'])); - $this->assertTrue($result['scope1'] instanceof ScopeEntity); - $this->assertTrue($result['scope2'] instanceof ScopeEntity); - } - - public function testGetScopes() - { - $server = M::mock('League\OAuth2\Server\AuthorizationServer'); - $server->shouldReceive('setAccessTokenStorage'); - $server->shouldReceive('setSessionStorage'); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $server->setAccessTokenStorage($accessTokenStorage); - - $server->shouldReceive('getAccessTokenStorage')->andReturn($accessTokenStorage); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('getScopes')->andReturn( - [] - ); - $sessionStorage->shouldReceive('setServer'); - $server->setSessionStorage($sessionStorage); - - $server->shouldReceive('getSessionStorage')->andReturn($sessionStorage); - - $entity = new SessionEntity($server); - $this->assertEquals($entity->getScopes(), []); - } - - public function testHasScopes() - { - $server = M::mock('League\OAuth2\Server\AuthorizationServer'); - $server->shouldReceive('setAccessTokenStorage'); - $server->shouldReceive('setSessionStorage'); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $server->setAccessTokenStorage($accessTokenStorage); - - $server->shouldReceive('getAccessTokenStorage')->andReturn($accessTokenStorage); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('getScopes')->andReturn( - [] - ); - $sessionStorage->shouldReceive('setServer'); - $server->setSessionStorage($sessionStorage); - - $server->shouldReceive('getSessionStorage')->andReturn($sessionStorage); - - $entity = new SessionEntity($server); - $this->assertFalse($entity->hasScope('foo')); - } - - public function testSave() - { - $server = M::mock('League\OAuth2\Server\AuthorizationServer'); - $server->shouldReceive('setSessionStorage'); - $server->shouldReceive('setClientStorage'); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('create'); - $sessionStorage->shouldReceive('associateScope'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - - $server->shouldReceive('getSessionStorage')->andReturn($sessionStorage); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('getBySession')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'foo']) - ); - $clientStorage->shouldReceive('setServer'); - - $server->shouldReceive('getClientStorage')->andReturn($clientStorage); - - $server->setSessionStorage($sessionStorage); - $server->setClientStorage($clientStorage); - - $entity = new SessionEntity($server); - $this->assertEquals(null, $entity->save()); - } -} diff --git a/tests/unit/Exception/OAuthExceptionTest.php b/tests/unit/Exception/OAuthExceptionTest.php deleted file mode 100644 index 273ed374..00000000 --- a/tests/unit/Exception/OAuthExceptionTest.php +++ /dev/null @@ -1,34 +0,0 @@ -httpStatusCode = 400; - $this->assertSame($exception->getHttpHeaders(), ['HTTP/1.1 400 Bad Request']); - - $exception->httpStatusCode = 401; - $this->assertSame($exception->getHttpHeaders(), ['HTTP/1.1 401 Unauthorized']); - - $exception->httpStatusCode = 500; - $this->assertSame($exception->getHttpHeaders(), ['HTTP/1.1 500 Internal Server Error']); - - $exception->httpStatusCode = 501; - $this->assertSame($exception->getHttpHeaders(), ['HTTP/1.1 501 Not Implemented']); - } - - public function testShouldRedirect() - { - $exception = new OAuthException(); - $exception->redirectUri = 'http://example.com/'; - $exception->errorType = 'Error'; - $this->assertTrue($exception->shouldRedirect()); - $this->assertEquals('http://example.com/?error=Error&message=An+error+occured', $exception->getRedirectUri()); - } -} diff --git a/tests/unit/Grant/AbstractGrantTest.php b/tests/unit/Grant/AbstractGrantTest.php deleted file mode 100644 index 8a57b61b..00000000 --- a/tests/unit/Grant/AbstractGrantTest.php +++ /dev/null @@ -1,160 +0,0 @@ -setIdentifier('foobar'); - $grant->setAccessTokenTTL(300); - $grant->setAuthorizationServer($server); - - $this->assertEquals('foobar', $grant->getIdentifier()); - $this->assertEquals('foobar', $grant->getResponseType()); - $this->assertEquals(300, $grant->getAccessTokenTTL()); - $this->assertTrue($grant->getAuthorizationServer() instanceof AuthorizationServer); - } - - public function testFormatScopes() - { - $server = M::mock('League\OAuth2\Server\AbstractServer'); - - $grant = new StubAbstractGrant(); - $reflectedGrant = new \ReflectionClass('LeagueTests\Stubs\StubAbstractGrant'); - $method = $reflectedGrant->getMethod('formatScopes'); - $method->setAccessible(true); - - $scopes = [ - (new ScopeEntity($server))->hydrate(['id' => 'scope1', 'description' => 'foo']), - (new ScopeEntity($server))->hydrate(['id' => 'scope2', 'description' => 'bar']), - ]; - - $result = $method->invokeArgs($grant, [$scopes]); - - $this->assertTrue(isset($result['scope1'])); - $this->assertTrue(isset($result['scope2'])); - $this->assertTrue($result['scope1'] instanceof ScopeEntity); - $this->assertTrue($result['scope2'] instanceof ScopeEntity); - } - - public function testValidateScopes() - { - $server = new AuthorizationServer(); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn( - (new ScopeEntity($server))->hydrate(['id' => 'foo']) - ); - - $server->setScopeStorage($scopeStorage); - - $grant = new StubAbstractGrant(); - $grant->setAuthorizationServer($server); - - $client = (new ClientEntity($server))->hydrate(['id' => 'testapp']); - - $this->assertEquals( - [ - 'foo' => (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ], - $grant->validateScopes('foo', $client) - ); - } - - public function testValidateScopesMissingScope() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - - $server = new AuthorizationServer(); - $server->requireScopeParam(true); - $server->setScopeStorage($scopeStorage); - - $grant = new StubAbstractGrant(); - $grant->setAuthorizationServer($server); - - $client = (new ClientEntity($server))->hydrate(['id' => 'testapp']); - - $grant->validateScopes(null, $client); - } - - public function testValidateScopesInvalidScope() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidScopeException'); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn(null); - - $server = new AuthorizationServer(); - $server->setScopeStorage($scopeStorage); - - $grant = new StubAbstractGrant(); - $grant->setAuthorizationServer($server); - - $client = (new ClientEntity($server))->hydrate(['id' => 'testapp']); - - $grant->validateScopes('blah', $client); - } - - public function testValidateScopesDefaultScope() - { - $server = new AuthorizationServer(); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn( - (new ScopeEntity($server))->hydrate(['id' => 'foo']) - ); - $server->setScopeStorage($scopeStorage); - - $server->requireScopeParam(true); - $server->setScopeStorage($scopeStorage); - $server->setDefaultScope('foo'); - - $grant = new StubAbstractGrant(); - $grant->setAuthorizationServer($server); - - $client = (new ClientEntity($server))->hydrate(['id' => 'testapp']); - - $grant->validateScopes(null, $client); - } - - public function testValidateScopesDefaultScopeArray() - { - $server = new AuthorizationServer(); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn( - (new ScopeEntity($server))->hydrate(['id' => 'foo']) - ); - $server->setScopeStorage($scopeStorage); - - $server->requireScopeParam(true); - $server->setScopeStorage($scopeStorage); - $server->setDefaultScope(['foo', 'bar']); - - $grant = new StubAbstractGrant(); - $grant->setAuthorizationServer($server); - - $client = (new ClientEntity($server))->hydrate(['id' => 'testapp']); - - $grant->validateScopes(null, $client); - } -} diff --git a/tests/unit/Grant/AuthCodeGrantTest.php b/tests/unit/Grant/AuthCodeGrantTest.php deleted file mode 100644 index 72a564d4..00000000 --- a/tests/unit/Grant/AuthCodeGrantTest.php +++ /dev/null @@ -1,696 +0,0 @@ -setAuthTokenTTL(100); - - $class = new \ReflectionClass($grant); - $property = $class->getProperty('authTokenTTL'); - $property->setAccessible(true); - $this->assertEquals(100, $property->getValue($grant)); - } - - public function testCheckAuthoriseParamsMissingClientId() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $_GET = []; - $server = new AuthorizationServer(); - - $grant = new AuthCodeGrant(); - - $server->addGrantType($grant); - $grant->checkAuthorizeParams(); - } - - public function testCheckAuthoriseParamsMissingRedirectUri() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $server = new AuthorizationServer(); - $_GET = [ - 'client_id' => 'testapp', - ]; - - $grant = new AuthCodeGrant(); - - $server->addGrantType($grant); - $grant->checkAuthorizeParams(); - } - - public function testCheckAuthoriseParamsInvalidClient() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidClientException'); - - $_GET = [ - 'client_id' => 'testapp', - 'redirect_uri' => 'http://foo/bar', - 'response_type' => 'code', - ]; - $server = new AuthorizationServer(); - - $grant = new AuthCodeGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn(null); - - $server->setClientStorage($clientStorage); - - $server->addGrantType($grant); - $grant->checkAuthorizeParams(); - } - - public function testCheckAuthoriseParamsMissingStateParam() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $_GET = [ - 'client_id' => 'testapp', - 'redirect_uri' => 'http://foo/bar', - ]; - $server = new AuthorizationServer(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - $server->setClientStorage($clientStorage); - - $grant = new AuthCodeGrant(); - $server->requireStateParam(true); - - $server->addGrantType($grant); - $grant->checkAuthorizeParams(); - } - - public function testCheckAuthoriseParamsMissingResponseType() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $_GET = [ - 'client_id' => 'testapp', - 'redirect_uri' => 'http://foo/bar', - ]; - $server = new AuthorizationServer(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - $server->setClientStorage($clientStorage); - - $grant = new AuthCodeGrant(); - - $server->addGrantType($grant); - $grant->checkAuthorizeParams(); - } - - public function testCheckAuthoriseParamsInvalidResponseType() - { - $this->setExpectedException('League\OAuth2\Server\Exception\UnsupportedResponseTypeException'); - - $_GET = [ - 'client_id' => 'testapp', - 'redirect_uri' => 'http://foo/bar', - 'response_type' => 'foobar', - ]; - $server = new AuthorizationServer(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - $server->setClientStorage($clientStorage); - - $grant = new AuthCodeGrant(); - - $server->addGrantType($grant); - $grant->checkAuthorizeParams(); - } - - public function testCheckAuthoriseParamsInvalidScope() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidScopeException'); - - $_GET = [ - 'response_type' => 'code', - 'client_id' => 'testapp', - 'redirect_uri' => 'http://foo/bar', - 'scope' => 'foo', - ]; - - $server = new AuthorizationServer(); - $grant = new AuthCodeGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('create'); - $sessionStorage->shouldReceive('getScopes')->andReturn([]); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([]); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn(null); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - - $server->addGrantType($grant); - $grant->checkAuthorizeParams(); - } - - public function testCheckAuthoriseParams() - { - $_GET = [ - 'response_type' => 'code', - 'client_id' => 'testapp', - 'redirect_uri' => 'http://foo/bar', - 'scope' => 'foo', - ]; - - $server = new AuthorizationServer(); - $grant = new AuthCodeGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('create')->andreturn(123); - $sessionStorage->shouldReceive('getScopes')->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - $sessionStorage->shouldReceive('associateScope'); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - $accessTokenStorage->shouldReceive('associateScope'); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn( - (new ScopeEntity($server))->hydrate(['id' => 'foo']) - ); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - - $server->addGrantType($grant); - - $result = $grant->checkAuthorizeParams(); - - $this->assertTrue($result['client'] instanceof ClientEntity); - $this->assertTrue($result['redirect_uri'] === $_GET['redirect_uri']); - $this->assertTrue($result['state'] === null); - $this->assertTrue($result['response_type'] === 'code'); - $this->assertTrue($result['scopes']['foo'] instanceof ScopeEntity); - } - - public function testNewAuthoriseRequest() - { - $server = new AuthorizationServer(); - $client = (new ClientEntity($server))->hydrate(['id' => 'testapp']); - $scope = (new ScopeEntity($server))->hydrate(['id' => 'foo']); - - $grant = new AuthCodeGrant(); - $server->addGrantType($grant); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('create')->andreturn(123); - $sessionStorage->shouldReceive('getScopes')->shouldReceive('getScopes')->andReturn([$scope]); - $sessionStorage->shouldReceive('associateScope'); - $server->setSessionStorage($sessionStorage); - - $authCodeStorage = M::mock('League\OAuth2\Server\Storage\AuthCodeInterface'); - $authCodeStorage->shouldReceive('setServer'); - $authCodeStorage->shouldReceive('get'); - $authCodeStorage->shouldReceive('create'); - $authCodeStorage->shouldReceive('associateScope'); - $server->setAuthCodeStorage($authCodeStorage); - - $grant->newAuthorizeRequest('user', 123, [ - 'client' => $client, - 'redirect_uri' => 'http://foo/bar', - 'scopes' => [$scope], - 'state' => 'foobar' - ]); - } - - public function testCompleteFlowMissingClientId() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $_POST['grant_type'] = 'authorization_code'; - - $server = new AuthorizationServer(); - $grant = new AuthCodeGrant(); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowMissingClientSecret() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $_POST = [ - 'grant_type' => 'authorization_code', - 'client_id' => 'testapp', - ]; - - $server = new AuthorizationServer(); - $grant = new AuthCodeGrant(); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowMissingRedirectUri() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $_POST = [ - 'grant_type' => 'authorization_code', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - ]; - - $server = new AuthorizationServer(); - $grant = new AuthCodeGrant(); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowInvalidClient() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidClientException'); - - $_POST = [ - 'grant_type' => 'authorization_code', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'redirect_uri' => 'http://foo/bar', - ]; - - $server = new AuthorizationServer(); - $grant = new AuthCodeGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn(null); - - $server->setClientStorage($clientStorage); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowMissingCode() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $_POST = [ - 'grant_type' => 'authorization_code', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'redirect_uri' => 'http://foo/bar', - ]; - - $server = new AuthorizationServer(); - $grant = new AuthCodeGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('create'); - $sessionStorage->shouldReceive('getScopes')->andReturn([]); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([]); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn(null); - - $authCodeStorage = M::mock('League\OAuth2\Server\Storage\AuthCodeInterface'); - $authCodeStorage->shouldReceive('setServer'); - $authCodeStorage->shouldReceive('get'); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - $server->setAuthCodeStorage($authCodeStorage); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowInvalidCode() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $_POST = [ - 'grant_type' => 'authorization_code', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'redirect_uri' => 'http://foo/bar', - 'code' => 'foobar', - ]; - - $server = new AuthorizationServer(); - $grant = new AuthCodeGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('create'); - $sessionStorage->shouldReceive('getScopes')->andReturn([]); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([]); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn(null); - - $authCodeStorage = M::mock('League\OAuth2\Server\Storage\AuthCodeInterface'); - $authCodeStorage->shouldReceive('setServer'); - $authCodeStorage->shouldReceive('get'); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - $server->setAuthCodeStorage($authCodeStorage); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowExpiredCode() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $_POST = [ - 'grant_type' => 'authorization_code', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'redirect_uri' => 'http://foo/bar', - 'code' => 'foobar', - ]; - - $server = new AuthorizationServer(); - $grant = new AuthCodeGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('create'); - $sessionStorage->shouldReceive('getScopes')->andReturn([]); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([]); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn(null); - - $authCodeStorage = M::mock('League\OAuth2\Server\Storage\AuthCodeInterface'); - $authCodeStorage->shouldReceive('setServer'); - $authCodeStorage->shouldReceive('get')->andReturn( - (new AuthCodeEntity($server))->setId('foobar')->setExpireTime(time() - 300)->setRedirectUri('http://foo/bar') - ); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - $server->setAuthCodeStorage($authCodeStorage); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowRedirectUriMismatch() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $_POST = [ - 'grant_type' => 'authorization_code', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'redirect_uri' => 'http://foo/bar', - 'code' => 'foobar', - ]; - - $server = new AuthorizationServer(); - $grant = new AuthCodeGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('create'); - $sessionStorage->shouldReceive('getScopes')->andReturn([]); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([]); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn(null); - - $authCodeStorage = M::mock('League\OAuth2\Server\Storage\AuthCodeInterface'); - $authCodeStorage->shouldReceive('setServer'); - $authCodeStorage->shouldReceive('get')->andReturn( - (new AuthCodeEntity($server))->setId('foobar')->setExpireTime(time() + 300)->setRedirectUri('http://fail/face') - ); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - $server->setAuthCodeStorage($authCodeStorage); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlow() - { - $_POST = [ - 'grant_type' => 'authorization_code', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'redirect_uri' => 'http://foo/bar', - 'code' => 'foo', - ]; - - $server = new AuthorizationServer(); - $grant = new AuthCodeGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('getBySession')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('create')->andreturn(123); - $sessionStorage->shouldReceive('associateScope'); - $sessionStorage->shouldReceive('getByAuthCode')->andReturn( - (new SessionEntity($server))->setId('foobar') - ); - $sessionStorage->shouldReceive('getByAccessToken')->andReturn( - (new SessionEntity($server))->setId('foobar') - ); - $sessionStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('associateScope'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn( - (new ScopeEntity($server))->hydrate(['id' => 'foo']) - ); - - $authCodeStorage = M::mock('League\OAuth2\Server\Storage\AuthCodeInterface'); - $authCodeStorage->shouldReceive('setServer'); - $authCodeStorage->shouldReceive('delete'); - $authCodeStorage->shouldReceive('get')->andReturn( - (new AuthCodeEntity($server))->setId('foobar')->setRedirectUri('http://foo/bar')->setExpireTime(time() + 300) - ); - $authCodeStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - $server->setAuthCodeStorage($authCodeStorage); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowWithRefreshToken() - { - $_POST = [ - 'grant_type' => 'authorization_code', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'redirect_uri' => 'http://foo/bar', - 'code' => 'foo', - ]; - - $server = new AuthorizationServer(); - $grant = new AuthCodeGrant(); - $rtgrant = new RefreshTokenGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('getBySession')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('create')->andreturn(123); - $sessionStorage->shouldReceive('associateScope'); - $sessionStorage->shouldReceive('getByAuthCode')->andReturn( - (new SessionEntity($server))->setId('foobar') - ); - $sessionStorage->shouldReceive('getByAccessToken')->andReturn( - (new SessionEntity($server))->setId('foobar') - ); - $sessionStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('associateScope'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn( - (new ScopeEntity($server))->hydrate(['id' => 'foo']) - ); - - $authCodeStorage = M::mock('League\OAuth2\Server\Storage\AuthCodeInterface'); - $authCodeStorage->shouldReceive('setServer'); - $authCodeStorage->shouldReceive('delete'); - $authCodeStorage->shouldReceive('get')->andReturn( - (new AuthCodeEntity($server))->setId('foobar')->setRedirectUri('http://foo/bar')->setExpireTime(time() + 300) - ); - $authCodeStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - - $refreshTokenStorage = M::mock('League\OAuth2\Server\Storage\RefreshTokenInterface'); - $refreshTokenStorage->shouldReceive('setServer'); - $refreshTokenStorage->shouldReceive('create'); - $refreshTokenStorage->shouldReceive('associateScope'); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - $server->setAuthCodeStorage($authCodeStorage); - $server->setRefreshTokenStorage($refreshTokenStorage); - - $server->addGrantType($grant); - $server->addGrantType($rtgrant); - $server->issueAccessToken(); - } -} diff --git a/tests/unit/Grant/ClientCredentialsGrantTest.php b/tests/unit/Grant/ClientCredentialsGrantTest.php deleted file mode 100644 index 8e5643f5..00000000 --- a/tests/unit/Grant/ClientCredentialsGrantTest.php +++ /dev/null @@ -1,251 +0,0 @@ -setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $_POST['grant_type'] = 'client_credentials'; - - $server = new AuthorizationServer(); - $grant = new ClientCredentialsGrant(); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowMissingClientSecret() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $_POST = [ - 'grant_type' => 'client_credentials', - 'client_id' => 'testapp', - ]; - - $server = new AuthorizationServer(); - $grant = new ClientCredentialsGrant(); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowInvalidClient() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidClientException'); - - $_POST = [ - 'grant_type' => 'client_credentials', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - ]; - - $server = new AuthorizationServer(); - $grant = new ClientCredentialsGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn(null); - - $server->setClientStorage($clientStorage); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowInvalidScope() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidScopeException'); - - $_POST = [ - 'grant_type' => 'client_credentials', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'scope' => 'foo', - ]; - - $server = new AuthorizationServer(); - $grant = new ClientCredentialsGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('create'); - $sessionStorage->shouldReceive('getScopes')->andReturn([]); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([]); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn(null); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowNoScopes() - { - $_POST = [ - 'grant_type' => 'client_credentials', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - ]; - - $server = new AuthorizationServer(); - $grant = new ClientCredentialsGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('create')->andreturn(123); - $sessionStorage->shouldReceive('getScopes')->shouldReceive('getScopes')->andReturn([]); - $sessionStorage->shouldReceive('getByAccessToken')->andReturn( - (new SessionEntity($server))->setId('foobar') - ); - $sessionStorage->shouldReceive('associateScope'); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([]); - $accessTokenStorage->shouldReceive('associateScope'); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - // $scopeStorage->shouldReceive('get')->andReturn( - // // (new ScopeEntity($server))->hydrate(['id' => 'foo']) - // ); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlow() - { - $_POST = [ - 'grant_type' => 'client_credentials', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'scope' => 'foo', - ]; - - $server = new AuthorizationServer(); - $grant = new ClientCredentialsGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('create')->andreturn(123); - $sessionStorage->shouldReceive('getScopes')->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - $sessionStorage->shouldReceive('getByAccessToken')->andReturn( - (new SessionEntity($server))->setId('foobar') - ); - $sessionStorage->shouldReceive('associateScope'); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - $accessTokenStorage->shouldReceive('associateScope'); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn( - (new ScopeEntity($server))->hydrate(['id' => 'foo']) - ); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testClientNotAuthorizedToUseGrant() - { - $this->setExpectedException('\League\OAuth2\Server\Exception\UnauthorizedClientException'); - - $_POST = [ - 'grant_type' => 'client_credentials', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'scope' => 'foo', - ]; - - $server = new AuthorizationServer(); - $grant = new ClientCredentialsGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andThrow( - new \League\OAuth2\Server\Exception\UnauthorizedClientException() - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('getByAccessToken')->andReturn( - (new SessionEntity($server))->setId('foobar') - ); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn( - (new ScopeEntity($server))->hydrate(['id' => 'foo']) - ); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } -} diff --git a/tests/unit/Grant/PasswordGrantTest.php b/tests/unit/Grant/PasswordGrantTest.php deleted file mode 100644 index e54ca479..00000000 --- a/tests/unit/Grant/PasswordGrantTest.php +++ /dev/null @@ -1,479 +0,0 @@ -setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $_POST['grant_type'] = 'password'; - - $server = new AuthorizationServer(); - $grant = new PasswordGrant(); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowMissingClientSecret() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $_POST = [ - 'grant_type' => 'password', - 'client_id' => 'testapp', - ]; - - $server = new AuthorizationServer(); - $grant = new PasswordGrant(); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowInvalidClient() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidClientException'); - - $_POST = [ - 'grant_type' => 'password', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - ]; - - $server = new AuthorizationServer(); - $grant = new PasswordGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn(null); - - $server->setClientStorage($clientStorage); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testNoUsername() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $_POST = [ - 'grant_type' => 'password', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - ]; - - $server = new AuthorizationServer(); - $grant = new PasswordGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('create'); - $sessionStorage->shouldReceive('getScopes')->andReturn([]); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([]); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn(null); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testNoPassword() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $_POST = [ - 'grant_type' => 'password', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'username' => 'foo', - ]; - - $server = new AuthorizationServer(); - $grant = new PasswordGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('create'); - $sessionStorage->shouldReceive('getScopes')->andReturn([]); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([]); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn(null); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testNoCallable() - { - $this->setExpectedException('League\OAuth2\Server\Exception\ServerErrorException'); - - $_POST = [ - 'grant_type' => 'password', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'username' => 'foo', - 'password' => 'foobar', - ]; - - $server = new AuthorizationServer(); - $grant = new PasswordGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('create'); - $sessionStorage->shouldReceive('getScopes')->andReturn([]); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([]); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn(null); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowInvalidScope() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidScopeException'); - - $_POST = [ - 'grant_type' => 'password', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'username' => 'foo', - 'password' => 'foobar', - 'scope' => 'foo', - ]; - - $server = new AuthorizationServer(); - $grant = new PasswordGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('create'); - $sessionStorage->shouldReceive('getScopes')->andReturn([]); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([]); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn(null); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - $grant->setVerifyCredentialsCallback(function () { - return 123; - }); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowNoScopes() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $_POST = [ - 'grant_type' => 'password', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'username' => 'username', - 'password' => 'password', - ]; - - $server = new AuthorizationServer(); - $grant = new PasswordGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('create')->andreturn(123); - $sessionStorage->shouldReceive('getScopes')->shouldReceive('getScopes')->andReturn([]); - $sessionStorage->shouldReceive('associateScope'); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([]); - $accessTokenStorage->shouldReceive('associateScope'); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - $server->requireScopeParam(true); - $grant->setVerifyCredentialsCallback(function () { - return 123; - }); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowInvalidCredentials() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidCredentialsException'); - - $_POST = [ - 'grant_type' => 'password', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'scope' => 'foo', - 'username' => 'username', - 'password' => 'password', - ]; - - $server = new AuthorizationServer(); - $grant = new PasswordGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('create')->andreturn(123); - $sessionStorage->shouldReceive('getScopes')->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - $sessionStorage->shouldReceive('associateScope'); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - $accessTokenStorage->shouldReceive('associateScope'); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn( - (new ScopeEntity($server))->hydrate(['id' => 'foo']) - ); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - $grant->setVerifyCredentialsCallback(function () { - return false; - }); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlow() - { - $_POST = [ - 'grant_type' => 'password', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'scope' => 'foo', - 'username' => 'username', - 'password' => 'password', - ]; - - $server = new AuthorizationServer(); - $grant = new PasswordGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('create')->andreturn(123); - $sessionStorage->shouldReceive('getScopes')->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - $sessionStorage->shouldReceive('getByAccessToken')->andReturn( - (new SessionEntity($server))->setId('foobar') - ); - $sessionStorage->shouldReceive('associateScope'); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - $accessTokenStorage->shouldReceive('associateScope'); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn( - (new ScopeEntity($server))->hydrate(['id' => 'foo']) - ); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - $grant->setVerifyCredentialsCallback(function () { - return 123; - }); - - $server->addGrantType($grant); - $response = $server->issueAccessToken(); - - $this->assertTrue(array_key_exists('access_token', $response)); - $this->assertTrue(array_key_exists('token_type', $response)); - $this->assertTrue(array_key_exists('expires_in', $response)); - } - - public function testCompleteFlowRefreshToken() - { - $_POST = [ - 'grant_type' => 'password', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'scope' => 'foo', - 'username' => 'username', - 'password' => 'password', - ]; - - $server = new AuthorizationServer(); - $grant = new PasswordGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('create')->andreturn(123); - $sessionStorage->shouldReceive('getScopes')->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - $sessionStorage->shouldReceive('getByAccessToken')->andReturn( - (new SessionEntity($server))->setId('foobar') - ); - $sessionStorage->shouldReceive('associateScope'); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - $accessTokenStorage->shouldReceive('associateScope'); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn( - (new ScopeEntity($server))->hydrate(['id' => 'foo']) - ); - - $refreshTokenStorage = M::mock('League\OAuth2\Server\Storage\RefreshTokenInterface'); - $refreshTokenStorage->shouldReceive('setServer'); - $refreshTokenStorage->shouldReceive('create'); - $refreshTokenStorage->shouldReceive('associateScope'); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - $server->setRefreshTokenStorage($refreshTokenStorage); - - $grant->setVerifyCredentialsCallback(function () { - return 123; - }); - - $server->addGrantType($grant); - $server->addGrantType(new RefreshTokenGrant()); - $response = $server->issueAccessToken(); - - $this->assertTrue(array_key_exists('access_token', $response)); - // $this->assertTrue(array_key_exists('refresh_token', $response)); - $this->assertTrue(array_key_exists('token_type', $response)); - $this->assertTrue(array_key_exists('expires_in', $response)); - } -} diff --git a/tests/unit/Grant/RefreshTokenGrantTest.php b/tests/unit/Grant/RefreshTokenGrantTest.php deleted file mode 100644 index bd5ae5ab..00000000 --- a/tests/unit/Grant/RefreshTokenGrantTest.php +++ /dev/null @@ -1,501 +0,0 @@ -setRefreshTokenTTL(86400); - - $property = new \ReflectionProperty($grant, 'refreshTokenTTL'); - $property->setAccessible(true); - - $this->assertEquals(86400, $property->getValue($grant)); - } - - public function testCompleteFlowMissingClientId() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $_POST['grant_type'] = 'refresh_token'; - - $server = new AuthorizationServer(); - $grant = new RefreshTokenGrant(); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowMissingClientSecret() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $_POST = [ - 'grant_type' => 'refresh_token', - 'client_id' => 'testapp', - ]; - - $server = new AuthorizationServer(); - $grant = new RefreshTokenGrant(); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowInvalidClient() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidClientException'); - - $_POST = [ - 'grant_type' => 'refresh_token', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - ]; - - $server = new AuthorizationServer(); - $grant = new RefreshTokenGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn(null); - - $server->setClientStorage($clientStorage); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowMissingRefreshToken() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $_POST = [ - 'grant_type' => 'refresh_token', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - ]; - - $server = new AuthorizationServer(); - $grant = new RefreshTokenGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->requireScopeParam(true); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowInvalidRefreshToken() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRefreshException'); - - $_POST = [ - 'grant_type' => 'refresh_token', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'refresh_token' => 'meh', - ]; - - $server = new AuthorizationServer(); - $grant = new RefreshTokenGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $refreshTokenStorage = M::mock('League\OAuth2\Server\Storage\RefreshTokenInterface'); - $refreshTokenStorage->shouldReceive('get'); - $refreshTokenStorage->shouldReceive('setServer'); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setRefreshTokenStorage($refreshTokenStorage); - $server->requireScopeParam(true); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowExistingScopes() - { - $_POST = [ - 'grant_type' => 'refresh_token', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'refresh_token' => 'refresh_token', - ]; - - $server = new AuthorizationServer(); - $grant = new RefreshTokenGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('getScopes')->shouldReceive('getScopes')->andReturn([]); - $sessionStorage->shouldReceive('associateScope'); - $sessionStorage->shouldReceive('getByAccessToken')->andReturn( - (new SessionEntity($server)) - ); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('get')->andReturn( - (new AccessTokenEntity($server)) - ); - $accessTokenStorage->shouldReceive('delete'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - $accessTokenStorage->shouldReceive('associateScope'); - - $refreshTokenStorage = M::mock('League\OAuth2\Server\Storage\RefreshTokenInterface'); - $refreshTokenStorage->shouldReceive('setServer'); - $refreshTokenStorage->shouldReceive('associateScope'); - $refreshTokenStorage->shouldReceive('delete'); - $refreshTokenStorage->shouldReceive('create'); - $refreshTokenStorage->shouldReceive('get')->andReturn( - (new RefreshTokenEntity($server))->setExpireTime(time() + 86400) - ); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn( - (new ScopeEntity($server))->hydrate(['id' => 'foo']) - ); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - $server->setRefreshTokenStorage($refreshTokenStorage); - - $server->addGrantType($grant); - $response = $server->issueAccessToken(); - - $this->assertTrue(array_key_exists('access_token', $response)); - $this->assertTrue(array_key_exists('refresh_token', $response)); - $this->assertTrue(array_key_exists('token_type', $response)); - $this->assertTrue(array_key_exists('expires_in', $response)); - } - - public function testCompleteFlowRequestScopes() - { - $_POST = [ - 'grant_type' => 'refresh_token', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'refresh_token' => 'refresh_token', - 'scope' => 'foo', - ]; - - $server = new AuthorizationServer(); - $grant = new RefreshTokenGrant(); - - $oldSession = (new SessionEntity($server))->associateScope((new ScopeEntity($server))->hydrate(['id' => 'foo'])); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('getScopes')->shouldReceive('getScopes')->andReturn([]); - $sessionStorage->shouldReceive('associateScope'); - $sessionStorage->shouldReceive('getByAccessToken')->andReturn( - $oldSession - ); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('get')->andReturn( - (new AccessTokenEntity($server)) - ); - $accessTokenStorage->shouldReceive('delete'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - $accessTokenStorage->shouldReceive('associateScope'); - - $refreshTokenStorage = M::mock('League\OAuth2\Server\Storage\RefreshTokenInterface'); - $refreshTokenStorage->shouldReceive('setServer'); - $refreshTokenStorage->shouldReceive('associateScope'); - $refreshTokenStorage->shouldReceive('delete'); - $refreshTokenStorage->shouldReceive('create'); - $refreshTokenStorage->shouldReceive('get')->andReturn( - (new RefreshTokenEntity($server))->setExpireTime(time() + 86400) - ); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn( - (new ScopeEntity($server))->hydrate(['id' => 'foo']) - ); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - $server->setRefreshTokenStorage($refreshTokenStorage); - - $server->addGrantType($grant); - $response = $server->issueAccessToken(); - - $this->assertTrue(isset($response['access_token'])); - $this->assertTrue(isset($response['refresh_token'])); - $this->assertTrue(isset($response['token_type'])); - $this->assertTrue(isset($response['expires_in'])); - } - - public function testCompleteFlowExpiredRefreshToken() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRefreshException'); - - $_POST = [ - 'grant_type' => 'refresh_token', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'refresh_token' => 'refresh_token', - 'scope' => 'foo', - ]; - - $server = new AuthorizationServer(); - $grant = new RefreshTokenGrant(); - - $oldSession = (new SessionEntity($server))->associateScope((new ScopeEntity($server))->hydrate(['id' => 'foo'])); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('getScopes')->shouldReceive('getScopes')->andReturn([]); - $sessionStorage->shouldReceive('associateScope'); - $sessionStorage->shouldReceive('getByAccessToken')->andReturn( - $oldSession - ); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('get')->andReturn( - (new AccessTokenEntity($server)) - ); - $accessTokenStorage->shouldReceive('delete'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - $accessTokenStorage->shouldReceive('associateScope'); - - $refreshTokenStorage = M::mock('League\OAuth2\Server\Storage\RefreshTokenInterface'); - $refreshTokenStorage->shouldReceive('setServer'); - $refreshTokenStorage->shouldReceive('associateScope'); - $refreshTokenStorage->shouldReceive('delete'); - $refreshTokenStorage->shouldReceive('create'); - $refreshTokenStorage->shouldReceive('get')->andReturn( - (new RefreshTokenEntity($server)) - ); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn( - (new ScopeEntity($server))->hydrate(['id' => 'foo']) - ); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - $server->setRefreshTokenStorage($refreshTokenStorage); - - $server->addGrantType($grant); - $server->issueAccessToken(); - } - - public function testCompleteFlowRequestScopesInvalid() - { - $_POST = [ - 'grant_type' => 'refresh_token', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'refresh_token' => 'refresh_token', - 'scope' => 'blah', - ]; - - $server = new AuthorizationServer(); - $grant = new RefreshTokenGrant(); - - $oldSession = (new SessionEntity($server))->associateScope((new ScopeEntity($server))->hydrate(['id' => 'foo'])); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('getScopes')->shouldReceive('getScopes')->andReturn([]); - $sessionStorage->shouldReceive('associateScope'); - $sessionStorage->shouldReceive('getByAccessToken')->andReturn( - $oldSession - ); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('get')->andReturn( - (new AccessTokenEntity($server)) - ); - $accessTokenStorage->shouldReceive('delete'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - $accessTokenStorage->shouldReceive('associateScope'); - - $refreshTokenStorage = M::mock('League\OAuth2\Server\Storage\RefreshTokenInterface'); - $refreshTokenStorage->shouldReceive('setServer'); - $refreshTokenStorage->shouldReceive('associateScope'); - $refreshTokenStorage->shouldReceive('delete'); - $refreshTokenStorage->shouldReceive('create'); - $refreshTokenStorage->shouldReceive('get')->andReturn( - (new RefreshTokenEntity($server))->setExpireTime(time() + 86400) - ); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn( - (new ScopeEntity($server))->hydrate(['id' => 'blah']) - ); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - $server->setRefreshTokenStorage($refreshTokenStorage); - - $server->addGrantType($grant); - - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidScopeException'); - - $server->issueAccessToken(); - } - - public function testCompleteFlowRotateRefreshToken() - { - $_POST = [ - 'grant_type' => 'refresh_token', - 'client_id' => 'testapp', - 'client_secret' => 'foobar', - 'refresh_token' => 'refresh_token', - ]; - - $server = new AuthorizationServer(); - $grant = new RefreshTokenGrant(); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $clientStorage->shouldReceive('get')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $sessionStorage->shouldReceive('getScopes')->shouldReceive('getScopes')->andReturn([]); - $sessionStorage->shouldReceive('associateScope'); - $sessionStorage->shouldReceive('getByAccessToken')->andReturn( - (new SessionEntity($server)) - ); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('get')->andReturn( - (new AccessTokenEntity($server)) - ); - $accessTokenStorage->shouldReceive('delete'); - $accessTokenStorage->shouldReceive('create'); - $accessTokenStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - ]); - $accessTokenStorage->shouldReceive('associateScope'); - - $refreshTokenStorage = M::mock('League\OAuth2\Server\Storage\RefreshTokenInterface'); - $refreshTokenStorage->shouldReceive('setServer'); - $refreshTokenStorage->shouldReceive('associateScope'); - $refreshTokenStorage->shouldReceive('delete'); - $refreshTokenStorage->shouldReceive('create'); - $refreshTokenStorage->shouldReceive('get')->andReturn( - (new RefreshTokenEntity($server))->setId('refresh_token')->setExpireTime(time() + 86400) - ); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - $scopeStorage->shouldReceive('get')->andReturn( - (new ScopeEntity($server))->hydrate(['id' => 'foo']) - ); - - $server->setClientStorage($clientStorage); - $server->setScopeStorage($scopeStorage); - $server->setSessionStorage($sessionStorage); - $server->setAccessTokenStorage($accessTokenStorage); - $server->setRefreshTokenStorage($refreshTokenStorage); - - $server->addGrantType($grant); - - $response = $server->issueAccessToken(); - $this->assertTrue(array_key_exists('access_token', $response)); - $this->assertTrue(array_key_exists('refresh_token', $response)); - $this->assertTrue(array_key_exists('token_type', $response)); - $this->assertTrue(array_key_exists('expires_in', $response)); - $this->assertNotEquals($response['refresh_token'], $_POST['refresh_token']); - - $grant->setRefreshTokenRotation(false); - $response = $server->issueAccessToken(); - $this->assertTrue(array_key_exists('access_token', $response)); - $this->assertTrue(array_key_exists('refresh_token', $response)); - $this->assertTrue(array_key_exists('token_type', $response)); - $this->assertTrue(array_key_exists('expires_in', $response)); - $this->assertEquals($response['refresh_token'], $_POST['refresh_token']); - } -} diff --git a/tests/unit/ResourceServerTest.php b/tests/unit/ResourceServerTest.php deleted file mode 100644 index 8855abad..00000000 --- a/tests/unit/ResourceServerTest.php +++ /dev/null @@ -1,226 +0,0 @@ -shouldReceive('setServer'); - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - - $server = new ResourceServer( - $sessionStorage, - $accessTokenStorage, - $clientStorage, - $scopeStorage - ); - - return $server; - } - - public function testGetSet() - { - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - - $server = new ResourceServer( - $sessionStorage, - $accessTokenStorage, - $clientStorage, - $scopeStorage - ); - } - - public function testDetermineAccessTokenMissingToken() - { - $this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException'); - - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('get')->andReturn(false); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - - $server = new ResourceServer( - $sessionStorage, - $accessTokenStorage, - $clientStorage, - $scopeStorage - ); - - $request = new \Symfony\Component\HttpFoundation\Request(); - $request->headers = new \Symfony\Component\HttpFoundation\ParameterBag([ - 'HTTP_AUTHORIZATION' => 'Bearer', - ]); - $server->setRequest($request); - - $reflector = new \ReflectionClass($server); - $method = $reflector->getMethod('determineAccessToken'); - $method->setAccessible(true); - - $method->invoke($server); - } - - public function testIsValidNotValid() - { - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - $accessTokenStorage->shouldReceive('get')->andReturn(false); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - - $server = new ResourceServer( - $sessionStorage, - $accessTokenStorage, - $clientStorage, - $scopeStorage - ); - - $this->setExpectedException('League\OAuth2\Server\Exception\AccessDeniedException'); - $server->isValidRequest(false, 'foobar'); - } - - public function testIsValid() - { - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - - $server = new ResourceServer( - $sessionStorage, - $accessTokenStorage, - $clientStorage, - $scopeStorage - ); - - $server->setIdKey('at'); - - $server->addEventListener('session.owner', function ($event) { - $this->assertTrue($event->getSession() instanceof \League\OAuth2\Server\Entity\SessionEntity); - }); - - $accessTokenStorage->shouldReceive('get')->andReturn( - (new AccessTokenEntity($server))->setId('abcdef')->setExpireTime(time() + 300) - ); - - $accessTokenStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - (new ScopeEntity($server))->hydrate(['id' => 'bar']), - ]); - - $sessionStorage->shouldReceive('getByAccessToken')->andReturn( - (new SessionEntity($server))->setId('foobar')->setOwner('user', 123) - ); - - $clientStorage->shouldReceive('getBySession')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $request = new \Symfony\Component\HttpFoundation\Request(); - $request->headers = new \Symfony\Component\HttpFoundation\ParameterBag([ - 'Authorization' => 'Bearer abcdef', - ]); - $server->setRequest($request); - - $this->assertTrue($server->isValidRequest()); - $this->assertEquals('abcdef', $server->getAccessToken()); - } - - /** - * @expectedException League\OAuth2\Server\Exception\AccessDeniedException - */ - public function testIsValidExpiredToken() - { - $sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface'); - $sessionStorage->shouldReceive('setServer'); - - $accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface'); - $accessTokenStorage->shouldReceive('setServer'); - - $clientStorage = M::mock('League\OAuth2\Server\Storage\ClientInterface'); - $clientStorage->shouldReceive('setServer'); - - $scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface'); - $scopeStorage->shouldReceive('setServer'); - - $server = new ResourceServer( - $sessionStorage, - $accessTokenStorage, - $clientStorage, - $scopeStorage - ); - - $server->setIdKey('at'); - - $server->addEventListener('session.owner', function ($event) { - $this->assertTrue($event->getSession() instanceof \League\OAuth2\Server\Entity\SessionEntity); - }); - - $accessTokenStorage->shouldReceive('get')->andReturn( - (new AccessTokenEntity($server))->setId('abcdef')->setExpireTime(time() - 300) - ); - - $accessTokenStorage->shouldReceive('getScopes')->andReturn([ - (new ScopeEntity($server))->hydrate(['id' => 'foo']), - (new ScopeEntity($server))->hydrate(['id' => 'bar']), - ]); - - $sessionStorage->shouldReceive('getByAccessToken')->andReturn( - (new SessionEntity($server))->setId('foobar')->setOwner('user', 123) - ); - - $clientStorage->shouldReceive('getBySession')->andReturn( - (new ClientEntity($server))->hydrate(['id' => 'testapp']) - ); - - $request = new \Symfony\Component\HttpFoundation\Request(); - $request->headers = new \Symfony\Component\HttpFoundation\ParameterBag([ - 'Authorization' => 'Bearer abcdef', - ]); - $server->setRequest($request); - - $server->isValidRequest(); - } -} diff --git a/tests/unit/Storage/AbstractStorageTest.php b/tests/unit/Storage/AbstractStorageTest.php deleted file mode 100644 index 30312cb7..00000000 --- a/tests/unit/Storage/AbstractStorageTest.php +++ /dev/null @@ -1,23 +0,0 @@ -getMethod('setServer'); - $setMethod->setAccessible(true); - $setMethod->invokeArgs($storage, [new StubAbstractServer()]); - $getMethod = $reflector->getMethod('getServer'); - $getMethod->setAccessible(true); - - $this->assertTrue($getMethod->invoke($storage) instanceof StubAbstractServer); - } -} diff --git a/tests/unit/Stubs/StubAbstractGrant.php b/tests/unit/Stubs/StubAbstractGrant.php deleted file mode 100644 index d58fb56e..00000000 --- a/tests/unit/Stubs/StubAbstractGrant.php +++ /dev/null @@ -1,18 +0,0 @@ -server; - } -} diff --git a/tests/unit/Stubs/StubAbstractServer.php b/tests/unit/Stubs/StubAbstractServer.php deleted file mode 100644 index 9254d80d..00000000 --- a/tests/unit/Stubs/StubAbstractServer.php +++ /dev/null @@ -1,8 +0,0 @@ -shouldReceive('create'); - - $server = new AuthorizationServer(); - $server->setMacStorage($macStorage); - - $tokenType = new MAC(); - $tokenType->setServer($server); - - $accessToken = new AccessTokenEntity($server); - $accessToken->setId(uniqid()); - $accessToken->setExpireTime(time()); - - $tokenType->setParam('access_token', $accessToken->getId()); - $tokenType->setParam('expires_in', 3600); - - $response = $tokenType->generateResponse(); - - $this->assertEquals($accessToken->getId(), $response['access_token']); - $this->assertEquals('mac', $response['token_type']); - $this->assertEquals(3600, $response['expires_in']); - $this->assertEquals('hmac-sha-256', $response['mac_algorithm']); - $this->assertArrayHasKey('mac_key', $response); - } - - public function testDetermineAccessTokenInHeaderValid() - { - $macStorage = M::mock('\League\OAuth2\Server\Storage\MacTokenInterface'); - $macStorage->shouldReceive('getByAccessToken')->andReturn('abcdef'); - - $server = new AuthorizationServer(); - $server->setMacStorage($macStorage); - - $ts = time(); - - $request = Request::createFromGlobals(); - $calculatedSignatureParts = [ - $ts, - 'foo', - strtoupper($request->getMethod()), - $request->getUri(), - $request->getHost(), - $request->getPort(), - 'ext' - ]; - $calculatedSignature = base64_encode(hash_hmac('sha256', implode("\n", $calculatedSignatureParts), 'abcdef')); - - $request->headers->set('Authorization', sprintf('MAC id="foo", nonce="foo", ts="%s", mac="%s", ext="ext"', $ts, $calculatedSignature)); - - $tokenType = new MAC(); - $tokenType->setServer($server); - - $response = $tokenType->determineAccessTokenInHeader($request); - $this->assertEquals('foo', $response); - } - - public function testDetermineAccessTokenInHeaderMissingHeader() - { - $macStorage = M::mock('\League\OAuth2\Server\Storage\MacTokenInterface'); - $macStorage->shouldReceive('getByAccessToken')->andReturn('abcdef'); - - $server = new AuthorizationServer(); - $server->setMacStorage($macStorage); - - $request = Request::createFromGlobals(); - $tokenType = new MAC(); - $tokenType->setServer($server); - - $response = $tokenType->determineAccessTokenInHeader($request); - - $this->assertEquals(null, $response); - } - - public function testDetermineAccessTokenInHeaderMissingAuthMac() - { - $macStorage = M::mock('\League\OAuth2\Server\Storage\MacTokenInterface'); - $macStorage->shouldReceive('getByAccessToken')->andReturn('abcdef'); - - $server = new AuthorizationServer(); - $server->setMacStorage($macStorage); - - $request = Request::createFromGlobals(); - $request->headers->set('Authorization', ''); - - $tokenType = new MAC(); - $tokenType->setServer($server); - - $response = $tokenType->determineAccessTokenInHeader($request); - - $this->assertEquals(null, $response); - } - - public function testDetermineAccessTokenInHeaderInvalidParam() - { - $macStorage = M::mock('\League\OAuth2\Server\Storage\MacTokenInterface'); - $macStorage->shouldReceive('getByAccessToken')->andReturn('abcdef'); - - $server = new AuthorizationServer(); - $server->setMacStorage($macStorage); - - $request = Request::createFromGlobals(); - $request->headers->set('Authorization', 'MAC '); - - $tokenType = new MAC(); - $tokenType->setServer($server); - - $response = $tokenType->determineAccessTokenInHeader($request); - - $this->assertEquals(null, $response); - } - - public function testDetermineAccessTokenInHeaderMismatchTimestamp() - { - $macStorage = M::mock('\League\OAuth2\Server\Storage\MacTokenInterface'); - $macStorage->shouldReceive('getByAccessToken')->andReturn('abcdef'); - - $server = new AuthorizationServer(); - $server->setMacStorage($macStorage); - - $ts = time() - 100; - - $request = Request::createFromGlobals(); - $request->headers->set('Authorization', sprintf('MAC id="foo", nonce="foo", ts="%s", mac="%s", ext="ext"', $ts, 'foo')); - - $tokenType = new MAC(); - $tokenType->setServer($server); - - $response = $tokenType->determineAccessTokenInHeader($request); - $this->assertEquals(null, $response); - } - - public function testDetermineAccessTokenInHeaderMissingMacKey() - { - $macStorage = M::mock('\League\OAuth2\Server\Storage\MacTokenInterface'); - $macStorage->shouldReceive('getByAccessToken')->andReturn(null); - - $server = new AuthorizationServer(); - $server->setMacStorage($macStorage); - - $ts = time(); - - $request = Request::createFromGlobals(); - $request->headers->set('Authorization', sprintf('MAC id="foo", nonce="foo", ts="%s", mac="%s", ext="ext"', $ts, 'foo')); - - $tokenType = new MAC(); - $tokenType->setServer($server); - - $response = $tokenType->determineAccessTokenInHeader($request); - $this->assertEquals(null, $response); - } -} diff --git a/tests/unit/util/RedirectUriTest.php b/tests/unit/util/RedirectUriTest.php deleted file mode 100644 index 6b677404..00000000 --- a/tests/unit/util/RedirectUriTest.php +++ /dev/null @@ -1,19 +0,0 @@ - 'bar']); - $v2 = RedirectUri::make('https://foobar/', ['foo' => 'bar'], '#'); - $v3 = RedirectUri::make('https://foobar/', ['foo' => 'bar', 'bar' => 'foo']); - - $this->assertEquals('https://foobar/?foo=bar', $v1); - $this->assertEquals('https://foobar/#foo=bar', $v2); - $this->assertEquals('https://foobar/?foo=bar&bar=foo', $v3); - } -} diff --git a/tests/unit/util/SecureKeyTest.php b/tests/unit/util/SecureKeyTest.php deleted file mode 100644 index 394226f5..00000000 --- a/tests/unit/util/SecureKeyTest.php +++ /dev/null @@ -1,35 +0,0 @@ -assertEquals(40, strlen($v1)); - $this->assertTrue($v1 !== $v2); - $this->assertEquals(50, strlen($v3)); - } - - public function testGenerateWithDifferentAlgorithm() - { - $algorithm = $this->getMock('League\OAuth2\Server\Util\KeyAlgorithm\KeyAlgorithmInterface'); - - $result = 'dasdsdsaads'; - $algorithm - ->expects($this->once()) - ->method('generate') - ->with(11) - ->will($this->returnValue($result)); - - SecureKey::setAlgorithm($algorithm); - $this->assertSame($algorithm, SecureKey::getAlgorithm()); - $this->assertEquals($result, SecureKey::generate(11)); - } -} From 9a8b7ec898c91bf0f3d84ccaf98cd99579230f58 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 17:46:30 +0000 Subject: [PATCH 02/49] Removed old codecept tests --- codeception.yml | 10 --- .../AuthorizationCodeRequestEntity.php | 79 ------------------- tests/_output/.gitignore | 0 tests/_support/ApiHelper.php | 10 --- tests/api/ClientCredentialsCept.php | 17 ---- .../ClientCredentialsInvalidClientIdCept.php | 17 ---- ...ientCredentialsInvalidClientSecretCept.php | 17 ---- .../ClientCredentialsMissingClientIdCept.php | 15 ---- ...ientCredentialsMissingClientSecretCept.php | 16 ---- tests/api/_bootstrap.php | 2 - 10 files changed, 183 deletions(-) delete mode 100644 codeception.yml delete mode 100644 src/Entities/AuthorizationCodeRequestEntity.php delete mode 100644 tests/_output/.gitignore delete mode 100644 tests/_support/ApiHelper.php delete mode 100644 tests/api/ClientCredentialsCept.php delete mode 100644 tests/api/ClientCredentialsInvalidClientIdCept.php delete mode 100644 tests/api/ClientCredentialsInvalidClientSecretCept.php delete mode 100644 tests/api/ClientCredentialsMissingClientIdCept.php delete mode 100644 tests/api/ClientCredentialsMissingClientSecretCept.php delete mode 100644 tests/api/_bootstrap.php diff --git a/codeception.yml b/codeception.yml deleted file mode 100644 index 35fa7fde..00000000 --- a/codeception.yml +++ /dev/null @@ -1,10 +0,0 @@ -actor: Tester -paths: - tests: tests - log: tests/_output - data: tests/_data - helpers: tests/_support -settings: - bootstrap: _bootstrap.php - colors: true - memory_limit: 1024M \ No newline at end of file diff --git a/src/Entities/AuthorizationCodeRequestEntity.php b/src/Entities/AuthorizationCodeRequestEntity.php deleted file mode 100644 index bd401b24..00000000 --- a/src/Entities/AuthorizationCodeRequestEntity.php +++ /dev/null @@ -1,79 +0,0 @@ -clientId; - } - - /** - * @return null|string - */ - public function getRedirectUri() - { - return $this->redirectUri; - } - - /** - * @return null|string - */ - public function getScope() - { - return $this->scope; - } - - /** - * @return null|string - */ - public function getState() - { - return $this->state; - } - - /** - * AuthorizationCodeRequestEntity constructor. - * - * @param string $clientId - * @param string|null $redirectUri - * @param string|null $scope - * @param string|null $state - */ - public function __construct($clientId, $redirectUri = null, $scope = null, $state = null) - { - $this->clientId = $clientId; - $this->redirectUri = $redirectUri; - $this->scope = $scope; - $this->state = $state; - } - - public function __sleep() - { - return ['clientId', 'redirectUri', 'scope', 'state']; - } -} diff --git a/tests/_output/.gitignore b/tests/_output/.gitignore deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/_support/ApiHelper.php b/tests/_support/ApiHelper.php deleted file mode 100644 index 5fcdbe2c..00000000 --- a/tests/_support/ApiHelper.php +++ /dev/null @@ -1,10 +0,0 @@ -wantTo('get an access token using the client credentials grant'); -$I->sendPOST( - 'client_credentials.php/access_token', - [ - 'grant_type' => 'client_credentials', - 'client_id' => 'myawesomeapp', - 'client_secret' => 'abc123', - 'scope' => 'basic' - ] -); -$I->canSeeResponseCodeIs(200); -$I->canSeeResponseIsJson(); -$I->seeResponseJsonMatchesJsonPath('$.token_type'); -$I->seeResponseJsonMatchesJsonPath('$.expires_in'); -$I->seeResponseJsonMatchesJsonPath('$.access_token'); \ No newline at end of file diff --git a/tests/api/ClientCredentialsInvalidClientIdCept.php b/tests/api/ClientCredentialsInvalidClientIdCept.php deleted file mode 100644 index 97f9fce4..00000000 --- a/tests/api/ClientCredentialsInvalidClientIdCept.php +++ /dev/null @@ -1,17 +0,0 @@ -wantTo('get an access token using the client credentials grant, invalid client id'); -$I->sendPOST( - 'client_credentials.php/access_token', - [ - 'grant_type' => 'client_credentials', - 'client_id' => 'myawesomeapp-wrong', - 'client_secret' => 'foobar' - ] -); -$I->canSeeResponseCodeIs(401); -$I->canSeeResponseIsJson(); -$I->seeResponseContainsJson([ - 'error' => 'invalid_client', - 'message' => 'Client authentication failed.' -]); diff --git a/tests/api/ClientCredentialsInvalidClientSecretCept.php b/tests/api/ClientCredentialsInvalidClientSecretCept.php deleted file mode 100644 index fe4f88fc..00000000 --- a/tests/api/ClientCredentialsInvalidClientSecretCept.php +++ /dev/null @@ -1,17 +0,0 @@ -wantTo('get an access token using the client credentials grant, invalid client secret'); -$I->sendPOST( - 'client_credentials.php/access_token', - [ - 'grant_type' => 'client_credentials', - 'client_id' => 'myawesomeapp', - 'client_secret' => 'foobar' - ] -); -$I->canSeeResponseCodeIs(401); -$I->canSeeResponseIsJson(); -$I->seeResponseContainsJson([ - 'error' => 'invalid_client', - 'message' => 'Client authentication failed.' -]); diff --git a/tests/api/ClientCredentialsMissingClientIdCept.php b/tests/api/ClientCredentialsMissingClientIdCept.php deleted file mode 100644 index 68135cdb..00000000 --- a/tests/api/ClientCredentialsMissingClientIdCept.php +++ /dev/null @@ -1,15 +0,0 @@ -wantTo('get an access token using the client credentials grant, missing client id'); -$I->sendPOST( - 'client_credentials.php/access_token', - [ - 'grant_type' => 'client_credentials' - ] -); -$I->canSeeResponseCodeIs(400); -$I->canSeeResponseIsJson(); -$I->seeResponseContainsJson([ - 'error' => 'invalid_request', - 'message' => 'The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the "client_id" parameter.' -]); diff --git a/tests/api/ClientCredentialsMissingClientSecretCept.php b/tests/api/ClientCredentialsMissingClientSecretCept.php deleted file mode 100644 index 369e22d6..00000000 --- a/tests/api/ClientCredentialsMissingClientSecretCept.php +++ /dev/null @@ -1,16 +0,0 @@ -wantTo('get an access token using the client credentials grant, missing client secret'); -$I->sendPOST( - 'client_credentials.php/access_token', - [ - 'grant_type' => 'client_credentials', - 'client_id' => 'myawesomeapp' - ] -); -$I->canSeeResponseCodeIs(400); -$I->canSeeResponseIsJson(); -$I->seeResponseContainsJson([ - 'error' => 'invalid_request', - 'message' => 'The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the "client_secret" parameter.' -]); diff --git a/tests/api/_bootstrap.php b/tests/api/_bootstrap.php deleted file mode 100644 index 8a885558..00000000 --- a/tests/api/_bootstrap.php +++ /dev/null @@ -1,2 +0,0 @@ - Date: Fri, 12 Feb 2016 17:46:42 +0000 Subject: [PATCH 03/49] Ignore build folder --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 3b5992e5..6b74c032 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ phpunit.xml /tests/_output examples/public.key examples/private.key +build From 21e2ccd0fbd03670abc8e16b62d635dbfbcdca51 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 17:51:10 +0000 Subject: [PATCH 04/49] Removed codeception --- composer.json | 7 ++----- tests/_bootstrap.php | 2 -- tests/api.suite.yml | 8 -------- tests/unit/Bootstrap.php | 5 ----- 4 files changed, 2 insertions(+), 20 deletions(-) delete mode 100644 tests/_bootstrap.php delete mode 100644 tests/api.suite.yml delete mode 100644 tests/unit/Bootstrap.php diff --git a/composer.json b/composer.json index 55357050..a1bfda41 100644 --- a/composer.json +++ b/composer.json @@ -11,10 +11,7 @@ "paragonie/random_compat": "^1.1" }, "require-dev": { - "phpunit/phpunit": "4.8.*", - "mockery/mockery": "0.9.*", - "codeception/codeception": "~2.0", - "flow/jsonpath": "0.2.*" + "phpunit/phpunit": "4.8.*" }, "repositories": [ { @@ -57,7 +54,7 @@ }, "autoload-dev": { "psr-4": { - "LeagueTests\\": "tests/unit/" + "LeagueTests\\": "tests/" } }, "extra": { diff --git a/tests/_bootstrap.php b/tests/_bootstrap.php deleted file mode 100644 index 243f9c85..00000000 --- a/tests/_bootstrap.php +++ /dev/null @@ -1,2 +0,0 @@ - wget http://getcomposer.org/composer.phar\n> php composer.phar install\n"); -} From fa3fb36ed8e8f2720c78cd083c62dbc771626143 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 17:51:16 +0000 Subject: [PATCH 05/49] Updated .travis.yml --- .travis.yml | 31 ++----------------------------- 1 file changed, 2 insertions(+), 29 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9ab34bb5..3ebf76cd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,37 +15,10 @@ php: install: - travis_retry composer install --no-interaction --prefer-source -before_script: - - cd examples/ - - composer install - - cd public/ - - php -S localhost:7777 & - - cd ../.. - script: - - vendor/bin/codecept build && vendor/bin/codecept run - -after_script: - - wget https://scrutinizer-ci.com/ocular.phar - - php ocular.phar code-coverage:upload --format=php-clover coverage.clover - - git config --global user.email "travis@travis-ci.org" - - git config --global user.name "TravisCI" - - cp -R coverage ${HOME}/coverage - - cd ${HOME} - - git clone --quiet --branch=gh-pages https://${GITHUBTOKEN}@github.com/thephpleague/oauth2-server.git gh-pages > /dev/null - - cd gh-pages - - mkdir ${TRAVIS_BRANCH} - - cd ${TRAVIS_BRANCH} - - cp -Rf $HOME/coverage/* . - - git add -f . - - git commit -m "Travis pushed coverage of ${TRAVIS_COMMIT}@${TRAVIS_BRANCH} to gh-pages" - - git push -fq origin gh-pages > /dev/null + - vendor/bin/phpunit branches: only: - master - - v5 - -env: - global: - secure: "C4wD/BQefKSu9W594iyLp+IBCjlM8kKlmp+nXKXnZGi0L8IkV3m4mmNOb8PExxGMhZ3mlev5DnU4Uoh4oJaUxnkR1FpX4dSEpyzU3VknUzSE2yZOlL+bdCw3o85TGoCcp/+ReJCOw5sncxTskJKHlW1YMa33FznaXwLNoImpjTg=" \ No newline at end of file + - V5-WIP \ No newline at end of file From 174ae490fcb28c30b57c5c76972090e7bddb56d9 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 17:51:28 +0000 Subject: [PATCH 06/49] Updated .gitignore / .gitattributes files --- .gitattributes | 3 +-- .gitignore | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.gitattributes b/.gitattributes index 58a5e5e6..d85a794e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -7,8 +7,7 @@ /.travis.yml export-ignore .travis.yml export-ignore .scrutinizer.yml export-ignore -/codeception.yml export-ignore /phpunit.xml.dist export-ignore /CHANGELOG.md export-ignore /CONTRIBUTING.md export-ignore -/README.md export-ignore +/README.md export-ignore \ No newline at end of file diff --git a/.gitignore b/.gitignore index 6b74c032..897c80b1 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,6 @@ phpunit.xml .idea /examples/vendor -/tests/_output examples/public.key examples/private.key build From 29068dd84c3e035cd95d2ebf2ab4b9faf082c564 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 17:51:59 +0000 Subject: [PATCH 07/49] Removed responseWith method --- src/Grant/AbstractGrant.php | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 39fbf543..5722357f 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -35,13 +35,6 @@ abstract class AbstractGrant implements GrantTypeInterface const SCOPE_DELIMITER_STRING = ' '; - /** - * Grant responds with - * - * @var string - */ - protected $respondsWith = 'token'; - /** * @var ServerRequestInterface */ @@ -133,14 +126,6 @@ abstract class AbstractGrant implements GrantTypeInterface $this->refreshTokenTTL = $refreshTokenTTL; } - /** - * {@inheritdoc} - */ - public function respondsWith() - { - return $this->respondsWith; - } - /** * Validate the client * From 7f2fd69d0a6df721d30ac2e6fcf554ff14d2a79c Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 17:52:37 +0000 Subject: [PATCH 08/49] Removed respondsWith from interface --- src/Grant/GrantTypeInterface.php | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/Grant/GrantTypeInterface.php b/src/Grant/GrantTypeInterface.php index 698639d9..1341c1fa 100644 --- a/src/Grant/GrantTypeInterface.php +++ b/src/Grant/GrantTypeInterface.php @@ -37,13 +37,6 @@ interface GrantTypeInterface extends EmitterAwareInterface */ public function getIdentifier(); - /** - * Details what the grant responds with - * - * @return string - */ - public function respondsWith(); - /** * Respond to an incoming request * From 08ad67e4011cac7b22288e73911fbd95ebdf6bbe Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 17:53:07 +0000 Subject: [PATCH 09/49] Updated phpunit tests --- phpunit.xml.dist | 6 +- tests/Bootstrap.php | 5 + tests/Grant/AbstractGrantTest.php | 289 ++++++++++++++++++++++++++++++ 3 files changed, 297 insertions(+), 3 deletions(-) create mode 100644 tests/Bootstrap.php create mode 100644 tests/Grant/AbstractGrantTest.php diff --git a/phpunit.xml.dist b/phpunit.xml.dist index f78850c1..43c0a02c 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,8 +1,8 @@ - + - ./tests/unit/ + ./tests/ @@ -11,7 +11,7 @@ - + diff --git a/tests/Bootstrap.php b/tests/Bootstrap.php new file mode 100644 index 00000000..7f8cf458 --- /dev/null +++ b/tests/Bootstrap.php @@ -0,0 +1,5 @@ + wget http://getcomposer.org/composer.phar\n> php composer.phar install\n"); +} diff --git a/tests/Grant/AbstractGrantTest.php b/tests/Grant/AbstractGrantTest.php new file mode 100644 index 00000000..30e0079c --- /dev/null +++ b/tests/Grant/AbstractGrantTest.php @@ -0,0 +1,289 @@ +getMock(ClientRepositoryInterface::class); + $accessTokenRepositoryMock = $this->getMock(AccessTokenRepositoryInterface::class); + $scopeRepositoryMock = $this->getMock(ScopeRepositoryInterface::class); + + /** @var AbstractGrant $grantMock */ + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + $grantMock->setClientRepository($clientRepositoryMock); + $grantMock->setAccessTokenRepository($accessTokenRepositoryMock); + $grantMock->setScopeRepository($scopeRepositoryMock); + $grantMock->setPathToPrivateKey('./private.key'); + $grantMock->setPathToPublicKey('./public.key'); + $grantMock->setEmitter(new Emitter()); + $grantMock->setRefreshTokenTTL(new \DateInterval('PT1H')); + } + + public function testValidateClient() + { + $client = new ClientEntity(); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + /** @var AbstractGrant $grantMock */ + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + $grantMock->setClientRepository($clientRepositoryMock); + + $abstractGrantReflection = new \ReflectionClass($grantMock); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody( + [ + 'client_id' => 'foo', + 'client_secret' => 'bar', + 'redirect_uri' => 'http://foo/bar', + ] + ); + $validateClientMethod = $abstractGrantReflection->getMethod('validateClient'); + $validateClientMethod->setAccessible(true); + + $result = $validateClientMethod->invoke($grantMock, $serverRequest, true, true); + $this->assertEquals($client, $result); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + */ + public function testValidateClientMissingClientId() + { + $client = new ClientEntity(); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + /** @var AbstractGrant $grantMock */ + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + $grantMock->setClientRepository($clientRepositoryMock); + + $abstractGrantReflection = new \ReflectionClass($grantMock); + + $serverRequest = new ServerRequest(); + $validateClientMethod = $abstractGrantReflection->getMethod('validateClient'); + $validateClientMethod->setAccessible(true); + + $validateClientMethod->invoke($grantMock, $serverRequest, true, true); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + */ + public function testValidateClientMissingClientSecret() + { + $client = new ClientEntity(); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + /** @var AbstractGrant $grantMock */ + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + $grantMock->setClientRepository($clientRepositoryMock); + + $abstractGrantReflection = new \ReflectionClass($grantMock); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody([ + 'client_id' => 'foo', + ]); + + $validateClientMethod = $abstractGrantReflection->getMethod('validateClient'); + $validateClientMethod->setAccessible(true); + + $validateClientMethod->invoke($grantMock, $serverRequest, true, true); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + */ + public function testValidateClientMissingRedirectUri() + { + $client = new ClientEntity(); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + /** @var AbstractGrant $grantMock */ + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + $grantMock->setClientRepository($clientRepositoryMock); + + $abstractGrantReflection = new \ReflectionClass($grantMock); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody([ + 'client_id' => 'foo', + 'client_secret' => 'bar', + ]); + + $validateClientMethod = $abstractGrantReflection->getMethod('validateClient'); + $validateClientMethod->setAccessible(true); + + $validateClientMethod->invoke($grantMock, $serverRequest, true, true); + } + + public function testCanRespondToRequest() + { + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + $grantMock->method('getIdentifier')->willReturn('foobar'); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody([ + 'grant_type' => 'foobar', + ]); + + $this->assertTrue($grantMock->canRespondToRequest($serverRequest)); + } + + public function testIssueRefreshToken() + { + /** @var AbstractGrant $grantMock */ + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + $grantMock->setRefreshTokenTTL(new \DateInterval('PT1M')); + + $abstractGrantReflection = new \ReflectionClass($grantMock); + $issueRefreshTokenMethod = $abstractGrantReflection->getMethod('issueRefreshToken'); + $issueRefreshTokenMethod->setAccessible(true); + + $accessToken = new AccessTokenEntity(); + /** @var RefreshTokenEntityInterface $refreshToken */ + $refreshToken = $issueRefreshTokenMethod->invoke($grantMock, $accessToken); + $this->assertTrue($refreshToken instanceof RefreshTokenEntityInterface); + $this->assertFalse($refreshToken->isExpired()); + $this->assertEquals($accessToken, $refreshToken->getAccessToken()); + } + + public function testIssueAccessToken() + { + /** @var AbstractGrant $grantMock */ + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + + $abstractGrantReflection = new \ReflectionClass($grantMock); + $issueAccessTokenMethod = $abstractGrantReflection->getMethod('issueAccessToken'); + $issueAccessTokenMethod->setAccessible(true); + + /** @var AccessTokenEntityInterface $accessToken */ + $accessToken = $issueAccessTokenMethod->invoke( + $grantMock, + new \DateInterval('PT1H'), + new ClientEntity(), + 123, + [new ScopeEntity()] + ); + $this->assertTrue($accessToken instanceof AccessTokenEntityInterface); + $this->assertFalse($accessToken->isExpired()); + } + + public function testIssueAuthCode() + { + /** @var AbstractGrant $grantMock */ + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + + $abstractGrantReflection = new \ReflectionClass($grantMock); + $issueAuthCodeMethod = $abstractGrantReflection->getMethod('issueAuthCode'); + $issueAuthCodeMethod->setAccessible(true); + + $this->assertTrue( + $issueAuthCodeMethod->invoke( + $grantMock, + new \DateInterval('PT1H'), + new ClientEntity(), + 123, + 'http://foo/bar', + [new ScopeEntity()] + ) instanceof AuthCodeEntityInterface + ); + } + + public function testGetCookieParameter() + { + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + $grantMock->method('getIdentifier')->willReturn('foobar'); + + $abstractGrantReflection = new \ReflectionClass($grantMock); + $method = $abstractGrantReflection->getMethod('getCookieParameter'); + $method->setAccessible(true); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withCookieParams([ + 'foo' => 'bar', + ]); + + $this->assertEquals('bar', $method->invoke($grantMock, 'foo', $serverRequest)); + $this->assertEquals('foo', $method->invoke($grantMock, 'bar', $serverRequest, 'foo')); + } + + public function testGetQueryStringParameter() + { + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + $grantMock->method('getIdentifier')->willReturn('foobar'); + + $abstractGrantReflection = new \ReflectionClass($grantMock); + $method = $abstractGrantReflection->getMethod('getQueryStringParameter'); + $method->setAccessible(true); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withQueryParams([ + 'foo' => 'bar', + ]); + + $this->assertEquals('bar', $method->invoke($grantMock, 'foo', $serverRequest)); + $this->assertEquals('foo', $method->invoke($grantMock, 'bar', $serverRequest, 'foo')); + } + + public function testValidateScopes() + { + $scope = new ScopeEntity(); + $scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(); + $scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn($scope); + + /** @var AbstractGrant $grantMock */ + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + $grantMock->setScopeRepository($scopeRepositoryMock); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody( + [ + 'scope' => 'basic ', + ] + ); + + $this->assertEquals([$scope], $grantMock->validateScopes($serverRequest, new ClientEntity())); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + */ + public function testValidateScopesBadScope() + { + $scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(); + $scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn(null); + + /** @var AbstractGrant $grantMock */ + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + $grantMock->setScopeRepository($scopeRepositoryMock); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody( + [ + 'scope' => 'basic ', + ] + ); + + $grantMock->validateScopes($serverRequest, new ClientEntity()); + } +} From e20c529f3963ab55d2106c26e8fe112c2d7527a1 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 17:53:42 +0000 Subject: [PATCH 10/49] Added isExpired method to refresh token --- src/Entities/Interfaces/RefreshTokenEntityInterface.php | 6 ++++++ src/Entities/Traits/RefreshTokenTrait.php | 9 +++++++++ 2 files changed, 15 insertions(+) diff --git a/src/Entities/Interfaces/RefreshTokenEntityInterface.php b/src/Entities/Interfaces/RefreshTokenEntityInterface.php index a095d4a1..5b382754 100644 --- a/src/Entities/Interfaces/RefreshTokenEntityInterface.php +++ b/src/Entities/Interfaces/RefreshTokenEntityInterface.php @@ -39,4 +39,10 @@ interface RefreshTokenEntityInterface * @return \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface */ public function getAccessToken(); + + /** + * Has the token expired? + * @return bool + */ + public function isExpired(); } diff --git a/src/Entities/Traits/RefreshTokenTrait.php b/src/Entities/Traits/RefreshTokenTrait.php index 0e0a3500..b0e2a247 100644 --- a/src/Entities/Traits/RefreshTokenTrait.php +++ b/src/Entities/Traits/RefreshTokenTrait.php @@ -50,4 +50,13 @@ trait RefreshTokenTrait { $this->expiryDateTime = $dateTime; } + + /** + * Has the token expired? + * @return bool + */ + public function isExpired() + { + return (new DateTime()) > $this->getExpiryDateTime(); + } } From de13e14cdd50dc0a92d3d5c74fd51e89300a12d6 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 18:08:13 +0000 Subject: [PATCH 11/49] Added test/Utils --- tests/Utils/KeyCryptTest.php | 34 ++++++++++++++++++++++++++++++++++ tests/Utils/SecureKeyTest.php | 13 +++++++++++++ tests/Utils/private.key | 15 +++++++++++++++ tests/Utils/public.key | 6 ++++++ 4 files changed, 68 insertions(+) create mode 100644 tests/Utils/KeyCryptTest.php create mode 100644 tests/Utils/SecureKeyTest.php create mode 100644 tests/Utils/private.key create mode 100644 tests/Utils/public.key diff --git a/tests/Utils/KeyCryptTest.php b/tests/Utils/KeyCryptTest.php new file mode 100644 index 00000000..9720dbd3 --- /dev/null +++ b/tests/Utils/KeyCryptTest.php @@ -0,0 +1,34 @@ +assertNotEquals($payload, $encrypted); + $this->assertEquals($payload, $plainText); + } + + /** + * @expectedException \LogicException + */ + public function testBadPrivateKey() + { + KeyCrypt::encrypt('', 'file://'.__DIR__.'/public.key'); + } + + /** + * @expectedException \LogicException + */ + public function testBadPublicKey() + { + KeyCrypt::decrypt('', 'file://'.__DIR__.'/private.key'); + } +} diff --git a/tests/Utils/SecureKeyTest.php b/tests/Utils/SecureKeyTest.php new file mode 100644 index 00000000..aebdb755 --- /dev/null +++ b/tests/Utils/SecureKeyTest.php @@ -0,0 +1,13 @@ +assertTrue(is_string(SecureKey::generate())); + } +} diff --git a/tests/Utils/private.key b/tests/Utils/private.key new file mode 100644 index 00000000..1d6a3bf6 --- /dev/null +++ b/tests/Utils/private.key @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXgIBAAKBgQDOBcFjGUlo3BJ9zjwQLgAHn6Oy5Si0uB7MublTiPob8rWTiCE4 +weAFqzPoAB07vB0t0f8c1R8rmwHMD5ljWPBgJ8FewtwAUzprOBcau6DWukd/TKxX +WeVLAl/NZxijI+jR5QDBYLNBtj1G4LBVHMmINd3ryCycbf9ac3rcC8zhrQIDAQAB +AoGADfOJ0wIlXHp6rhZHLvlOezWuSjEGfqZxP3/cMvH1rerTrPfs+AD5AKlFTJKl +aCQm/bFYy0ULZVKL3pu30Wh2bo1nh/wLuLSI9Nz3O8jqAP3z0i07SoRoQmb8fRnn +dwoDFqnk3uGqcOenheSqheIgl9vdW/3avhD6nkMKZGxPYwECQQDoSj/xHogEzMqB +1Z2E5H/exeE9GQ7+dGITRR2MSgo9WvcKdRhGaQ44dsnTmqiZWAfqAPJjTQIIA/Cn +YRRTeBbNAkEA4w0iEvCIygGQOAnWuvVzlh+pxIB+BTeGkbiBG7nkYYc9b6B/Tw1B +GWGRddBr/FIfPvy1X2ip/TBpH+9bHnE2YQJBAIbZw/EYhmIy+UUSW9WwSUNsoOu1 +Rm0V53HEZ/jvaq5fxpa9j5AgoO7KlzROzp3m6wE/93cKV6mLkAO7ae9jAekCQQCf +B6DZIS6+RrAMACAt3SOzf8P6BYG/B7Ayusd7cw2ang4S9JiW9xKkw2kN2wj3t1F5 +XalwBTAjTdgj7ROmU+ehAkEAkOyXKONGBoVfaixRHgBP6jIBSSPbB2Aosi0QAURX +6GOY7wOS1pCSntTOBQxV7wVjqFwYAR10MSxFSNfpJ7RkzA== +-----END RSA PRIVATE KEY----- diff --git a/tests/Utils/public.key b/tests/Utils/public.key new file mode 100644 index 00000000..25010108 --- /dev/null +++ b/tests/Utils/public.key @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOBcFjGUlo3BJ9zjwQLgAHn6Oy +5Si0uB7MublTiPob8rWTiCE4weAFqzPoAB07vB0t0f8c1R8rmwHMD5ljWPBgJ8Fe +wtwAUzprOBcau6DWukd/TKxXWeVLAl/NZxijI+jR5QDBYLNBtj1G4LBVHMmINd3r +yCycbf9ac3rcC8zhrQIDAQAB +-----END PUBLIC KEY----- From 335630f150f87b43e562484daf36c3510041038a Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 18:08:27 +0000 Subject: [PATCH 12/49] Added code coverage ignore docblocks --- src/Utils/KeyCrypt.php | 4 ++++ src/Utils/SecureKey.php | 2 ++ 2 files changed, 6 insertions(+) diff --git a/src/Utils/KeyCrypt.php b/src/Utils/KeyCrypt.php index 634cd80b..8b62c10a 100644 --- a/src/Utils/KeyCrypt.php +++ b/src/Utils/KeyCrypt.php @@ -36,7 +36,9 @@ class KeyCrypt $chunk = substr($unencryptedData, 0, $chunkSize); $unencryptedData = substr($unencryptedData, $chunkSize); if (openssl_private_encrypt($chunk, $encrypted, $privateKey) === false) { + // @codeCoverageIgnoreStart throw new \LogicException('Failed to encrypt data'); + // @codeCoverageIgnoreEnd } $output .= $encrypted; } @@ -72,7 +74,9 @@ class KeyCrypt $chunk = substr($encryptedData, 0, $chunkSize); $encryptedData = substr($encryptedData, $chunkSize); if (openssl_public_decrypt($chunk, $decrypted, $publicKey) === false) { + // @codeCoverageIgnoreStart throw new \LogicException('Failed to decrypt data'); + // @codeCoverageIgnoreEnd } $output .= $decrypted; } diff --git a/src/Utils/SecureKey.php b/src/Utils/SecureKey.php index f5078bbf..ee5a85ea 100644 --- a/src/Utils/SecureKey.php +++ b/src/Utils/SecureKey.php @@ -31,6 +31,7 @@ class SecureKey { try { $string = random_bytes($len); + // @codeCoverageIgnoreStart } catch (\TypeError $e) { // Well, it's an integer, so this IS unexpected. throw OAuthServerException::serverError("An unexpected error has occurred"); @@ -41,6 +42,7 @@ class SecureKey // If you get this message, the CSPRNG failed hard. throw OAuthServerException::serverError("Could not generate a random string. Is our OS secure?"); } + // @codeCoverageIgnoreEnd return bin2hex($string); } From 186853390a3f3b43e9000701e8da2a0ce85737e3 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 12 Feb 2016 18:08:35 +0000 Subject: [PATCH 13/49] Updated phpunit.xml.dist --- phpunit.xml.dist | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 43c0a02c..943b7857 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,17 +1,23 @@ - - - - ./tests/ - - - - - src - - - - - - + + + + ./tests/ + + + + + src + + src/ResponseTypes/DefaultTemplates + + + + + + + From 099c9ce41bccddac4bfc84dd240326ab707771da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Guti=C3=A9rrez?= Date: Sat, 13 Feb 2016 14:07:09 +0100 Subject: [PATCH 14/49] move token identifier generation --- src/Grant/AbstractGrant.php | 29 +++++++++++++++++++---- src/Utils/SecureKey.php | 47 ------------------------------------- 2 files changed, 25 insertions(+), 51 deletions(-) delete mode 100644 src/Utils/SecureKey.php diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 39fbf543..c18058f8 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -23,7 +23,6 @@ use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; -use League\OAuth2\Server\Utils\SecureKey; use Psr\Http\Message\ServerRequestInterface; /** @@ -310,7 +309,7 @@ abstract class AbstractGrant implements GrantTypeInterface array $scopes = [] ) { $accessToken = new AccessTokenEntity(); - $accessToken->setIdentifier(SecureKey::generate()); + $accessToken->setIdentifier($this->generateUniqueIdentifier()); $accessToken->setExpiryDateTime((new \DateTime())->add($tokenTTL)); $accessToken->setClient($client); $accessToken->setUserIdentifier($userIdentifier); @@ -342,7 +341,7 @@ abstract class AbstractGrant implements GrantTypeInterface array $scopes = [] ) { $authCode = new AuthCodeEntity(); - $authCode->setIdentifier(SecureKey::generate()); + $authCode->setIdentifier($this->generateUniqueIdentifier()); $authCode->setExpiryDateTime((new \DateTime())->add($tokenTTL)); $authCode->setClient($client); $authCode->setUserIdentifier($userIdentifier); @@ -363,13 +362,35 @@ abstract class AbstractGrant implements GrantTypeInterface protected function issueRefreshToken(AccessTokenEntity $accessToken) { $refreshToken = new RefreshTokenEntity(); - $refreshToken->setIdentifier(SecureKey::generate()); + $refreshToken->setIdentifier($this->generateUniqueIdentifier()); $refreshToken->setExpiryDateTime((new \DateTime())->add($this->refreshTokenTTL)); $refreshToken->setAccessToken($accessToken); return $refreshToken; } + /** + * Generate a new unique identifier + * + * @param int $length + * + * @return string + * + * @throws \League\OAuth2\Server\Exception\OAuthServerException + */ + protected function generateUniqueIdentifier($length = 40) + { + try { + return bin2hex(random_bytes($length)); + } catch (\TypeError $e) { + throw OAuthServerException::serverError('An unexpected error has occurred'); + } catch (\Error $e) { + throw OAuthServerException::serverError('An unexpected error has occurred'); + } catch (\Exception $e) { + throw OAuthServerException::serverError('Could not generate a random string'); + } + } + /** * @inheritdoc */ diff --git a/src/Utils/SecureKey.php b/src/Utils/SecureKey.php deleted file mode 100644 index f5078bbf..00000000 --- a/src/Utils/SecureKey.php +++ /dev/null @@ -1,47 +0,0 @@ - - * @copyright Copyright (c) 2013 PHP League of Extraordinary Packages - * @license http://mit-license.org/ - * @link http://github.com/php-loep/oauth2-server - */ - -namespace League\OAuth2\Server\Utils; - -use League\OAuth2\Server\Exception\OAuthServerException; - - -/** - * SecureKey class - */ -class SecureKey -{ - /** - * Generate a new unique code - * - * @param integer $len Length of the generated code - * - * @return string - * @throws \League\OAuth2\Server\Exception\OAuthServerException - */ - public static function generate($len = 40) - { - try { - $string = random_bytes($len); - } catch (\TypeError $e) { - // Well, it's an integer, so this IS unexpected. - throw OAuthServerException::serverError("An unexpected error has occurred"); - } catch (\Error $e) { - // This is also unexpected because 32 is a reasonable integer. - throw OAuthServerException::serverError("An unexpected error has occurred"); - } catch (\Exception $e) { - // If you get this message, the CSPRNG failed hard. - throw OAuthServerException::serverError("Could not generate a random string. Is our OS secure?"); - } - - return bin2hex($string); - } -} From fc53d636f5d434218941b4d0fafbd06bd6b33dbb Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 18 Feb 2016 10:47:06 +0000 Subject: [PATCH 15/49] Updated getClientEntity now just requires the client ID and the grant type --- src/Repositories/ClientRepositoryInterface.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Repositories/ClientRepositoryInterface.php b/src/Repositories/ClientRepositoryInterface.php index 3bec9452..eb88a6cd 100644 --- a/src/Repositories/ClientRepositoryInterface.php +++ b/src/Repositories/ClientRepositoryInterface.php @@ -19,12 +19,10 @@ interface ClientRepositoryInterface extends RepositoryInterface /** * Get a client * - * @param string $grantType The grant type used * @param string $clientIdentifier The client's identifier - * @param string|null $clientSecret The client's secret - * @param string|null $redirectUri The client's redirect URI + * @param string $grantType The grant type used * * @return \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface */ - public function getClientEntity($grantType, $clientIdentifier, $clientSecret = null, $redirectUri = null); + public function getClientEntity($clientIdentifier, $grantType); } From 0d8cb0d06f7811a3572ce595bb53d74c8defb665 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 18 Feb 2016 10:47:30 +0000 Subject: [PATCH 16/49] Fixes for RefreshTokenGrant --- src/Grant/RefreshTokenGrant.php | 11 +++- tests/Grant/RefreshTokenGrantTest.php | 82 +++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 3 deletions(-) create mode 100644 tests/Grant/RefreshTokenGrantTest.php diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index b43792ee..665d60a4 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -12,6 +12,7 @@ namespace League\OAuth2\Server\Grant; use League\Event\Event; +use League\OAuth2\Server\Entities\ScopeEntity; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; @@ -47,13 +48,17 @@ class RefreshTokenGrant extends AbstractGrant \DateInterval $accessTokenTTL ) { // Validate request - $client = $this->validateClient($request); + $client = $this->validateClient($request); $oldRefreshToken = $this->validateOldRefreshToken($request, $client->getIdentifier()); - $scopes = $this->validateScopes($request, $client); + $scopes = $this->validateScopes($request, $client); // If no new scopes are requested then give the access token the original session scopes if (count($scopes) === 0) { - $scopes = $oldRefreshToken['scopes']; + $scopes = array_map(function ($scopeId) { + $scope = new ScopeEntity(); + $scope->setIdentifier($scopeId); + return $scope; + }, $oldRefreshToken['scopes']); } else { // The OAuth spec says that a refreshed access token can have the original scopes or fewer so ensure // the request doesn't include any new scopes diff --git a/tests/Grant/RefreshTokenGrantTest.php b/tests/Grant/RefreshTokenGrantTest.php new file mode 100644 index 00000000..dc28b51f --- /dev/null +++ b/tests/Grant/RefreshTokenGrantTest.php @@ -0,0 +1,82 @@ +getMock(RefreshTokenRepositoryInterface::class); + + $grant = new RefreshTokenGrant($refreshTokenRepositoryMock); + $this->assertEquals('refresh_token', $grant->getIdentifier()); + } + + public function testRespondToRequest() + { + $client = new ClientEntity(); + $client->setIdentifier('foo'); + $client->setSecret('bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); + + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + $userEntity = new UserEntity(); + $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); + + $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + + $grant = new RefreshTokenGrant($refreshTokenRepositoryMock); + $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + $grant->setPathToPublicKey('file://'.__DIR__.'/../Utils/public.key'); + $grant->setPathToPrivateKey('file://'.__DIR__.'/../Utils/private.key'); + + $oldRefreshToken = KeyCrypt::encrypt( + json_encode( + [ + 'client_id' => 'foo', + 'refresh_token_id' => 'zyxwvu', + 'access_token_id' => 'abcdef', + 'scopes' => ['foo'], + 'user_id' => 123, + 'expire_time' => time() + 3600, + ] + ), + 'file://'.__DIR__.'/../Utils/private.key' + ); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody( + [ + 'client_id' => 'foo', + 'client_secret' => 'bar', + 'refresh_token' => $oldRefreshToken, + ] + ); + + $responseType = new StubResponseType(); + $grant->respondToRequest($serverRequest, $responseType, new \DateInterval('PT5M')); + + $this->assertTrue($responseType->getAccessToken() instanceof AccessTokenEntityInterface); + $this->assertTrue($responseType->getRefreshToken() instanceof RefreshTokenEntityInterface); + } +} From fb77a78fb37c9e3af8ad47b0ee567b368887a9c4 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 18 Feb 2016 10:47:52 +0000 Subject: [PATCH 17/49] Added Password Grant test --- tests/Grant/PasswordGrantTest.php | 64 +++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 tests/Grant/PasswordGrantTest.php diff --git a/tests/Grant/PasswordGrantTest.php b/tests/Grant/PasswordGrantTest.php new file mode 100644 index 00000000..8dd7a48d --- /dev/null +++ b/tests/Grant/PasswordGrantTest.php @@ -0,0 +1,64 @@ +getMock(UserRepositoryInterface::class); + $refreshTokenRepositoryMock = $this->getMock(RefreshTokenRepositoryInterface::class); + + $grant = new PasswordGrant($userRepositoryMock, $refreshTokenRepositoryMock); + $this->assertEquals('password', $grant->getIdentifier()); + } + + public function testRespondToRequest() + { + $client = new ClientEntity(); + $client->setSecret('bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); + + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + $userEntity = new UserEntity(); + $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); + + $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + + $grant = new PasswordGrant($userRepositoryMock, $refreshTokenRepositoryMock); + $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody( + [ + 'client_id' => 'foo', + 'client_secret' => 'bar', + 'username' => 'foo', + 'password' => 'bar', + ] + ); + + $responseType = new StubResponseType(); + $grant->respondToRequest($serverRequest, $responseType, new \DateInterval('PT5M')); + + $this->assertTrue($responseType->getAccessToken() instanceof AccessTokenEntityInterface); + $this->assertTrue($responseType->getRefreshToken() instanceof RefreshTokenEntityInterface); + } +} From e808528cc854a436b5523ef854a05cb78f412c97 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 18 Feb 2016 10:47:59 +0000 Subject: [PATCH 18/49] Added test stubs --- tests/Stubs/StubResponseType.php | 60 ++++++++++++++++++++++++++++++++ tests/Stubs/UserEntity.php | 13 +++++++ 2 files changed, 73 insertions(+) create mode 100644 tests/Stubs/StubResponseType.php create mode 100644 tests/Stubs/UserEntity.php diff --git a/tests/Stubs/StubResponseType.php b/tests/Stubs/StubResponseType.php new file mode 100644 index 00000000..4d40b089 --- /dev/null +++ b/tests/Stubs/StubResponseType.php @@ -0,0 +1,60 @@ +accessToken; + } + + public function getRefreshToken() + { + return $this->refreshToken; + } + + /** + * @param \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface $accessToken + */ + public function setAccessToken(AccessTokenEntityInterface $accessToken) + { + $this->accessToken = $accessToken; + } + + /** + * @param \League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface $refreshToken + */ + public function setRefreshToken(RefreshTokenEntityInterface $refreshToken) + { + $this->refreshToken = $refreshToken; + } + + /** + * @param ServerRequestInterface $request + * + * @return ServerRequestInterface + */ + public function determineAccessTokenInHeader(ServerRequestInterface $request) + { + // TODO: Implement determineAccessTokenInHeader() method. + } + + /** + * @param ResponseInterface $response + * + * @return ResponseInterface + */ + public function generateHttpResponse(ResponseInterface $response) + { + // TODO: Implement generateHttpResponse() method. + } +} \ No newline at end of file diff --git a/tests/Stubs/UserEntity.php b/tests/Stubs/UserEntity.php new file mode 100644 index 00000000..4c157df5 --- /dev/null +++ b/tests/Stubs/UserEntity.php @@ -0,0 +1,13 @@ + Date: Thu, 18 Feb 2016 10:48:12 +0000 Subject: [PATCH 19/49] Updated ClientEntityInterface with additional methods --- .../Interfaces/ClientEntityInterface.php | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/Entities/Interfaces/ClientEntityInterface.php b/src/Entities/Interfaces/ClientEntityInterface.php index c0d0e812..2761c214 100644 --- a/src/Entities/Interfaces/ClientEntityInterface.php +++ b/src/Entities/Interfaces/ClientEntityInterface.php @@ -11,6 +11,7 @@ interface ClientEntityInterface /** * Set the client's identifier + * * @param $identifier */ public function setIdentifier($identifier); @@ -23,7 +24,42 @@ interface ClientEntityInterface /** * Set the client's name + * * @param string $name */ public function setName($name); + + /** + * @param string $secret + */ + public function setSecret($secret); + + /** + * Validate the secret provided by the client + * + * @param string $submittedSecret + * + * @return boolean + */ + public function validateSecret($submittedSecret); + + /** + * Set the client's redirect uri + * + * @param string $redirectUri + */ + public function setRedirectUri($redirectUri); + + /** + * Returns the registered redirect URI + * + * @return string + */ + public function getRedirectUri(); + + /** + * Returns true if the client is capable of keeping it's secrets secret + * @return boolean + */ + public function canKeepASecret(); } From 7f67000d531758129ce77e7d5beacc4fd4872224 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 18 Feb 2016 10:48:23 +0000 Subject: [PATCH 20/49] Provided implementation of new client entity methods --- src/Entities/Traits/ClientEntityTrait.php | 56 +++++++++++++++++++++-- 1 file changed, 52 insertions(+), 4 deletions(-) diff --git a/src/Entities/Traits/ClientEntityTrait.php b/src/Entities/Traits/ClientEntityTrait.php index 80e61b93..d7665fcf 100644 --- a/src/Entities/Traits/ClientEntityTrait.php +++ b/src/Entities/Traits/ClientEntityTrait.php @@ -9,8 +9,17 @@ trait ClientEntityTrait protected $name; /** - * Get the client's name - * @return string + * @var string + */ + protected $secret; + + /** + * @var string + */ + protected $redirectUri; + + /** + * @inheritdoc */ public function getName() { @@ -18,11 +27,50 @@ trait ClientEntityTrait } /** - * Set the client's name - * @param string $name + * @inheritdoc */ public function setName($name) { $this->name = $name; } + + /** + * @inheritdoc + */ + public function canKeepASecret() + { + return $this->secret === null; + } + + /** + * @inheritdoc + */ + public function setSecret($secret) + { + $this->secret = $secret; + } + + /** + * @inheritdoc + */ + public function validateSecret($submittedSecret) + { + return strcmp((string) $submittedSecret, $this->secret) === 0; + } + + /** + * @inheritdoc + */ + public function setRedirectUri($redirectUri) + { + $this->redirectUri = $redirectUri; + } + + /** + * @inheritdoc + */ + public function getRedirectUri() + { + return $this->redirectUri; + } } From 3b36ae9000328ccba408b20752021cfbc51e7a6d Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 18 Feb 2016 10:49:05 +0000 Subject: [PATCH 21/49] Rewrote validateClient method to progressively test client secret and redirect URI --- src/Grant/AbstractGrant.php | 41 ++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 5722357f..2139e6fa 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -130,17 +130,12 @@ abstract class AbstractGrant implements GrantTypeInterface * Validate the client * * @param \Psr\Http\Message\ServerRequestInterface $request - * @param bool $validateSecret - * @param bool $validateRedirectUri * * @return \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface * @throws \League\OAuth2\Server\Exception\OAuthServerException */ - protected function validateClient( - ServerRequestInterface $request, - $validateSecret = true, - $validateRedirectUri = false - ) { + protected function validateClient(ServerRequestInterface $request) + { $clientId = $this->getRequestParameter( 'client_id', $request, @@ -150,30 +145,34 @@ abstract class AbstractGrant implements GrantTypeInterface throw OAuthServerException::invalidRequest('client_id', null, '`%s` parameter is missing'); } + $client = $this->clientRepository->getClientEntity( + $clientId, + $this->getIdentifier() + ); + + if (!$client instanceof ClientEntityInterface) { + throw OAuthServerException::invalidClient(); + } + + // If the client is confidential require the client secret $clientSecret = $this->getRequestParameter( 'client_secret', $request, $this->getServerParameter('PHP_AUTH_PW', $request) ); - if (is_null($clientSecret) && $validateSecret === true) { + + if ($client->canKeepASecret() && is_null($clientSecret)) { throw OAuthServerException::invalidRequest('client_secret', null, '`%s` parameter is missing'); } - $redirectUri = $this->getRequestParameter('redirect_uri', $request, null); - if (is_null($redirectUri) && $validateRedirectUri === true) { - throw OAuthServerException::invalidRequest('redirect_uri', null, '`%s` parameter is missing'); + if ($client->canKeepASecret() && $client->validateSecret($clientSecret) === false) { + $this->getEmitter()->emit(new Event('client.authentication.failed', $request)); + throw OAuthServerException::invalidClient(); } - $client = $this->clientRepository->getClientEntity( - $clientId, - $clientSecret, - $redirectUri, - $this->getIdentifier() - ); - - if (!$client instanceof ClientEntityInterface) { - $this->getEmitter()->emit(new Event('client.authentication.failed', $request)); - + // If a redirect URI is provided ensure it matches what is pre-registered + $redirectUri = $this->getRequestParameter('redirect_uri', $request, null); + if ($redirectUri !== null && (strcmp($client->getRedirectUri(), $redirectUri) !== 0)) { throw OAuthServerException::invalidClient(); } From 73cd377c4bc127ffc17918aa90fa75859c8f81f2 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 18 Feb 2016 10:49:13 +0000 Subject: [PATCH 22/49] Added client credentials grant test --- tests/Grant/ClientCredentialsGrantTest.php | 48 ++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 tests/Grant/ClientCredentialsGrantTest.php diff --git a/tests/Grant/ClientCredentialsGrantTest.php b/tests/Grant/ClientCredentialsGrantTest.php new file mode 100644 index 00000000..52e51c9a --- /dev/null +++ b/tests/Grant/ClientCredentialsGrantTest.php @@ -0,0 +1,48 @@ +assertEquals('client_credentials', $grant->getIdentifier()); + } + + public function testRespondToRequest() + { + $client = new ClientEntity(); + $client->setSecret('bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); + + $grant = new ClientCredentialsGrant(); + $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody( + [ + 'client_id' => 'foo', + 'client_secret' => 'bar', + ] + ); + + $responseType = new StubResponseType(); + $grant->respondToRequest($serverRequest, $responseType, new \DateInterval('PT5M')); + + $this->assertTrue($responseType->getAccessToken() instanceof AccessTokenEntityInterface); + } +} From 704e1145685070f778093e1111ccc77dcc77cef1 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 18 Feb 2016 10:49:39 +0000 Subject: [PATCH 23/49] Updated AuthCodeGrant --- src/Grant/AuthCodeGrant.php | 37 +++++++++++++------------------------ 1 file changed, 13 insertions(+), 24 deletions(-) diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 560b8ad1..cc0a1f81 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -89,26 +89,7 @@ class AuthCodeGrant extends AbstractGrant protected function respondToAuthorizationRequest( ServerRequestInterface $request ) { - $clientId = $this->getQueryStringParameter( - 'client_id', - $request, - $this->getServerParameter('PHP_AUTH_USER', $request) - ); - if (is_null($clientId)) { - throw OAuthServerException::invalidRequest('client_id', null, '`%s` parameter is missing'); - } - - $redirectUri = $this->getQueryStringParameter('redirect_uri', $request, null); - if (is_null($redirectUri)) { - throw OAuthServerException::invalidRequest('redirect_uri', null, '`%s` parameter is missing'); - } - - $client = $this->clientRepository->getClientEntity( - $clientId, - null, - $redirectUri, - $this->getIdentifier() - ); + $client = $this->validateClient($request); if ($client instanceof ClientEntityInterface === false) { $this->emitter->emit(new Event('client.authentication.failed', $request)); @@ -116,7 +97,7 @@ class AuthCodeGrant extends AbstractGrant throw OAuthServerException::invalidClient(); } - $scopes = $this->validateScopes($request, $client, $redirectUri); + $scopes = $this->validateScopes($request, $client, $client->getRedirectUri()); $queryString = http_build_query($request->getQueryParams()); $postbackUri = new Uri( sprintf( @@ -168,8 +149,9 @@ class AuthCodeGrant extends AbstractGrant // The user hasn't logged in yet so show a login form if ($userId === null) { $engine = new Engine(dirname($this->pathToLoginTemplate)); + $pathParts = explode(DIRECTORY_SEPARATOR, $this->pathToLoginTemplate); $html = $engine->render( - 'login_user', + end($pathParts), [ 'error' => $loginError, 'postback_uri' => (string) $postbackUri->withQuery($queryString), @@ -183,8 +165,9 @@ class AuthCodeGrant extends AbstractGrant // The user hasn't approved the client yet so show an authorize form if ($userId !== null && $userHasApprovedClient === null) { $engine = new Engine(dirname($this->pathToAuthorizeTemplate)); + $pathParts = explode(DIRECTORY_SEPARATOR, $this->pathToAuthorizeTemplate); $html = $engine->render( - 'authorize_client', + end($pathParts), [ 'client' => $client, 'scopes' => $scopes, @@ -212,7 +195,7 @@ class AuthCodeGrant extends AbstractGrant $stateParameter = $this->getQueryStringParameter('state', $request); - $redirectUri = new Uri($redirectUri); + $redirectUri = new Uri($client->getRedirectUri()); parse_str($redirectUri->getQuery(), $redirectPayload); if ($stateParameter !== null) { $redirectPayload['state'] = $stateParameter; @@ -263,6 +246,12 @@ class AuthCodeGrant extends AbstractGrant ResponseTypeInterface $responseType, DateInterval $accessTokenTTL ) { + // The redirect URI is required in this request + $redirectUri = $this->getQueryStringParameter('redirect_uri', $request, null); + if (is_null($redirectUri)) { + throw OAuthServerException::invalidRequest('redirect_uri', null, '`%s` parameter is missing'); + } + // Validate request $client = $this->validateClient($request); $encryptedAuthCode = $this->getRequestParameter('code', $request, null); From ad5b242d10b1718e4c312b6fcbb4cef27e86a45f Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 18 Feb 2016 11:36:20 +0000 Subject: [PATCH 24/49] Updated AbstractGrantTest --- tests/Grant/AbstractGrantTest.php | 105 ++++++++++++++++++++++++++---- 1 file changed, 91 insertions(+), 14 deletions(-) diff --git a/tests/Grant/AbstractGrantTest.php b/tests/Grant/AbstractGrantTest.php index 30e0079c..92acf384 100644 --- a/tests/Grant/AbstractGrantTest.php +++ b/tests/Grant/AbstractGrantTest.php @@ -10,7 +10,6 @@ use League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; use League\OAuth2\Server\Entities\ScopeEntity; use League\OAuth2\Server\Grant\AbstractGrant; -use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use Zend\Diactoros\ServerRequest; @@ -19,24 +18,45 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase { public function testGetSet() { - $clientRepositoryMock = $this->getMock(ClientRepositoryInterface::class); - $accessTokenRepositoryMock = $this->getMock(AccessTokenRepositoryInterface::class); - $scopeRepositoryMock = $this->getMock(ScopeRepositoryInterface::class); + /** @var AbstractGrant $grantMock */ + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + $grantMock->setPathToPrivateKey('./private.key'); + $grantMock->setPathToPublicKey('./public.key'); + $grantMock->setEmitter(new Emitter()); + } + + public function testValidateClientPublic() + { + $client = new ClientEntity(); + + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); /** @var AbstractGrant $grantMock */ $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); $grantMock->setClientRepository($clientRepositoryMock); - $grantMock->setAccessTokenRepository($accessTokenRepositoryMock); - $grantMock->setScopeRepository($scopeRepositoryMock); - $grantMock->setPathToPrivateKey('./private.key'); - $grantMock->setPathToPublicKey('./public.key'); - $grantMock->setEmitter(new Emitter()); - $grantMock->setRefreshTokenTTL(new \DateInterval('PT1H')); + + $abstractGrantReflection = new \ReflectionClass($grantMock); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody( + [ + 'client_id' => 'foo', + ] + ); + $validateClientMethod = $abstractGrantReflection->getMethod('validateClient'); + $validateClientMethod->setAccessible(true); + + $result = $validateClientMethod->invoke($grantMock, $serverRequest, true, true); + $this->assertEquals($client, $result); } - public function testValidateClient() + public function testValidateClientConfidential() { $client = new ClientEntity(); + $client->setSecret('bar'); + $client->setRedirectUri('http://foo/bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); $clientRepositoryMock->method('getClientEntity')->willReturn($client); @@ -89,6 +109,7 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase public function testValidateClientMissingClientSecret() { $client = new ClientEntity(); + $client->setSecret('bar'); $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); $clientRepositoryMock->method('getClientEntity')->willReturn($client); @@ -112,11 +133,67 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase /** * @expectedException \League\OAuth2\Server\Exception\OAuthServerException */ - public function testValidateClientMissingRedirectUri() + public function testValidateClientInvalidClientSecret() + { + $client = new ClientEntity(); + $client->setSecret('bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + /** @var AbstractGrant $grantMock */ + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + $grantMock->setClientRepository($clientRepositoryMock); + + $abstractGrantReflection = new \ReflectionClass($grantMock); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody([ + 'client_id' => 'foo', + 'client_secret' => 'foo', + ]); + + $validateClientMethod = $abstractGrantReflection->getMethod('validateClient'); + $validateClientMethod->setAccessible(true); + + $validateClientMethod->invoke($grantMock, $serverRequest, true, true); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + */ + public function testValidateClientInvalidRedirectUri() + { + $client = new ClientEntity(); + $client->setRedirectUri('http://foo/bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + /** @var AbstractGrant $grantMock */ + $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + $grantMock->setClientRepository($clientRepositoryMock); + + $abstractGrantReflection = new \ReflectionClass($grantMock); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody([ + 'client_id' => 'foo', + 'redirect_uri' => 'http://bar/foo' + ]); + + $validateClientMethod = $abstractGrantReflection->getMethod('validateClient'); + $validateClientMethod->setAccessible(true); + + $validateClientMethod->invoke($grantMock, $serverRequest, true, true); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + */ + public function testValidateClientBadClient() { $client = new ClientEntity(); $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); - $clientRepositoryMock->method('getClientEntity')->willReturn($client); + $clientRepositoryMock->method('getClientEntity')->willReturn(null); /** @var AbstractGrant $grantMock */ $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); @@ -133,7 +210,7 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase $validateClientMethod = $abstractGrantReflection->getMethod('validateClient'); $validateClientMethod->setAccessible(true); - $validateClientMethod->invoke($grantMock, $serverRequest, true, true); + $validateClientMethod->invoke($grantMock, $serverRequest, true); } public function testCanRespondToRequest() From 064eb85f4e7c697f2d565af710399317e81441d5 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 18 Feb 2016 12:07:23 +0000 Subject: [PATCH 25/49] AbstractGrant now handles persisting tokens --- src/Grant/AbstractGrant.php | 51 ++++++++++++++++++++++++++++ src/Grant/AuthCodeGrant.php | 17 ++-------- src/Grant/ClientCredentialsGrant.php | 1 - src/Grant/PasswordGrant.php | 9 +---- src/Grant/RefreshTokenGrant.php | 13 +++---- 5 files changed, 59 insertions(+), 32 deletions(-) diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 2139e6fa..142e930d 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -21,9 +21,12 @@ use League\OAuth2\Server\Entities\RefreshTokenEntity; use League\OAuth2\Server\Entities\ScopeEntity; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; +use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; +use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use League\OAuth2\Server\Utils\SecureKey; +use OAuth2ServerExamples\Repositories\AuthCodeRepository; use Psr\Http\Message\ServerRequestInterface; /** @@ -55,6 +58,16 @@ abstract class AbstractGrant implements GrantTypeInterface */ protected $scopeRepository; + /** + * @var \League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface + */ + private $authCodeRepository; + + /** + * @var \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface + */ + private $refreshTokenRepository; + /** * @var string */ @@ -94,6 +107,22 @@ abstract class AbstractGrant implements GrantTypeInterface $this->scopeRepository = $scopeRepository; } + /** + * @param \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface $refreshTokenRepository + */ + public function setRefreshTokenRepository(RefreshTokenRepositoryInterface $refreshTokenRepository) + { + $this->refreshTokenRepository = $refreshTokenRepository; + } + + /** + * @param \League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface $authCodeRepository + */ + public function setAuthCodeRepository(AuthCodeRepositoryInterface $authCodeRepository) + { + $this->authCodeRepository = $authCodeRepository; + } + /** * @param string $pathToPrivateKey */ @@ -126,6 +155,22 @@ abstract class AbstractGrant implements GrantTypeInterface $this->refreshTokenTTL = $refreshTokenTTL; } + /** + * @return AuthCodeRepositoryInterface + */ + protected function getAuthCodeRepository() + { + return $this->authCodeRepository; + } + + /** + * @return RefreshTokenRepositoryInterface + */ + protected function getRefreshTokenRepository() + { + return $this->refreshTokenRepository; + } + /** * Validate the client * @@ -303,6 +348,8 @@ abstract class AbstractGrant implements GrantTypeInterface $accessToken->addScope($scope); } + $this->accessTokenRepository->persistNewAccessToken($accessToken); + return $accessToken; } @@ -336,6 +383,8 @@ abstract class AbstractGrant implements GrantTypeInterface $authCode->addScope($scope); } + $this->authCodeRepository->persistNewAuthCode($authCode); + return $authCode; } @@ -351,6 +400,8 @@ abstract class AbstractGrant implements GrantTypeInterface $refreshToken->setExpiryDateTime((new \DateTime())->add($this->refreshTokenTTL)); $refreshToken->setAccessToken($accessToken); + $this->refreshTokenRepository->persistNewRefreshToken($refreshToken); + return $refreshToken; } diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index cc0a1f81..13b8a984 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -23,10 +23,6 @@ class AuthCodeGrant extends AbstractGrant * @var \DateInterval */ private $authCodeTTL; - /** - * @var \League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface - */ - private $authCodeRepository; /** * @var \League\OAuth2\Server\Repositories\UserRepositoryInterface @@ -43,10 +39,6 @@ class AuthCodeGrant extends AbstractGrant */ private $pathToAuthorizeTemplate; - /** - * @var \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface - */ - private $refreshTokenRepository; /** * @param \League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface $authCodeRepository @@ -64,8 +56,8 @@ class AuthCodeGrant extends AbstractGrant $pathToLoginTemplate = null, $pathToAuthorizeTemplate = null ) { - $this->authCodeRepository = $authCodeRepository; - $this->refreshTokenRepository = $refreshTokenRepository; + $this->setAuthCodeRepository($authCodeRepository); + $this->setRefreshTokenRepository($refreshTokenRepository); $this->userRepository = $userRepository; $this->authCodeTTL = $authCodeTTL; $this->pathToLoginTemplate = ($pathToLoginTemplate === null) @@ -209,7 +201,6 @@ class AuthCodeGrant extends AbstractGrant $redirectUri, $scopes ); - $this->authCodeRepository->persistNewAuthCode($authCode); $redirectPayload['code'] = KeyCrypt::encrypt( json_encode( @@ -267,7 +258,7 @@ class AuthCodeGrant extends AbstractGrant throw OAuthServerException::invalidRequest('code', 'Authorization code has expired'); } - if ($this->authCodeRepository->isAuthCodeRevoked($authCodePayload->auth_code_id) === true) { + if ($this->getAuthCodeRepository()->isAuthCodeRevoked($authCodePayload->auth_code_id) === true) { throw OAuthServerException::invalidRequest('code', 'Authorization code has been revoked'); } @@ -286,8 +277,6 @@ class AuthCodeGrant extends AbstractGrant $authCodePayload->scopes ); $refreshToken = $this->issueRefreshToken($accessToken); - $this->accessTokenRepository->persistNewAccessToken($accessToken); - $this->refreshTokenRepository->persistNewRefreshToken($refreshToken); // Inject tokens into response type $responseType->setAccessToken($accessToken); diff --git a/src/Grant/ClientCredentialsGrant.php b/src/Grant/ClientCredentialsGrant.php index cf6ce268..f5881e12 100644 --- a/src/Grant/ClientCredentialsGrant.php +++ b/src/Grant/ClientCredentialsGrant.php @@ -33,7 +33,6 @@ class ClientCredentialsGrant extends AbstractGrant // Issue and persist access token $accessToken = $this->issueAccessToken($accessTokenTTL, $client, $client->getIdentifier(), $scopes); - $this->accessTokenRepository->persistNewAccessToken($accessToken); // Inject access token into response type $responseType->setAccessToken($accessToken); diff --git a/src/Grant/PasswordGrant.php b/src/Grant/PasswordGrant.php index 00ffa149..0b30bfe2 100644 --- a/src/Grant/PasswordGrant.php +++ b/src/Grant/PasswordGrant.php @@ -29,11 +29,6 @@ class PasswordGrant extends AbstractGrant */ private $userRepository; - /** - * @var \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface - */ - private $refreshTokenRepository; - /** * @param \League\OAuth2\Server\Repositories\UserRepositoryInterface $userRepository * @param \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface $refreshTokenRepository @@ -43,7 +38,7 @@ class PasswordGrant extends AbstractGrant RefreshTokenRepositoryInterface $refreshTokenRepository ) { $this->userRepository = $userRepository; - $this->refreshTokenRepository = $refreshTokenRepository; + $this->setRefreshTokenRepository($refreshTokenRepository); $this->refreshTokenTTL = new \DateInterval('P1M'); } @@ -64,8 +59,6 @@ class PasswordGrant extends AbstractGrant // Issue and persist new tokens $accessToken = $this->issueAccessToken($accessTokenTTL, $client, $user->getIdentifier(), $scopes); $refreshToken = $this->issueRefreshToken($accessToken); - $this->accessTokenRepository->persistNewAccessToken($accessToken); - $this->refreshTokenRepository->persistNewRefreshToken($refreshToken); // Inject tokens into response $responseType->setAccessToken($accessToken); diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index 665d60a4..adaa2306 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -24,17 +24,12 @@ use Psr\Http\Message\ServerRequestInterface; */ class RefreshTokenGrant extends AbstractGrant { - /** - * @var \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface - */ - private $refreshTokenRepository; - /** * @param \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface $refreshTokenRepository */ public function __construct(RefreshTokenRepositoryInterface $refreshTokenRepository) { - $this->refreshTokenRepository = $refreshTokenRepository; + $this->setRefreshTokenRepository($refreshTokenRepository); $this->refreshTokenTTL = new \DateInterval('P1M'); } @@ -73,13 +68,13 @@ class RefreshTokenGrant extends AbstractGrant // Expire old tokens $this->accessTokenRepository->revokeAccessToken($oldRefreshToken['access_token_id']); - $this->refreshTokenRepository->revokeRefreshToken($oldRefreshToken['refresh_token_id']); + $this->getRefreshTokenRepository()->revokeRefreshToken($oldRefreshToken['refresh_token_id']); // Issue and persist new tokens $accessToken = $this->issueAccessToken($accessTokenTTL, $client, $oldRefreshToken['user_id'], $scopes); $refreshToken = $this->issueRefreshToken($accessToken); $this->accessTokenRepository->persistNewAccessToken($accessToken); - $this->refreshTokenRepository->persistNewRefreshToken($refreshToken); + $this->getRefreshTokenRepository()->persistNewRefreshToken($refreshToken); // Inject tokens into response $responseType->setAccessToken($accessToken); @@ -125,7 +120,7 @@ class RefreshTokenGrant extends AbstractGrant throw OAuthServerException::invalidRefreshToken('Token has expired'); } - if ($this->refreshTokenRepository->isRefreshTokenRevoked($refreshTokenData['refresh_token_id']) === true) { + if ($this->getRefreshTokenRepository()->isRefreshTokenRevoked($refreshTokenData['refresh_token_id']) === true) { throw OAuthServerException::invalidRefreshToken('Token has been revoked'); } From e8a01c3bcd3e5ff62bcd4db4e1ea09a910f3cd89 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 18 Feb 2016 12:07:36 +0000 Subject: [PATCH 26/49] Fix for logic --- src/Entities/Traits/ClientEntityTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Entities/Traits/ClientEntityTrait.php b/src/Entities/Traits/ClientEntityTrait.php index d7665fcf..bac3ccda 100644 --- a/src/Entities/Traits/ClientEntityTrait.php +++ b/src/Entities/Traits/ClientEntityTrait.php @@ -39,7 +39,7 @@ trait ClientEntityTrait */ public function canKeepASecret() { - return $this->secret === null; + return $this->secret !== null; } /** From 13baa0bb26ff8a70b49ea655d21b26f0e6d2b3de Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 18 Feb 2016 12:07:50 +0000 Subject: [PATCH 27/49] Updated tests --- tests/Grant/AbstractGrantTest.php | 13 ++++++- tests/Grant/PasswordGrantTest.php | 1 + tests/Grant/RefreshTokenGrantTest.php | 1 + tests/ServerTest.php | 56 +++++++++++++++++++++++++++ tests/Stubs/StubResponseType.php | 3 +- 5 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 tests/ServerTest.php diff --git a/tests/Grant/AbstractGrantTest.php b/tests/Grant/AbstractGrantTest.php index 92acf384..cb19bf52 100644 --- a/tests/Grant/AbstractGrantTest.php +++ b/tests/Grant/AbstractGrantTest.php @@ -12,6 +12,9 @@ use League\OAuth2\Server\Entities\ScopeEntity; use League\OAuth2\Server\Grant\AbstractGrant; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; +use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; +use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; +use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface; use Zend\Diactoros\ServerRequest; class AbstractGrantTest extends \PHPUnit_Framework_TestCase @@ -191,7 +194,6 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase */ public function testValidateClientBadClient() { - $client = new ClientEntity(); $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); $clientRepositoryMock->method('getClientEntity')->willReturn(null); @@ -228,9 +230,12 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase public function testIssueRefreshToken() { + $refreshTokenRepoMock = $this->getMock(RefreshTokenRepositoryInterface::class); + /** @var AbstractGrant $grantMock */ $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); $grantMock->setRefreshTokenTTL(new \DateInterval('PT1M')); + $grantMock->setRefreshTokenRepository($refreshTokenRepoMock); $abstractGrantReflection = new \ReflectionClass($grantMock); $issueRefreshTokenMethod = $abstractGrantReflection->getMethod('issueRefreshToken'); @@ -246,8 +251,11 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase public function testIssueAccessToken() { + $accessTokenRepoMock = $this->getMock(AccessTokenRepositoryInterface::class); + /** @var AbstractGrant $grantMock */ $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + $grantMock->setAccessTokenRepository($accessTokenRepoMock); $abstractGrantReflection = new \ReflectionClass($grantMock); $issueAccessTokenMethod = $abstractGrantReflection->getMethod('issueAccessToken'); @@ -267,8 +275,11 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase public function testIssueAuthCode() { + $authCodeRepoMock = $this->getMock(AuthCodeRepositoryInterface::class); + /** @var AbstractGrant $grantMock */ $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); + $grantMock->setAuthCodeRepository($authCodeRepoMock); $abstractGrantReflection = new \ReflectionClass($grantMock); $issueAuthCodeMethod = $abstractGrantReflection->getMethod('issueAuthCode'); diff --git a/tests/Grant/PasswordGrantTest.php b/tests/Grant/PasswordGrantTest.php index 8dd7a48d..c81e4c61 100644 --- a/tests/Grant/PasswordGrantTest.php +++ b/tests/Grant/PasswordGrantTest.php @@ -40,6 +40,7 @@ class PasswordGrantTest extends \PHPUnit_Framework_TestCase $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + $refreshTokenRepositoryMock->method('persistNewRefreshToken')->willReturnSelf(); $grant = new PasswordGrant($userRepositoryMock, $refreshTokenRepositoryMock); $grant->setClientRepository($clientRepositoryMock); diff --git a/tests/Grant/RefreshTokenGrantTest.php b/tests/Grant/RefreshTokenGrantTest.php index dc28b51f..8bfe71c9 100644 --- a/tests/Grant/RefreshTokenGrantTest.php +++ b/tests/Grant/RefreshTokenGrantTest.php @@ -43,6 +43,7 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + $refreshTokenRepositoryMock->method('persistNewRefreshToken')->willReturnSelf(); $grant = new RefreshTokenGrant($refreshTokenRepositoryMock); $grant->setClientRepository($clientRepositoryMock); diff --git a/tests/ServerTest.php b/tests/ServerTest.php new file mode 100644 index 00000000..9a85c351 --- /dev/null +++ b/tests/ServerTest.php @@ -0,0 +1,56 @@ +getMock(ClientRepositoryInterface::class), + $this->getMock(AccessTokenRepositoryInterface::class), + $this->getMock(ScopeRepositoryInterface::class), + '', + '', + new StubResponseType() + ); + + $server->enableGrantType(new ClientCredentialsGrant(), new \DateInterval('PT1M')); + + $response = $server->respondToRequest(); + $this->assertTrue($response instanceof ResponseInterface); + $this->assertEquals(400, $response->getStatusCode()); + } + + public function testRespondToRequest() + { + $clientRepository = $this->getMock(ClientRepositoryInterface::class); + $clientRepository->method('getClientEntity')->willReturn(new ClientEntity()); + + $server = new Server( + $clientRepository, + $this->getMock(AccessTokenRepositoryInterface::class), + $this->getMock(ScopeRepositoryInterface::class), + '', + '', + new StubResponseType() + ); + + $server->enableGrantType(new ClientCredentialsGrant(), new \DateInterval('PT1M')); + + $_POST['grant_type'] = 'client_credentials'; + $_POST['client_id'] = 'foo'; + $_POST['client_secret'] = 'bar'; + $response = $server->respondToRequest(); + $this->assertEquals(200, $response->getStatusCode()); + } +} diff --git a/tests/Stubs/StubResponseType.php b/tests/Stubs/StubResponseType.php index 4d40b089..d62daf9b 100644 --- a/tests/Stubs/StubResponseType.php +++ b/tests/Stubs/StubResponseType.php @@ -7,6 +7,7 @@ use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; use League\OAuth2\Server\ResponseTypes\AbstractResponseType; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; +use Zend\Diactoros\Response; class StubResponseType extends AbstractResponseType { @@ -55,6 +56,6 @@ class StubResponseType extends AbstractResponseType */ public function generateHttpResponse(ResponseInterface $response) { - // TODO: Implement generateHttpResponse() method. + return new Response(); } } \ No newline at end of file From 65bcc97fc3cf2fad0857ef8ee3ecbbd6a1e3a2d5 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 19 Feb 2016 23:08:32 +0000 Subject: [PATCH 28/49] Create .styleci.yml --- .styleci.yml | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 .styleci.yml diff --git a/.styleci.yml b/.styleci.yml new file mode 100644 index 00000000..6caf80c5 --- /dev/null +++ b/.styleci.yml @@ -0,0 +1,53 @@ +preset: psr2 + +enabled: + - binary_operator_spaces + - blank_line_before_return + - concat_with_spaces + - function_typehint_space + - hash_to_slash_comment + - include + - lowercase_cast + - method_separation + - native_function_casing + - no_blank_lines_after_class_opening + - no_blank_lines_between_uses + - no_duplicate_semicolons + - no_leading_import_slash + - no_leading_namespace_whitespace + - no_multiline_whitespace_before_semicolons + - no_php4_constructor + - no_short_bool_cast + - no_singleline_whitespace_before_semicolons + - no_trailing_comma_in_singleline_array + - no_unreachable_default_argument_value + - no_unused_imports + - no_whitespace_before_comma_in_array + - ordered_imports + - phpdoc_align + - phpdoc_indent + - phpdoc_inline_tag + - phpdoc_no_access + - phpdoc_no_simplified_null_return + - phpdoc_order + - phpdoc_property + - phpdoc_scalar + - phpdoc_separation + - phpdoc_to_comment + - phpdoc_trim + - phpdoc_type_to_var + - phpdoc_types + - phpdoc_var_without_name + - print_to_echo + - short_array_syntax + - short_scalar_cast + - simplified_null_return + - single_quote + - spaces_cast + - standardize_not_equal + - ternary_operator_spaces + - trailing_comma_in_multiline_array + - trim_array_spaces + - unary_operator_spaces + - whitespace_after_comma_in_array + - whitespacy_lines From a2460886f63ed3c0d5961bf06bbbbff1be4adca3 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 19 Feb 2016 18:09:39 -0500 Subject: [PATCH 29/49] Applied fixes from StyleCI --- examples/public/auth_code.php | 8 ++-- examples/public/client_credentials.php | 10 ++--- examples/public/middleware_authentication.php | 10 ++--- examples/public/password.php | 10 ++--- examples/public/protected_api.php | 12 +++--- examples/public/refresh_token.php | 10 ++--- examples/src/Entities/UserEntity.php | 5 ++- .../Repositories/AccessTokenRepository.php | 7 ++-- .../src/Repositories/AuthCodeRepository.php | 9 ++-- .../src/Repositories/ClientRepository.php | 13 +++--- .../Repositories/RefreshTokenRepository.php | 7 ++-- examples/src/Repositories/ScopeRepository.php | 11 ++--- examples/src/Repositories/UserRepository.php | 5 ++- src/Entities/AccessTokenEntity.php | 1 + src/Entities/AuthCodeEntity.php | 4 +- src/Entities/ClientEntity.php | 4 +- .../Interfaces/AccessTokenEntityInterface.php | 2 +- .../Interfaces/ClientEntityInterface.php | 24 ++++++----- .../RefreshTokenEntityInterface.php | 19 ++++++--- .../Interfaces/ScopeEntityInterface.php | 7 +++- src/Entities/Interfaces/TokenInterface.php | 37 ++++++++++------ .../Interfaces/UserEntityInterface.php | 3 +- src/Entities/RefreshTokenEntity.php | 4 +- src/Entities/ScopeEntity.php | 6 +-- src/Entities/Traits/ClientEntityTrait.php | 15 +++---- src/Entities/Traits/EntityTrait.php | 1 + src/Entities/Traits/RefreshTokenTrait.php | 11 +++-- src/Entities/Traits/TokenEntityTrait.php | 26 +++++++----- src/Exception/OAuthServerException.php | 41 +++++++++--------- src/Grant/AbstractGrant.php | 42 +++++++++---------- src/Grant/AuthCodeGrant.php | 31 +++++++------- src/Grant/ClientCredentialsGrant.php | 11 +++-- src/Grant/GrantTypeInterface.php | 25 ++++++----- src/Grant/PasswordGrant.php | 17 ++++---- src/Grant/RefreshTokenGrant.php | 24 +++++------ .../AccessTokenRepositoryInterface.php | 13 +++--- .../AuthCodeRepositoryInterface.php | 13 +++--- .../ClientRepositoryInterface.php | 13 +++--- src/Repositories/MacTokenInterface.php | 13 +++--- .../RefreshTokenRepositoryInterface.php | 13 +++--- src/Repositories/RepositoryInterface.php | 7 ++-- src/Repositories/ScopeRepositoryInterface.php | 9 ++-- src/Repositories/UserRepositoryInterface.php | 2 +- src/ResponseTypes/AbstractResponseType.php | 5 +-- src/ResponseTypes/BearerTokenResponse.php | 7 ++-- src/ResponseTypes/MAC.php | 25 +++++------ src/ResponseTypes/ResponseTypeInterface.php | 7 ++-- src/Server.php | 17 ++++---- src/Utils/KeyCrypt.php | 9 ++-- src/Utils/SecureKey.php | 21 +++++----- tests/Bootstrap.php | 2 +- tests/Grant/AbstractGrantTest.php | 10 ++--- tests/Grant/ClientCredentialsGrantTest.php | 2 +- tests/Grant/RefreshTokenGrantTest.php | 2 - tests/ServerTest.php | 6 +-- tests/Stubs/StubResponseType.php | 6 ++- tests/Stubs/UserEntity.php | 2 +- 57 files changed, 346 insertions(+), 330 deletions(-) diff --git a/examples/public/auth_code.php b/examples/public/auth_code.php index 761f7ae3..d15a1561 100644 --- a/examples/public/auth_code.php +++ b/examples/public/auth_code.php @@ -3,19 +3,17 @@ use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\AuthCodeGrant; use League\OAuth2\Server\Server; - use OAuth2ServerExamples\Repositories\AccessTokenRepository; use OAuth2ServerExamples\Repositories\AuthCodeRepository; use OAuth2ServerExamples\Repositories\ClientRepository; use OAuth2ServerExamples\Repositories\RefreshTokenRepository; use OAuth2ServerExamples\Repositories\ScopeRepository; use OAuth2ServerExamples\Repositories\UserRepository; - use Slim\App; use Slim\Http\Request; use Slim\Http\Response; -include(__DIR__ . '/../vendor/autoload.php'); +include __DIR__.'/../vendor/autoload.php'; // App $app = new App([ @@ -29,8 +27,8 @@ $app = new App([ $refreshTokenRepository = new RefreshTokenRepository(); $authCodeRepository = new AuthCodeRepository(); - $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; - $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; + $privateKeyPath = 'file://'.__DIR__.'/../private.key'; + $publicKeyPath = 'file://'.__DIR__.'/../public.key'; // Setup the authorization server $server = new Server( diff --git a/examples/public/client_credentials.php b/examples/public/client_credentials.php index 684e3003..48ee0b6f 100644 --- a/examples/public/client_credentials.php +++ b/examples/public/client_credentials.php @@ -3,16 +3,14 @@ use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\ClientCredentialsGrant; use League\OAuth2\Server\Server; - use OAuth2ServerExamples\Repositories\AccessTokenRepository; use OAuth2ServerExamples\Repositories\ClientRepository; use OAuth2ServerExamples\Repositories\ScopeRepository; - use Slim\App; use Slim\Http\Request; use Slim\Http\Response; -include(__DIR__ . '/../vendor/autoload.php'); +include __DIR__.'/../vendor/autoload.php'; // App $app = new App([ @@ -23,8 +21,8 @@ $app = new App([ $scopeRepository = new ScopeRepository(); $accessTokenRepository = new AccessTokenRepository(); - $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; - $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; + $privateKeyPath = 'file://'.__DIR__.'/../private.key'; + $publicKeyPath = 'file://'.__DIR__.'/../public.key'; // Setup the authorization server $server = new Server( @@ -39,7 +37,7 @@ $app = new App([ $server->enableGrantType(new ClientCredentialsGrant(), new \DateInterval('PT1H')); return $server; - } + }, ]); $app->post('/access_token', function (Request $request, Response $response) { diff --git a/examples/public/middleware_authentication.php b/examples/public/middleware_authentication.php index d928e19d..27f03c5a 100644 --- a/examples/public/middleware_authentication.php +++ b/examples/public/middleware_authentication.php @@ -4,16 +4,14 @@ use League\OAuth2\Server\Grant\PasswordGrant; use League\OAuth2\Server\Grant\RefreshTokenGrant; use League\OAuth2\Server\Middleware\AuthenticationServerMiddleware; use League\OAuth2\Server\Server; - use OAuth2ServerExamples\Repositories\AccessTokenRepository; use OAuth2ServerExamples\Repositories\ClientRepository; use OAuth2ServerExamples\Repositories\RefreshTokenRepository; use OAuth2ServerExamples\Repositories\ScopeRepository; use OAuth2ServerExamples\Repositories\UserRepository; - use Slim\App; -include(__DIR__ . '/../vendor/autoload.php'); +include __DIR__.'/../vendor/autoload.php'; // App $app = new App([ @@ -29,8 +27,8 @@ $app = new App([ $userRepository = new UserRepository(); $refreshTokenRepository = new RefreshTokenRepository(); - $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; - $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; + $privateKeyPath = 'file://'.__DIR__.'/../private.key'; + $publicKeyPath = 'file://'.__DIR__.'/../public.key'; // Setup the authorization server $server = new Server( @@ -52,7 +50,7 @@ $app = new App([ ); return $server; - } + }, ]); $app->post('/access_token', function () { diff --git a/examples/public/password.php b/examples/public/password.php index 036d1b4f..4c0548b4 100644 --- a/examples/public/password.php +++ b/examples/public/password.php @@ -3,18 +3,16 @@ use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\PasswordGrant; use League\OAuth2\Server\Server; - use OAuth2ServerExamples\Repositories\AccessTokenRepository; use OAuth2ServerExamples\Repositories\ClientRepository; use OAuth2ServerExamples\Repositories\RefreshTokenRepository; use OAuth2ServerExamples\Repositories\ScopeRepository; use OAuth2ServerExamples\Repositories\UserRepository; - use Slim\App; use Slim\Http\Request; use Slim\Http\Response; -include(__DIR__ . '/../vendor/autoload.php'); +include __DIR__.'/../vendor/autoload.php'; // App $app = new App([ @@ -27,8 +25,8 @@ $app = new App([ $userRepository = new UserRepository(); $refreshTokenRepository = new RefreshTokenRepository(); - $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; - $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; + $privateKeyPath = 'file://'.__DIR__.'/../private.key'; + $publicKeyPath = 'file://'.__DIR__.'/../public.key'; // Setup the authorization server $server = new Server( @@ -46,7 +44,7 @@ $app = new App([ ); return $server; - } + }, ]); $app->post('/access_token', function (Request $request, Response $response) { diff --git a/examples/public/protected_api.php b/examples/public/protected_api.php index f7362d63..35b829ae 100644 --- a/examples/public/protected_api.php +++ b/examples/public/protected_api.php @@ -2,16 +2,14 @@ use League\OAuth2\Server\Middleware\ResourceServerMiddleware; use League\OAuth2\Server\Server; - use OAuth2ServerExamples\Repositories\AccessTokenRepository; use OAuth2ServerExamples\Repositories\ClientRepository; use OAuth2ServerExamples\Repositories\ScopeRepository; - use Slim\App; use Slim\Http\Request; use Slim\Http\Response; -include(__DIR__ . '/../vendor/autoload.php'); +include __DIR__.'/../vendor/autoload.php'; // App $app = new App([ @@ -25,8 +23,8 @@ $app = new App([ $scopeRepository = new ScopeRepository(); $accessTokenRepository = new AccessTokenRepository(); - $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; - $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; + $privateKeyPath = 'file://'.__DIR__.'/../private.key'; + $publicKeyPath = 'file://'.__DIR__.'/../public.key'; // Setup the authorization server $server = new Server( @@ -38,7 +36,7 @@ $app = new App([ ); return $server; - } + }, ]); $app->add(new ResourceServerMiddleware($app->getContainer()->get(Server::class))); @@ -50,7 +48,7 @@ $app->post('/api/example', function (Request $request, Response $response) { $params = [ 'id' => 1, 'name' => 'Alex', - 'city' => 'London' + 'city' => 'London', ]; } diff --git a/examples/public/refresh_token.php b/examples/public/refresh_token.php index ad9bf0cb..6ecf5122 100644 --- a/examples/public/refresh_token.php +++ b/examples/public/refresh_token.php @@ -3,19 +3,15 @@ use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\RefreshTokenGrant; use League\OAuth2\Server\Server; - use OAuth2ServerExamples\Repositories\AccessTokenRepository; use OAuth2ServerExamples\Repositories\ClientRepository; use OAuth2ServerExamples\Repositories\RefreshTokenRepository; use OAuth2ServerExamples\Repositories\ScopeRepository; - use Slim\App; use Slim\Http\Request; use Slim\Http\Response; -include(__DIR__ . '/../vendor/autoload.php'); - - +include __DIR__.'/../vendor/autoload.php'; // App $app = new App([Server::class => function () { @@ -25,8 +21,8 @@ $app = new App([Server::class => function () { $accessTokenRepository = new AccessTokenRepository(); $refreshTokenRepository = new RefreshTokenRepository(); - $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; - $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; + $privateKeyPath = 'file://'.__DIR__.'/../private.key'; + $publicKeyPath = 'file://'.__DIR__.'/../public.key'; // Setup the authorization server $server = new Server( diff --git a/examples/src/Entities/UserEntity.php b/examples/src/Entities/UserEntity.php index 8feb8c73..9efe6611 100644 --- a/examples/src/Entities/UserEntity.php +++ b/examples/src/Entities/UserEntity.php @@ -7,11 +7,12 @@ use League\OAuth2\Server\Entities\Interfaces\UserEntityInterface; class UserEntity implements UserEntityInterface { /** - * Return the user's identifier + * Return the user's identifier. + * * @return mixed */ public function getIdentifier() { return 1; } -} \ No newline at end of file +} diff --git a/examples/src/Repositories/AccessTokenRepository.php b/examples/src/Repositories/AccessTokenRepository.php index bc8ada68..5a58c915 100644 --- a/examples/src/Repositories/AccessTokenRepository.php +++ b/examples/src/Repositories/AccessTokenRepository.php @@ -1,4 +1,5 @@ [ 'secret' => password_hash('abc123', PASSWORD_BCRYPT), 'name' => 'My Awesome App', - 'redirect_uri' => 'http://foo/bar' - ] + 'redirect_uri' => 'http://foo/bar', + ], ]; // Check if client is registered if (array_key_exists($clientIdentifier, $clients) === false) { - return null; + return; } // Check if client secret is valid if ($clientSecret !== null && password_verify($clientSecret, $clients[$clientIdentifier]['secret']) === false) { - return null; + return; } // Check if redirect URI is valid if ($redirectUri !== null && $redirectUri !== $clients[$clientIdentifier]['redirect_uri']) { - return null; + return; } $client = new ClientEntity(); diff --git a/examples/src/Repositories/RefreshTokenRepository.php b/examples/src/Repositories/RefreshTokenRepository.php index a7a4e079..15f19ddf 100644 --- a/examples/src/Repositories/RefreshTokenRepository.php +++ b/examples/src/Repositories/RefreshTokenRepository.php @@ -7,9 +7,8 @@ use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; class RefreshTokenRepository implements RefreshTokenRepositoryInterface { - /** - * Create a new refresh token_name + * Create a new refresh token_name. * * @param \League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface $refreshTokenEntityInterface */ @@ -19,7 +18,7 @@ class RefreshTokenRepository implements RefreshTokenRepositoryInterface } /** - * Revoke the refresh token + * Revoke the refresh token. * * @param string $tokenId */ @@ -29,7 +28,7 @@ class RefreshTokenRepository implements RefreshTokenRepositoryInterface } /** - * Check if the refresh token has been revoked + * Check if the refresh token has been revoked. * * @param string $tokenId * diff --git a/examples/src/Repositories/ScopeRepository.php b/examples/src/Repositories/ScopeRepository.php index ecfadd11..f48aac5b 100644 --- a/examples/src/Repositories/ScopeRepository.php +++ b/examples/src/Repositories/ScopeRepository.php @@ -1,4 +1,5 @@ [ - 'description' => 'Basic details about you' + 'description' => 'Basic details about you', ], 'email' => [ - 'description' => 'Your email address' - ] + 'description' => 'Your email address', + ], ]; if (array_key_exists($scopeIdentifier, $scopes) === false) { - return null; + return; } $scope = new ScopeEntity(); diff --git a/examples/src/Repositories/UserRepository.php b/examples/src/Repositories/UserRepository.php index 1ad9914d..ec930500 100644 --- a/examples/src/Repositories/UserRepository.php +++ b/examples/src/Repositories/UserRepository.php @@ -1,4 +1,5 @@ $this->errorType, - 'message' => $this->getMessage() + 'message' => $this->getMessage(), ]; if ($this->hint !== null) { @@ -264,14 +265,14 @@ class OAuthServerException extends \Exception } /** - * Get all headers that have to be send with the error response + * Get all headers that have to be send with the error response. * * @return array Array with header values */ public function getHttpHeaders() { $headers = [ - 'Content-type' => 'application/json' + 'Content-type' => 'application/json', ]; // Add "WWW-Authenticate" header @@ -303,7 +304,7 @@ class OAuthServerException extends \Exception } } if ($authScheme !== null) { - $headers[] = 'WWW-Authenticate: ' . $authScheme . ' realm="OAuth"'; + $headers[] = 'WWW-Authenticate: '.$authScheme.' realm="OAuth"'; } } @@ -312,7 +313,7 @@ class OAuthServerException extends \Exception } /** - * Returns the HTTP status code to send when the exceptions is output + * Returns the HTTP status code to send when the exceptions is output. * * @return int */ diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index b2d06179..ee4ab684 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -1,14 +1,13 @@ * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ + * * @link https://github.com/thephpleague/oauth2-server */ - namespace League\OAuth2\Server\Grant; use League\Event\EmitterAwareTrait; @@ -29,7 +28,7 @@ use OAuth2ServerExamples\Repositories\AuthCodeRepository; use Psr\Http\Message\ServerRequestInterface; /** - * Abstract grant class + * Abstract grant class. */ abstract class AbstractGrant implements GrantTypeInterface { @@ -139,7 +138,7 @@ abstract class AbstractGrant implements GrantTypeInterface } /** - * @inheritdoc + * {@inheritdoc} */ public function setEmitter(EmitterInterface $emitter = null) { @@ -147,7 +146,7 @@ abstract class AbstractGrant implements GrantTypeInterface } /** - * @inheritdoc + * {@inheritdoc} */ public function setRefreshTokenTTL(\DateInterval $refreshTokenTTL) { @@ -171,12 +170,13 @@ abstract class AbstractGrant implements GrantTypeInterface } /** - * Validate the client + * Validate the client. * * @param \Psr\Http\Message\ServerRequestInterface $request * - * @return \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface * @throws \League\OAuth2\Server\Exception\OAuthServerException + * + * @return \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface */ protected function validateClient(ServerRequestInterface $request) { @@ -224,15 +224,15 @@ abstract class AbstractGrant implements GrantTypeInterface } /** - * Validate scopes in the request + * Validate scopes in the request. * * @param \Psr\Http\Message\ServerRequestInterface $request * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client * @param string $redirectUri * - * @return \League\OAuth2\Server\Entities\ScopeEntity[] - * * @throws \League\OAuth2\Server\Exception\OAuthServerException + * + * @return \League\OAuth2\Server\Entities\ScopeEntity[] */ public function validateScopes( ServerRequestInterface $request, @@ -322,7 +322,7 @@ abstract class AbstractGrant implements GrantTypeInterface } /** - * Issue an access token + * Issue an access token. * * @param \DateInterval $tokenTTL * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client @@ -353,7 +353,7 @@ abstract class AbstractGrant implements GrantTypeInterface } /** - * Issue an auth code + * Issue an auth code. * * @param \DateInterval $tokenTTL * @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client @@ -361,8 +361,9 @@ abstract class AbstractGrant implements GrantTypeInterface * @param string $redirectUri * @param array $scopes * - * @return \League\OAuth2\Server\Entities\AuthCodeEntity * @throws \League\OAuth2\Server\Exception\OAuthServerException + * + * @return \League\OAuth2\Server\Entities\AuthCodeEntity */ protected function issueAuthCode( \DateInterval $tokenTTL, @@ -405,13 +406,13 @@ abstract class AbstractGrant implements GrantTypeInterface } /** - * Generate a new unique identifier + * Generate a new unique identifier. * * @param int $length * - * @return string - * * @throws \League\OAuth2\Server\Exception\OAuthServerException + * + * @return string */ protected function generateUniqueIdentifier($length = 40) { @@ -430,13 +431,12 @@ abstract class AbstractGrant implements GrantTypeInterface } /** - * @inheritdoc + * {@inheritdoc} */ public function canRespondToRequest(ServerRequestInterface $request) { - return ( + return isset($request->getParsedBody()['grant_type']) - && $request->getParsedBody()['grant_type'] === $this->getIdentifier() - ); + && $request->getParsedBody()['grant_type'] === $this->getIdentifier(); } } diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 13b8a984..e134b59f 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -3,6 +3,7 @@ namespace League\OAuth2\Server\Grant; use DateInterval; +use League\Event\Event; use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; use League\OAuth2\Server\Entities\Interfaces\UserEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; @@ -12,7 +13,6 @@ use League\OAuth2\Server\Repositories\UserRepositoryInterface; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; use League\OAuth2\Server\Utils\KeyCrypt; use League\Plates\Engine; -use League\Event\Event; use Psr\Http\Message\ServerRequestInterface; use Zend\Diactoros\Response; use Zend\Diactoros\Uri; @@ -39,7 +39,6 @@ class AuthCodeGrant extends AbstractGrant */ private $pathToAuthorizeTemplate; - /** * @param \League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface $authCodeRepository * @param \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface $refreshTokenRepository @@ -61,22 +60,22 @@ class AuthCodeGrant extends AbstractGrant $this->userRepository = $userRepository; $this->authCodeTTL = $authCodeTTL; $this->pathToLoginTemplate = ($pathToLoginTemplate === null) - ? __DIR__ . '/../ResponseTypes/DefaultTemplates/login_user.php' + ? __DIR__.'/../ResponseTypes/DefaultTemplates/login_user.php' : $this->pathToLoginTemplate; $this->pathToAuthorizeTemplate = ($pathToLoginTemplate === null) - ? __DIR__ . '/../ResponseTypes/DefaultTemplates/authorize_client.php' + ? __DIR__.'/../ResponseTypes/DefaultTemplates/authorize_client.php' : $this->pathToAuthorizeTemplate; $this->refreshTokenTTL = new \DateInterval('P1M'); } - /** - * Respond to an authorization request + * Respond to an authorization request. * * @param \Psr\Http\Message\ServerRequestInterface $request * - * @return \Psr\Http\Message\ResponseInterface * @throws \League\OAuth2\Server\Exception\OAuthServerException + * + * @return \Psr\Http\Message\ResponseInterface */ protected function respondToAuthorizationRequest( ServerRequestInterface $request @@ -153,7 +152,6 @@ class AuthCodeGrant extends AbstractGrant return new Response\HtmlResponse($html); } - // The user hasn't approved the client yet so show an authorize form if ($userId !== null && $userHasApprovedClient === null) { $engine = new Engine(dirname($this->pathToAuthorizeTemplate)); @@ -219,18 +217,20 @@ class AuthCodeGrant extends AbstractGrant } $exception = OAuthServerException::accessDenied('The user denied the request', (string) $redirectUri); + return $exception->generateHttpResponse(); } /** - * Respond to an access token request + * Respond to an access token request. * * @param \Psr\Http\Message\ServerRequestInterface $request * @param \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface $responseType * @param \DateInterval $accessTokenTTL * - * @return \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface * @throws \League\OAuth2\Server\Exception\OAuthServerException + * + * @return \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface */ protected function respondToAccessTokenRequest( ServerRequestInterface $request, @@ -286,21 +286,20 @@ class AuthCodeGrant extends AbstractGrant } /** - * @inheritdoc + * {@inheritdoc} */ public function canRespondToRequest(ServerRequestInterface $request) { - return ( + return ( isset($request->getQueryParams()['response_type']) && $request->getQueryParams()['response_type'] === 'code' && isset($request->getQueryParams()['client_id']) - ) || (parent::canRespondToRequest($request)) - ); + ) || (parent::canRespondToRequest($request)); } /** - * Return the grant identifier that can be used in matching up requests + * Return the grant identifier that can be used in matching up requests. * * @return string */ @@ -310,7 +309,7 @@ class AuthCodeGrant extends AbstractGrant } /** - * @inheritdoc + * {@inheritdoc} */ public function respondToRequest( ServerRequestInterface $request, diff --git a/src/Grant/ClientCredentialsGrant.php b/src/Grant/ClientCredentialsGrant.php index f5881e12..6da17f21 100644 --- a/src/Grant/ClientCredentialsGrant.php +++ b/src/Grant/ClientCredentialsGrant.php @@ -1,26 +1,25 @@ * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ + * * @link https://github.com/thephpleague/oauth2-server */ - namespace League\OAuth2\Server\Grant; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; use Psr\Http\Message\ServerRequestInterface; /** - * Client credentials grant class + * Client credentials grant class. */ class ClientCredentialsGrant extends AbstractGrant { /** - * @inheritdoc + * {@inheritdoc} */ public function respondToRequest( ServerRequestInterface $request, @@ -41,7 +40,7 @@ class ClientCredentialsGrant extends AbstractGrant } /** - * @inheritdoc + * {@inheritdoc} */ public function getIdentifier() { diff --git a/src/Grant/GrantTypeInterface.php b/src/Grant/GrantTypeInterface.php index 1341c1fa..5ddd81b8 100644 --- a/src/Grant/GrantTypeInterface.php +++ b/src/Grant/GrantTypeInterface.php @@ -1,14 +1,13 @@ * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ + * * @link https://github.com/thephpleague/oauth2-server */ - namespace League\OAuth2\Server\Grant; use League\Event\EmitterAwareInterface; @@ -19,26 +18,26 @@ use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; use Psr\Http\Message\ServerRequestInterface; /** - * Grant type interface + * Grant type interface. */ interface GrantTypeInterface extends EmitterAwareInterface { /** - * Set refresh token TTL + * Set refresh token TTL. * * @param \DateInterval $refreshTokenTTL */ public function setRefreshTokenTTL(\DateInterval $refreshTokenTTL); /** - * Return the grant identifier that can be used in matching up requests + * Return the grant identifier that can be used in matching up requests. * * @return string */ public function getIdentifier(); /** - * Respond to an incoming request + * Respond to an incoming request. * * @param \Psr\Http\Message\ServerRequestInterface $request * @param \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface $responseType @@ -62,40 +61,40 @@ interface GrantTypeInterface extends EmitterAwareInterface * * @param \Psr\Http\Message\ServerRequestInterface $request * - * @return boolean + * @return bool */ public function canRespondToRequest(ServerRequestInterface $request); /** - * Set the client repository + * Set the client repository. * * @param \League\OAuth2\Server\Repositories\ClientRepositoryInterface $clientRepository */ public function setClientRepository(ClientRepositoryInterface $clientRepository); /** - * Set the access token repository + * Set the access token repository. * * @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository */ public function setAccessTokenRepository(AccessTokenRepositoryInterface $accessTokenRepository); /** - * Set the scope repository + * Set the scope repository. * * @param \League\OAuth2\Server\Repositories\ScopeRepositoryInterface $scopeRepository */ public function setScopeRepository(ScopeRepositoryInterface $scopeRepository); /** - * Set the path to the private key + * Set the path to the private key. * * @param string $pathToPrivateKey */ public function setPathToPrivateKey($pathToPrivateKey); /** - * Set the path to the public key + * Set the path to the public key. * * @param string $pathToPublicKey */ diff --git a/src/Grant/PasswordGrant.php b/src/Grant/PasswordGrant.php index 0b30bfe2..1145e6ab 100644 --- a/src/Grant/PasswordGrant.php +++ b/src/Grant/PasswordGrant.php @@ -1,14 +1,13 @@ * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ + * * @link https://github.com/thephpleague/oauth2-server */ - namespace League\OAuth2\Server\Grant; use League\Event\Event; @@ -20,7 +19,7 @@ use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; use Psr\Http\Message\ServerRequestInterface; /** - * Password grant class + * Password grant class. */ class PasswordGrant extends AbstractGrant { @@ -44,7 +43,7 @@ class PasswordGrant extends AbstractGrant } /** - * @inheritdoc + * {@inheritdoc} */ public function respondToRequest( ServerRequestInterface $request, @@ -53,7 +52,7 @@ class PasswordGrant extends AbstractGrant ) { // Validate request $client = $this->validateClient($request); - $user = $this->validateUser($request); + $user = $this->validateUser($request); $scopes = $this->validateScopes($request, $client); // Issue and persist new tokens @@ -70,9 +69,9 @@ class PasswordGrant extends AbstractGrant /** * @param \Psr\Http\Message\ServerRequestInterface $request * - * @return \League\OAuth2\Server\Entities\Interfaces\UserEntityInterface - * * @throws \League\OAuth2\Server\Exception\OAuthServerException + * + * @return \League\OAuth2\Server\Entities\Interfaces\UserEntityInterface */ protected function validateUser(ServerRequestInterface $request) { @@ -97,7 +96,7 @@ class PasswordGrant extends AbstractGrant } /** - * @inheritdoc + * {@inheritdoc} */ public function getIdentifier() { diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index adaa2306..19bab077 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -1,14 +1,13 @@ * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ + * * @link https://github.com/thephpleague/oauth2-server */ - namespace League\OAuth2\Server\Grant; use League\Event\Event; @@ -20,7 +19,7 @@ use League\OAuth2\Server\Utils\KeyCrypt; use Psr\Http\Message\ServerRequestInterface; /** - * Refresh token grant + * Refresh token grant. */ class RefreshTokenGrant extends AbstractGrant { @@ -35,7 +34,7 @@ class RefreshTokenGrant extends AbstractGrant } /** - * @inheritdoc + * {@inheritdoc} */ public function respondToRequest( ServerRequestInterface $request, @@ -52,6 +51,7 @@ class RefreshTokenGrant extends AbstractGrant $scopes = array_map(function ($scopeId) { $scope = new ScopeEntity(); $scope->setIdentifier($scopeId); + return $scope; }, $oldRefreshToken['scopes']); } else { @@ -87,9 +87,9 @@ class RefreshTokenGrant extends AbstractGrant * @param \Psr\Http\Message\ServerRequestInterface $request * @param string $clientId * - * @return array - * * @throws \League\OAuth2\Server\Exception\OAuthServerException + * + * @return array */ protected function validateOldRefreshToken(ServerRequestInterface $request, $clientId) { @@ -102,7 +102,7 @@ class RefreshTokenGrant extends AbstractGrant try { $refreshToken = KeyCrypt::decrypt($encryptedRefreshToken, $this->pathToPublicKey); } catch (\LogicException $e) { - throw OAuthServerException::invalidRefreshToken('Cannot parse refresh token: ' . $e->getMessage()); + throw OAuthServerException::invalidRefreshToken('Cannot parse refresh token: '.$e->getMessage()); } $refreshTokenData = json_decode($refreshToken, true); @@ -110,9 +110,9 @@ class RefreshTokenGrant extends AbstractGrant $this->getEmitter()->emit(new Event('refresh_token.client.failed', $request)); throw OAuthServerException::invalidRefreshToken( - 'Token is not linked to client,' . - ' got: ' . $clientId . - ' expected: ' . $refreshTokenData['client_id'] + 'Token is not linked to client,'. + ' got: '.$clientId. + ' expected: '.$refreshTokenData['client_id'] ); } @@ -128,7 +128,7 @@ class RefreshTokenGrant extends AbstractGrant } /** - * @inheritdoc + * {@inheritdoc} */ public function getIdentifier() { diff --git a/src/Repositories/AccessTokenRepositoryInterface.php b/src/Repositories/AccessTokenRepositoryInterface.php index f39351ff..d9e054d8 100644 --- a/src/Repositories/AccessTokenRepositoryInterface.php +++ b/src/Repositories/AccessTokenRepositoryInterface.php @@ -1,39 +1,38 @@ * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ + * * @link https://github.com/thephpleague/oauth2-server */ - namespace League\OAuth2\Server\Repositories; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; /** - * Access token interface + * Access token interface. */ interface AccessTokenRepositoryInterface extends RepositoryInterface { /** - * Persists a new access token to permanent storage + * Persists a new access token to permanent storage. * * @param \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface $accessTokenEntity */ public function persistNewAccessToken(AccessTokenEntityInterface $accessTokenEntity); /** - * Revoke an access token + * Revoke an access token. * * @param string $tokenId */ public function revokeAccessToken($tokenId); /** - * Check if the access token has been revoked + * Check if the access token has been revoked. * * @param string $tokenId * diff --git a/src/Repositories/AuthCodeRepositoryInterface.php b/src/Repositories/AuthCodeRepositoryInterface.php index a6742092..16c48742 100644 --- a/src/Repositories/AuthCodeRepositoryInterface.php +++ b/src/Repositories/AuthCodeRepositoryInterface.php @@ -1,39 +1,38 @@ * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ + * * @link https://github.com/thephpleague/oauth2-server */ - namespace League\OAuth2\Server\Repositories; use League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface; /** - * Auth code storage interface + * Auth code storage interface. */ interface AuthCodeRepositoryInterface extends RepositoryInterface { /** - * Persists a new auth code to permanent storage + * Persists a new auth code to permanent storage. * * @param \League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface $authCodeEntity */ public function persistNewAuthCode(AuthCodeEntityInterface $authCodeEntity); /** - * Revoke an auth code + * Revoke an auth code. * * @param string $codeId */ public function revokeAuthCode($codeId); /** - * Check if the auth code has been revoked + * Check if the auth code has been revoked. * * @param string $codeId * diff --git a/src/Repositories/ClientRepositoryInterface.php b/src/Repositories/ClientRepositoryInterface.php index eb88a6cd..0c7ebe4f 100644 --- a/src/Repositories/ClientRepositoryInterface.php +++ b/src/Repositories/ClientRepositoryInterface.php @@ -1,26 +1,25 @@ * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ + * * @link https://github.com/thephpleague/oauth2-server */ - namespace League\OAuth2\Server\Repositories; /** - * Client storage interface + * Client storage interface. */ interface ClientRepositoryInterface extends RepositoryInterface { /** - * Get a client + * Get a client. * - * @param string $clientIdentifier The client's identifier - * @param string $grantType The grant type used + * @param string $clientIdentifier The client's identifier + * @param string $grantType The grant type used * * @return \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface */ diff --git a/src/Repositories/MacTokenInterface.php b/src/Repositories/MacTokenInterface.php index 833a0d7b..00e35a4c 100644 --- a/src/Repositories/MacTokenInterface.php +++ b/src/Repositories/MacTokenInterface.php @@ -1,25 +1,24 @@ * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ + * * @link https://github.com/thephpleague/oauth2-server */ - namespace League\OAuth2\Server\Storage; use League\OAuth2\Server\Repositories\RepositoryInterface; /** - * MacTokenInterface + * MacTokenInterface. */ interface MacTokenInterface extends RepositoryInterface { /** - * Create a MAC key linked to an access token + * Create a MAC key linked to an access token. * * @param string $macKey * @param string $accessToken @@ -27,9 +26,9 @@ interface MacTokenInterface extends RepositoryInterface public function persistMacTokenEntity($macKey, $accessToken); /** - * Get a MAC key by access token + * Get a MAC key by access token. * - * @param string $accessToken + * @param string $accessToken * * @return string */ diff --git a/src/Repositories/RefreshTokenRepositoryInterface.php b/src/Repositories/RefreshTokenRepositoryInterface.php index 533351d8..d987ab22 100644 --- a/src/Repositories/RefreshTokenRepositoryInterface.php +++ b/src/Repositories/RefreshTokenRepositoryInterface.php @@ -1,39 +1,38 @@ * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ + * * @link https://github.com/thephpleague/oauth2-server */ - namespace League\OAuth2\Server\Repositories; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; /** - * Refresh token interface + * Refresh token interface. */ interface RefreshTokenRepositoryInterface extends RepositoryInterface { /** - * Create a new refresh token_name + * Create a new refresh token_name. * * @param \League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface $refreshTokenEntity */ public function persistNewRefreshToken(RefreshTokenEntityInterface $refreshTokenEntity); /** - * Revoke the refresh token + * Revoke the refresh token. * * @param string $tokenId */ public function revokeRefreshToken($tokenId); /** - * Check if the refresh token has been revoked + * Check if the refresh token has been revoked. * * @param string $tokenId * diff --git a/src/Repositories/RepositoryInterface.php b/src/Repositories/RepositoryInterface.php index 030c116f..5273057c 100644 --- a/src/Repositories/RepositoryInterface.php +++ b/src/Repositories/RepositoryInterface.php @@ -1,18 +1,17 @@ * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ + * * @link https://github.com/thephpleague/oauth2-server */ - namespace League\OAuth2\Server\Repositories; /** - * Repository interface + * Repository interface. */ interface RepositoryInterface { diff --git a/src/Repositories/ScopeRepositoryInterface.php b/src/Repositories/ScopeRepositoryInterface.php index 0b45efe9..5ac9aff8 100644 --- a/src/Repositories/ScopeRepositoryInterface.php +++ b/src/Repositories/ScopeRepositoryInterface.php @@ -1,23 +1,22 @@ * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ + * * @link https://github.com/thephpleague/oauth2-server */ - namespace League\OAuth2\Server\Repositories; /** - * Scope interface + * Scope interface. */ interface ScopeRepositoryInterface extends RepositoryInterface { /** - * Return information about a scope + * Return information about a scope. * * @param string $identifier The scope identifier * @param string $grantType The grant type used in the request diff --git a/src/Repositories/UserRepositoryInterface.php b/src/Repositories/UserRepositoryInterface.php index 5767a5ed..d93c85a7 100644 --- a/src/Repositories/UserRepositoryInterface.php +++ b/src/Repositories/UserRepositoryInterface.php @@ -5,7 +5,7 @@ namespace League\OAuth2\Server\Repositories; interface UserRepositoryInterface extends RepositoryInterface { /** - * Get a user entity + * Get a user entity. * * @param string $username * @param string $password diff --git a/src/ResponseTypes/AbstractResponseType.php b/src/ResponseTypes/AbstractResponseType.php index 9605a463..bc218266 100644 --- a/src/ResponseTypes/AbstractResponseType.php +++ b/src/ResponseTypes/AbstractResponseType.php @@ -1,14 +1,13 @@ * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ + * * @link https://github.com/thephpleague/oauth2-server */ - namespace League\OAuth2\Server\ResponseTypes; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; diff --git a/src/ResponseTypes/BearerTokenResponse.php b/src/ResponseTypes/BearerTokenResponse.php index d1b88218..28e9003a 100644 --- a/src/ResponseTypes/BearerTokenResponse.php +++ b/src/ResponseTypes/BearerTokenResponse.php @@ -1,14 +1,13 @@ * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ + * * @link https://github.com/thephpleague/oauth2-server */ - namespace League\OAuth2\Server\ResponseTypes; use Lcobucci\JWT\Builder; @@ -43,7 +42,7 @@ class BearerTokenResponse extends AbstractResponseType $responseParams = [ 'token_type' => 'Bearer', - 'expires_in' => $expireDateTime - (new \DateTime)->getTimestamp(), + 'expires_in' => $expireDateTime - (new \DateTime())->getTimestamp(), 'access_token' => (string) $jwtAccessToken, ]; diff --git a/src/ResponseTypes/MAC.php b/src/ResponseTypes/MAC.php index 48c2274f..598214d4 100644 --- a/src/ResponseTypes/MAC.php +++ b/src/ResponseTypes/MAC.php @@ -1,14 +1,13 @@ * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ + * * @link https://github.com/thephpleague/oauth2-server */ - namespace League\OAuth2\Server\TokenTypes; use League\OAuth2\Server\Util\SecureKey; @@ -16,7 +15,7 @@ use Symfony\Component\HttpFoundation\ParameterBag; use Symfony\Component\HttpFoundation\Request; /** - * MAC Token Type + * MAC Token Type. */ class MAC extends AbstractTokenType implements TokenTypeInterface { @@ -29,11 +28,11 @@ class MAC extends AbstractTokenType implements TokenTypeInterface $this->server->getMacStorage()->create($macKey, $this->getParam('access_token')); $response = [ - 'access_token' => $this->getParam('access_token'), - 'token_type' => 'mac', - 'expires_in' => $this->getParam('expires_in'), - 'mac_key' => $macKey, - 'mac_algorithm' => 'hmac-sha-256', + 'access_token' => $this->getParam('access_token'), + 'token_type' => 'mac', + 'expires_in' => $this->getParam('expires_in'), + 'mac_key' => $macKey, + 'mac_algorithm' => 'hmac-sha-256', ]; return $response; @@ -121,9 +120,11 @@ class MAC extends AbstractTokenType implements TokenTypeInterface } /** - * Prevent timing attack - * @param string $knownString - * @param string $userString + * Prevent timing attack. + * + * @param string $knownString + * @param string $userString + * * @return bool */ private function hash_equals($knownString, $userString) diff --git a/src/ResponseTypes/ResponseTypeInterface.php b/src/ResponseTypes/ResponseTypeInterface.php index 6524f049..34198eaf 100644 --- a/src/ResponseTypes/ResponseTypeInterface.php +++ b/src/ResponseTypes/ResponseTypeInterface.php @@ -1,14 +1,13 @@ * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ + * * @link https://github.com/thephpleague/oauth2-server */ - namespace League\OAuth2\Server\ResponseTypes; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; @@ -30,7 +29,7 @@ interface ResponseTypeInterface /** * Determine the access token in the authorization header and append OAUth properties to the request - * as attributes + * as attributes. * * @param ServerRequestInterface $request * diff --git a/src/Server.php b/src/Server.php index 4e7799d3..248a5b7c 100644 --- a/src/Server.php +++ b/src/Server.php @@ -62,7 +62,7 @@ class Server implements EmitterAwareInterface private $scopeRepository; /** - * New server instance + * New server instance. * * @param \League\OAuth2\Server\Repositories\ClientRepositoryInterface $clientRepository * @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository @@ -88,7 +88,7 @@ class Server implements EmitterAwareInterface } /** - * Enable a grant type on the server + * Enable a grant type on the server. * * @param \League\OAuth2\Server\Grant\GrantTypeInterface $grantType * @param \DateInterval $accessTokenTTL @@ -108,13 +108,14 @@ class Server implements EmitterAwareInterface } /** - * Return an access token response + * Return an access token response. * * @param \Psr\Http\Message\ServerRequestInterface|null $request * @param \Psr\Http\Message\ResponseInterface|null $response * - * @return \Psr\Http\Message\ResponseInterface * @throws \League\OAuth2\Server\Exception\OAuthServerException + * + * @return \Psr\Http\Message\ResponseInterface */ public function respondToRequest(ServerRequestInterface $request = null, ResponseInterface $response = null) { @@ -149,13 +150,13 @@ class Server implements EmitterAwareInterface } /** - * Determine the access token validity + * Determine the access token validity. * * @param \Psr\Http\Message\ServerRequestInterface $request * - * @return \Psr\Http\Message\ServerRequestInterface - * * @throws \League\OAuth2\Server\Exception\OAuthServerException + * + * @return \Psr\Http\Message\ServerRequestInterface */ public function validateRequest(ServerRequestInterface $request) { @@ -163,7 +164,7 @@ class Server implements EmitterAwareInterface } /** - * Get the token type that grants will return in the HTTP response + * Get the token type that grants will return in the HTTP response. * * @return ResponseTypeInterface */ diff --git a/src/Utils/KeyCrypt.php b/src/Utils/KeyCrypt.php index 8b62c10a..48659bde 100644 --- a/src/Utils/KeyCrypt.php +++ b/src/Utils/KeyCrypt.php @@ -1,20 +1,19 @@ * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ + * * @link https://github.com/thephpleague/oauth2-server */ - namespace League\OAuth2\Server\Utils; class KeyCrypt { /** - * Encrypt data with a private key + * Encrypt data with a private key. * * @param string $unencryptedData * @param string $pathToPrivateKey @@ -48,7 +47,7 @@ class KeyCrypt } /** - * Decrypt data with a public key + * Decrypt data with a public key. * * @param string $encryptedData * @param string $pathToPublicKey diff --git a/src/Utils/SecureKey.php b/src/Utils/SecureKey.php index ee5a85ea..17a2fcf2 100644 --- a/src/Utils/SecureKey.php +++ b/src/Utils/SecureKey.php @@ -1,31 +1,30 @@ * @copyright Copyright (c) 2013 PHP League of Extraordinary Packages * @license http://mit-license.org/ + * * @link http://github.com/php-loep/oauth2-server */ - namespace League\OAuth2\Server\Utils; use League\OAuth2\Server\Exception\OAuthServerException; - /** - * SecureKey class + * SecureKey class. */ class SecureKey { /** - * Generate a new unique code + * Generate a new unique code. * - * @param integer $len Length of the generated code + * @param int $len Length of the generated code + * + * @throws \League\OAuth2\Server\Exception\OAuthServerException * * @return string - * @throws \League\OAuth2\Server\Exception\OAuthServerException */ public static function generate($len = 40) { @@ -34,13 +33,13 @@ class SecureKey // @codeCoverageIgnoreStart } catch (\TypeError $e) { // Well, it's an integer, so this IS unexpected. - throw OAuthServerException::serverError("An unexpected error has occurred"); + throw OAuthServerException::serverError('An unexpected error has occurred'); } catch (\Error $e) { // This is also unexpected because 32 is a reasonable integer. - throw OAuthServerException::serverError("An unexpected error has occurred"); + throw OAuthServerException::serverError('An unexpected error has occurred'); } catch (\Exception $e) { // If you get this message, the CSPRNG failed hard. - throw OAuthServerException::serverError("Could not generate a random string. Is our OS secure?"); + throw OAuthServerException::serverError('Could not generate a random string. Is our OS secure?'); } // @codeCoverageIgnoreEnd diff --git a/tests/Bootstrap.php b/tests/Bootstrap.php index 7f8cf458..8ea9bc26 100644 --- a/tests/Bootstrap.php +++ b/tests/Bootstrap.php @@ -1,5 +1,5 @@ wget http://getcomposer.org/composer.phar\n> php composer.phar install\n"); } diff --git a/tests/Grant/AbstractGrantTest.php b/tests/Grant/AbstractGrantTest.php index d64f6edb..a2b764d2 100644 --- a/tests/Grant/AbstractGrantTest.php +++ b/tests/Grant/AbstractGrantTest.php @@ -10,11 +10,11 @@ use League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; use League\OAuth2\Server\Entities\ScopeEntity; use League\OAuth2\Server\Grant\AbstractGrant; -use League\OAuth2\Server\Repositories\ClientRepositoryInterface; -use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; -use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface; +use League\OAuth2\Server\Repositories\ClientRepositoryInterface; +use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; +use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use Zend\Diactoros\ServerRequest; class AbstractGrantTest extends \PHPUnit_Framework_TestCase @@ -151,7 +151,7 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase $serverRequest = new ServerRequest(); $serverRequest = $serverRequest->withParsedBody([ - 'client_id' => 'foo', + 'client_id' => 'foo', 'client_secret' => 'foo', ]); @@ -180,7 +180,7 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase $serverRequest = new ServerRequest(); $serverRequest = $serverRequest->withParsedBody([ 'client_id' => 'foo', - 'redirect_uri' => 'http://bar/foo' + 'redirect_uri' => 'http://bar/foo', ]); $validateClientMethod = $abstractGrantReflection->getMethod('validateClient'); diff --git a/tests/Grant/ClientCredentialsGrantTest.php b/tests/Grant/ClientCredentialsGrantTest.php index 52e51c9a..c67e889c 100644 --- a/tests/Grant/ClientCredentialsGrantTest.php +++ b/tests/Grant/ClientCredentialsGrantTest.php @@ -42,7 +42,7 @@ class ClientCredentialsGrantTest extends \PHPUnit_Framework_TestCase $responseType = new StubResponseType(); $grant->respondToRequest($serverRequest, $responseType, new \DateInterval('PT5M')); - + $this->assertTrue($responseType->getAccessToken() instanceof AccessTokenEntityInterface); } } diff --git a/tests/Grant/RefreshTokenGrantTest.php b/tests/Grant/RefreshTokenGrantTest.php index 8bfe71c9..3be59bdb 100644 --- a/tests/Grant/RefreshTokenGrantTest.php +++ b/tests/Grant/RefreshTokenGrantTest.php @@ -5,7 +5,6 @@ namespace LeagueTests\Grant; use League\OAuth2\Server\Entities\ClientEntity; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; -use League\OAuth2\Server\Grant\PasswordGrant; use League\OAuth2\Server\Grant\RefreshTokenGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; @@ -14,7 +13,6 @@ use League\OAuth2\Server\Repositories\UserRepositoryInterface; use League\OAuth2\Server\Utils\KeyCrypt; use LeagueTests\Stubs\StubResponseType; use LeagueTests\Stubs\UserEntity; -use OAuth2ServerExamples\Repositories\RefreshTokenRepository; use Zend\Diactoros\ServerRequest; class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase diff --git a/tests/ServerTest.php b/tests/ServerTest.php index 9a85c351..3f823a17 100644 --- a/tests/ServerTest.php +++ b/tests/ServerTest.php @@ -4,11 +4,11 @@ namespace LeagueTests; use League\OAuth2\Server\Entities\ClientEntity; use League\OAuth2\Server\Grant\ClientCredentialsGrant; +use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; +use League\OAuth2\Server\Repositories\ClientRepositoryInterface; +use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use League\OAuth2\Server\Server; use LeagueTests\Stubs\StubResponseType; -use League\OAuth2\Server\Repositories\ClientRepositoryInterface; -use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; -use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use Psr\Http\Message\ResponseInterface; class ServerTest extends \PHPUnit_Framework_TestCase diff --git a/tests/Stubs/StubResponseType.php b/tests/Stubs/StubResponseType.php index d62daf9b..22d093a0 100644 --- a/tests/Stubs/StubResponseType.php +++ b/tests/Stubs/StubResponseType.php @@ -11,7 +11,9 @@ use Zend\Diactoros\Response; class StubResponseType extends AbstractResponseType { - public function __construct() {} + public function __construct() + { + } public function getAccessToken() { @@ -58,4 +60,4 @@ class StubResponseType extends AbstractResponseType { return new Response(); } -} \ No newline at end of file +} diff --git a/tests/Stubs/UserEntity.php b/tests/Stubs/UserEntity.php index 4c157df5..5d102c77 100644 --- a/tests/Stubs/UserEntity.php +++ b/tests/Stubs/UserEntity.php @@ -10,4 +10,4 @@ class UserEntity implements UserEntityInterface { return 123; } -} \ No newline at end of file +} From 97c138bb0b0591680459874ec8dbcc0eb7b83236 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 20 Feb 2016 10:05:15 +0000 Subject: [PATCH 30/49] Removed unused SecureKey class --- src/Utils/SecureKey.php | 48 ----------------------------------------- 1 file changed, 48 deletions(-) delete mode 100644 src/Utils/SecureKey.php diff --git a/src/Utils/SecureKey.php b/src/Utils/SecureKey.php deleted file mode 100644 index 17a2fcf2..00000000 --- a/src/Utils/SecureKey.php +++ /dev/null @@ -1,48 +0,0 @@ - - * @copyright Copyright (c) 2013 PHP League of Extraordinary Packages - * @license http://mit-license.org/ - * - * @link http://github.com/php-loep/oauth2-server - */ -namespace League\OAuth2\Server\Utils; - -use League\OAuth2\Server\Exception\OAuthServerException; - -/** - * SecureKey class. - */ -class SecureKey -{ - /** - * Generate a new unique code. - * - * @param int $len Length of the generated code - * - * @throws \League\OAuth2\Server\Exception\OAuthServerException - * - * @return string - */ - public static function generate($len = 40) - { - try { - $string = random_bytes($len); - // @codeCoverageIgnoreStart - } catch (\TypeError $e) { - // Well, it's an integer, so this IS unexpected. - throw OAuthServerException::serverError('An unexpected error has occurred'); - } catch (\Error $e) { - // This is also unexpected because 32 is a reasonable integer. - throw OAuthServerException::serverError('An unexpected error has occurred'); - } catch (\Exception $e) { - // If you get this message, the CSPRNG failed hard. - throw OAuthServerException::serverError('Could not generate a random string. Is our OS secure?'); - } - // @codeCoverageIgnoreEnd - - return bin2hex($string); - } -} From d0878300d0461f77267ab707949aa12a93d4bef9 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 21 Feb 2016 14:32:16 +0000 Subject: [PATCH 31/49] Bug fix for AuthCodeGrant --- src/Grant/AuthCodeGrant.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index e134b59f..cdd0f1cd 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -80,7 +80,19 @@ class AuthCodeGrant extends AbstractGrant protected function respondToAuthorizationRequest( ServerRequestInterface $request ) { - $client = $this->validateClient($request); + $clientId = $this->getQueryStringParameter( + 'client_id', + $request, + $this->getServerParameter('PHP_AUTH_USER', $request) + ); + if (is_null($clientId)) { + throw OAuthServerException::invalidRequest('client_id', null, '`%s` parameter is missing'); + } + + $client = $this->clientRepository->getClientEntity( + $clientId, + $this->getIdentifier() + ); if ($client instanceof ClientEntityInterface === false) { $this->emitter->emit(new Event('client.authentication.failed', $request)); From 8b601d79b9bd0819450e95d34c19f62bda279e3c Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 21 Feb 2016 14:32:27 +0000 Subject: [PATCH 32/49] First commit of AuthCodeGrant test --- tests/Grant/AuthCodeGrantTest.php | 114 ++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 tests/Grant/AuthCodeGrantTest.php diff --git a/tests/Grant/AuthCodeGrantTest.php b/tests/Grant/AuthCodeGrantTest.php new file mode 100644 index 00000000..41979461 --- /dev/null +++ b/tests/Grant/AuthCodeGrantTest.php @@ -0,0 +1,114 @@ +getMock(AuthCodeRepositoryInterface::class), + $this->getMock(RefreshTokenRepositoryInterface::class), + $this->getMock(UserRepositoryInterface::class), + new \DateInterval('PT10M') + ); + + $this->assertEquals('authorization_code', $grant->getIdentifier()); + } + + public function testCanRespondToRequest() + { + $grant = new AuthCodeGrant( + $this->getMock(AuthCodeRepositoryInterface::class), + $this->getMock(RefreshTokenRepositoryInterface::class), + $this->getMock(UserRepositoryInterface::class), + new \DateInterval('PT10M') + ); + + $request = new ServerRequest( + [], + [] + , + null, + null, + 'php://input', + $headers = [], + $cookies = [], + $queryParams = [ + 'response_type' => 'code', + 'client_id' => 'foo' + ] + ); + + $this->assertTrue($grant->canRespondToRequest($request)); + } + + public function testRespondToAuthorizationRequest() + { + $client = new ClientEntity(); + $client->setRedirectUri('http://foo/bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + $userEntity = new UserEntity(); + $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); + + $grant = new AuthCodeGrant( + $this->getMock(AuthCodeRepositoryInterface::class), + $this->getMock(RefreshTokenRepositoryInterface::class), + $userRepositoryMock, + new \DateInterval('PT10M'), + '', + '' + ); + $grant->setClientRepository($clientRepositoryMock); + $grant->setPathToPublicKey('file://'.__DIR__.'/../Utils/public.key'); + $grant->setPathToPrivateKey('file://'.__DIR__.'/../Utils/private.key'); + + $request = new ServerRequest( + [ + 'HTTP_HOST' => 'auth-server.tld', + 'REQUEST_URI' => '/authorize', + ], + [] + , + null, + 'POST', + 'php://input', + [], + [ + 'oauth_authorize_request' => KeyCrypt::encrypt( + json_encode(['user_id' => 123]), + 'file://'.__DIR__.'/../Utils/private.key' + ) + ], + [ + 'response_type' => 'code', + 'client_id' => 'foo', + ], + [ + 'username' => 'alex', + 'password' => 'whisky', + 'action' => 'approve' + ] + ); + + $response = $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + + $this->assertTrue($response instanceof ResponseInterface); + } +} From a4b65241adbe622ab37a67befa440eed44577862 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 21 Feb 2016 16:09:39 +0000 Subject: [PATCH 33/49] Updated PasswordGrant test --- tests/Grant/PasswordGrantTest.php | 101 ++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/tests/Grant/PasswordGrantTest.php b/tests/Grant/PasswordGrantTest.php index c81e4c61..096f374e 100644 --- a/tests/Grant/PasswordGrantTest.php +++ b/tests/Grant/PasswordGrantTest.php @@ -5,6 +5,7 @@ namespace LeagueTests\Grant; use League\OAuth2\Server\Entities\ClientEntity; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; +use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\PasswordGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; @@ -62,4 +63,104 @@ class PasswordGrantTest extends \PHPUnit_Framework_TestCase $this->assertTrue($responseType->getAccessToken() instanceof AccessTokenEntityInterface); $this->assertTrue($responseType->getRefreshToken() instanceof RefreshTokenEntityInterface); } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + */ + public function testRespondToRequestMissingUsername() + { + $client = new ClientEntity(); + $client->setSecret('bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + + $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + + $grant = new PasswordGrant($userRepositoryMock, $refreshTokenRepositoryMock); + $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody( + [ + 'client_id' => 'foo', + 'client_secret' => 'bar', + ] + ); + + $responseType = new StubResponseType(); + $grant->respondToRequest($serverRequest, $responseType, new \DateInterval('PT5M')); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + */ + public function testRespondToRequestMissingPassword() + { + $client = new ClientEntity(); + $client->setSecret('bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + + $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + + $grant = new PasswordGrant($userRepositoryMock, $refreshTokenRepositoryMock); + $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody( + [ + 'client_id' => 'foo', + 'client_secret' => 'bar', + 'username' => 'alex', + ] + ); + + $responseType = new StubResponseType(); + $grant->respondToRequest($serverRequest, $responseType, new \DateInterval('PT5M')); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + */ + public function testRespondToRequestBadCredentials() + { + $client = new ClientEntity(); + $client->setSecret('bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn(null); + + $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + + $grant = new PasswordGrant($userRepositoryMock, $refreshTokenRepositoryMock); + $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody( + [ + 'client_id' => 'foo', + 'client_secret' => 'bar', + 'username' => 'alex', + 'password' => 'whisky', + ] + ); + + $responseType = new StubResponseType(); + $grant->respondToRequest($serverRequest, $responseType, new \DateInterval('PT5M')); + } } From 7f539f8736ac9bc9c3f05fa40f4865159ae359c7 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 21 Feb 2016 16:40:01 +0000 Subject: [PATCH 34/49] Removed unused exception parameters --- src/Exception/OAuthServerException.php | 108 +++++++++---------------- src/Grant/AbstractGrant.php | 6 +- src/Grant/AuthCodeGrant.php | 10 +-- 3 files changed, 45 insertions(+), 79 deletions(-) diff --git a/src/Exception/OAuthServerException.php b/src/Exception/OAuthServerException.php index 3a8aa469..061722d7 100644 --- a/src/Exception/OAuthServerException.php +++ b/src/Exception/OAuthServerException.php @@ -33,14 +33,15 @@ class OAuthServerException extends \Exception * Throw a new exception. * * @param string $message Error message + * @param int $code Error code * @param string $errorType Error type * @param int $httpStatusCode HTTP status code to send (default = 400) * @param null|string $hint A helper hint * @param null|string $redirectUri A HTTP URI to redirect the user back to */ - public function __construct($message, $errorType, $httpStatusCode = 400, $hint = null, $redirectUri = null) + public function __construct($message, $code, $errorType, $httpStatusCode = 400, $hint = null, $redirectUri = null) { - parent::__construct($message); + parent::__construct($message, $code); $this->httpStatusCode = $httpStatusCode; $this->errorType = $errorType; $this->hint = $hint; @@ -49,110 +50,73 @@ class OAuthServerException extends \Exception /** * Invalid grant type error. - * - * @param null|string $localizedError - * @param null|string $localizedHint - * * @return static */ - public static function invalidGrantType( - $localizedError = null, - $localizedHint = null - ) { - $errorMessage = (is_null($localizedError)) - ? 'The provided authorization grant is invalid, expired, revoked, does not match '. - 'the redirection URI used in the authorization request, or was issued to another client.' - : $localizedError; - $hint = (is_null($localizedHint)) - ? 'Check the `grant_type` parameter' - : $localizedHint; + public static function invalidGrantType() + { + $errorMessage = 'The provided authorization grant is invalid, expired, revoked, does not match ' . + 'the redirection URI used in the authorization request, or was issued to another client.'; + $hint = 'Check the `grant_type` parameter'; - return new static($errorMessage, 'invalid_grant', 400, $hint); + return new static($errorMessage, 1, 'invalid_grant', 400, $hint); } /** * Unsupported grant type error. * - * @param null|string $localizedError - * @param null|string $localizedHint - * * @return static */ - public static function unsupportedGrantType( - $localizedError = null, - $localizedHint = null - ) { - $errorMessage = (is_null($localizedError)) - ? 'The authorization grant type is not supported by the authorization server.' - : $localizedError; - $hint = (is_null($localizedHint)) - ? 'Check the `grant_type` parameter' - : $localizedHint; + public static function unsupportedGrantType() + { + $errorMessage = 'The authorization grant type is not supported by the authorization server.'; + $hint = 'Check the `grant_type` parameter'; - return new static($errorMessage, 'unsupported_grant_type', 400, $hint); + return new static($errorMessage, 2, 'unsupported_grant_type', 400, $hint); } /** * Invalid request error. * - * @param string $parameter The invalid parameter - * @param null|string $localizedError - * @param null|string $localizedHint + * @param string $parameter The invalid parameter + * @param string|null $hint * * @return static */ - public static function invalidRequest( - $parameter, - $localizedError = null, - $localizedHint = null - ) { - $errorMessage = (is_null($localizedError)) - ? 'The request is missing a required parameter, includes an invalid parameter value, '. - 'includes a parameter more than once, or is otherwise malformed.' - : $localizedError; - $hint = (is_null($localizedHint)) - ? sprintf('Check the `%s` parameter', $parameter) - : sprintf($localizedHint, $parameter); + public static function invalidRequest($parameter, $hint = null) + { + $errorMessage = 'The request is missing a required parameter, includes an invalid parameter value, ' . + 'includes a parameter more than once, or is otherwise malformed.'; + $hint = ($hint === null) ? sprintf('Check the `%s` parameter', $parameter) : $hint; - return new static($errorMessage, 'invalid_request', 400, $hint); + return new static($errorMessage, 3, 'invalid_request', 400, $hint); } /** * Invalid client error. * - * @param null|string $localizedError - * * @return static */ - public static function invalidClient($localizedError = null) + public static function invalidClient() { - $errorMessage = (is_null($localizedError)) - ? 'Client authentication failed' - : $localizedError; + $errorMessage = 'Client authentication failed'; - return new static($errorMessage, 'invalid_client', 401); + return new static($errorMessage, 4, 'invalid_client', 401); } /** * Invalid scope error. * - * @param string $scope The bad scope - * @param null|string $localizedError A localized error message - * @param null|string $localizedHint A localized error hint - * @param null|string $redirectUri A HTTP URI to redirect the user back to + * @param string $scope The bad scope + * @param null|string $redirectUri A HTTP URI to redirect the user back to * * @return static */ - public static function invalidScope($scope, $localizedError = null, $localizedHint = null, $redirectUri = null) + public static function invalidScope($scope, $redirectUri = null) { - $errorMessage = (is_null($localizedError)) - ? 'The requested scope is invalid, unknown, or malformed' - : $localizedError; - $hint = (is_null($localizedHint)) - ? sprintf('Check the `%s` scope', $scope) - : sprintf($localizedHint, $scope); + $errorMessage = 'The requested scope is invalid, unknown, or malformed'; + $hint = sprintf('Check the `%s` scope', $scope); - return new static($errorMessage, 'invalid_scope', 400, $hint, $redirectUri); + return new static($errorMessage, 5, 'invalid_scope', 400, $hint, $redirectUri); } /** @@ -162,7 +126,7 @@ class OAuthServerException extends \Exception */ public static function invalidCredentials() { - return new static('The user credentials were incorrect.', 'invalid_credentials', 401); + return new static('The user credentials were incorrect.', 6, 'invalid_credentials', 401); } /** @@ -176,7 +140,8 @@ class OAuthServerException extends \Exception { return new static( 'The authorization server encountered an unexpected condition which prevented it from fulfilling' - .'the request.', + . 'the request.', + 7, 'server_error', 500, $hint @@ -192,7 +157,7 @@ class OAuthServerException extends \Exception */ public static function invalidRefreshToken($hint = null) { - return new static('The refresh token is invalid.', 'invalid_request', 400, $hint); + return new static('The refresh token is invalid.', 8, 'invalid_request', 400, $hint); } /** @@ -208,6 +173,7 @@ class OAuthServerException extends \Exception return new static( 'The resource owner or authorization server denied the request.', 'access_denied', + 9, 401, $hint, $redirectUri @@ -304,7 +270,7 @@ class OAuthServerException extends \Exception } } if ($authScheme !== null) { - $headers[] = 'WWW-Authenticate: '.$authScheme.' realm="OAuth"'; + $headers[] = 'WWW-Authenticate: ' . $authScheme . ' realm="OAuth"'; } } diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index ee4ab684..3823047d 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -186,7 +186,7 @@ abstract class AbstractGrant implements GrantTypeInterface $this->getServerParameter('PHP_AUTH_USER', $request) ); if (is_null($clientId)) { - throw OAuthServerException::invalidRequest('client_id', null, '`%s` parameter is missing'); + throw OAuthServerException::invalidRequest('client_id', '`%s` parameter is missing'); } $client = $this->clientRepository->getClientEntity( @@ -206,7 +206,7 @@ abstract class AbstractGrant implements GrantTypeInterface ); if ($client->canKeepASecret() && is_null($clientSecret)) { - throw OAuthServerException::invalidRequest('client_secret', null, '`%s` parameter is missing'); + throw OAuthServerException::invalidRequest('client_secret', '`%s` parameter is missing'); } if ($client->canKeepASecret() && $client->validateSecret($clientSecret) === false) { @@ -256,7 +256,7 @@ abstract class AbstractGrant implements GrantTypeInterface ); if (($scope instanceof ScopeEntity) === false) { - throw OAuthServerException::invalidScope($scopeItem, null, null, $redirectUri); + throw OAuthServerException::invalidScope($scopeItem, $redirectUri); } $scopes[] = $scope; diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index cdd0f1cd..4c808ad9 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -60,10 +60,10 @@ class AuthCodeGrant extends AbstractGrant $this->userRepository = $userRepository; $this->authCodeTTL = $authCodeTTL; $this->pathToLoginTemplate = ($pathToLoginTemplate === null) - ? __DIR__.'/../ResponseTypes/DefaultTemplates/login_user.php' + ? __DIR__ . '/../ResponseTypes/DefaultTemplates/login_user.php' : $this->pathToLoginTemplate; $this->pathToAuthorizeTemplate = ($pathToLoginTemplate === null) - ? __DIR__.'/../ResponseTypes/DefaultTemplates/authorize_client.php' + ? __DIR__ . '/../ResponseTypes/DefaultTemplates/authorize_client.php' : $this->pathToAuthorizeTemplate; $this->refreshTokenTTL = new \DateInterval('P1M'); } @@ -86,7 +86,7 @@ class AuthCodeGrant extends AbstractGrant $this->getServerParameter('PHP_AUTH_USER', $request) ); if (is_null($clientId)) { - throw OAuthServerException::invalidRequest('client_id', null, '`%s` parameter is missing'); + throw OAuthServerException::invalidRequest('client_id'); } $client = $this->clientRepository->getClientEntity( @@ -252,7 +252,7 @@ class AuthCodeGrant extends AbstractGrant // The redirect URI is required in this request $redirectUri = $this->getQueryStringParameter('redirect_uri', $request, null); if (is_null($redirectUri)) { - throw OAuthServerException::invalidRequest('redirect_uri', null, '`%s` parameter is missing'); + throw OAuthServerException::invalidRequest('redirect_uri'); } // Validate request @@ -278,7 +278,7 @@ class AuthCodeGrant extends AbstractGrant throw OAuthServerException::invalidRequest('code', 'Authorization code was not issued to this client'); } } catch (\LogicException $e) { - throw OAuthServerException::invalidRequest('code', null, 'Cannot decrypt the authorization code'); + throw OAuthServerException::invalidRequest('code', 'Cannot decrypt the authorization code'); } // Issue and persist access + refresh tokens From bc82f5baddd9e655b9d2bc4999a1be107571c6b8 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 21 Feb 2016 16:40:16 +0000 Subject: [PATCH 35/49] Improved RefreshTokenGrant tests --- tests/Grant/RefreshTokenGrantTest.php | 347 +++++++++++++++++++++++++- 1 file changed, 338 insertions(+), 9 deletions(-) diff --git a/tests/Grant/RefreshTokenGrantTest.php b/tests/Grant/RefreshTokenGrantTest.php index 3be59bdb..c9edebe2 100644 --- a/tests/Grant/RefreshTokenGrantTest.php +++ b/tests/Grant/RefreshTokenGrantTest.php @@ -5,14 +5,14 @@ namespace LeagueTests\Grant; use League\OAuth2\Server\Entities\ClientEntity; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; +use League\OAuth2\Server\Entities\ScopeEntity; use League\OAuth2\Server\Grant\RefreshTokenGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; -use League\OAuth2\Server\Repositories\UserRepositoryInterface; +use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use League\OAuth2\Server\Utils\KeyCrypt; use LeagueTests\Stubs\StubResponseType; -use LeagueTests\Stubs\UserEntity; use Zend\Diactoros\ServerRequest; class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase @@ -36,18 +36,14 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); - $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); - $userEntity = new UserEntity(); - $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); - $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); $refreshTokenRepositoryMock->method('persistNewRefreshToken')->willReturnSelf(); $grant = new RefreshTokenGrant($refreshTokenRepositoryMock); $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); - $grant->setPathToPublicKey('file://'.__DIR__.'/../Utils/public.key'); - $grant->setPathToPrivateKey('file://'.__DIR__.'/../Utils/private.key'); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); $oldRefreshToken = KeyCrypt::encrypt( json_encode( @@ -60,7 +56,7 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase 'expire_time' => time() + 3600, ] ), - 'file://'.__DIR__.'/../Utils/private.key' + 'file://' . __DIR__ . '/../Utils/private.key' ); $serverRequest = new ServerRequest(); @@ -78,4 +74,337 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase $this->assertTrue($responseType->getAccessToken() instanceof AccessTokenEntityInterface); $this->assertTrue($responseType->getRefreshToken() instanceof RefreshTokenEntityInterface); } + + public function testRespondToReducedScopes() + { + $client = new ClientEntity(); + $client->setIdentifier('foo'); + $client->setSecret('bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); + + $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + $refreshTokenRepositoryMock->method('persistNewRefreshToken')->willReturnSelf(); + + $scope = new ScopeEntity(); + $scope->setIdentifier('foo'); + $scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(); + $scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn($scope); + + $grant = new RefreshTokenGrant($refreshTokenRepositoryMock); + $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + $grant->setScopeRepository($scopeRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $oldRefreshToken = KeyCrypt::encrypt( + json_encode( + [ + 'client_id' => 'foo', + 'refresh_token_id' => 'zyxwvu', + 'access_token_id' => 'abcdef', + 'scopes' => ['foo', 'bar'], + 'user_id' => 123, + 'expire_time' => time() + 3600, + ] + ), + 'file://' . __DIR__ . '/../Utils/private.key' + ); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody( + [ + 'client_id' => 'foo', + 'client_secret' => 'bar', + 'refresh_token' => $oldRefreshToken, + 'scope' => 'foo', + ] + ); + + $responseType = new StubResponseType(); + $grant->respondToRequest($serverRequest, $responseType, new \DateInterval('PT5M')); + + $this->assertTrue($responseType->getAccessToken() instanceof AccessTokenEntityInterface); + $this->assertTrue($responseType->getRefreshToken() instanceof RefreshTokenEntityInterface); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + * @expectedExceptionCode 5 + */ + public function testRespondToUnexpectedScope() + { + $client = new ClientEntity(); + $client->setIdentifier('foo'); + $client->setSecret('bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); + + $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + $refreshTokenRepositoryMock->method('persistNewRefreshToken')->willReturnSelf(); + + $scope = new ScopeEntity(); + $scope->setIdentifier('foobar'); + $scopeRepositoryMock = $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(); + $scopeRepositoryMock->method('getScopeEntityByIdentifier')->willReturn($scope); + + $grant = new RefreshTokenGrant($refreshTokenRepositoryMock); + $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + $grant->setScopeRepository($scopeRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $oldRefreshToken = KeyCrypt::encrypt( + json_encode( + [ + 'client_id' => 'foo', + 'refresh_token_id' => 'zyxwvu', + 'access_token_id' => 'abcdef', + 'scopes' => ['foo', 'bar'], + 'user_id' => 123, + 'expire_time' => time() + 3600, + ] + ), + 'file://' . __DIR__ . '/../Utils/private.key' + ); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody( + [ + 'client_id' => 'foo', + 'client_secret' => 'bar', + 'refresh_token' => $oldRefreshToken, + 'scope' => 'foobar', + ] + ); + + $responseType = new StubResponseType(); + $grant->respondToRequest($serverRequest, $responseType, new \DateInterval('PT5M')); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + * @expectedExceptionCode 3 + */ + public function testRespondToRequestMissingOldToken() + { + $client = new ClientEntity(); + $client->setIdentifier('foo'); + $client->setSecret('bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + + $grant = new RefreshTokenGrant($refreshTokenRepositoryMock); + $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody( + [ + 'client_id' => 'foo', + 'client_secret' => 'bar', + ] + ); + + $responseType = new StubResponseType(); + $grant->respondToRequest($serverRequest, $responseType, new \DateInterval('PT5M')); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + * @expectedExceptionCode 8 + */ + public function testRespondToRequestInvalidOldToken() + { + $client = new ClientEntity(); + $client->setIdentifier('foo'); + $client->setSecret('bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + + $grant = new RefreshTokenGrant($refreshTokenRepositoryMock); + $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $oldRefreshToken = 'foobar'; + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody( + [ + 'client_id' => 'foo', + 'client_secret' => 'bar', + 'refresh_token' => $oldRefreshToken, + ] + ); + + $responseType = new StubResponseType(); + $grant->respondToRequest($serverRequest, $responseType, new \DateInterval('PT5M')); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + * @expectedExceptionCode 8 + */ + public function testRespondToRequestClientMismatch() + { + $client = new ClientEntity(); + $client->setIdentifier('foo'); + $client->setSecret('bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); + + + $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + $refreshTokenRepositoryMock->method('persistNewRefreshToken')->willReturnSelf(); + + $grant = new RefreshTokenGrant($refreshTokenRepositoryMock); + $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $oldRefreshToken = KeyCrypt::encrypt( + json_encode( + [ + 'client_id' => 'bar', + 'refresh_token_id' => 'zyxwvu', + 'access_token_id' => 'abcdef', + 'scopes' => ['foo'], + 'user_id' => 123, + 'expire_time' => time() + 3600, + ] + ), + 'file://' . __DIR__ . '/../Utils/private.key' + ); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody( + [ + 'client_id' => 'foo', + 'client_secret' => 'bar', + 'refresh_token' => $oldRefreshToken, + ] + ); + + $responseType = new StubResponseType(); + $grant->respondToRequest($serverRequest, $responseType, new \DateInterval('PT5M')); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + * @expectedExceptionCode 8 + */ + public function testRespondToRequestExpiredToken() + { + $client = new ClientEntity(); + $client->setIdentifier('foo'); + $client->setSecret('bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + + $grant = new RefreshTokenGrant($refreshTokenRepositoryMock); + $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $oldRefreshToken = KeyCrypt::encrypt( + json_encode( + [ + 'client_id' => 'foo', + 'refresh_token_id' => 'zyxwvu', + 'access_token_id' => 'abcdef', + 'scopes' => ['foo'], + 'user_id' => 123, + 'expire_time' => time() - 3600, + ] + ), + 'file://' . __DIR__ . '/../Utils/private.key' + ); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody( + [ + 'client_id' => 'foo', + 'client_secret' => 'bar', + 'refresh_token' => $oldRefreshToken, + ] + ); + + $responseType = new StubResponseType(); + $grant->respondToRequest($serverRequest, $responseType, new \DateInterval('PT5M')); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + * @expectedExceptionCode 8 + */ + public function testRespondToRequestRevokedToken() + { + $client = new ClientEntity(); + $client->setIdentifier('foo'); + $client->setSecret('bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + $refreshTokenRepositoryMock->method('isRefreshTokenRevoked')->willReturn(true); + + $grant = new RefreshTokenGrant($refreshTokenRepositoryMock); + $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $oldRefreshToken = KeyCrypt::encrypt( + json_encode( + [ + 'client_id' => 'foo', + 'refresh_token_id' => 'zyxwvu', + 'access_token_id' => 'abcdef', + 'scopes' => ['foo'], + 'user_id' => 123, + 'expire_time' => time() + 3600, + ] + ), + 'file://' . __DIR__ . '/../Utils/private.key' + ); + + $serverRequest = new ServerRequest(); + $serverRequest = $serverRequest->withParsedBody( + [ + 'client_id' => 'foo', + 'client_secret' => 'bar', + 'refresh_token' => $oldRefreshToken, + ] + ); + + $responseType = new StubResponseType(); + $grant->respondToRequest($serverRequest, $responseType, new \DateInterval('PT5M')); + } } From 27d4441d1d885f5054f0bde197f70b8cabff5c9e Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 21 Feb 2016 16:40:29 +0000 Subject: [PATCH 36/49] Updated to phpunit 5 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index a1bfda41..800e0f1a 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,7 @@ "paragonie/random_compat": "^1.1" }, "require-dev": { - "phpunit/phpunit": "4.8.*" + "phpunit/phpunit": "~5.2" }, "repositories": [ { From 2488cbd55d122741664b653157ba44d3fdcdb837 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 21 Feb 2016 17:08:49 +0000 Subject: [PATCH 37/49] Bug fixes --- src/Grant/AuthCodeGrant.php | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 4c808ad9..27dbb1c0 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -59,13 +59,21 @@ class AuthCodeGrant extends AbstractGrant $this->setRefreshTokenRepository($refreshTokenRepository); $this->userRepository = $userRepository; $this->authCodeTTL = $authCodeTTL; - $this->pathToLoginTemplate = ($pathToLoginTemplate === null) - ? __DIR__ . '/../ResponseTypes/DefaultTemplates/login_user.php' - : $this->pathToLoginTemplate; - $this->pathToAuthorizeTemplate = ($pathToLoginTemplate === null) - ? __DIR__ . '/../ResponseTypes/DefaultTemplates/authorize_client.php' - : $this->pathToAuthorizeTemplate; $this->refreshTokenTTL = new \DateInterval('P1M'); + + $this->pathToLoginTemplate = __DIR__ . '/../ResponseTypes/DefaultTemplates/login_user'; + if ($pathToLoginTemplate !== null) { + $this->pathToLoginTemplate = (substr($pathToLoginTemplate, -4) === '.php') + ? substr($pathToLoginTemplate, 0, -4) + : $pathToLoginTemplate; + } + + $this->pathToAuthorizeTemplate = __DIR__ . '/../ResponseTypes/DefaultTemplates/authorize_client'; + if ($pathToAuthorizeTemplate !== null) { + $this->pathToAuthorizeTemplate = (substr($pathToAuthorizeTemplate, -4) === '.php') + ? substr($pathToAuthorizeTemplate, 0, -4) + : $pathToAuthorizeTemplate; + } } /** @@ -95,7 +103,7 @@ class AuthCodeGrant extends AbstractGrant ); if ($client instanceof ClientEntityInterface === false) { - $this->emitter->emit(new Event('client.authentication.failed', $request)); + $this->getEmitter()->emit(new Event('client.authentication.failed', $request)); throw OAuthServerException::invalidClient(); } @@ -329,13 +337,12 @@ class AuthCodeGrant extends AbstractGrant \DateInterval $accessTokenTTL ) { if ( - isset($request->getQueryParams()['response_type']) + array_key_exists('response_type', $request->getQueryParams()) && $request->getQueryParams()['response_type'] === 'code' - && isset($request->getQueryParams()['client_id']) ) { return $this->respondToAuthorizationRequest($request); } elseif ( - isset($request->getParsedBody()['grant_type']) + array_key_exists('grant_type', $request->getParsedBody()) && $request->getParsedBody()['grant_type'] === 'authorization_code' ) { return $this->respondToAccessTokenRequest($request, $responseType, $accessTokenTTL); From 9675dff220fe4e4063452c7ac22f2a2c5ca40482 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 21 Feb 2016 17:08:57 +0000 Subject: [PATCH 38/49] Added AuthCodeGrant tests --- tests/Grant/AuthCodeGrantTest.php | 419 +++++++++++++++++++++++++++++- 1 file changed, 412 insertions(+), 7 deletions(-) diff --git a/tests/Grant/AuthCodeGrantTest.php b/tests/Grant/AuthCodeGrantTest.php index 41979461..faf18318 100644 --- a/tests/Grant/AuthCodeGrantTest.php +++ b/tests/Grant/AuthCodeGrantTest.php @@ -23,7 +23,9 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $this->getMock(AuthCodeRepositoryInterface::class), $this->getMock(RefreshTokenRepositoryInterface::class), $this->getMock(UserRepositoryInterface::class), - new \DateInterval('PT10M') + new \DateInterval('PT10M'), + '', + '' ); $this->assertEquals('authorization_code', $grant->getIdentifier()); @@ -49,7 +51,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $cookies = [], $queryParams = [ 'response_type' => 'code', - 'client_id' => 'foo' + 'client_id' => 'foo', ] ); @@ -76,8 +78,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase '' ); $grant->setClientRepository($clientRepositoryMock); - $grant->setPathToPublicKey('file://'.__DIR__.'/../Utils/public.key'); - $grant->setPathToPrivateKey('file://'.__DIR__.'/../Utils/private.key'); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); $request = new ServerRequest( [ @@ -93,8 +95,187 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase [ 'oauth_authorize_request' => KeyCrypt::encrypt( json_encode(['user_id' => 123]), - 'file://'.__DIR__.'/../Utils/private.key' - ) + 'file://' . __DIR__ . '/../Utils/private.key' + ), + ], + [ + 'response_type' => 'code', + 'client_id' => 'foo', + 'state' => 'foobar', + ], + [ + 'username' => 'alex', + 'password' => 'whisky', + 'action' => 'approve', + ] + ); + + $response = $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + + $this->assertTrue($response instanceof ResponseInterface); + $this->assertTrue(strstr($response->getHeader('location')[0], 'http://foo/bar') !== false); + } + + public function testRespondToAuthorizationRequestUserDenied() + { + $client = new ClientEntity(); + $client->setRedirectUri('http://foo/bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + $userEntity = new UserEntity(); + $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); + + $grant = new AuthCodeGrant( + $this->getMock(AuthCodeRepositoryInterface::class), + $this->getMock(RefreshTokenRepositoryInterface::class), + $userRepositoryMock, + new \DateInterval('PT10M'), + '', + '' + ); + $grant->setClientRepository($clientRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $request = new ServerRequest( + [ + 'HTTP_HOST' => 'auth-server.tld', + 'REQUEST_URI' => '/authorize', + ], + [] + , + null, + 'POST', + 'php://input', + [], + [ + 'oauth_authorize_request' => KeyCrypt::encrypt( + json_encode(['user_id' => 123]), + 'file://' . __DIR__ . '/../Utils/private.key' + ), + ], + [ + 'response_type' => 'code', + 'client_id' => 'foo', + 'state' => 'foobar', + ], + [ + 'username' => 'alex', + 'password' => 'whisky', + 'action' => 'denied', + ] + ); + + $response = $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + + $this->assertTrue($response instanceof ResponseInterface); + $this->assertTrue(strstr($response->getHeader('location')[0], 'http://foo/bar') !== false); + $this->assertTrue(strstr($response->getHeader('location')[0], 'access_denied') !== false); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + * @expectedExceptionCode 3 + */ + public function testRespondToAuthorizationRequestMissingClientId() + { + $client = new ClientEntity(); + $client->setRedirectUri('http://foo/bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + $userEntity = new UserEntity(); + $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); + + $grant = new AuthCodeGrant( + $this->getMock(AuthCodeRepositoryInterface::class), + $this->getMock(RefreshTokenRepositoryInterface::class), + $userRepositoryMock, + new \DateInterval('PT10M'), + '', + '' + ); + $grant->setClientRepository($clientRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $request = new ServerRequest( + [ + 'HTTP_HOST' => 'auth-server.tld', + 'REQUEST_URI' => '/authorize', + ], + [] + , + null, + 'POST', + 'php://input', + [], + [ + 'oauth_authorize_request' => KeyCrypt::encrypt( + json_encode(['user_id' => 123]), + 'file://' . __DIR__ . '/../Utils/private.key' + ), + ], + [ + 'response_type' => 'code', + ], + [ + 'username' => 'alex', + 'password' => 'whisky', + 'action' => 'approve', + ] + ); + + $response = $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + + $this->assertTrue($response instanceof ResponseInterface); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + * @expectedExceptionCode 4 + */ + public function testRespondToAuthorizationRequestBadClient() + { + $client = null; + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + $userEntity = new UserEntity(); + $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); + + $grant = new AuthCodeGrant( + $this->getMock(AuthCodeRepositoryInterface::class), + $this->getMock(RefreshTokenRepositoryInterface::class), + $userRepositoryMock, + new \DateInterval('PT10M'), + '', + '' + ); + $grant->setClientRepository($clientRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $request = new ServerRequest( + [ + 'HTTP_HOST' => 'auth-server.tld', + 'REQUEST_URI' => '/authorize', + ], + [] + , + null, + 'POST', + 'php://input', + [], + [ + 'oauth_authorize_request' => KeyCrypt::encrypt( + json_encode(['user_id' => 123]), + 'file://' . __DIR__ . '/../Utils/private.key' + ), ], [ 'response_type' => 'code', @@ -103,7 +284,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase [ 'username' => 'alex', 'password' => 'whisky', - 'action' => 'approve' + 'action' => 'approve', ] ); @@ -111,4 +292,228 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $this->assertTrue($response instanceof ResponseInterface); } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + * @expectedExceptionCode 7 + */ + public function testRespondToAuthorizationRequestBadCookie() + { + $client = new ClientEntity(); + $client->setRedirectUri('http://foo/bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + $userEntity = new UserEntity(); + $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); + + $grant = new AuthCodeGrant( + $this->getMock(AuthCodeRepositoryInterface::class), + $this->getMock(RefreshTokenRepositoryInterface::class), + $userRepositoryMock, + new \DateInterval('PT10M'), + '', + '' + ); + $grant->setClientRepository($clientRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $request = new ServerRequest( + [ + 'HTTP_HOST' => 'auth-server.tld', + 'REQUEST_URI' => '/authorize', + ], + [] + , + null, + 'POST', + 'php://input', + [], + [ + 'oauth_authorize_request' => 'blah', + ], + [ + 'response_type' => 'code', + 'client_id' => 'foo', + ], + [ + 'username' => 'alex', + 'password' => 'whisky', + 'action' => 'approve', + ] + ); + + $response = $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + + $this->assertTrue($response instanceof ResponseInterface); + } + + public function testRespondToAuthorizationRequestTryLogin() + { + $client = new ClientEntity(); + $client->setRedirectUri('http://foo/bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + $userEntity = new UserEntity(); + $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); + + $grant = new AuthCodeGrant( + $this->getMock(AuthCodeRepositoryInterface::class), + $this->getMock(RefreshTokenRepositoryInterface::class), + $userRepositoryMock, + new \DateInterval('PT10M'), + '', + '' + ); + $grant->setClientRepository($clientRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $request = new ServerRequest( + [ + 'HTTP_HOST' => 'auth-server.tld', + 'REQUEST_URI' => '/authorize', + ], + [] + , + null, + 'POST', + 'php://input', + [], + [ + 'oauth_authorize_request' => KeyCrypt::encrypt( + json_encode(['user_id' => null]), + 'file://' . __DIR__ . '/../Utils/private.key' + ), + ], + [ + 'response_type' => 'code', + 'client_id' => 'foo', + ], + [ + 'username' => 'alex', + 'password' => 'whisky', + 'action' => 'approve', + ] + ); + + $response = $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + + $this->assertTrue($response instanceof ResponseInterface); + $this->assertTrue(strstr($response->getHeader('location')[0], 'http://foo/bar') !== false); + } + + public function testRespondToAuthorizationRequestShowLoginForm() + { + $client = new ClientEntity(); + $client->setRedirectUri('http://foo/bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + $userEntity = null; + $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); + + $grant = new AuthCodeGrant( + $this->getMock(AuthCodeRepositoryInterface::class), + $this->getMock(RefreshTokenRepositoryInterface::class), + $userRepositoryMock, + new \DateInterval('PT10M') + ); + $grant->setClientRepository($clientRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $request = new ServerRequest( + [ + 'HTTP_HOST' => 'auth-server.tld', + 'REQUEST_URI' => '/authorize', + ], + [] + , + null, + 'POST', + 'php://input', + [], + [ + 'oauth_authorize_request' => KeyCrypt::encrypt( + json_encode(['user_id' => null]), + 'file://' . __DIR__ . '/../Utils/private.key' + ), + ], + [ + 'response_type' => 'code', + 'client_id' => 'foo', + ], + [ + 'username' => 'alex', + 'password' => 'whisky', + 'action' => 'approve', + ] + ); + + $response = $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + + $this->assertTrue($response instanceof ResponseInterface); + $this->assertTrue(strstr($response->getHeader('content-type')[0], 'text/html') !== false); + $this->assertTrue(strstr($response->getBody()->getContents(), 'Incorrect username or password') !== false); + } + + public function testRespondToAuthorizationRequestShowAuthorizeForm() + { + $client = new ClientEntity(); + $client->setRedirectUri('http://foo/bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + $userEntity = new UserEntity(); + $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); + + $grant = new AuthCodeGrant( + $this->getMock(AuthCodeRepositoryInterface::class), + $this->getMock(RefreshTokenRepositoryInterface::class), + $userRepositoryMock, + new \DateInterval('PT10M') + ); + $grant->setClientRepository($clientRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $request = new ServerRequest( + [ + 'HTTP_HOST' => 'auth-server.tld', + 'REQUEST_URI' => '/authorize', + ], + [] + , + null, + 'POST', + 'php://input', + [], + [ + 'oauth_authorize_request' => KeyCrypt::encrypt( + json_encode(['user_id' => 123]), + 'file://' . __DIR__ . '/../Utils/private.key' + ), + ], + [ + 'response_type' => 'code', + 'client_id' => 'foo', + ], + [ + 'username' => 'alex', + 'password' => 'whisky', + ] + ); + + $response = $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + + $this->assertTrue($response instanceof ResponseInterface); + $this->assertTrue(strstr($response->getHeader('set-cookie')[0], 'oauth_authorize_request') !== false); + } } From f06adb38cd62f58f9b644307a0e0c12c8c3b92ca Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 21 Feb 2016 17:09:04 +0000 Subject: [PATCH 39/49] Require dev league/plates --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 800e0f1a..7d6ba886 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,8 @@ "paragonie/random_compat": "^1.1" }, "require-dev": { - "phpunit/phpunit": "~5.2" + "phpunit/phpunit": "~5.2", + "league/plates": "^3.1" }, "repositories": [ { From eedcfe115c0e8827c697e962e58e3ccb2cd781f7 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 21 Feb 2016 17:09:12 +0000 Subject: [PATCH 40/49] Bug fixes --- src/Exception/OAuthServerException.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Exception/OAuthServerException.php b/src/Exception/OAuthServerException.php index 061722d7..951f8a82 100644 --- a/src/Exception/OAuthServerException.php +++ b/src/Exception/OAuthServerException.php @@ -140,11 +140,10 @@ class OAuthServerException extends \Exception { return new static( 'The authorization server encountered an unexpected condition which prevented it from fulfilling' - . 'the request.', + . ' the request: ' . $hint, 7, 'server_error', - 500, - $hint + 500 ); } @@ -172,8 +171,8 @@ class OAuthServerException extends \Exception { return new static( 'The resource owner or authorization server denied the request.', - 'access_denied', 9, + 'access_denied', 401, $hint, $redirectUri From cee4147688e289cc573dcb9e80c1f391196183c8 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 21 Feb 2016 17:11:58 +0000 Subject: [PATCH 41/49] PHP 5.5 doesn't support phpunit 5 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 7d6ba886..67e551a9 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,7 @@ "paragonie/random_compat": "^1.1" }, "require-dev": { - "phpunit/phpunit": "~5.2", + "phpunit/phpunit": "^4.8", "league/plates": "^3.1" }, "repositories": [ From d02437dd7397df13f0aba782e6dbb2cd0e0e867e Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 21 Feb 2016 18:13:39 +0000 Subject: [PATCH 42/49] Improved testing --- src/Exception/OAuthServerException.php | 8 + src/Grant/AbstractGrant.php | 11 +- src/Grant/AuthCodeGrant.php | 23 +- tests/Grant/AuthCodeGrantTest.php | 502 ++++++++++++++++++++++++- 4 files changed, 521 insertions(+), 23 deletions(-) diff --git a/src/Exception/OAuthServerException.php b/src/Exception/OAuthServerException.php index 951f8a82..af9379d9 100644 --- a/src/Exception/OAuthServerException.php +++ b/src/Exception/OAuthServerException.php @@ -286,4 +286,12 @@ class OAuthServerException extends \Exception { return $this->httpStatusCode; } + + /** + * @return null|string + */ + public function getHint() + { + return $this->hint; + } } diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 3823047d..407ae4db 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -16,6 +16,7 @@ use League\Event\Event; use League\OAuth2\Server\Entities\AccessTokenEntity; use League\OAuth2\Server\Entities\AuthCodeEntity; use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; +use League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface; use League\OAuth2\Server\Entities\RefreshTokenEntity; use League\OAuth2\Server\Entities\ScopeEntity; use League\OAuth2\Server\Exception\OAuthServerException; @@ -344,6 +345,11 @@ abstract class AbstractGrant implements GrantTypeInterface $accessToken->setUserIdentifier($userIdentifier); foreach ($scopes as $scope) { + if (is_string($scope)) { + $s = new ScopeEntity(); + $s->setIdentifier($scope); + $scope = $s; + } $accessToken->addScope($scope); } @@ -435,8 +441,7 @@ abstract class AbstractGrant implements GrantTypeInterface */ public function canRespondToRequest(ServerRequestInterface $request) { - return - isset($request->getParsedBody()['grant_type']) - && $request->getParsedBody()['grant_type'] === $this->getIdentifier(); + return isset($request->getParsedBody()['grant_type']) + && $request->getParsedBody()['grant_type'] === $this->getIdentifier(); } } diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 27dbb1c0..05afc7fd 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -61,7 +61,7 @@ class AuthCodeGrant extends AbstractGrant $this->authCodeTTL = $authCodeTTL; $this->refreshTokenTTL = new \DateInterval('P1M'); - $this->pathToLoginTemplate = __DIR__ . '/../ResponseTypes/DefaultTemplates/login_user'; + $this->pathToLoginTemplate = __DIR__ . '/../ResponseTypes/DefaultTemplates/login_user'; if ($pathToLoginTemplate !== null) { $this->pathToLoginTemplate = (substr($pathToLoginTemplate, -4) === '.php') ? substr($pathToLoginTemplate, 0, -4) @@ -108,6 +108,11 @@ class AuthCodeGrant extends AbstractGrant throw OAuthServerException::invalidClient(); } + $redirectUriParameter = $this->getQueryStringParameter('redirect_uri', $request, $client->getRedirectUri()); + if ($redirectUriParameter !== $client->getRedirectUri()) { + throw OAuthServerException::invalidClient(); + } + $scopes = $this->validateScopes($request, $client, $client->getRedirectUri()); $queryString = http_build_query($request->getQueryParams()); $postbackUri = new Uri( @@ -224,6 +229,7 @@ class AuthCodeGrant extends AbstractGrant json_encode( [ 'client_id' => $authCode->getClient()->getIdentifier(), + 'redirect_uri' => $authCode->getRedirectUri(), 'auth_code_id' => $authCode->getIdentifier(), 'scopes' => $authCode->getScopes(), 'user_id' => $authCode->getUserIdentifier(), @@ -258,7 +264,7 @@ class AuthCodeGrant extends AbstractGrant DateInterval $accessTokenTTL ) { // The redirect URI is required in this request - $redirectUri = $this->getQueryStringParameter('redirect_uri', $request, null); + $redirectUri = $this->getRequestParameter('redirect_uri', $request, null); if (is_null($redirectUri)) { throw OAuthServerException::invalidRequest('redirect_uri'); } @@ -285,6 +291,10 @@ class AuthCodeGrant extends AbstractGrant if ($authCodePayload->client_id !== $client->getIdentifier()) { throw OAuthServerException::invalidRequest('code', 'Authorization code was not issued to this client'); } + + if ($authCodePayload->redirect_uri !== $redirectUri) { + throw OAuthServerException::invalidRequest('redirect_uri', 'Invalid redirect URI'); + } } catch (\LogicException $e) { throw OAuthServerException::invalidRequest('code', 'Cannot decrypt the authorization code'); } @@ -341,13 +351,8 @@ class AuthCodeGrant extends AbstractGrant && $request->getQueryParams()['response_type'] === 'code' ) { return $this->respondToAuthorizationRequest($request); - } elseif ( - array_key_exists('grant_type', $request->getParsedBody()) - && $request->getParsedBody()['grant_type'] === 'authorization_code' - ) { - return $this->respondToAccessTokenRequest($request, $responseType, $accessTokenTTL); - } else { - throw OAuthServerException::serverError('respondToRequest() should not have been called'); } + + return $this->respondToAccessTokenRequest($request, $responseType, $accessTokenTTL); } } diff --git a/tests/Grant/AuthCodeGrantTest.php b/tests/Grant/AuthCodeGrantTest.php index faf18318..d5764843 100644 --- a/tests/Grant/AuthCodeGrantTest.php +++ b/tests/Grant/AuthCodeGrantTest.php @@ -3,10 +3,14 @@ namespace LeagueTests\Grant; use League\OAuth2\Server\Entities\ClientEntity; +use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; +use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; +use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\AuthCodeGrant; use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; +use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface; use League\OAuth2\Server\Utils\KeyCrypt; use LeagueTests\Stubs\StubResponseType; @@ -24,8 +28,8 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $this->getMock(RefreshTokenRepositoryInterface::class), $this->getMock(UserRepositoryInterface::class), new \DateInterval('PT10M'), - '', - '' + 'foo/bar.php', + 'foo/bar.php' ); $this->assertEquals('authorization_code', $grant->getIdentifier()); @@ -234,10 +238,6 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $this->assertTrue($response instanceof ResponseInterface); } - /** - * @expectedException \League\OAuth2\Server\Exception\OAuthServerException - * @expectedExceptionCode 4 - */ public function testRespondToAuthorizationRequestBadClient() { $client = null; @@ -252,9 +252,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $this->getMock(AuthCodeRepositoryInterface::class), $this->getMock(RefreshTokenRepositoryInterface::class), $userRepositoryMock, - new \DateInterval('PT10M'), - '', - '' + new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); @@ -288,9 +286,69 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase ] ); - $response = $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + try { + /** @var StubResponseType $response */ + $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + } catch (OAuthServerException $e) { + $this->assertEquals($e->getMessage(), 'Client authentication failed'); + } + } - $this->assertTrue($response instanceof ResponseInterface); + public function testRespondToAuthorizationRequestBadRedirectUri() + { + $client = new ClientEntity(); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + $userEntity = new UserEntity(); + $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); + + $grant = new AuthCodeGrant( + $this->getMock(AuthCodeRepositoryInterface::class), + $this->getMock(RefreshTokenRepositoryInterface::class), + $userRepositoryMock, + new \DateInterval('PT10M') + ); + $grant->setClientRepository($clientRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $request = new ServerRequest( + [ + 'HTTP_HOST' => 'auth-server.tld', + 'REQUEST_URI' => '/authorize', + ], + [] + , + null, + 'POST', + 'php://input', + [], + [ + 'oauth_authorize_request' => KeyCrypt::encrypt( + json_encode(['user_id' => 123]), + 'file://' . __DIR__ . '/../Utils/private.key' + ), + ], + [ + 'response_type' => 'code', + 'client_id' => 'foo', + 'redirect_uri' => 'sdfsdf' + ], + [ + 'username' => 'alex', + 'password' => 'whisky', + 'action' => 'approve', + ] + ); + + try { + /** @var StubResponseType $response */ + $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + } catch (OAuthServerException $e) { + $this->assertEquals($e->getMessage(), 'Client authentication failed'); + } } /** @@ -516,4 +574,426 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $this->assertTrue($response instanceof ResponseInterface); $this->assertTrue(strstr($response->getHeader('set-cookie')[0], 'oauth_authorize_request') !== false); } + + public function testRespondToAccessTokenRequest() + { + $client = new ClientEntity(); + $client->setIdentifier('foo'); + $client->setRedirectUri('http://foo/bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + $userEntity = new UserEntity(); + $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); + + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); + + $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + $refreshTokenRepositoryMock->method('persistNewRefreshToken')->willReturnSelf(); + + $grant = new AuthCodeGrant( + $this->getMock(AuthCodeRepositoryInterface::class), + $this->getMock(RefreshTokenRepositoryInterface::class), + $userRepositoryMock, + new \DateInterval('PT10M') + ); + $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $request = new ServerRequest( + [], + [] + , + null, + 'POST', + 'php://input', + [], + [], + [], + [ + 'grant_type' => 'authorization_code', + 'client_id' => 'foo', + 'redirect_uri' => 'http://foo/bar', + 'code' => KeyCrypt::encrypt( + json_encode( + [ + 'auth_code_id' => uniqid(), + 'expire_time' => time() + 3600, + 'client_id' => 'foo', + 'user_id' => 123, + 'scopes' => ['foo'], + 'redirect_uri' => 'http://foo/bar', + ] + ), + 'file://' . __DIR__ . '/../Utils/private.key' + ), + ] + ); + + /** @var StubResponseType $response */ + $response = $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + + $this->assertTrue($response->getAccessToken() instanceof AccessTokenEntityInterface); + $this->assertTrue($response->getRefreshToken() instanceof RefreshTokenEntityInterface); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + * @expectedExceptionCode 3 + */ + public function testRespondToAccessTokenRequestMissingRedirectUri() + { + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + + $grant = new AuthCodeGrant( + $this->getMock(AuthCodeRepositoryInterface::class), + $this->getMock(RefreshTokenRepositoryInterface::class), + $userRepositoryMock, + new \DateInterval('PT10M') + ); + $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $request = new ServerRequest( + [], + [] + , + null, + 'POST', + 'php://input', + [], + [], + [], + [ + 'grant_type' => 'authorization_code', + ] + ); + + /** @var StubResponseType $response */ + $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + * @expectedExceptionCode 3 + */ + public function testRespondToAccessTokenRequestMissingCode() + { + $client = new ClientEntity(); + $client->setSecret('bar'); + $client->setRedirectUri('http://foo/bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + + $grant = new AuthCodeGrant( + $this->getMock(AuthCodeRepositoryInterface::class), + $this->getMock(RefreshTokenRepositoryInterface::class), + $userRepositoryMock, + new \DateInterval('PT10M') + ); + $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $request = new ServerRequest( + [], + [] + , + null, + 'POST', + 'php://input', + [], + [], + [], + [ + 'grant_type' => 'authorization_code', + 'client_id' => 'foo', + 'client_secret' => 'bar', + 'redirect_uri' => 'http://foo/bar', + ] + ); + + /** @var StubResponseType $response */ + $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + } + + public function testRespondToAccessTokenRequestExpiredCode() + { + $client = new ClientEntity(); + $client->setIdentifier('foo'); + $client->setRedirectUri('http://foo/bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + $userEntity = new UserEntity(); + $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); + + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); + + $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + $refreshTokenRepositoryMock->method('persistNewRefreshToken')->willReturnSelf(); + + $grant = new AuthCodeGrant( + $this->getMock(AuthCodeRepositoryInterface::class), + $this->getMock(RefreshTokenRepositoryInterface::class), + $userRepositoryMock, + new \DateInterval('PT10M') + ); + $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $request = new ServerRequest( + [], + [] + , + null, + 'POST', + 'php://input', + [], + [], + [], + [ + 'grant_type' => 'authorization_code', + 'client_id' => 'foo', + 'redirect_uri' => 'http://foo/bar', + 'code' => KeyCrypt::encrypt( + json_encode( + [ + 'auth_code_id' => uniqid(), + 'expire_time' => time() - 3600, + 'client_id' => 'foo', + 'user_id' => 123, + 'scopes' => ['foo'], + 'redirect_uri' => 'http://foo/bar', + ] + ), + 'file://' . __DIR__ . '/../Utils/private.key' + ), + ] + ); + + try { + /** @var StubResponseType $response */ + $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + } catch (OAuthServerException $e) { + $this->assertEquals($e->getHint(), 'Authorization code has expired'); + } + } + + public function testRespondToAccessTokenRequestRevokedCode() + { + $client = new ClientEntity(); + $client->setIdentifier('foo'); + $client->setRedirectUri('http://foo/bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + $userEntity = new UserEntity(); + $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); + + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); + + $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + $refreshTokenRepositoryMock->method('persistNewRefreshToken')->willReturnSelf(); + + $authCodeRepositoryMock = $this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock(); + $authCodeRepositoryMock->method('isAuthCodeRevoked')->willReturn(true); + + $grant = new AuthCodeGrant( + $authCodeRepositoryMock, + $this->getMock(RefreshTokenRepositoryInterface::class), + $userRepositoryMock, + new \DateInterval('PT10M') + ); + $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $request = new ServerRequest( + [], + [] + , + null, + 'POST', + 'php://input', + [], + [], + [], + [ + 'grant_type' => 'authorization_code', + 'client_id' => 'foo', + 'redirect_uri' => 'http://foo/bar', + 'code' => KeyCrypt::encrypt( + json_encode( + [ + 'auth_code_id' => uniqid(), + 'expire_time' => time() + 3600, + 'client_id' => 'foo', + 'user_id' => 123, + 'scopes' => ['foo'], + 'redirect_uri' => 'http://foo/bar', + ] + ), + 'file://' . __DIR__ . '/../Utils/private.key' + ), + ] + ); + + try { + /** @var StubResponseType $response */ + $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + } catch (OAuthServerException $e) { + $this->assertEquals($e->getHint(), 'Authorization code has been revoked'); + } + } + + public function testRespondToAccessTokenRequestClientMismatch() + { + $client = new ClientEntity(); + $client->setIdentifier('foo'); + $client->setRedirectUri('http://foo/bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + $userEntity = new UserEntity(); + $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); + + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); + + $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + $refreshTokenRepositoryMock->method('persistNewRefreshToken')->willReturnSelf(); + + $grant = new AuthCodeGrant( + $this->getMock(AuthCodeRepositoryInterface::class), + $this->getMock(RefreshTokenRepositoryInterface::class), + $userRepositoryMock, + new \DateInterval('PT10M') + ); + $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $request = new ServerRequest( + [], + [] + , + null, + 'POST', + 'php://input', + [], + [], + [], + [ + 'grant_type' => 'authorization_code', + 'client_id' => 'foo', + 'redirect_uri' => 'http://foo/bar', + 'code' => KeyCrypt::encrypt( + json_encode( + [ + 'auth_code_id' => uniqid(), + 'expire_time' => time() + 3600, + 'client_id' => 'bar', + 'user_id' => 123, + 'scopes' => ['foo'], + 'redirect_uri' => 'http://foo/bar', + ] + ), + 'file://' . __DIR__ . '/../Utils/private.key' + ), + ] + ); + + try { + /** @var StubResponseType $response */ + $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + } catch (OAuthServerException $e) { + $this->assertEquals($e->getHint(), 'Authorization code was not issued to this client'); + } + } + + public function testRespondToAccessTokenRequestBadCodeEncryption() + { + $client = new ClientEntity(); + $client->setIdentifier('foo'); + $client->setRedirectUri('http://foo/bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $userRepositoryMock = $this->getMockBuilder(UserRepositoryInterface::class)->getMock(); + $userEntity = new UserEntity(); + $userRepositoryMock->method('getUserEntityByUserCredentials')->willReturn($userEntity); + + $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); + $accessTokenRepositoryMock->method('persistNewAccessToken')->willReturnSelf(); + + $refreshTokenRepositoryMock = $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(); + $refreshTokenRepositoryMock->method('persistNewRefreshToken')->willReturnSelf(); + + $grant = new AuthCodeGrant( + $this->getMock(AuthCodeRepositoryInterface::class), + $this->getMock(RefreshTokenRepositoryInterface::class), + $userRepositoryMock, + new \DateInterval('PT10M') + ); + $grant->setClientRepository($clientRepositoryMock); + $grant->setAccessTokenRepository($accessTokenRepositoryMock); + $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); + $grant->setPathToPublicKey('file://' . __DIR__ . '/../Utils/public.key'); + $grant->setPathToPrivateKey('file://' . __DIR__ . '/../Utils/private.key'); + + $request = new ServerRequest( + [], + [] + , + null, + 'POST', + 'php://input', + [], + [], + [], + [ + 'grant_type' => 'authorization_code', + 'client_id' => 'foo', + 'redirect_uri' => 'http://foo/bar', + 'code' => 'sdfsfsd', + ] + ); + + try { + /** @var StubResponseType $response */ + $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); + } catch (OAuthServerException $e) { + $this->assertEquals($e->getHint(), 'Cannot decrypt the authorization code'); + } + } } From e08669d50cc2589297f117062757ec5c92b37fc1 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 22 Feb 2016 07:58:12 +0000 Subject: [PATCH 43/49] Doc improvements --- src/Grant/AuthCodeGrant.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 05afc7fd..4d253488 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -208,14 +208,16 @@ class AuthCodeGrant extends AbstractGrant ); } - $stateParameter = $this->getQueryStringParameter('state', $request); - + // The user has either approved or denied the client, so redirect them back $redirectUri = new Uri($client->getRedirectUri()); parse_str($redirectUri->getQuery(), $redirectPayload); + + $stateParameter = $this->getQueryStringParameter('state', $request); if ($stateParameter !== null) { $redirectPayload['state'] = $stateParameter; } + // THe user approved the client, redirect them back with an auth code if ($userHasApprovedClient === true) { $authCode = $this->issueAuthCode( $this->authCodeTTL, @@ -242,6 +244,7 @@ class AuthCodeGrant extends AbstractGrant return new Response\RedirectResponse($redirectUri->withQuery(http_build_query($redirectPayload))); } + // The user denied the client, redirect them back with an error $exception = OAuthServerException::accessDenied('The user denied the request', (string) $redirectUri); return $exception->generateHttpResponse(); From a1bdaae9a94c897a9ee71a76ffa9964504339bd9 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 22 Feb 2016 07:58:25 +0000 Subject: [PATCH 44/49] Access token can now return a JWT from itself --- src/Entities/AccessTokenEntity.php | 23 +++++++++++++++++++ .../Interfaces/AccessTokenEntityInterface.php | 10 ++++++++ 2 files changed, 33 insertions(+) diff --git a/src/Entities/AccessTokenEntity.php b/src/Entities/AccessTokenEntity.php index d95eee31..75bcb4c6 100644 --- a/src/Entities/AccessTokenEntity.php +++ b/src/Entities/AccessTokenEntity.php @@ -2,6 +2,8 @@ namespace League\OAuth2\Server\Entities; +use Lcobucci\JWT\Builder; +use Lcobucci\JWT\Signer\Rsa\Sha256; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\Traits\EntityTrait; use League\OAuth2\Server\Entities\Traits\TokenEntityTrait; @@ -9,4 +11,25 @@ use League\OAuth2\Server\Entities\Traits\TokenEntityTrait; class AccessTokenEntity implements AccessTokenEntityInterface { use EntityTrait, TokenEntityTrait; + + /** + * Generate a JWT from the access token + * + * @param string $pathToPrivateKey + * + * @return string + */ + public function convertToJWT($pathToPrivateKey) + { + return (new Builder()) + ->setAudience($this->getClient()->getIdentifier()) + ->setId($this->getIdentifier(), true) + ->setIssuedAt(time()) + ->setNotBefore(time()) + ->setExpiration($this->getExpiryDateTime()->getTimestamp()) + ->setSubject($this->getUserIdentifier()) + ->set('scopes', $this->getScopes()) + ->sign(new Sha256(), new Key($pathToPrivateKey)) + ->getToken(); + } } diff --git a/src/Entities/Interfaces/AccessTokenEntityInterface.php b/src/Entities/Interfaces/AccessTokenEntityInterface.php index a4252bae..2a7ef985 100644 --- a/src/Entities/Interfaces/AccessTokenEntityInterface.php +++ b/src/Entities/Interfaces/AccessTokenEntityInterface.php @@ -2,6 +2,16 @@ namespace League\OAuth2\Server\Entities\Interfaces; +use Lcobucci\JWT\Builder; + interface AccessTokenEntityInterface extends TokenInterface { + /** + * Generate a JWT from the access token + * + * @param string $pathToPrivateKey + * + * @return string + */ + public function convertToJWT($pathToPrivateKey); } From ad270f7d9df097a8fb910b64fc866844eb5c1032 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 22 Feb 2016 07:58:44 +0000 Subject: [PATCH 45/49] Redirect either with query string parameters or fragment parameters --- src/Exception/OAuthServerException.php | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/Exception/OAuthServerException.php b/src/Exception/OAuthServerException.php index af9379d9..3bd4e934 100644 --- a/src/Exception/OAuthServerException.php +++ b/src/Exception/OAuthServerException.php @@ -191,10 +191,12 @@ class OAuthServerException extends \Exception * Generate a HTTP response. * * @param \Psr\Http\Message\ResponseInterface $response + * @param bool $useFragment True if errors should be in the URI fragment instead of + * query string * * @return \Psr\Http\Message\ResponseInterface */ - public function generateHttpResponse(ResponseInterface $response = null) + public function generateHttpResponse(ResponseInterface $response = null, $useFragment = false) { if (!$response instanceof ResponseInterface) { $response = new Response(); @@ -215,9 +217,15 @@ class OAuthServerException extends \Exception $redirectUri = new Uri($this->redirectUri); parse_str($redirectUri->getQuery(), $redirectPayload); - $headers['Location'] = (string) $redirectUri->withQuery(http_build_query( - array_merge($redirectPayload, $payload) - )); + if ($useFragment === true) { + $headers['Location'] = (string) $redirectUri->withFragment(http_build_query( + array_merge($redirectPayload, $payload) + )); + } else { + $headers['Location'] = (string) $redirectUri->withQuery(http_build_query( + array_merge($redirectPayload, $payload) + )); + } } foreach ($headers as $header => $content) { From 0d0aaa8764f091b5647d1f3aced732edf9fd67ff Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 22 Feb 2016 07:58:59 +0000 Subject: [PATCH 46/49] Use the new access token covertToJWT method --- src/ResponseTypes/BearerTokenResponse.php | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/ResponseTypes/BearerTokenResponse.php b/src/ResponseTypes/BearerTokenResponse.php index 28e9003a..a1da1fe8 100644 --- a/src/ResponseTypes/BearerTokenResponse.php +++ b/src/ResponseTypes/BearerTokenResponse.php @@ -29,16 +29,7 @@ class BearerTokenResponse extends AbstractResponseType { $expireDateTime = $this->accessToken->getExpiryDateTime()->getTimestamp(); - $jwtAccessToken = (new Builder()) - ->setAudience($this->accessToken->getClient()->getIdentifier()) - ->setId($this->accessToken->getIdentifier(), true) - ->setIssuedAt(time()) - ->setNotBefore(time()) - ->setExpiration($expireDateTime) - ->setSubject($this->accessToken->getUserIdentifier()) - ->set('scopes', $this->accessToken->getScopes()) - ->sign(new Sha256(), new Key($this->pathToPrivateKey)) - ->getToken(); + $jwtAccessToken = $this->accessToken->convertToJWT($this->pathToPrivateKey); $responseParams = [ 'token_type' => 'Bearer', From e2794c47afdf5667d774d97b6a6d88710f515964 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 22 Feb 2016 07:59:17 +0000 Subject: [PATCH 47/49] First commit of the implicit grant --- src/Grant/ImplicitGrant.php | 242 ++++++++++++++++++++++++++++++++++++ 1 file changed, 242 insertions(+) create mode 100644 src/Grant/ImplicitGrant.php diff --git a/src/Grant/ImplicitGrant.php b/src/Grant/ImplicitGrant.php new file mode 100644 index 00000000..959c69b2 --- /dev/null +++ b/src/Grant/ImplicitGrant.php @@ -0,0 +1,242 @@ +userRepository = $userRepository; + $this->refreshTokenTTL = new \DateInterval('P1M'); + + $this->pathToLoginTemplate = __DIR__ . '/../ResponseTypes/DefaultTemplates/login_user'; + if ($pathToLoginTemplate !== null) { + $this->pathToLoginTemplate = (substr($pathToLoginTemplate, -4) === '.php') + ? substr($pathToLoginTemplate, 0, -4) + : $pathToLoginTemplate; + } + + $this->pathToAuthorizeTemplate = __DIR__ . '/../ResponseTypes/DefaultTemplates/authorize_client'; + if ($pathToAuthorizeTemplate !== null) { + $this->pathToAuthorizeTemplate = (substr($pathToAuthorizeTemplate, -4) === '.php') + ? substr($pathToAuthorizeTemplate, 0, -4) + : $pathToAuthorizeTemplate; + } + } + + /** + * {@inheritdoc} + */ + public function canRespondToRequest(ServerRequestInterface $request) + { + return (array_key_exists('response_type', $request->getQueryParams()) + && $request->getQueryParams()['response_type'] === 'token'); + } + + /** + * Return the grant identifier that can be used in matching up requests. + * + * @return string + */ + public function getIdentifier() + { + return 'implicit'; + } + + /** + * {@inheritdoc} + */ + public function respondToRequest( + ServerRequestInterface $request, + ResponseTypeInterface $responseType, + \DateInterval $accessTokenTTL + ) { + $clientId = $this->getQueryStringParameter( + 'client_id', + $request, + $this->getServerParameter('PHP_AUTH_USER', $request) + ); + if (is_null($clientId)) { + throw OAuthServerException::invalidRequest('client_id'); + } + + $client = $this->clientRepository->getClientEntity( + $clientId, + $this->getIdentifier() + ); + + if ($client instanceof ClientEntityInterface === false) { + $this->getEmitter()->emit(new Event('client.authentication.failed', $request)); + + throw OAuthServerException::invalidClient(); + } + + $redirectUriParameter = $this->getQueryStringParameter('redirect_uri', $request, $client->getRedirectUri()); + if ($redirectUriParameter !== $client->getRedirectUri()) { + $this->getEmitter()->emit(new Event('client.authentication.failed', $request)); + + throw OAuthServerException::invalidClient(); + } + + $scopes = $this->validateScopes($request, $client, $client->getRedirectUri()); + $queryString = http_build_query($request->getQueryParams()); + $postbackUri = new Uri( + sprintf( + '//%s%s', + $request->getServerParams()['HTTP_HOST'], + $request->getServerParams()['REQUEST_URI'] + ) + ); + + $userId = null; + $userHasApprovedClient = null; + if ($this->getRequestParameter('action', $request, null) !== null) { + $userHasApprovedClient = ($this->getRequestParameter('action', $request) === 'approve'); + } + + // Check if the user has been authenticated + $oauthCookie = $this->getCookieParameter('oauth_authorize_request', $request, null); + if ($oauthCookie !== null) { + try { + $oauthCookiePayload = json_decode(KeyCrypt::decrypt($oauthCookie, $this->pathToPublicKey)); + if (is_object($oauthCookiePayload)) { + $userId = $oauthCookiePayload->user_id; + } + } catch (\LogicException $e) { + throw OAuthServerException::serverError($e->getMessage()); + } + } + + // The username + password might be available in $_POST + $usernameParameter = $this->getRequestParameter('username', $request, null); + $passwordParameter = $this->getRequestParameter('password', $request, null); + + $loginError = null; + + // Assert if the user has logged in already + if ($userId === null && $usernameParameter !== null && $passwordParameter !== null) { + $userEntity = $this->userRepository->getUserEntityByUserCredentials( + $usernameParameter, + $passwordParameter + ); + + if ($userEntity instanceof UserEntityInterface) { + $userId = $userEntity->getIdentifier(); + } else { + $loginError = 'Incorrect username or password'; + } + } + + // The user hasn't logged in yet so show a login form + if ($userId === null) { + $engine = new Engine(dirname($this->pathToLoginTemplate)); + $pathParts = explode(DIRECTORY_SEPARATOR, $this->pathToLoginTemplate); + $html = $engine->render( + end($pathParts), + [ + 'error' => $loginError, + 'postback_uri' => (string) $postbackUri->withQuery($queryString), + ] + ); + + return new Response\HtmlResponse($html); + } + + // The user hasn't approved the client yet so show an authorize form + if ($userId !== null && $userHasApprovedClient === null) { + $engine = new Engine(dirname($this->pathToAuthorizeTemplate)); + $pathParts = explode(DIRECTORY_SEPARATOR, $this->pathToAuthorizeTemplate); + $html = $engine->render( + end($pathParts), + [ + 'client' => $client, + 'scopes' => $scopes, + 'postback_uri' => (string) $postbackUri->withQuery($queryString), + ] + ); + + return new Response\HtmlResponse( + $html, + 200, + [ + 'Set-Cookie' => sprintf( + 'oauth_authorize_request=%s; Expires=%s', + urlencode(KeyCrypt::encrypt( + json_encode([ + 'user_id' => $userId, + ]), + $this->pathToPrivateKey + )), + (new \DateTime())->add(new \DateInterval('PT5M'))->format('D, d M Y H:i:s e') + ), + ] + ); + } + + // The user has either approved or denied the client, so redirect them back + $redirectUri = new Uri($client->getRedirectUri()); + $redirectPayload = []; + + $stateParameter = $this->getQueryStringParameter('state', $request); + if ($stateParameter !== null) { + $redirectPayload['state'] = $stateParameter; + } + + // THe user approved the client, redirect them back with an access token + if ($userHasApprovedClient === true) { + $accessToken = $this->issueAccessToken( + $accessTokenTTL, + $client, + $userId, + $scopes + ); + + $redirectPayload['access_token'] = $accessToken->convertToJWT($this->pathToPrivateKey); + $redirectPayload['token_type'] = 'bearer'; + $redirectPayload['expires_in'] = time() - $accessToken->getExpiryDateTime()->getTimestamp(); + + return new Response\RedirectResponse($redirectUri->withFragment(http_build_query($redirectPayload))); + } + + // The user denied the client, redirect them back with an error + $exception = OAuthServerException::accessDenied('The user denied the request', (string) $redirectUri); + + return $exception->generateHttpResponse(null, true); + } +} From 997d390f3d60734b02cf6cc48f2d54da62dbcfe0 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 22 Feb 2016 03:00:50 -0500 Subject: [PATCH 48/49] Applied fixes from StyleCI --- examples/public/auth_code.php | 6 +- examples/public/client_credentials.php | 6 +- examples/public/middleware_authentication.php | 6 +- examples/public/password.php | 6 +- examples/public/protected_api.php | 6 +- examples/public/refresh_token.php | 6 +- .../Interfaces/AccessTokenEntityInterface.php | 2 - src/Exception/OAuthServerException.php | 1 + src/Grant/AbstractGrant.php | 1 - src/Grant/ImplicitGrant.php | 1 - src/Grant/RefreshTokenGrant.php | 8 +-- src/ResponseTypes/BearerTokenResponse.php | 2 - tests/Bootstrap.php | 2 +- tests/Grant/AuthCodeGrantTest.php | 72 +++++++------------ tests/Grant/PasswordGrantTest.php | 1 - tests/Utils/KeyCryptTest.php | 8 +-- 16 files changed, 55 insertions(+), 79 deletions(-) diff --git a/examples/public/auth_code.php b/examples/public/auth_code.php index d15a1561..998101dc 100644 --- a/examples/public/auth_code.php +++ b/examples/public/auth_code.php @@ -13,7 +13,7 @@ use Slim\App; use Slim\Http\Request; use Slim\Http\Response; -include __DIR__.'/../vendor/autoload.php'; +include __DIR__ . '/../vendor/autoload.php'; // App $app = new App([ @@ -27,8 +27,8 @@ $app = new App([ $refreshTokenRepository = new RefreshTokenRepository(); $authCodeRepository = new AuthCodeRepository(); - $privateKeyPath = 'file://'.__DIR__.'/../private.key'; - $publicKeyPath = 'file://'.__DIR__.'/../public.key'; + $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; + $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; // Setup the authorization server $server = new Server( diff --git a/examples/public/client_credentials.php b/examples/public/client_credentials.php index 48ee0b6f..a36207ee 100644 --- a/examples/public/client_credentials.php +++ b/examples/public/client_credentials.php @@ -10,7 +10,7 @@ use Slim\App; use Slim\Http\Request; use Slim\Http\Response; -include __DIR__.'/../vendor/autoload.php'; +include __DIR__ . '/../vendor/autoload.php'; // App $app = new App([ @@ -21,8 +21,8 @@ $app = new App([ $scopeRepository = new ScopeRepository(); $accessTokenRepository = new AccessTokenRepository(); - $privateKeyPath = 'file://'.__DIR__.'/../private.key'; - $publicKeyPath = 'file://'.__DIR__.'/../public.key'; + $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; + $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; // Setup the authorization server $server = new Server( diff --git a/examples/public/middleware_authentication.php b/examples/public/middleware_authentication.php index 27f03c5a..f5790687 100644 --- a/examples/public/middleware_authentication.php +++ b/examples/public/middleware_authentication.php @@ -11,7 +11,7 @@ use OAuth2ServerExamples\Repositories\ScopeRepository; use OAuth2ServerExamples\Repositories\UserRepository; use Slim\App; -include __DIR__.'/../vendor/autoload.php'; +include __DIR__ . '/../vendor/autoload.php'; // App $app = new App([ @@ -27,8 +27,8 @@ $app = new App([ $userRepository = new UserRepository(); $refreshTokenRepository = new RefreshTokenRepository(); - $privateKeyPath = 'file://'.__DIR__.'/../private.key'; - $publicKeyPath = 'file://'.__DIR__.'/../public.key'; + $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; + $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; // Setup the authorization server $server = new Server( diff --git a/examples/public/password.php b/examples/public/password.php index 4c0548b4..aa4f75dc 100644 --- a/examples/public/password.php +++ b/examples/public/password.php @@ -12,7 +12,7 @@ use Slim\App; use Slim\Http\Request; use Slim\Http\Response; -include __DIR__.'/../vendor/autoload.php'; +include __DIR__ . '/../vendor/autoload.php'; // App $app = new App([ @@ -25,8 +25,8 @@ $app = new App([ $userRepository = new UserRepository(); $refreshTokenRepository = new RefreshTokenRepository(); - $privateKeyPath = 'file://'.__DIR__.'/../private.key'; - $publicKeyPath = 'file://'.__DIR__.'/../public.key'; + $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; + $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; // Setup the authorization server $server = new Server( diff --git a/examples/public/protected_api.php b/examples/public/protected_api.php index 35b829ae..6e502fba 100644 --- a/examples/public/protected_api.php +++ b/examples/public/protected_api.php @@ -9,7 +9,7 @@ use Slim\App; use Slim\Http\Request; use Slim\Http\Response; -include __DIR__.'/../vendor/autoload.php'; +include __DIR__ . '/../vendor/autoload.php'; // App $app = new App([ @@ -23,8 +23,8 @@ $app = new App([ $scopeRepository = new ScopeRepository(); $accessTokenRepository = new AccessTokenRepository(); - $privateKeyPath = 'file://'.__DIR__.'/../private.key'; - $publicKeyPath = 'file://'.__DIR__.'/../public.key'; + $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; + $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; // Setup the authorization server $server = new Server( diff --git a/examples/public/refresh_token.php b/examples/public/refresh_token.php index 6ecf5122..bbec33e3 100644 --- a/examples/public/refresh_token.php +++ b/examples/public/refresh_token.php @@ -11,7 +11,7 @@ use Slim\App; use Slim\Http\Request; use Slim\Http\Response; -include __DIR__.'/../vendor/autoload.php'; +include __DIR__ . '/../vendor/autoload.php'; // App $app = new App([Server::class => function () { @@ -21,8 +21,8 @@ $app = new App([Server::class => function () { $accessTokenRepository = new AccessTokenRepository(); $refreshTokenRepository = new RefreshTokenRepository(); - $privateKeyPath = 'file://'.__DIR__.'/../private.key'; - $publicKeyPath = 'file://'.__DIR__.'/../public.key'; + $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; + $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; // Setup the authorization server $server = new Server( diff --git a/src/Entities/Interfaces/AccessTokenEntityInterface.php b/src/Entities/Interfaces/AccessTokenEntityInterface.php index 2a7ef985..884c0187 100644 --- a/src/Entities/Interfaces/AccessTokenEntityInterface.php +++ b/src/Entities/Interfaces/AccessTokenEntityInterface.php @@ -2,8 +2,6 @@ namespace League\OAuth2\Server\Entities\Interfaces; -use Lcobucci\JWT\Builder; - interface AccessTokenEntityInterface extends TokenInterface { /** diff --git a/src/Exception/OAuthServerException.php b/src/Exception/OAuthServerException.php index 3bd4e934..7b8a1016 100644 --- a/src/Exception/OAuthServerException.php +++ b/src/Exception/OAuthServerException.php @@ -50,6 +50,7 @@ class OAuthServerException extends \Exception /** * Invalid grant type error. + * * @return static */ public static function invalidGrantType() diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index 407ae4db..a7b5fbd1 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -16,7 +16,6 @@ use League\Event\Event; use League\OAuth2\Server\Entities\AccessTokenEntity; use League\OAuth2\Server\Entities\AuthCodeEntity; use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; -use League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface; use League\OAuth2\Server\Entities\RefreshTokenEntity; use League\OAuth2\Server\Entities\ScopeEntity; use League\OAuth2\Server\Exception\OAuthServerException; diff --git a/src/Grant/ImplicitGrant.php b/src/Grant/ImplicitGrant.php index 959c69b2..8123550e 100644 --- a/src/Grant/ImplicitGrant.php +++ b/src/Grant/ImplicitGrant.php @@ -2,7 +2,6 @@ namespace League\OAuth2\Server\Grant; -use DateInterval; use League\Event\Event; use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface; use League\OAuth2\Server\Entities\Interfaces\UserEntityInterface; diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index 19bab077..83ffe5ed 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -102,7 +102,7 @@ class RefreshTokenGrant extends AbstractGrant try { $refreshToken = KeyCrypt::decrypt($encryptedRefreshToken, $this->pathToPublicKey); } catch (\LogicException $e) { - throw OAuthServerException::invalidRefreshToken('Cannot parse refresh token: '.$e->getMessage()); + throw OAuthServerException::invalidRefreshToken('Cannot parse refresh token: ' . $e->getMessage()); } $refreshTokenData = json_decode($refreshToken, true); @@ -110,9 +110,9 @@ class RefreshTokenGrant extends AbstractGrant $this->getEmitter()->emit(new Event('refresh_token.client.failed', $request)); throw OAuthServerException::invalidRefreshToken( - 'Token is not linked to client,'. - ' got: '.$clientId. - ' expected: '.$refreshTokenData['client_id'] + 'Token is not linked to client,' . + ' got: ' . $clientId . + ' expected: ' . $refreshTokenData['client_id'] ); } diff --git a/src/ResponseTypes/BearerTokenResponse.php b/src/ResponseTypes/BearerTokenResponse.php index a1da1fe8..fdbe73b0 100644 --- a/src/ResponseTypes/BearerTokenResponse.php +++ b/src/ResponseTypes/BearerTokenResponse.php @@ -10,9 +10,7 @@ */ namespace League\OAuth2\Server\ResponseTypes; -use Lcobucci\JWT\Builder; use Lcobucci\JWT\Parser; -use Lcobucci\JWT\Signer\Key; use Lcobucci\JWT\Signer\Rsa\Sha256; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; diff --git a/tests/Bootstrap.php b/tests/Bootstrap.php index 8ea9bc26..99c00e16 100644 --- a/tests/Bootstrap.php +++ b/tests/Bootstrap.php @@ -1,5 +1,5 @@ wget http://getcomposer.org/composer.phar\n> php composer.phar install\n"); } diff --git a/tests/Grant/AuthCodeGrantTest.php b/tests/Grant/AuthCodeGrantTest.php index d5764843..1508329c 100644 --- a/tests/Grant/AuthCodeGrantTest.php +++ b/tests/Grant/AuthCodeGrantTest.php @@ -7,16 +7,15 @@ use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\AuthCodeGrant; +use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; -use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\UserRepositoryInterface; use League\OAuth2\Server\Utils\KeyCrypt; use LeagueTests\Stubs\StubResponseType; use LeagueTests\Stubs\UserEntity; use Psr\Http\Message\ResponseInterface; -use Zend\Diactoros\Response; use Zend\Diactoros\ServerRequest; class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase @@ -46,8 +45,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $request = new ServerRequest( [], - [] - , + [], null, null, 'php://input', @@ -90,8 +88,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'HTTP_HOST' => 'auth-server.tld', 'REQUEST_URI' => '/authorize', ], - [] - , + [], null, 'POST', 'php://input', @@ -148,8 +145,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'HTTP_HOST' => 'auth-server.tld', 'REQUEST_URI' => '/authorize', ], - [] - , + [], null, 'POST', 'php://input', @@ -211,8 +207,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'HTTP_HOST' => 'auth-server.tld', 'REQUEST_URI' => '/authorize', ], - [] - , + [], null, 'POST', 'php://input', @@ -263,8 +258,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'HTTP_HOST' => 'auth-server.tld', 'REQUEST_URI' => '/authorize', ], - [] - , + [], null, 'POST', 'php://input', @@ -287,7 +281,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase ); try { - /** @var StubResponseType $response */ + /* @var StubResponseType $response */ $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); } catch (OAuthServerException $e) { $this->assertEquals($e->getMessage(), 'Client authentication failed'); @@ -319,8 +313,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'HTTP_HOST' => 'auth-server.tld', 'REQUEST_URI' => '/authorize', ], - [] - , + [], null, 'POST', 'php://input', @@ -334,7 +327,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase [ 'response_type' => 'code', 'client_id' => 'foo', - 'redirect_uri' => 'sdfsdf' + 'redirect_uri' => 'sdfsdf', ], [ 'username' => 'alex', @@ -344,7 +337,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase ); try { - /** @var StubResponseType $response */ + /* @var StubResponseType $response */ $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); } catch (OAuthServerException $e) { $this->assertEquals($e->getMessage(), 'Client authentication failed'); @@ -383,8 +376,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'HTTP_HOST' => 'auth-server.tld', 'REQUEST_URI' => '/authorize', ], - [] - , + [], null, 'POST', 'php://input', @@ -436,8 +428,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'HTTP_HOST' => 'auth-server.tld', 'REQUEST_URI' => '/authorize', ], - [] - , + [], null, 'POST', 'php://input', @@ -491,8 +482,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'HTTP_HOST' => 'auth-server.tld', 'REQUEST_URI' => '/authorize', ], - [] - , + [], null, 'POST', 'php://input', @@ -547,8 +537,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'HTTP_HOST' => 'auth-server.tld', 'REQUEST_URI' => '/authorize', ], - [] - , + [], null, 'POST', 'php://input', @@ -607,8 +596,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $request = new ServerRequest( [], - [] - , + [], null, 'POST', 'php://input', @@ -667,8 +655,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $request = new ServerRequest( [], - [] - , + [], null, 'POST', 'php://input', @@ -680,7 +667,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase ] ); - /** @var StubResponseType $response */ + /* @var StubResponseType $response */ $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); } @@ -714,8 +701,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $request = new ServerRequest( [], - [] - , + [], null, 'POST', 'php://input', @@ -730,7 +716,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase ] ); - /** @var StubResponseType $response */ + /* @var StubResponseType $response */ $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); } @@ -766,8 +752,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $request = new ServerRequest( [], - [] - , + [], null, 'POST', 'php://input', @@ -795,7 +780,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase ); try { - /** @var StubResponseType $response */ + /* @var StubResponseType $response */ $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); } catch (OAuthServerException $e) { $this->assertEquals($e->getHint(), 'Authorization code has expired'); @@ -837,8 +822,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $request = new ServerRequest( [], - [] - , + [], null, 'POST', 'php://input', @@ -866,7 +850,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase ); try { - /** @var StubResponseType $response */ + /* @var StubResponseType $response */ $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); } catch (OAuthServerException $e) { $this->assertEquals($e->getHint(), 'Authorization code has been revoked'); @@ -905,8 +889,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $request = new ServerRequest( [], - [] - , + [], null, 'POST', 'php://input', @@ -934,7 +917,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase ); try { - /** @var StubResponseType $response */ + /* @var StubResponseType $response */ $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); } catch (OAuthServerException $e) { $this->assertEquals($e->getHint(), 'Authorization code was not issued to this client'); @@ -973,8 +956,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $request = new ServerRequest( [], - [] - , + [], null, 'POST', 'php://input', @@ -990,7 +972,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase ); try { - /** @var StubResponseType $response */ + /* @var StubResponseType $response */ $grant->respondToRequest($request, new StubResponseType(), new \DateInterval('PT10M')); } catch (OAuthServerException $e) { $this->assertEquals($e->getHint(), 'Cannot decrypt the authorization code'); diff --git a/tests/Grant/PasswordGrantTest.php b/tests/Grant/PasswordGrantTest.php index 096f374e..e4f9e3a9 100644 --- a/tests/Grant/PasswordGrantTest.php +++ b/tests/Grant/PasswordGrantTest.php @@ -5,7 +5,6 @@ namespace LeagueTests\Grant; use League\OAuth2\Server\Entities\ClientEntity; use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface; -use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\PasswordGrant; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; diff --git a/tests/Utils/KeyCryptTest.php b/tests/Utils/KeyCryptTest.php index 9720dbd3..3fa1f17c 100644 --- a/tests/Utils/KeyCryptTest.php +++ b/tests/Utils/KeyCryptTest.php @@ -9,8 +9,8 @@ class KeyCryptTest extends \PHPUnit_Framework_TestCase public function testEncryptDecrypt() { $payload = 'alex loves whisky'; - $encrypted = KeyCrypt::encrypt($payload, 'file://'.__DIR__.'/private.key'); - $plainText = KeyCrypt::decrypt($encrypted, 'file://'.__DIR__.'/public.key'); + $encrypted = KeyCrypt::encrypt($payload, 'file://' . __DIR__ . '/private.key'); + $plainText = KeyCrypt::decrypt($encrypted, 'file://' . __DIR__ . '/public.key'); $this->assertNotEquals($payload, $encrypted); $this->assertEquals($payload, $plainText); @@ -21,7 +21,7 @@ class KeyCryptTest extends \PHPUnit_Framework_TestCase */ public function testBadPrivateKey() { - KeyCrypt::encrypt('', 'file://'.__DIR__.'/public.key'); + KeyCrypt::encrypt('', 'file://' . __DIR__ . '/public.key'); } /** @@ -29,6 +29,6 @@ class KeyCryptTest extends \PHPUnit_Framework_TestCase */ public function testBadPublicKey() { - KeyCrypt::decrypt('', 'file://'.__DIR__.'/private.key'); + KeyCrypt::decrypt('', 'file://' . __DIR__ . '/private.key'); } } From da53067e6372421e33c84cdfb3420a98581a91e4 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Mon, 22 Feb 2016 11:04:03 +0000 Subject: [PATCH 49/49] Updated README --- README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8c3c3ca1..29e0e0e2 100644 --- a/README.md +++ b/README.md @@ -5,18 +5,19 @@ [![Build Status](https://img.shields.io/travis/thephpleague/oauth2-server/master.svg?style=flat-square)](https://travis-ci.org/thephpleague/oauth2-server) [![Coverage Status](https://img.shields.io/scrutinizer/coverage/g/thephpleague/oauth2-server.svg?style=flat-square)](https://scrutinizer-ci.com/g/thephpleague/oauth2-server/code-structure) [![Quality Score](https://img.shields.io/scrutinizer/g/thephpleague/oauth2-server.svg?style=flat-square)](https://scrutinizer-ci.com/g/thephpleague/oauth2-server) -[![Total Downloads](https://img.shields.io/packagist/dt/league/oauth2-server.svg?style=flat-square)](https://packagist.org/packages/league/oauth2-server) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/thephpleague/oauth2-server?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) +[![Total Downloads](https://img.shields.io/packagist/dt/league/oauth2-server.svg?style=flat-square)](https://packagist.org/packages/league/oauth2-server) `league/oauth2-server` is a a standards compliant implementation of an [OAuth 2.0](https://tools.ietf.org/html/rfc6749) authorization server written in PHP which makes working with OAuth 2.0 trivial. You can easily configure an OAuth 2.0 server to protect your API with access tokens, or allow clients to request new access tokens and refresh them. It supports out of the box the following grants: * Authorization code grant +* Implicit grant * Client credentials grant * Resource owner password credentials grant * Refresh grant -You can also define your own grants. +You can also easily define your own grants. In addition it supports the following token response types: @@ -49,7 +50,9 @@ Please see [CONTRIBUTING.md](https://github.com/thephpleague/oauth2-server/blob/ ## Support -Bugs and feature request are tracked on [GitHub](https://github.com/thephpleague/oauth2-server/issues) +Bugs and feature request are tracked on [GitHub](https://github.com/thephpleague/oauth2-server/issues). + +If you have any questions about OAuth _please_ open a ticket here; please **don't** email the address below. ## Security