From 518c1fcec57a170e09649df38738e06e6e7cbd46 Mon Sep 17 00:00:00 2001 From: George Wilson Date: Tue, 8 Nov 2016 12:27:49 +0000 Subject: [PATCH 01/55] Fix middleware example fatal error --- examples/public/middleware_use.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/examples/public/middleware_use.php b/examples/public/middleware_use.php index 2dfe1834..68b4ebc1 100644 --- a/examples/public/middleware_use.php +++ b/examples/public/middleware_use.php @@ -8,6 +8,7 @@ */ use League\OAuth2\Server\AuthorizationServer; +use League\OAuth2\Server\ResourceServer; use League\OAuth2\Server\Grant\AuthCodeGrant; use League\OAuth2\Server\Grant\RefreshTokenGrant; use League\OAuth2\Server\Middleware\AuthorizationServerMiddleware; @@ -66,6 +67,15 @@ $app = new App([ return $server; }, + ResourceServer::class => function () { + $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; + + $server = new ResourceServer( + new AccessTokenRepository(), + $publicKeyPath + ); + return $server; + }, ]); // Access token issuer @@ -94,6 +104,6 @@ $app->group('/api', function () { return $response->withBody($body); }); -})->add(new ResourceServerMiddleware($app->getContainer()->get(AuthorizationServer::class))); +})->add(new ResourceServerMiddleware($app->getContainer()->get(ResourceServer::class))); $app->run(); From 90cb1bf012b8d1643f68593f3c1ee154d64d7ebd Mon Sep 17 00:00:00 2001 From: Sam Stenvall Date: Fri, 23 Dec 2016 00:30:54 +0200 Subject: [PATCH 02/55] Fix typo in the first README sentence --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index de5f3471..dfaa938c 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ [![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) -`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. +`league/oauth2-server` is 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: From ded7c1ed47dd5f7cdf7af6409c47e5bdfada9313 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 2 Feb 2017 17:29:06 +0000 Subject: [PATCH 03/55] Mentioned PHP 7.1 support --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index dfaa938c..8da0cf44 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ The following versions of PHP are supported: * PHP 5.5 (>=5.5.9) * PHP 5.6 * PHP 7.0 +* PHP 7.1 * HHVM The `openssl` extension is also required. From 13c608b849a6d805f119bf046651363171d6fe51 Mon Sep 17 00:00:00 2001 From: Toby Griffiths Date: Wed, 1 Mar 2017 13:08:42 +0000 Subject: [PATCH 04/55] Corrected DateInterval from 1 min to 1 month --- examples/public/middleware_use.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/public/middleware_use.php b/examples/public/middleware_use.php index 68b4ebc1..21f6bc23 100644 --- a/examples/public/middleware_use.php +++ b/examples/public/middleware_use.php @@ -62,7 +62,7 @@ $app = new App([ // Enable the refresh token grant on the server with a token TTL of 1 month $server->enableGrantType( new RefreshTokenGrant($refreshTokenRepository), - new \DateInterval('PT1M') + new \DateInterval('P1M') ); return $server; From 83228bdcd52e47c1824cfcc394b74bed97eb10a0 Mon Sep 17 00:00:00 2001 From: Dave Marshall Date: Mon, 27 Mar 2017 12:11:25 +0100 Subject: [PATCH 05/55] Change case for implict grant token_type --- src/Grant/ImplicitGrant.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Grant/ImplicitGrant.php b/src/Grant/ImplicitGrant.php index 62a48147..466f32ce 100644 --- a/src/Grant/ImplicitGrant.php +++ b/src/Grant/ImplicitGrant.php @@ -200,7 +200,7 @@ class ImplicitGrant extends AbstractAuthorizeGrant $finalRedirectUri, [ 'access_token' => (string) $accessToken->convertToJWT($this->privateKey), - 'token_type' => 'bearer', + 'token_type' => 'Bearer', 'expires_in' => $accessToken->getExpiryDateTime()->getTimestamp() - (new \DateTime())->getTimestamp(), 'state' => $authorizationRequest->getState(), ], From 170ce2fd2d238a6c0cba46dbb4d27f28089f35b8 Mon Sep 17 00:00:00 2001 From: Diogo Oliveira de Melo Date: Fri, 30 Jun 2017 15:42:23 -0300 Subject: [PATCH 06/55] Replaces array_key_exists by isset, which is faster, on ImplicitGrant. --- src/Grant/ImplicitGrant.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Grant/ImplicitGrant.php b/src/Grant/ImplicitGrant.php index 62a48147..2ec9aed7 100644 --- a/src/Grant/ImplicitGrant.php +++ b/src/Grant/ImplicitGrant.php @@ -95,8 +95,8 @@ class ImplicitGrant extends AbstractAuthorizeGrant public function canRespondToAuthorizationRequest(ServerRequestInterface $request) { return ( - array_key_exists('response_type', $request->getQueryParams()) - && $request->getQueryParams()['response_type'] === 'token' + isset($request->getQueryParams()['response_type']) + && 'token' === $request->getQueryParams()['response_type'] && isset($request->getQueryParams()['client_id']) ); } From 6bdd108145d16af2f0493d29c45eef988088bd87 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 16 Jun 2017 16:51:16 +0100 Subject: [PATCH 07/55] Escape scope parameter to reduce pontential XSS vector --- src/Exception/OAuthServerException.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Exception/OAuthServerException.php b/src/Exception/OAuthServerException.php index 6ffa0fb1..6cd82bb3 100644 --- a/src/Exception/OAuthServerException.php +++ b/src/Exception/OAuthServerException.php @@ -105,7 +105,10 @@ class OAuthServerException extends \Exception public static function invalidScope($scope, $redirectUri = null) { $errorMessage = 'The requested scope is invalid, unknown, or malformed'; - $hint = sprintf('Check the `%s` scope', $scope); + $hint = sprintf( + 'Check the `%s` scope', + htmlspecialchars($scope, ENT_QUOTES, 'UTF-8', false) + ); return new static($errorMessage, 5, 'invalid_scope', 400, $hint, $redirectUri); } From 57d199b88962c4f462719a55eb72cdb373efc7aa Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 16 Jun 2017 16:52:36 +0100 Subject: [PATCH 08/55] Stricter validation of code challenge value to match RFC 7636 requirements --- src/Grant/AuthCodeGrant.php | 7 ++ tests/Grant/AuthCodeGrantTest.php | 113 +++++++++++++++++++++++++++++- 2 files changed, 119 insertions(+), 1 deletion(-) diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index df89400e..119c1f96 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -264,6 +264,13 @@ class AuthCodeGrant extends AbstractAuthorizeGrant throw OAuthServerException::invalidRequest('code_challenge'); } + if (preg_match("/^[A-Za-z0-9-._~]{43,128}$/", $codeChallenge) !== 1) { + throw OAuthServerException::invalidRequest( + 'code_challenge', + 'The code_challenge must be between 43 and 128 characters' + ); + } + $codeChallengeMethod = $this->getQueryStringParameter('code_challenge_method', $request, 'plain'); if (in_array($codeChallengeMethod, ['plain', 'S256']) === false) { throw OAuthServerException::invalidRequest( diff --git a/tests/Grant/AuthCodeGrantTest.php b/tests/Grant/AuthCodeGrantTest.php index 498fdb4e..63c9042a 100644 --- a/tests/Grant/AuthCodeGrantTest.php +++ b/tests/Grant/AuthCodeGrantTest.php @@ -164,13 +164,124 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase 'response_type' => 'code', 'client_id' => 'foo', 'redirect_uri' => 'http://foo/bar', - 'code_challenge' => 'FOOBAR', + 'code_challenge' => str_repeat('A', 43), ] ); $this->assertTrue($grant->validateAuthorizationRequest($request) instanceof AuthorizationRequest); } + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + */ + public function testValidateAuthorizationRequestCodeChallengeInvalidLengthTooShort() + { + $client = new ClientEntity(); + $client->setRedirectUri('http://foo/bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $grant = new AuthCodeGrant( + $this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock(), + $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(), + new \DateInterval('PT10M') + ); + $grant->enableCodeExchangeProof(); + $grant->setClientRepository($clientRepositoryMock); + + $request = new ServerRequest( + [], + [], + null, + null, + 'php://input', + [], + [], + [ + 'response_type' => 'code', + 'client_id' => 'foo', + 'redirect_uri' => 'http://foo/bar', + 'code_challenge' => str_repeat('A', 42), + ] + ); + + $grant->validateAuthorizationRequest($request); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + */ + public function testValidateAuthorizationRequestCodeChallengeInvalidLengthTooLong() + { + $client = new ClientEntity(); + $client->setRedirectUri('http://foo/bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $grant = new AuthCodeGrant( + $this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock(), + $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(), + new \DateInterval('PT10M') + ); + $grant->enableCodeExchangeProof(); + $grant->setClientRepository($clientRepositoryMock); + + $request = new ServerRequest( + [], + [], + null, + null, + 'php://input', + [], + [], + [ + 'response_type' => 'code', + 'client_id' => 'foo', + 'redirect_uri' => 'http://foo/bar', + 'code_challenge' => str_repeat('A', 129), + ] + ); + + $grant->validateAuthorizationRequest($request); + } + + /** + * @expectedException \League\OAuth2\Server\Exception\OAuthServerException + */ + public function testValidateAuthorizationRequestCodeChallengeInvalidCharacters() + { + $client = new ClientEntity(); + $client->setRedirectUri('http://foo/bar'); + $clientRepositoryMock = $this->getMockBuilder(ClientRepositoryInterface::class)->getMock(); + $clientRepositoryMock->method('getClientEntity')->willReturn($client); + + $grant = new AuthCodeGrant( + $this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock(), + $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(), + new \DateInterval('PT10M') + ); + $grant->enableCodeExchangeProof(); + $grant->setClientRepository($clientRepositoryMock); + + $request = new ServerRequest( + [], + [], + null, + null, + 'php://input', + [], + [], + [ + 'response_type' => 'code', + 'client_id' => 'foo', + 'redirect_uri' => 'http://foo/bar', + 'code_challenge' => str_repeat('A', 42) . '!', + ] + ); + + $grant->validateAuthorizationRequest($request); + } + /** * @expectedException \League\OAuth2\Server\Exception\OAuthServerException * @expectedExceptionCode 3 From 2f8de3d2302beb490abb9475cf426148801c25c4 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 16 Jun 2017 16:58:49 +0100 Subject: [PATCH 09/55] Ensure the server is the exclusive owner of the key --- src/CryptKey.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/CryptKey.php b/src/CryptKey.php index aedeafb0..8133c607 100644 --- a/src/CryptKey.php +++ b/src/CryptKey.php @@ -44,6 +44,23 @@ class CryptKey throw new \LogicException(sprintf('Key path "%s" does not exist or is not readable', $keyPath)); } + // Verify the permissions of the key + $keyPathPerms = decoct(fileperms($keyPath) & 0777); + if ($keyPathPerms !== '600') { + // Attempt to correct the permissions + if (chmod($keyPath, 0600) === false) { + // @codeCoverageIgnoreStart + throw new \LogicException( + sprintf( + 'Key file "%s" permissions are not correct, should be 600 instead of %s, unable to automatically resolve the issue', + $keyPath, + $keyPathPerms + ) + ); + // @codeCoverageIgnoreEnd + } + } + $this->keyPath = $keyPath; $this->passPhrase = $passPhrase; } From 63530443fed426621d93abe19584aefcbe22e33d Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 16 Jun 2017 16:59:29 +0100 Subject: [PATCH 10/55] Better error checking when saving a temporary key to ensure file was written successfully and the server is the exclusive mode --- src/CryptKey.php | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/CryptKey.php b/src/CryptKey.php index 8133c607..f3051d04 100644 --- a/src/CryptKey.php +++ b/src/CryptKey.php @@ -74,7 +74,8 @@ class CryptKey */ private function saveKeyToFile($key) { - $keyPath = sys_get_temp_dir() . '/' . sha1($key) . '.key'; + $tmpDir = sys_get_temp_dir(); + $keyPath = $tmpDir . '/' . sha1($key) . '.key'; if (!file_exists($keyPath) && !touch($keyPath)) { // @codeCoverageIgnoreStart @@ -82,7 +83,17 @@ class CryptKey // @codeCoverageIgnoreEnd } - file_put_contents($keyPath, $key); + if (file_put_contents($keyPath, $key) === false) { + // @codeCoverageIgnoreStart + throw new \RuntimeException('Unable to write key file to temporary directory "%s"', $tmpDir); + // @codeCoverageIgnoreEnd + } + + if (chmod($keyPath, 0600) === false) { + // @codeCoverageIgnoreStart + throw new \RuntimeException('The key file "%s" file mode could not be changed with chmod to 600', $keyPath); + // @codeCoverageIgnoreEnd + } return 'file://' . $keyPath; } From 4a717104fa57287182f73b57a7788b32b629bfb9 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 1 Jul 2017 15:30:21 +0100 Subject: [PATCH 11/55] Shuffle the contents of the authorization code payload --- src/Grant/AuthCodeGrant.php | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 119c1f96..5adb2a69 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -311,6 +311,26 @@ class AuthCodeGrant extends AbstractAuthorizeGrant $authorizationRequest->getScopes() ); + $payload = [ + 'client_id' => $authCode->getClient()->getIdentifier(), + 'redirect_uri' => $authCode->getRedirectUri(), + 'auth_code_id' => $authCode->getIdentifier(), + 'scopes' => $authCode->getScopes(), + 'user_id' => $authCode->getUserIdentifier(), + 'expire_time' => (new \DateTime())->add($this->authCodeTTL)->format('U'), + 'code_challenge' => $authorizationRequest->getCodeChallenge(), + 'code_challenge_method ' => $authorizationRequest->getCodeChallengeMethod(), + '_padding' => base64_encode(random_bytes(mt_rand(8, 256))) + ]; + + // Shuffle the payload so that the structure is no longer know and obvious + $keys = array_keys($payload); + shuffle($keys); + $shuffledPayload = []; + foreach ($keys as $key) { + $shuffledPayload[$key] = $payload[$key]; + } + $response = new RedirectResponse(); $response->setRedirectUri( $this->makeRedirectUri( @@ -318,16 +338,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant [ 'code' => $this->encrypt( json_encode( - [ - 'client_id' => $authCode->getClient()->getIdentifier(), - 'redirect_uri' => $authCode->getRedirectUri(), - 'auth_code_id' => $authCode->getIdentifier(), - 'scopes' => $authCode->getScopes(), - 'user_id' => $authCode->getUserIdentifier(), - 'expire_time' => (new \DateTime())->add($this->authCodeTTL)->format('U'), - 'code_challenge' => $authorizationRequest->getCodeChallenge(), - 'code_challenge_method ' => $authorizationRequest->getCodeChallengeMethod(), - ] + $shuffledPayload ) ), 'state' => $authorizationRequest->getState(), From 1af4012df459cf8382b9d184af59161fbe62f192 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 1 Jul 2017 15:57:40 +0100 Subject: [PATCH 12/55] New property on AuthorizationServer to receive an encryption key which is used for future encryption/decryption instead of keybased encryption/decryption --- composer.json | 3 ++- src/AuthorizationServer.php | 26 +++++++++++++++++++ src/CryptTrait.php | 25 ++++++++++++++++++ src/Grant/GrantTypeInterface.php | 7 +++++ tests/AuthorizationServerTest.php | 6 +++++ .../AuthorizationServerMiddlewareTest.php | 2 ++ 6 files changed, 68 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 64df3ccb..7ce6374e 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,8 @@ "league/event": "^2.1", "lcobucci/jwt": "^3.1", "paragonie/random_compat": "^1.1 || ^2.0", - "psr/http-message": "^1.0" + "psr/http-message": "^1.0", + "defuse/php-encryption": "^2.1" }, "require-dev": { "phpunit/phpunit": "^4.8 || ^5.0", diff --git a/src/AuthorizationServer.php b/src/AuthorizationServer.php index 0517124a..4ba9b8d1 100644 --- a/src/AuthorizationServer.php +++ b/src/AuthorizationServer.php @@ -26,6 +26,8 @@ class AuthorizationServer implements EmitterAwareInterface { use EmitterAwareTrait; + const ENCRYPTION_KEY_ERROR = 'You must set the encryption key going forward to improve the security of this library - see this page for more information https://xxxx/xxxx'; + /** * @var GrantTypeInterface[] */ @@ -66,6 +68,11 @@ class AuthorizationServer implements EmitterAwareInterface */ private $scopeRepository; + /** + * @var string + */ + private $encryptionKey; + /** * New server instance. * @@ -101,6 +108,16 @@ class AuthorizationServer implements EmitterAwareInterface $this->responseType = $responseType; } + /** + * Set the encryption key + * + * @param string $key + */ + public function setEncryptionKey($key) + { + $this->encryptionKey = $key; + } + /** * Enable a grant type on the server. * @@ -120,6 +137,11 @@ class AuthorizationServer implements EmitterAwareInterface $grantType->setPublicKey($this->publicKey); $grantType->setEmitter($this->getEmitter()); + if ($this->encryptionKey === null) { + error_log(self::ENCRYPTION_KEY_ERROR); + } + $grantType->setEncryptionKey($this->encryptionKey); + $this->enabledGrantTypes[$grantType->getIdentifier()] = $grantType; $this->grantTypeAccessTokenTTL[$grantType->getIdentifier()] = $accessTokenTTL; } @@ -135,6 +157,10 @@ class AuthorizationServer implements EmitterAwareInterface */ public function validateAuthorizationRequest(ServerRequestInterface $request) { + if ($this->encryptionKey === null) { + error_log(self::ENCRYPTION_KEY_ERROR); + } + foreach ($this->enabledGrantTypes as $grantType) { if ($grantType->canRespondToAuthorizationRequest($request)) { return $grantType->validateAuthorizationRequest($request); diff --git a/src/CryptTrait.php b/src/CryptTrait.php index d417e115..8e6808d0 100644 --- a/src/CryptTrait.php +++ b/src/CryptTrait.php @@ -11,6 +11,8 @@ namespace League\OAuth2\Server; +use Defuse\Crypto\Crypto; + trait CryptTrait { /** @@ -23,6 +25,11 @@ trait CryptTrait */ protected $publicKey; + /** + * @var string + */ + protected $encryptionKey; + /** * Set path to private key. * @@ -54,6 +61,10 @@ trait CryptTrait */ protected function encrypt($unencryptedData) { + if ($this->encryptionKey !== null) { + return Crypto::encryptWithPassword($unencryptedData, $this->encryptionKey); + } + $privateKey = openssl_pkey_get_private($this->privateKey->getKeyPath(), $this->privateKey->getPassPhrase()); $privateKeyDetails = @openssl_pkey_get_details($privateKey); if ($privateKeyDetails === null) { @@ -91,6 +102,10 @@ trait CryptTrait */ protected function decrypt($encryptedData) { + if ($this->encryptionKey !== null) { + return Crypto::decryptWithPassword($encryptedData, $this->encryptionKey); + } + $publicKey = openssl_pkey_get_public($this->publicKey->getKeyPath()); $publicKeyDetails = @openssl_pkey_get_details($publicKey); if ($publicKeyDetails === null) { @@ -118,4 +133,14 @@ trait CryptTrait return $output; } + + /** + * Set the encryption key + * + * @param string $key + */ + public function setEncryptionKey($key = null) + { + $this->encryptionKey = $key; + } } diff --git a/src/Grant/GrantTypeInterface.php b/src/Grant/GrantTypeInterface.php index c01a571d..34028ccb 100644 --- a/src/Grant/GrantTypeInterface.php +++ b/src/Grant/GrantTypeInterface.php @@ -132,4 +132,11 @@ interface GrantTypeInterface extends EmitterAwareInterface * @param CryptKey $publicKey */ public function setPublicKey(CryptKey $publicKey); + + /** + * Set the encryption key + * + * @param string|null $key + */ + public function setEncryptionKey($key = null); } diff --git a/tests/AuthorizationServerTest.php b/tests/AuthorizationServerTest.php index 909da159..ead431b3 100644 --- a/tests/AuthorizationServerTest.php +++ b/tests/AuthorizationServerTest.php @@ -36,6 +36,7 @@ class AuthorizationServerTest extends \PHPUnit_Framework_TestCase 'file://' . __DIR__ . '/Stubs/public.key', new StubResponseType() ); + $server->setEncryptionKey(base64_encode(random_bytes(36))); $server->enableGrantType(new ClientCredentialsGrant(), new \DateInterval('PT1M')); @@ -66,6 +67,7 @@ class AuthorizationServerTest extends \PHPUnit_Framework_TestCase 'file://' . __DIR__ . '/Stubs/public.key', new StubResponseType() ); + $server->setEncryptionKey(base64_encode(random_bytes(36))); $server->enableGrantType(new ClientCredentialsGrant(), new \DateInterval('PT1M')); @@ -87,6 +89,7 @@ class AuthorizationServerTest extends \PHPUnit_Framework_TestCase 'file://' . __DIR__ . '/Stubs/private.key', 'file://' . __DIR__ . '/Stubs/public.key' ); + $server->setEncryptionKey(base64_encode(random_bytes(36))); $abstractGrantReflection = new \ReflectionClass($server); $method = $abstractGrantReflection->getMethod('getResponseType'); @@ -106,6 +109,7 @@ class AuthorizationServerTest extends \PHPUnit_Framework_TestCase 'file://' . __DIR__ . '/Stubs/private.key', 'file://' . __DIR__ . '/Stubs/public.key' ); + $server->setEncryptionKey(base64_encode(random_bytes(36))); $authCodeRepository = $this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock(); $authCodeRepository->method('getNewAuthCode')->willReturn(new AuthCodeEntity()); @@ -152,6 +156,7 @@ class AuthorizationServerTest extends \PHPUnit_Framework_TestCase 'file://' . __DIR__ . '/Stubs/private.key', 'file://' . __DIR__ . '/Stubs/public.key' ); + $server->setEncryptionKey(base64_encode(random_bytes(36))); $server->enableGrantType($grant); $request = new ServerRequest( @@ -184,6 +189,7 @@ class AuthorizationServerTest extends \PHPUnit_Framework_TestCase 'file://' . __DIR__ . '/Stubs/private.key', 'file://' . __DIR__ . '/Stubs/public.key' ); + $server->setEncryptionKey(base64_encode(random_bytes(36))); $request = new ServerRequest( [], diff --git a/tests/Middleware/AuthorizationServerMiddlewareTest.php b/tests/Middleware/AuthorizationServerMiddlewareTest.php index affc2a3b..f4c417f0 100644 --- a/tests/Middleware/AuthorizationServerMiddlewareTest.php +++ b/tests/Middleware/AuthorizationServerMiddlewareTest.php @@ -36,6 +36,7 @@ class AuthorizationServerMiddlewareTest extends \PHPUnit_Framework_TestCase 'file://' . __DIR__ . '/../Stubs/public.key', new StubResponseType() ); + $server->setEncryptionKey(base64_encode(random_bytes(36))); $server->enableGrantType(new ClientCredentialsGrant()); @@ -69,6 +70,7 @@ class AuthorizationServerMiddlewareTest extends \PHPUnit_Framework_TestCase 'file://' . __DIR__ . '/../Stubs/public.key', new StubResponseType() ); + $server->setEncryptionKey(base64_encode(random_bytes(36))); $server->enableGrantType(new ClientCredentialsGrant(), new \DateInterval('PT1M')); From 76c1349181138532747ad704b4907b558dfecad4 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 1 Jul 2017 16:29:23 +0100 Subject: [PATCH 13/55] Updated random_compat version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 7ce6374e..5360a945 100644 --- a/composer.json +++ b/composer.json @@ -8,7 +8,7 @@ "ext-openssl": "*", "league/event": "^2.1", "lcobucci/jwt": "^3.1", - "paragonie/random_compat": "^1.1 || ^2.0", + "paragonie/random_compat": "^2.0", "psr/http-message": "^1.0", "defuse/php-encryption": "^2.1" }, From dd5eee150d2e30e792bf982cde83700929a0e72d Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 1 Jul 2017 16:29:50 +0100 Subject: [PATCH 14/55] Ensure response type also has access to the encryption key --- src/AuthorizationServer.php | 1 + src/ResponseTypes/ResponseTypeInterface.php | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/src/AuthorizationServer.php b/src/AuthorizationServer.php index 4ba9b8d1..8c100775 100644 --- a/src/AuthorizationServer.php +++ b/src/AuthorizationServer.php @@ -226,6 +226,7 @@ class AuthorizationServer implements EmitterAwareInterface } $this->responseType->setPrivateKey($this->privateKey); + $this->responseType->setEncryptionKey($this->encryptionKey); return $this->responseType; } diff --git a/src/ResponseTypes/ResponseTypeInterface.php b/src/ResponseTypes/ResponseTypeInterface.php index 9f358a53..8ac20b8c 100644 --- a/src/ResponseTypes/ResponseTypeInterface.php +++ b/src/ResponseTypes/ResponseTypeInterface.php @@ -33,4 +33,11 @@ interface ResponseTypeInterface * @return ResponseInterface */ public function generateHttpResponse(ResponseInterface $response); + + /** + * Set the encryption key + * + * @param string|null $key + */ + public function setEncryptionKey($key = null); } From 1954120c3df2ddd7256a2dafc1e2b34d3d40ddab Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 1 Jul 2017 16:30:29 +0100 Subject: [PATCH 15/55] Use catch all exception --- src/Grant/RefreshTokenGrant.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Grant/RefreshTokenGrant.php b/src/Grant/RefreshTokenGrant.php index 17448a92..53dfdf7d 100644 --- a/src/Grant/RefreshTokenGrant.php +++ b/src/Grant/RefreshTokenGrant.php @@ -102,7 +102,7 @@ class RefreshTokenGrant extends AbstractGrant // Validate refresh token try { $refreshToken = $this->decrypt($encryptedRefreshToken); - } catch (\LogicException $e) { + } catch (\Exception $e) { throw OAuthServerException::invalidRefreshToken('Cannot decrypt the refresh token'); } From 107cfc3678d3ed9d44b88e2654b37d101ed6b964 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 1 Jul 2017 16:30:36 +0100 Subject: [PATCH 16/55] Updated examples --- examples/composer.json | 5 +- examples/composer.lock | 178 ++++++++++++++++++++----- examples/public/auth_code.php | 1 + examples/public/client_credentials.php | 1 + examples/public/implicit.php | 1 + examples/public/middleware_use.php | 1 + examples/public/password.php | 1 + examples/public/refresh_token.php | 7 +- 8 files changed, 158 insertions(+), 37 deletions(-) diff --git a/examples/composer.json b/examples/composer.json index 3c6e550b..79ab47cd 100644 --- a/examples/composer.json +++ b/examples/composer.json @@ -5,8 +5,9 @@ "require-dev": { "league/event": "^2.1", "lcobucci/jwt": "^3.1", - "paragonie/random_compat": "^1.1", - "psr/http-message": "^1.0" + "paragonie/random_compat": "^2.0", + "psr/http-message": "^1.0", + "defuse/php-encryption": "^2.1" }, "autoload": { "psr-4": { diff --git a/examples/composer.lock b/examples/composer.lock index 9c6c83cb..7210f31e 100644 --- a/examples/composer.lock +++ b/examples/composer.lock @@ -4,23 +4,25 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "48bcb7a3514d7c7f271c554ba1440124", - "content-hash": "e41be75973527cb9d63f27ad14ac8624", + "content-hash": "9813ed7c3b6dcf107f44df9392935b8f", "packages": [ { "name": "container-interop/container-interop", - "version": "1.1.0", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/container-interop/container-interop.git", - "reference": "fc08354828f8fd3245f77a66b9e23a6bca48297e" + "reference": "79cbf1341c22ec75643d841642dd5d6acd83bdb8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/container-interop/container-interop/zipball/fc08354828f8fd3245f77a66b9e23a6bca48297e", - "reference": "fc08354828f8fd3245f77a66b9e23a6bca48297e", + "url": "https://api.github.com/repos/container-interop/container-interop/zipball/79cbf1341c22ec75643d841642dd5d6acd83bdb8", + "reference": "79cbf1341c22ec75643d841642dd5d6acd83bdb8", "shasum": "" }, + "require": { + "psr/container": "^1.0" + }, "type": "library", "autoload": { "psr-4": { @@ -32,7 +34,8 @@ "MIT" ], "description": "Promoting the interoperability of container objects (DIC, SL, etc.)", - "time": "2014-12-30 15:22:37" + "homepage": "https://github.com/container-interop/container-interop", + "time": "2017-02-14T19:40:03+00:00" }, { "name": "nikic/fast-route", @@ -75,7 +78,7 @@ "router", "routing" ], - "time": "2015-06-18 19:15:47" + "time": "2015-06-18T19:15:47+00:00" }, { "name": "pimple/pimple", @@ -121,20 +124,69 @@ "container", "dependency injection" ], - "time": "2015-09-11 15:10:35" + "time": "2015-09-11T15:10:35+00:00" }, { - "name": "psr/http-message", - "version": "1.0", + "name": "psr/container", + "version": "1.0.0", "source": { "type": "git", - "url": "https://github.com/php-fig/http-message.git", - "reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298" + "url": "https://github.com/php-fig/container.git", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/85d63699f0dbedb190bbd4b0d2b9dc707ea4c298", - "reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298", + "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "time": "2017-02-14T16:28:37+00:00" + }, + { + "name": "psr/http-message", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", "shasum": "" }, "require": { @@ -162,6 +214,7 @@ } ], "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", "keywords": [ "http", "http-message", @@ -170,7 +223,7 @@ "request", "response" ], - "time": "2015-05-04 20:22:00" + "time": "2016-08-06T14:39:51+00:00" }, { "name": "slim/slim", @@ -236,22 +289,85 @@ "micro", "router" ], - "time": "2015-12-07 14:11:09" + "time": "2015-12-07T14:11:09+00:00" } ], "packages-dev": [ { - "name": "lcobucci/jwt", - "version": "3.1.1", + "name": "defuse/php-encryption", + "version": "v2.1.0", "source": { "type": "git", - "url": "https://github.com/lcobucci/jwt.git", - "reference": "afea8e682e911a21574fd8519321b32522fa25b5" + "url": "https://github.com/defuse/php-encryption.git", + "reference": "5176f5abb38d3ea8a6e3ac6cd3bbb54d8185a689" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/lcobucci/jwt/zipball/afea8e682e911a21574fd8519321b32522fa25b5", - "reference": "afea8e682e911a21574fd8519321b32522fa25b5", + "url": "https://api.github.com/repos/defuse/php-encryption/zipball/5176f5abb38d3ea8a6e3ac6cd3bbb54d8185a689", + "reference": "5176f5abb38d3ea8a6e3ac6cd3bbb54d8185a689", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "paragonie/random_compat": "~2.0", + "php": ">=5.4.0" + }, + "require-dev": { + "nikic/php-parser": "^2.0|^3.0", + "phpunit/phpunit": "^4|^5" + }, + "bin": [ + "bin/generate-defuse-key" + ], + "type": "library", + "autoload": { + "psr-4": { + "Defuse\\Crypto\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Hornby", + "email": "taylor@defuse.ca", + "homepage": "https://defuse.ca/" + }, + { + "name": "Scott Arciszewski", + "email": "info@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "description": "Secure PHP Encryption Library", + "keywords": [ + "aes", + "authenticated encryption", + "cipher", + "crypto", + "cryptography", + "encrypt", + "encryption", + "openssl", + "security", + "symmetric key cryptography" + ], + "time": "2017-05-18T21:28:48+00:00" + }, + { + "name": "lcobucci/jwt", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/lcobucci/jwt.git", + "reference": "ddce703826f9c5229781933b1a39069e38e6a0f3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lcobucci/jwt/zipball/ddce703826f9c5229781933b1a39069e38e6a0f3", + "reference": "ddce703826f9c5229781933b1a39069e38e6a0f3", "shasum": "" }, "require": { @@ -259,7 +375,7 @@ "php": ">=5.5" }, "require-dev": { - "mdanter/ecc": "~0.3", + "mdanter/ecc": "~0.3.1", "mikey179/vfsstream": "~1.5", "phpmd/phpmd": "~2.2", "phpunit/php-invoker": "~1.1", @@ -296,7 +412,7 @@ "JWS", "jwt" ], - "time": "2016-03-24 22:46:13" + "time": "2016-10-31T20:09:32+00:00" }, { "name": "league/event", @@ -346,20 +462,20 @@ "event", "listener" ], - "time": "2015-05-21 12:24:47" + "time": "2015-05-21T12:24:47+00:00" }, { "name": "paragonie/random_compat", - "version": "v1.4.1", + "version": "v2.0.10", "source": { "type": "git", "url": "https://github.com/paragonie/random_compat.git", - "reference": "c7e26a21ba357863de030f0b9e701c7d04593774" + "reference": "634bae8e911eefa89c1abfbf1b66da679ac8f54d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paragonie/random_compat/zipball/c7e26a21ba357863de030f0b9e701c7d04593774", - "reference": "c7e26a21ba357863de030f0b9e701c7d04593774", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/634bae8e911eefa89c1abfbf1b66da679ac8f54d", + "reference": "634bae8e911eefa89c1abfbf1b66da679ac8f54d", "shasum": "" }, "require": { @@ -394,7 +510,7 @@ "pseudorandom", "random" ], - "time": "2016-03-18 20:34:03" + "time": "2017-03-13T16:27:32+00:00" } ], "aliases": [], diff --git a/examples/public/auth_code.php b/examples/public/auth_code.php index e014f55a..51f1838c 100644 --- a/examples/public/auth_code.php +++ b/examples/public/auth_code.php @@ -46,6 +46,7 @@ $app = new App([ $privateKeyPath, $publicKeyPath ); + $server->setEncryptionKey('lxZFUEsBCJ2Yb14IF2ygAHI5N4+ZAUXXaSeeJm6+twsUmIen'); // Enable the authentication code grant on the server with a token TTL of 1 hour $server->enableGrantType( diff --git a/examples/public/client_credentials.php b/examples/public/client_credentials.php index c982f275..fd7f5ee9 100644 --- a/examples/public/client_credentials.php +++ b/examples/public/client_credentials.php @@ -42,6 +42,7 @@ $app = new App([ $privateKey, $publicKey ); + $server->setEncryptionKey('lxZFUEsBCJ2Yb14IF2ygAHI5N4+ZAUXXaSeeJm6+twsUmIen'); // Enable the client credentials grant on the server $server->enableGrantType( diff --git a/examples/public/implicit.php b/examples/public/implicit.php index 2a82097f..b496ce19 100644 --- a/examples/public/implicit.php +++ b/examples/public/implicit.php @@ -42,6 +42,7 @@ $app = new App([ $privateKeyPath, $publicKeyPath ); + $server->setEncryptionKey('lxZFUEsBCJ2Yb14IF2ygAHI5N4+ZAUXXaSeeJm6+twsUmIen'); // Enable the implicit grant on the server with a token TTL of 1 hour $server->enableGrantType(new ImplicitGrant(new \DateInterval('PT1H'))); diff --git a/examples/public/middleware_use.php b/examples/public/middleware_use.php index 21f6bc23..32b17aff 100644 --- a/examples/public/middleware_use.php +++ b/examples/public/middleware_use.php @@ -48,6 +48,7 @@ $app = new App([ $privateKeyPath, $publicKeyPath ); + $server->setEncryptionKey('lxZFUEsBCJ2Yb14IF2ygAHI5N4+ZAUXXaSeeJm6+twsUmIen'); // Enable the authentication code grant on the server with a token TTL of 1 hour $server->enableGrantType( diff --git a/examples/public/password.php b/examples/public/password.php index 02a85a56..b62acc95 100644 --- a/examples/public/password.php +++ b/examples/public/password.php @@ -26,6 +26,7 @@ $app = new App([ 'file://' . __DIR__ . '/../private.key', // path to private key 'file://' . __DIR__ . '/../public.key' // path to public key ); + $server->setEncryptionKey('lxZFUEsBCJ2Yb14IF2ygAHI5N4+ZAUXXaSeeJm6+twsUmIen'); $grant = new PasswordGrant( new UserRepository(), // instance of UserRepositoryInterface diff --git a/examples/public/refresh_token.php b/examples/public/refresh_token.php index 0649c117..b4efd45b 100644 --- a/examples/public/refresh_token.php +++ b/examples/public/refresh_token.php @@ -43,6 +43,7 @@ $app = new App([ $privateKeyPath, $publicKeyPath ); + $server->setEncryptionKey('lxZFUEsBCJ2Yb14IF2ygAHI5N4+ZAUXXaSeeJm6+twsUmIen'); // Enable the refresh token grant on the server $grant = new RefreshTokenGrant($refreshTokenRepository); @@ -66,10 +67,8 @@ $app->post('/access_token', function (ServerRequestInterface $request, ResponseI } catch (OAuthServerException $exception) { return $exception->generateHttpResponse($response); } catch (\Exception $exception) { - $body = new Stream('php://temp', 'r+'); - $body->write($exception->getMessage()); - - return $response->withStatus(500)->withBody($body); + $response->getBody()->write($exception->getMessage()); + return $response->withStatus(500); } }); From e123fe82d0f70191276b88acf377d4fbe19b5cc3 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 1 Jul 2017 16:33:56 +0100 Subject: [PATCH 17/55] Ignore error_log messages in code coverage --- src/AuthorizationServer.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/AuthorizationServer.php b/src/AuthorizationServer.php index 8c100775..bbe9c4b8 100644 --- a/src/AuthorizationServer.php +++ b/src/AuthorizationServer.php @@ -138,7 +138,9 @@ class AuthorizationServer implements EmitterAwareInterface $grantType->setEmitter($this->getEmitter()); if ($this->encryptionKey === null) { + // @codeCoverageIgnoreStart error_log(self::ENCRYPTION_KEY_ERROR); + // @codeCoverageIgnoreEnd } $grantType->setEncryptionKey($this->encryptionKey); @@ -158,7 +160,9 @@ class AuthorizationServer implements EmitterAwareInterface public function validateAuthorizationRequest(ServerRequestInterface $request) { if ($this->encryptionKey === null) { + // @codeCoverageIgnoreStart error_log(self::ENCRYPTION_KEY_ERROR); + // @codeCoverageIgnoreEnd } foreach ($this->enabledGrantTypes as $grantType) { From 0706d66c76e1ff77fe004dcde13c1a3120b71b36 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 1 Jul 2017 16:37:53 +0100 Subject: [PATCH 18/55] =?UTF-8?q?Don=E2=80=99t=20pad=20and=20shuffle=20the?= =?UTF-8?q?=20payload=20if=20an=20encryption=20key=20has=20been=20set?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Grant/AuthCodeGrant.php | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 5adb2a69..a8787a54 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -320,15 +320,20 @@ class AuthCodeGrant extends AbstractAuthorizeGrant 'expire_time' => (new \DateTime())->add($this->authCodeTTL)->format('U'), 'code_challenge' => $authorizationRequest->getCodeChallenge(), 'code_challenge_method ' => $authorizationRequest->getCodeChallengeMethod(), - '_padding' => base64_encode(random_bytes(mt_rand(8, 256))) ]; - // Shuffle the payload so that the structure is no longer know and obvious - $keys = array_keys($payload); - shuffle($keys); - $shuffledPayload = []; - foreach ($keys as $key) { - $shuffledPayload[$key] = $payload[$key]; + if ($this->encryptionKey === null) { + // Add padding to vary the length of the payload + $payload['_padding'] = base64_encode(random_bytes(mt_rand(8, 256))); + // Shuffle the payload so that the structure is no longer know and obvious + $keys = array_keys($payload); + shuffle($keys); + $shuffledPayload = []; + foreach ($keys as $key) { + $shuffledPayload[$key] = $payload[$key]; + } + } else { + $shuffledPayload = $payload; } $response = new RedirectResponse(); From 765a01021bdd7abaa35d4f1347e6e883f51d82c4 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 1 Jul 2017 16:37:59 +0100 Subject: [PATCH 19/55] Updated error message --- src/AuthorizationServer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AuthorizationServer.php b/src/AuthorizationServer.php index bbe9c4b8..a298944f 100644 --- a/src/AuthorizationServer.php +++ b/src/AuthorizationServer.php @@ -26,7 +26,7 @@ class AuthorizationServer implements EmitterAwareInterface { use EmitterAwareTrait; - const ENCRYPTION_KEY_ERROR = 'You must set the encryption key going forward to improve the security of this library - see this page for more information https://xxxx/xxxx'; + const ENCRYPTION_KEY_ERROR = 'You must set the encryption key going forward to improve the security of this library - see this page for more information https://oauth2.thephpleague.com/v5-security-improvements/'; /** * @var GrantTypeInterface[] From 09c167ac43548af6320546a23a51ac50349c0155 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 1 Jul 2017 17:17:55 +0100 Subject: [PATCH 20/55] Updated changelog and readme --- CHANGELOG.md | 9 +++++++++ README.md | 4 +++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ae31e9d..9391de30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 5.1.4 (released 2017-07-01) + +* Fixed multiple security vulnerabilities as a result of a security audit paid for by the [Mozilla Secure Open Source Fund](https://wiki.mozilla.org/MOSS/Secure_Open_Source). All users of this library are encouraged to update as soon as possible to this version or version 6.0 or greater. + * It is recommended on each `AuthorizationServer` instance you set the `setEncryptionKey()`. This will result in stronger encryption being used. If this method is not set messages will be sent to the defined error handling routines (using `error_log`). Please see the examples and documentation for examples. +* TravisCI now tests PHP 7.1 (Issue #671) +* Fix middleware example fatal error (Issue #682) +* Fix typo in the first README sentence (Issue #690) +* Corrected DateInterval from 1 min to 1 month (Issue #709) + ## 5.1.3 (released 2016-10-12) * Fixed WWW-Authenticate header (Issue #669) diff --git a/README.md b/README.md index 8da0cf44..d86bb3f7 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,8 @@ This package is released under the MIT License. See the bundled [LICENSE](https: This code is principally developed and maintained by [Alex Bilbie](https://twitter.com/alexbilbie). -Special thanks to [all of these awesome contributors](https://github.com/thephpleague/oauth2-server/contributors) +Special thanks to [all of these awesome contributors](https://github.com/thephpleague/oauth2-server/contributors). + +Additional thanks go to the [Mozilla Secure Open Source Fund](https://wiki.mozilla.org/MOSS/Secure_Open_Source) for funding a security audit of this library. The initial code was developed as part of the [Linkey](http://linkey.blogs.lincoln.ac.uk) project which was funded by [JISC](http://jisc.ac.uk) under the Access and Identity Management programme. From aee1779432498dfc3db4677476b21ff44b524c65 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 1 Jul 2017 16:19:23 +0000 Subject: [PATCH 21/55] Apply fixes from StyleCI --- examples/public/middleware_use.php | 3 ++- examples/public/refresh_token.php | 2 +- src/Grant/AuthCodeGrant.php | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/examples/public/middleware_use.php b/examples/public/middleware_use.php index 32b17aff..f6a7fcf9 100644 --- a/examples/public/middleware_use.php +++ b/examples/public/middleware_use.php @@ -8,11 +8,11 @@ */ use League\OAuth2\Server\AuthorizationServer; -use League\OAuth2\Server\ResourceServer; use League\OAuth2\Server\Grant\AuthCodeGrant; use League\OAuth2\Server\Grant\RefreshTokenGrant; use League\OAuth2\Server\Middleware\AuthorizationServerMiddleware; use League\OAuth2\Server\Middleware\ResourceServerMiddleware; +use League\OAuth2\Server\ResourceServer; use OAuth2ServerExamples\Repositories\AccessTokenRepository; use OAuth2ServerExamples\Repositories\AuthCodeRepository; use OAuth2ServerExamples\Repositories\ClientRepository; @@ -75,6 +75,7 @@ $app = new App([ new AccessTokenRepository(), $publicKeyPath ); + return $server; }, ]); diff --git a/examples/public/refresh_token.php b/examples/public/refresh_token.php index b4efd45b..25c32100 100644 --- a/examples/public/refresh_token.php +++ b/examples/public/refresh_token.php @@ -17,7 +17,6 @@ use OAuth2ServerExamples\Repositories\ScopeRepository; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Slim\App; -use Zend\Diactoros\Stream; include __DIR__ . '/../vendor/autoload.php'; @@ -68,6 +67,7 @@ $app->post('/access_token', function (ServerRequestInterface $request, ResponseI return $exception->generateHttpResponse($response); } catch (\Exception $exception) { $response->getBody()->write($exception->getMessage()); + return $response->withStatus(500); } }); diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index a8787a54..2a05355e 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -264,7 +264,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant throw OAuthServerException::invalidRequest('code_challenge'); } - if (preg_match("/^[A-Za-z0-9-._~]{43,128}$/", $codeChallenge) !== 1) { + if (preg_match('/^[A-Za-z0-9-._~]{43,128}$/', $codeChallenge) !== 1) { throw OAuthServerException::invalidRequest( 'code_challenge', 'The code_challenge must be between 43 and 128 characters' From 06424fdbe2fff2475976b2f7a46a6b4a4f2cdde4 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 1 Jul 2017 17:24:11 +0100 Subject: [PATCH 22/55] Use Trusty for TravisCI --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 13962424..9536e362 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,8 @@ language: php sudo: false +dist: trusty + cache: directories: - vendor From cc2c3a704446700653235b42116a4540e460e8b3 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 1 Jul 2017 18:07:01 +0100 Subject: [PATCH 23/55] Removed unnecessary stuff from composer.json --- composer.json | 5 ----- 1 file changed, 5 deletions(-) diff --git a/composer.json b/composer.json index 5360a945..51d467b5 100644 --- a/composer.json +++ b/composer.json @@ -61,11 +61,6 @@ "LeagueTests\\": "tests/" } }, - "extra": { - "branch-alias": { - "dev-V5-WIP": "5.0-dev" - } - }, "suggest": { "indigophp/hash-compat": "Polyfill for hash_equals function for PHP 5.5" } From 7953f27b38ee349686d615024760a993a40a1511 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 1 Jul 2017 18:07:09 +0100 Subject: [PATCH 24/55] Stop testing HHVM --- .travis.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9536e362..c0ce917b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,8 +2,6 @@ language: php sudo: false -dist: trusty - cache: directories: - vendor @@ -14,7 +12,6 @@ php: - 5.6 - 7.0 - 7.1 - - hhvm install: - travis_retry composer install --no-interaction --prefer-source From 0f73bf0054604d3620e121b70d81c97f873b66ac Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 1 Jul 2017 18:07:42 +0100 Subject: [PATCH 25/55] Encryption key just uses Defuse\Crypto now, no key based crypto --- src/CryptTrait.php | 94 +++------------------------------------------- 1 file changed, 6 insertions(+), 88 deletions(-) diff --git a/src/CryptTrait.php b/src/CryptTrait.php index 8e6808d0..805969b0 100644 --- a/src/CryptTrait.php +++ b/src/CryptTrait.php @@ -1,11 +1,9 @@ * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ - * * @link https://github.com/thephpleague/oauth2-server */ @@ -15,80 +13,26 @@ use Defuse\Crypto\Crypto; trait CryptTrait { - /** - * @var CryptKey - */ - protected $privateKey; - - /** - * @var CryptKey - */ - protected $publicKey; - /** * @var string */ protected $encryptionKey; - /** - * Set path to private key. - * - * @param CryptKey $privateKey - */ - public function setPrivateKey(CryptKey $privateKey) - { - $this->privateKey = $privateKey; - } - - /** - * Set path to public key. - * - * @param CryptKey $publicKey - */ - public function setPublicKey(CryptKey $publicKey) - { - $this->publicKey = $publicKey; - } - /** * Encrypt data with a private key. * * @param string $unencryptedData * * @throws \LogicException - * * @return string */ protected function encrypt($unencryptedData) { - if ($this->encryptionKey !== null) { + try { return Crypto::encryptWithPassword($unencryptedData, $this->encryptionKey); + } catch (\Exception $e) { + throw new \LogicException($e->getMessage()); } - - $privateKey = openssl_pkey_get_private($this->privateKey->getKeyPath(), $this->privateKey->getPassPhrase()); - $privateKeyDetails = @openssl_pkey_get_details($privateKey); - if ($privateKeyDetails === null) { - throw new \LogicException( - sprintf('Could not get details of private key: %s', $this->privateKey->getKeyPath()) - ); - } - - $chunkSize = ceil($privateKeyDetails['bits'] / 8) - 11; - $output = ''; - - while ($unencryptedData) { - $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; - } - openssl_pkey_free($privateKey); - - return base64_encode($output); } /** @@ -97,41 +41,15 @@ trait CryptTrait * @param string $encryptedData * * @throws \LogicException - * * @return string */ protected function decrypt($encryptedData) { - if ($this->encryptionKey !== null) { + try { return Crypto::decryptWithPassword($encryptedData, $this->encryptionKey); + } catch (\Exception $e) { + throw new \LogicException($e->getMessage()); } - - $publicKey = openssl_pkey_get_public($this->publicKey->getKeyPath()); - $publicKeyDetails = @openssl_pkey_get_details($publicKey); - if ($publicKeyDetails === null) { - throw new \LogicException( - sprintf('Could not get details of public key: %s', $this->publicKey->getKeyPath()) - ); - } - - $chunkSize = ceil($publicKeyDetails['bits'] / 8); - $output = ''; - - $encryptedData = base64_decode($encryptedData); - - while ($encryptedData) { - $chunk = substr($encryptedData, 0, $chunkSize); - $encryptedData = substr($encryptedData, $chunkSize); - if (openssl_public_decrypt($chunk, $decrypted, $publicKey/*, OPENSSL_PKCS1_OAEP_PADDING*/) === false) { - // @codeCoverageIgnoreStart - throw new \LogicException('Failed to decrypt data'); - // @codeCoverageIgnoreEnd - } - $output .= $decrypted; - } - openssl_pkey_free($publicKey); - - return $output; } /** From 850793ab88e0baa6c063cd662ebec41b1bb617a5 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 1 Jul 2017 18:08:49 +0100 Subject: [PATCH 26/55] Added missing methods --- .../BearerTokenValidator.php | 16 ++++++++++++++++ src/Grant/AbstractGrant.php | 16 ++++++++++++++++ src/Grant/GrantTypeInterface.php | 7 ------- src/ResponseTypes/AbstractResponseType.php | 17 +++++++++++++++++ 4 files changed, 49 insertions(+), 7 deletions(-) diff --git a/src/AuthorizationValidators/BearerTokenValidator.php b/src/AuthorizationValidators/BearerTokenValidator.php index 2bab4cb5..1547f6bf 100644 --- a/src/AuthorizationValidators/BearerTokenValidator.php +++ b/src/AuthorizationValidators/BearerTokenValidator.php @@ -12,6 +12,7 @@ namespace League\OAuth2\Server\AuthorizationValidators; use Lcobucci\JWT\Parser; use Lcobucci\JWT\Signer\Rsa\Sha256; use Lcobucci\JWT\ValidationData; +use League\OAuth2\Server\CryptKey; use League\OAuth2\Server\CryptTrait; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; @@ -26,6 +27,11 @@ class BearerTokenValidator implements AuthorizationValidatorInterface */ private $accessTokenRepository; + /** + * @var \League\OAuth2\Server\CryptKey + */ + protected $publicKey; + /** * @param AccessTokenRepositoryInterface $accessTokenRepository */ @@ -34,6 +40,16 @@ class BearerTokenValidator implements AuthorizationValidatorInterface $this->accessTokenRepository = $accessTokenRepository; } + /** + * Set the private key + * + * @param \League\OAuth2\Server\CryptKey $key + */ + public function setPublicKey(CryptKey $key) + { + $this->publicKey = $key; + } + /** * {@inheritdoc} */ diff --git a/src/Grant/AbstractGrant.php b/src/Grant/AbstractGrant.php index d916e3f1..3ac98cf4 100644 --- a/src/Grant/AbstractGrant.php +++ b/src/Grant/AbstractGrant.php @@ -11,6 +11,7 @@ namespace League\OAuth2\Server\Grant; use League\Event\EmitterAwareTrait; +use League\OAuth2\Server\CryptKey; use League\OAuth2\Server\CryptTrait; use League\OAuth2\Server\Entities\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\AuthCodeEntityInterface; @@ -75,6 +76,11 @@ abstract class AbstractGrant implements GrantTypeInterface */ protected $refreshTokenTTL; + /** + * @var \League\OAuth2\Server\CryptKey + */ + protected $privateKey; + /** * @param ClientRepositoryInterface $clientRepository */ @@ -131,6 +137,16 @@ abstract class AbstractGrant implements GrantTypeInterface $this->refreshTokenTTL = $refreshTokenTTL; } + /** + * Set the private key + * + * @param \League\OAuth2\Server\CryptKey $key + */ + public function setPrivateKey(CryptKey $key) + { + $this->privateKey = $key; + } + /** * Validate the client. * diff --git a/src/Grant/GrantTypeInterface.php b/src/Grant/GrantTypeInterface.php index 34028ccb..7aa98242 100644 --- a/src/Grant/GrantTypeInterface.php +++ b/src/Grant/GrantTypeInterface.php @@ -126,13 +126,6 @@ interface GrantTypeInterface extends EmitterAwareInterface */ public function setPrivateKey(CryptKey $privateKey); - /** - * Set the path to the public key. - * - * @param CryptKey $publicKey - */ - public function setPublicKey(CryptKey $publicKey); - /** * Set the encryption key * diff --git a/src/ResponseTypes/AbstractResponseType.php b/src/ResponseTypes/AbstractResponseType.php index 6e164392..0c256f17 100644 --- a/src/ResponseTypes/AbstractResponseType.php +++ b/src/ResponseTypes/AbstractResponseType.php @@ -11,6 +11,7 @@ namespace League\OAuth2\Server\ResponseTypes; +use League\OAuth2\Server\CryptKey; use League\OAuth2\Server\CryptTrait; use League\OAuth2\Server\Entities\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\RefreshTokenEntityInterface; @@ -29,6 +30,11 @@ abstract class AbstractResponseType implements ResponseTypeInterface */ protected $refreshToken; + /** + * @var CryptKey + */ + protected $privateKey; + /** * {@inheritdoc} */ @@ -44,4 +50,15 @@ abstract class AbstractResponseType implements ResponseTypeInterface { $this->refreshToken = $refreshToken; } + + /** + * Set the private key + * + * @param \League\OAuth2\Server\CryptKey $key + */ + public function setPrivateKey(CryptKey $key) + { + $this->privateKey = $key; + } + } From 72349ef22f94b940a406c0e506fda3beb6f0289b Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 1 Jul 2017 18:10:33 +0100 Subject: [PATCH 27/55] Encryption key is now always required so remove redundent code --- src/AuthorizationServer.php | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/src/AuthorizationServer.php b/src/AuthorizationServer.php index a298944f..0df6b1f9 100644 --- a/src/AuthorizationServer.php +++ b/src/AuthorizationServer.php @@ -26,8 +26,6 @@ class AuthorizationServer implements EmitterAwareInterface { use EmitterAwareTrait; - const ENCRYPTION_KEY_ERROR = 'You must set the encryption key going forward to improve the security of this library - see this page for more information https://oauth2.thephpleague.com/v5-security-improvements/'; - /** * @var GrantTypeInterface[] */ @@ -108,16 +106,6 @@ class AuthorizationServer implements EmitterAwareInterface $this->responseType = $responseType; } - /** - * Set the encryption key - * - * @param string $key - */ - public function setEncryptionKey($key) - { - $this->encryptionKey = $key; - } - /** * Enable a grant type on the server. * @@ -136,12 +124,6 @@ class AuthorizationServer implements EmitterAwareInterface $grantType->setPrivateKey($this->privateKey); $grantType->setPublicKey($this->publicKey); $grantType->setEmitter($this->getEmitter()); - - if ($this->encryptionKey === null) { - // @codeCoverageIgnoreStart - error_log(self::ENCRYPTION_KEY_ERROR); - // @codeCoverageIgnoreEnd - } $grantType->setEncryptionKey($this->encryptionKey); $this->enabledGrantTypes[$grantType->getIdentifier()] = $grantType; @@ -159,12 +141,6 @@ class AuthorizationServer implements EmitterAwareInterface */ public function validateAuthorizationRequest(ServerRequestInterface $request) { - if ($this->encryptionKey === null) { - // @codeCoverageIgnoreStart - error_log(self::ENCRYPTION_KEY_ERROR); - // @codeCoverageIgnoreEnd - } - foreach ($this->enabledGrantTypes as $grantType) { if ($grantType->canRespondToAuthorizationRequest($request)) { return $grantType->validateAuthorizationRequest($request); From 76c2b6f88cccaa07f9eceaab42e0306dd839cacb Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 1 Jul 2017 18:11:10 +0100 Subject: [PATCH 28/55] AuthorizationServer no longer needs to know about the public key --- src/AuthorizationServer.php | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/AuthorizationServer.php b/src/AuthorizationServer.php index 0df6b1f9..ece5458b 100644 --- a/src/AuthorizationServer.php +++ b/src/AuthorizationServer.php @@ -3,7 +3,6 @@ * @author Alex Bilbie * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ - * * @link https://github.com/thephpleague/oauth2-server */ @@ -78,7 +77,7 @@ class AuthorizationServer implements EmitterAwareInterface * @param AccessTokenRepositoryInterface $accessTokenRepository * @param ScopeRepositoryInterface $scopeRepository * @param CryptKey|string $privateKey - * @param CryptKey|string $publicKey + * @param string $encryptionKey * @param null|ResponseTypeInterface $responseType */ public function __construct( @@ -86,7 +85,7 @@ class AuthorizationServer implements EmitterAwareInterface AccessTokenRepositoryInterface $accessTokenRepository, ScopeRepositoryInterface $scopeRepository, $privateKey, - $publicKey, + $encryptionKey, ResponseTypeInterface $responseType = null ) { $this->clientRepository = $clientRepository; @@ -98,11 +97,7 @@ class AuthorizationServer implements EmitterAwareInterface } $this->privateKey = $privateKey; - if ($publicKey instanceof CryptKey === false) { - $publicKey = new CryptKey($publicKey); - } - $this->publicKey = $publicKey; - + $this->encryptionKey = $encryptionKey; $this->responseType = $responseType; } From aac467e6165247741829f700a15985f67acad5a7 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 1 Jul 2017 18:11:19 +0100 Subject: [PATCH 29/55] Fixed broken tests --- tests/AuthorizationServerTest.php | 13 +--- tests/CryptTraitTest.php | 28 +------- tests/Grant/AbstractGrantTest.php | 2 - tests/Grant/AuthCodeGrantTest.php | 65 ++++++------------- tests/Grant/ImplicitGrantTest.php | 5 -- tests/Grant/RefreshTokenGrantTest.php | 19 +++--- .../AuthorizationServerMiddlewareTest.php | 12 ++-- .../ResponseTypes/BearerResponseTypeTest.php | 19 ++---- tests/Stubs/CryptTraitStub.php | 8 ++- 9 files changed, 51 insertions(+), 120 deletions(-) diff --git a/tests/AuthorizationServerTest.php b/tests/AuthorizationServerTest.php index ead431b3..7b921ff9 100644 --- a/tests/AuthorizationServerTest.php +++ b/tests/AuthorizationServerTest.php @@ -33,10 +33,9 @@ class AuthorizationServerTest extends \PHPUnit_Framework_TestCase $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(), $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(), 'file://' . __DIR__ . '/Stubs/private.key', - 'file://' . __DIR__ . '/Stubs/public.key', + base64_encode(random_bytes(36)), new StubResponseType() ); - $server->setEncryptionKey(base64_encode(random_bytes(36))); $server->enableGrantType(new ClientCredentialsGrant(), new \DateInterval('PT1M')); @@ -64,10 +63,9 @@ class AuthorizationServerTest extends \PHPUnit_Framework_TestCase $accessTokenRepositoryMock, $scopeRepositoryMock, 'file://' . __DIR__ . '/Stubs/private.key', - 'file://' . __DIR__ . '/Stubs/public.key', + base64_encode(random_bytes(36)), new StubResponseType() ); - $server->setEncryptionKey(base64_encode(random_bytes(36))); $server->enableGrantType(new ClientCredentialsGrant(), new \DateInterval('PT1M')); @@ -89,7 +87,6 @@ class AuthorizationServerTest extends \PHPUnit_Framework_TestCase 'file://' . __DIR__ . '/Stubs/private.key', 'file://' . __DIR__ . '/Stubs/public.key' ); - $server->setEncryptionKey(base64_encode(random_bytes(36))); $abstractGrantReflection = new \ReflectionClass($server); $method = $abstractGrantReflection->getMethod('getResponseType'); @@ -109,7 +106,6 @@ class AuthorizationServerTest extends \PHPUnit_Framework_TestCase 'file://' . __DIR__ . '/Stubs/private.key', 'file://' . __DIR__ . '/Stubs/public.key' ); - $server->setEncryptionKey(base64_encode(random_bytes(36))); $authCodeRepository = $this->getMockBuilder(AuthCodeRepositoryInterface::class)->getMock(); $authCodeRepository->method('getNewAuthCode')->willReturn(new AuthCodeEntity()); @@ -120,9 +116,6 @@ class AuthorizationServerTest extends \PHPUnit_Framework_TestCase new \DateInterval('PT10M') ); - $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/Stubs/private.key')); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/Stubs/public.key')); - $server->enableGrantType($grant); $authRequest = new AuthorizationRequest(); @@ -156,7 +149,6 @@ class AuthorizationServerTest extends \PHPUnit_Framework_TestCase 'file://' . __DIR__ . '/Stubs/private.key', 'file://' . __DIR__ . '/Stubs/public.key' ); - $server->setEncryptionKey(base64_encode(random_bytes(36))); $server->enableGrantType($grant); $request = new ServerRequest( @@ -189,7 +181,6 @@ class AuthorizationServerTest extends \PHPUnit_Framework_TestCase 'file://' . __DIR__ . '/Stubs/private.key', 'file://' . __DIR__ . '/Stubs/public.key' ); - $server->setEncryptionKey(base64_encode(random_bytes(36))); $request = new ServerRequest( [], diff --git a/tests/CryptTraitTest.php b/tests/CryptTraitTest.php index d0ada49e..8c7d2642 100644 --- a/tests/CryptTraitTest.php +++ b/tests/CryptTraitTest.php @@ -8,7 +8,7 @@ use LeagueTests\Stubs\CryptTraitStub; class CryptTraitTest extends \PHPUnit_Framework_TestCase { /** - * CryptTrait stub + * @var \LeagueTests\Stubs\CryptTraitStub */ protected $cryptStub; @@ -26,30 +26,4 @@ class CryptTraitTest extends \PHPUnit_Framework_TestCase $this->assertNotEquals($payload, $encrypted); $this->assertEquals($payload, $plainText); } - - /** - * @expectedException \LogicException - */ - public function testBadPrivateKey() - { - $this->cryptStub->setPrivateKey(new CryptKey(__DIR__ . '/Stubs/public.key')); - $this->cryptStub->doEncrypt(''); - } - - /** - * @expectedException \LogicException - */ - public function testBadPublicKey() - { - $this->cryptStub->setPublicKey(new CryptKey(__DIR__ . '/Stubs/private.key')); - $this->cryptStub->doDecrypt(''); - } - - /** - * @expectedException \LogicException - */ - public function testNonExistentKey() - { - new CryptKey('foo/bar'); - } } diff --git a/tests/Grant/AbstractGrantTest.php b/tests/Grant/AbstractGrantTest.php index 3ef3f133..542c78dc 100644 --- a/tests/Grant/AbstractGrantTest.php +++ b/tests/Grant/AbstractGrantTest.php @@ -27,8 +27,6 @@ class AbstractGrantTest extends \PHPUnit_Framework_TestCase { /** @var AbstractGrant $grantMock */ $grantMock = $this->getMockForAbstractClass(AbstractGrant::class); - $grantMock->setPrivateKey(new CryptKey(__DIR__ . '/../Stubs/private.key')); - $grantMock->setPublicKey(new CryptKey(__DIR__ . '/../Stubs/public.key')); $grantMock->setEmitter(new Emitter()); } diff --git a/tests/Grant/AuthCodeGrantTest.php b/tests/Grant/AuthCodeGrantTest.php index 63c9042a..3bccba0a 100644 --- a/tests/Grant/AuthCodeGrantTest.php +++ b/tests/Grant/AuthCodeGrantTest.php @@ -510,9 +510,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(), new \DateInterval('PT10M') ); - - $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setEncryptionKey($this->cryptStub->getKey()); $this->assertTrue($grant->completeAuthorizationRequest($authRequest) instanceof RedirectResponse); } @@ -537,9 +535,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(), new \DateInterval('PT10M') ); - - $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setEncryptionKey($this->cryptStub->getKey()); $grant->completeAuthorizationRequest($authRequest); } @@ -574,8 +570,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant->setScopeRepository($scopeRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); - $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); + $grant->setEncryptionKey($this->cryptStub->getKey()); $request = new ServerRequest( [], @@ -643,8 +638,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant->setScopeRepository($scopeRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); - $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); + $grant->setEncryptionKey($this->cryptStub->getKey()); $request = new ServerRequest( [], @@ -715,8 +709,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant->setScopeRepository($scopeRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); - $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); + $grant->setEncryptionKey($this->cryptStub->getKey()); $request = new ServerRequest( [], @@ -773,7 +766,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setEncryptionKey($this->cryptStub->getKey()); $request = new ServerRequest( [], @@ -820,7 +813,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase new \DateInterval('PT10M') ); $grant->setClientRepository($clientRepositoryMock); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setEncryptionKey($this->cryptStub->getKey()); $request = new ServerRequest( [], @@ -873,8 +866,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); - $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); + $grant->setEncryptionKey($this->cryptStub->getKey()); $request = new ServerRequest( [], @@ -919,8 +911,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); - $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); + $grant->setEncryptionKey($this->cryptStub->getKey()); $request = new ServerRequest( [], @@ -983,8 +974,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); - $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); + $grant->setEncryptionKey($this->cryptStub->getKey()); $request = new ServerRequest( [], @@ -1044,8 +1034,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); - $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); + $grant->setEncryptionKey($this->cryptStub->getKey()); $request = new ServerRequest( [], @@ -1105,8 +1094,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); - $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); + $grant->setEncryptionKey($this->cryptStub->getKey()); $request = new ServerRequest( [], @@ -1164,8 +1152,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); $grant->setScopeRepository($scopeRepositoryMock); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); - $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); + $grant->setEncryptionKey($this->cryptStub->getKey()); $request = new ServerRequest( [], @@ -1237,8 +1224,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); $grant->setScopeRepository($scopeRepositoryMock); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); - $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); + $grant->setEncryptionKey($this->cryptStub->getKey()); $request = new ServerRequest( [], @@ -1310,8 +1296,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); $grant->setScopeRepository($scopeRepositoryMock); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); - $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); + $grant->setEncryptionKey($this->cryptStub->getKey()); $request = new ServerRequest( [], @@ -1370,9 +1355,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(), new \DateInterval('PT10M') ); - - $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setEncryptionKey($this->cryptStub->getKey()); $this->assertTrue($grant->completeAuthorizationRequest($authRequest) instanceof RedirectResponse); } @@ -1398,9 +1381,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $this->getMockBuilder(RefreshTokenRepositoryInterface::class)->getMock(), new \DateInterval('PT10M') ); - - $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setEncryptionKey($this->cryptStub->getKey()); $this->assertTrue($grant->completeAuthorizationRequest($authRequest) instanceof RedirectResponse); } @@ -1427,9 +1408,6 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase new \DateInterval('PT10M') ); - $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); - $this->assertTrue($grant->completeAuthorizationRequest($authRequest) instanceof RedirectResponse); } @@ -1464,8 +1442,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant->setScopeRepository($scopeRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); - $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); + $grant->setEncryptionKey($this->cryptStub->getKey()); $request = new ServerRequest( [], @@ -1536,8 +1513,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant->setScopeRepository($scopeRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); - $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); + $grant->setEncryptionKey($this->cryptStub->getKey()); $request = new ServerRequest( [], @@ -1608,8 +1584,7 @@ class AuthCodeGrantTest extends \PHPUnit_Framework_TestCase $grant->setScopeRepository($scopeRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setRefreshTokenRepository($refreshTokenRepositoryMock); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); - $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); + $grant->setEncryptionKey($this->cryptStub->getKey()); $request = new ServerRequest( [], diff --git a/tests/Grant/ImplicitGrantTest.php b/tests/Grant/ImplicitGrantTest.php index 0fc06370..3bfe4b84 100644 --- a/tests/Grant/ImplicitGrantTest.php +++ b/tests/Grant/ImplicitGrantTest.php @@ -283,7 +283,6 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase $grant = new ImplicitGrant(new \DateInterval('PT10M')); $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $this->assertTrue($grant->completeAuthorizationRequest($authRequest) instanceof RedirectResponse); @@ -307,7 +306,6 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase $grant = new ImplicitGrant(new \DateInterval('PT10M')); $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->completeAuthorizationRequest($authRequest); @@ -329,7 +327,6 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase $grant = new ImplicitGrant(new \DateInterval('PT10M')); $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $this->assertTrue($grant->completeAuthorizationRequest($authRequest) instanceof RedirectResponse); @@ -354,7 +351,6 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase $grant = new ImplicitGrant(new \DateInterval('PT10M')); $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->completeAuthorizationRequest($authRequest); @@ -379,7 +375,6 @@ class ImplicitGrantTest extends \PHPUnit_Framework_TestCase $grant = new ImplicitGrant(new \DateInterval('PT10M')); $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->completeAuthorizationRequest($authRequest); diff --git a/tests/Grant/RefreshTokenGrantTest.php b/tests/Grant/RefreshTokenGrantTest.php index 90a63276..47d7ad17 100644 --- a/tests/Grant/RefreshTokenGrantTest.php +++ b/tests/Grant/RefreshTokenGrantTest.php @@ -21,7 +21,7 @@ use Zend\Diactoros\ServerRequest; class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase { /** - * CryptTrait stub + * @var CryptTraitStub */ protected $cryptStub; @@ -65,7 +65,7 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase $grant->setClientRepository($clientRepositoryMock); $grant->setScopeRepository($scopeRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setEncryptionKey($this->cryptStub->getKey()); $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $oldRefreshToken = $this->cryptStub->doEncrypt( @@ -121,7 +121,7 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setScopeRepository($scopeRepositoryMock); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setEncryptionKey($this->cryptStub->getKey()); $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $oldRefreshToken = $this->cryptStub->doEncrypt( @@ -180,7 +180,7 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); $grant->setScopeRepository($scopeRepositoryMock); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setEncryptionKey($this->cryptStub->getKey()); $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $oldRefreshToken = $this->cryptStub->doEncrypt( @@ -227,7 +227,7 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase $grant = new RefreshTokenGrant($refreshTokenRepositoryMock); $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setEncryptionKey($this->cryptStub->getKey()); $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $serverRequest = new ServerRequest(); @@ -259,7 +259,7 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase $grant = new RefreshTokenGrant($refreshTokenRepositoryMock); $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setEncryptionKey($this->cryptStub->getKey()); $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $oldRefreshToken = 'foobar'; @@ -291,14 +291,13 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase $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->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setEncryptionKey($this->cryptStub->getKey()); $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $oldRefreshToken = $this->cryptStub->doEncrypt( @@ -344,7 +343,7 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase $grant = new RefreshTokenGrant($refreshTokenRepositoryMock); $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setEncryptionKey($this->cryptStub->getKey()); $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $oldRefreshToken = $this->cryptStub->doEncrypt( @@ -391,7 +390,7 @@ class RefreshTokenGrantTest extends \PHPUnit_Framework_TestCase $grant = new RefreshTokenGrant($refreshTokenRepositoryMock); $grant->setClientRepository($clientRepositoryMock); $grant->setAccessTokenRepository($accessTokenRepositoryMock); - $grant->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $grant->setEncryptionKey($this->cryptStub->getKey()); $grant->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $oldRefreshToken = $this->cryptStub->doEncrypt( diff --git a/tests/Middleware/AuthorizationServerMiddlewareTest.php b/tests/Middleware/AuthorizationServerMiddlewareTest.php index f4c417f0..74dffbf7 100644 --- a/tests/Middleware/AuthorizationServerMiddlewareTest.php +++ b/tests/Middleware/AuthorizationServerMiddlewareTest.php @@ -33,10 +33,9 @@ class AuthorizationServerMiddlewareTest extends \PHPUnit_Framework_TestCase $accessRepositoryMock, $scopeRepositoryMock, 'file://' . __DIR__ . '/../Stubs/private.key', - 'file://' . __DIR__ . '/../Stubs/public.key', + base64_encode(random_bytes(36)), new StubResponseType() ); - $server->setEncryptionKey(base64_encode(random_bytes(36))); $server->enableGrantType(new ClientCredentialsGrant()); @@ -67,10 +66,9 @@ class AuthorizationServerMiddlewareTest extends \PHPUnit_Framework_TestCase $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(), $this->getMockBuilder(ScopeRepositoryInterface::class)->getMock(), 'file://' . __DIR__ . '/../Stubs/private.key', - 'file://' . __DIR__ . '/../Stubs/public.key', + base64_encode(random_bytes(36)), new StubResponseType() ); - $server->setEncryptionKey(base64_encode(random_bytes(36))); $server->enableGrantType(new ClientCredentialsGrant(), new \DateInterval('PT1M')); @@ -99,7 +97,8 @@ class AuthorizationServerMiddlewareTest extends \PHPUnit_Framework_TestCase $response = $exception->generateHttpResponse(new Response()); $this->assertEquals(302, $response->getStatusCode()); - $this->assertEquals('http://foo/bar?error=invalid_scope&message=The+requested+scope+is+invalid%2C+unknown%2C+or+malformed&hint=Check+the+%60test%60+scope', $response->getHeader('location')[0]); + $this->assertEquals('http://foo/bar?error=invalid_scope&message=The+requested+scope+is+invalid%2C+unknown%2C+or+malformed&hint=Check+the+%60test%60+scope', + $response->getHeader('location')[0]); } public function testOAuthErrorResponseRedirectUriFragment() @@ -108,6 +107,7 @@ class AuthorizationServerMiddlewareTest extends \PHPUnit_Framework_TestCase $response = $exception->generateHttpResponse(new Response(), true); $this->assertEquals(302, $response->getStatusCode()); - $this->assertEquals('http://foo/bar#error=invalid_scope&message=The+requested+scope+is+invalid%2C+unknown%2C+or+malformed&hint=Check+the+%60test%60+scope', $response->getHeader('location')[0]); + $this->assertEquals('http://foo/bar#error=invalid_scope&message=The+requested+scope+is+invalid%2C+unknown%2C+or+malformed&hint=Check+the+%60test%60+scope', + $response->getHeader('location')[0]); } } diff --git a/tests/ResponseTypes/BearerResponseTypeTest.php b/tests/ResponseTypes/BearerResponseTypeTest.php index ca660ab7..7f710d92 100644 --- a/tests/ResponseTypes/BearerResponseTypeTest.php +++ b/tests/ResponseTypes/BearerResponseTypeTest.php @@ -23,7 +23,7 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase $responseType = new BearerTokenResponse($accessTokenRepositoryMock); $responseType->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); - $responseType->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $responseType->setEncryptionKey(base64_encode(random_bytes(36))); $client = new ClientEntity(); $client->setIdentifier('clientName'); @@ -67,7 +67,7 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase $responseType = new BearerTokenResponseWithParams($accessTokenRepositoryMock); $responseType->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); - $responseType->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $responseType->setEncryptionKey(base64_encode(random_bytes(36))); $client = new ClientEntity(); $client->setIdentifier('clientName'); @@ -115,7 +115,7 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase $responseType = new BearerTokenResponse($accessTokenRepositoryMock); $responseType->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); - $responseType->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $responseType->setEncryptionKey(base64_encode(random_bytes(36))); $client = new ClientEntity(); $client->setIdentifier('clientName'); @@ -141,7 +141,6 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase $accessTokenRepositoryMock->method('isAccessTokenRevoked')->willReturn(false); $authorizationValidator = new BearerTokenValidator($accessTokenRepositoryMock); - $authorizationValidator->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $authorizationValidator->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); $request = new ServerRequest(); @@ -162,7 +161,7 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase $responseType = new BearerTokenResponse($accessTokenRepositoryMock); $responseType->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); - $responseType->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $responseType->setEncryptionKey(base64_encode(random_bytes(36))); $client = new ClientEntity(); $client->setIdentifier('clientName'); @@ -185,7 +184,6 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase $json = json_decode((string) $response->getBody()); $authorizationValidator = new BearerTokenValidator($accessTokenRepositoryMock); - $authorizationValidator->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $authorizationValidator->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); $request = new ServerRequest(); @@ -205,7 +203,7 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase { $responseType = new BearerTokenResponse(); $responseType->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); - $responseType->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $responseType->setEncryptionKey(base64_encode(random_bytes(36))); $client = new ClientEntity(); $client->setIdentifier('clientName'); @@ -231,7 +229,6 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase $accessTokenRepositoryMock->method('isAccessTokenRevoked')->willReturn(true); $authorizationValidator = new BearerTokenValidator($accessTokenRepositoryMock); - $authorizationValidator->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $authorizationValidator->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); $request = new ServerRequest(); @@ -253,12 +250,11 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase $responseType = new BearerTokenResponse($accessTokenRepositoryMock); $responseType->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); - $responseType->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $responseType->setEncryptionKey(base64_encode(random_bytes(36))); $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); $authorizationValidator = new BearerTokenValidator($accessTokenRepositoryMock); - $authorizationValidator->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $authorizationValidator->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); $request = new ServerRequest(); @@ -280,12 +276,11 @@ class BearerResponseTypeTest extends \PHPUnit_Framework_TestCase $responseType = new BearerTokenResponse($accessTokenRepositoryMock); $responseType->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); - $responseType->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); + $responseType->setEncryptionKey(base64_encode(random_bytes(36))); $accessTokenRepositoryMock = $this->getMockBuilder(AccessTokenRepositoryInterface::class)->getMock(); $authorizationValidator = new BearerTokenValidator($accessTokenRepositoryMock); - $authorizationValidator->setPrivateKey(new CryptKey('file://' . __DIR__ . '/../Stubs/private.key')); $authorizationValidator->setPublicKey(new CryptKey('file://' . __DIR__ . '/../Stubs/public.key')); $request = new ServerRequest(); diff --git a/tests/Stubs/CryptTraitStub.php b/tests/Stubs/CryptTraitStub.php index 2414c199..a481a849 100644 --- a/tests/Stubs/CryptTraitStub.php +++ b/tests/Stubs/CryptTraitStub.php @@ -11,8 +11,12 @@ class CryptTraitStub public function __construct() { - $this->setPrivateKey(new CryptKey('file://' . __DIR__ . '/private.key')); - $this->setPublicKey(new CryptKey('file://' . __DIR__ . '/public.key')); + $this->setEncryptionKey(base64_encode(random_bytes(36))); + } + + public function getKey() + { + return $this->encryptionKey; } public function doEncrypt($unencryptedData) From 523434902cc43fb43b281fb5b7c05c76f3a1834c Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 1 Jul 2017 18:15:41 +0100 Subject: [PATCH 30/55] Removed dead code --- src/AuthorizationServer.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/AuthorizationServer.php b/src/AuthorizationServer.php index ece5458b..46a9b27a 100644 --- a/src/AuthorizationServer.php +++ b/src/AuthorizationServer.php @@ -117,7 +117,6 @@ class AuthorizationServer implements EmitterAwareInterface $grantType->setClientRepository($this->clientRepository); $grantType->setScopeRepository($this->scopeRepository); $grantType->setPrivateKey($this->privateKey); - $grantType->setPublicKey($this->publicKey); $grantType->setEmitter($this->getEmitter()); $grantType->setEncryptionKey($this->encryptionKey); From e1ef13306773e87d0ab6e358d93def3786c0d729 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 1 Jul 2017 18:22:44 +0100 Subject: [PATCH 31/55] Dropped PHP 5.5 compatability --- .travis.yml | 2 -- README.md | 2 -- composer.json | 8 ++------ 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index c0ce917b..1f085674 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,8 +7,6 @@ cache: - vendor php: - - 5.5.9 - - 5.5 - 5.6 - 7.0 - 7.1 diff --git a/README.md b/README.md index d86bb3f7..62c865e8 100644 --- a/README.md +++ b/README.md @@ -30,11 +30,9 @@ This library was created by Alex Bilbie. Find him on Twitter at [@alexbilbie](ht The following versions of PHP are supported: -* PHP 5.5 (>=5.5.9) * PHP 5.6 * PHP 7.0 * PHP 7.1 -* HHVM The `openssl` extension is also required. diff --git a/composer.json b/composer.json index 51d467b5..d6740aa4 100644 --- a/composer.json +++ b/composer.json @@ -4,7 +4,7 @@ "homepage": "https://oauth2.thephpleague.com/", "license": "MIT", "require": { - "php": ">=5.5.9", + "php": ">=5.6.0", "ext-openssl": "*", "league/event": "^2.1", "lcobucci/jwt": "^3.1", @@ -14,8 +14,7 @@ }, "require-dev": { "phpunit/phpunit": "^4.8 || ^5.0", - "zendframework/zend-diactoros": "^1.0", - "indigophp/hash-compat": "^1.1" + "zendframework/zend-diactoros": "^1.0" }, "repositories": [ { @@ -60,8 +59,5 @@ "psr-4": { "LeagueTests\\": "tests/" } - }, - "suggest": { - "indigophp/hash-compat": "Polyfill for hash_equals function for PHP 5.5" } } From f5c3ba0b244c427d265749b076a99077d99a4631 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 1 Jul 2017 18:22:51 +0100 Subject: [PATCH 32/55] Removed dead code --- src/Grant/AuthCodeGrant.php | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 2a05355e..594bc7ab 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -322,20 +322,6 @@ class AuthCodeGrant extends AbstractAuthorizeGrant 'code_challenge_method ' => $authorizationRequest->getCodeChallengeMethod(), ]; - if ($this->encryptionKey === null) { - // Add padding to vary the length of the payload - $payload['_padding'] = base64_encode(random_bytes(mt_rand(8, 256))); - // Shuffle the payload so that the structure is no longer know and obvious - $keys = array_keys($payload); - shuffle($keys); - $shuffledPayload = []; - foreach ($keys as $key) { - $shuffledPayload[$key] = $payload[$key]; - } - } else { - $shuffledPayload = $payload; - } - $response = new RedirectResponse(); $response->setRedirectUri( $this->makeRedirectUri( @@ -343,7 +329,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant [ 'code' => $this->encrypt( json_encode( - $shuffledPayload + $payload ) ), 'state' => $authorizationRequest->getState(), From 417a64ad43b52b7bb7a627d50e84adffe2481a4e Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 1 Jul 2017 18:33:03 +0100 Subject: [PATCH 33/55] Added security notice --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 62c865e8..08ca06b5 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,11 @@ # PHP OAuth 2.0 Server +### :warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning: +### Security Notice + +### Please upgrade to version `>=5.1.14` (backwards compatible) or `6.x` (one tiny breaking change) to fix some potential security vulnerabilities +### :warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning: + [![Latest Version](http://img.shields.io/packagist/v/league/oauth2-server.svg?style=flat-square)](https://github.com/thephpleague/oauth2-server/releases) [![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md) [![Build Status](https://img.shields.io/travis/thephpleague/oauth2-server/master.svg?style=flat-square)](https://travis-ci.org/thephpleague/oauth2-server) From 00c645545accf9941c4a401037f143523c5dd3b8 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 1 Jul 2017 18:33:17 +0100 Subject: [PATCH 34/55] Updated changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9391de30..ca978bc7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 6.0.0 (released 2017-07-01) + +* Breaking change: The `AuthorizationServer` constructor now expects an encryption key string instead of a public key +* Remove support for HHVM +* Remove support for PHP 5.5 + ## 5.1.4 (released 2017-07-01) * Fixed multiple security vulnerabilities as a result of a security audit paid for by the [Mozilla Secure Open Source Fund](https://wiki.mozilla.org/MOSS/Secure_Open_Source). All users of this library are encouraged to update as soon as possible to this version or version 6.0 or greater. From 0a6a4deca65b049e1d1739a0ba3f46c98c22209e Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 1 Jul 2017 18:38:35 +0100 Subject: [PATCH 35/55] 5.1.4 not 5.1.14 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 08ca06b5..e63865d8 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ### :warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning: ### Security Notice -### Please upgrade to version `>=5.1.14` (backwards compatible) or `6.x` (one tiny breaking change) to fix some potential security vulnerabilities +### Please upgrade to version `>=5.1.4` (backwards compatible) or `6.x` (one tiny breaking change) to fix some potential security vulnerabilities ### :warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning: [![Latest Version](http://img.shields.io/packagist/v/league/oauth2-server.svg?style=flat-square)](https://github.com/thephpleague/oauth2-server/releases) From 2824f7d27e7bf3f1a711aad24db96425f3278906 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 1 Jul 2017 18:46:48 +0100 Subject: [PATCH 36/55] Fixed examples --- examples/public/auth_code.php | 4 +--- examples/public/client_credentials.php | 4 +--- examples/public/implicit.php | 3 +-- examples/public/middleware_use.php | 4 +--- examples/public/password.php | 3 +-- examples/public/refresh_token.php | 4 +--- 6 files changed, 6 insertions(+), 16 deletions(-) diff --git a/examples/public/auth_code.php b/examples/public/auth_code.php index 51f1838c..3c4ca68d 100644 --- a/examples/public/auth_code.php +++ b/examples/public/auth_code.php @@ -36,7 +36,6 @@ $app = new App([ $refreshTokenRepository = new RefreshTokenRepository(); $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; - $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; // Setup the authorization server $server = new AuthorizationServer( @@ -44,9 +43,8 @@ $app = new App([ $accessTokenRepository, $scopeRepository, $privateKeyPath, - $publicKeyPath + 'lxZFUEsBCJ2Yb14IF2ygAHI5N4+ZAUXXaSeeJm6+twsUmIen' ); - $server->setEncryptionKey('lxZFUEsBCJ2Yb14IF2ygAHI5N4+ZAUXXaSeeJm6+twsUmIen'); // Enable the authentication code grant on the server with a token TTL of 1 hour $server->enableGrantType( diff --git a/examples/public/client_credentials.php b/examples/public/client_credentials.php index fd7f5ee9..433fbdce 100644 --- a/examples/public/client_credentials.php +++ b/examples/public/client_credentials.php @@ -32,7 +32,6 @@ $app = new App([ // Path to public and private keys $privateKey = 'file://' . __DIR__ . '/../private.key'; //$privateKey = new CryptKey('file://path/to/private.key', 'passphrase'); // if private key has a pass phrase - $publicKey = 'file://' . __DIR__ . '/../public.key'; // Setup the authorization server $server = new AuthorizationServer( @@ -40,9 +39,8 @@ $app = new App([ $accessTokenRepository, $scopeRepository, $privateKey, - $publicKey + 'lxZFUEsBCJ2Yb14IF2ygAHI5N4+ZAUXXaSeeJm6+twsUmIen' ); - $server->setEncryptionKey('lxZFUEsBCJ2Yb14IF2ygAHI5N4+ZAUXXaSeeJm6+twsUmIen'); // Enable the client credentials grant on the server $server->enableGrantType( diff --git a/examples/public/implicit.php b/examples/public/implicit.php index b496ce19..73de09ec 100644 --- a/examples/public/implicit.php +++ b/examples/public/implicit.php @@ -32,7 +32,6 @@ $app = new App([ $accessTokenRepository = new AccessTokenRepository(); $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; - $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; // Setup the authorization server $server = new AuthorizationServer( @@ -40,7 +39,7 @@ $app = new App([ $accessTokenRepository, $scopeRepository, $privateKeyPath, - $publicKeyPath + 'lxZFUEsBCJ2Yb14IF2ygAHI5N4+ZAUXXaSeeJm6+twsUmIen' ); $server->setEncryptionKey('lxZFUEsBCJ2Yb14IF2ygAHI5N4+ZAUXXaSeeJm6+twsUmIen'); diff --git a/examples/public/middleware_use.php b/examples/public/middleware_use.php index f6a7fcf9..121b9155 100644 --- a/examples/public/middleware_use.php +++ b/examples/public/middleware_use.php @@ -38,7 +38,6 @@ $app = new App([ $refreshTokenRepository = new RefreshTokenRepository(); $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; - $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; // Setup the authorization server $server = new AuthorizationServer( @@ -46,9 +45,8 @@ $app = new App([ $accessTokenRepository, $scopeRepository, $privateKeyPath, - $publicKeyPath + 'lxZFUEsBCJ2Yb14IF2ygAHI5N4+ZAUXXaSeeJm6+twsUmIen' ); - $server->setEncryptionKey('lxZFUEsBCJ2Yb14IF2ygAHI5N4+ZAUXXaSeeJm6+twsUmIen'); // Enable the authentication code grant on the server with a token TTL of 1 hour $server->enableGrantType( diff --git a/examples/public/password.php b/examples/public/password.php index b62acc95..6857e988 100644 --- a/examples/public/password.php +++ b/examples/public/password.php @@ -24,9 +24,8 @@ $app = new App([ new AccessTokenRepository(), // instance of AccessTokenRepositoryInterface new ScopeRepository(), // instance of ScopeRepositoryInterface 'file://' . __DIR__ . '/../private.key', // path to private key - 'file://' . __DIR__ . '/../public.key' // path to public key + 'lxZFUEsBCJ2Yb14IF2ygAHI5N4+ZAUXXaSeeJm6+twsUmIen' // encryption key ); - $server->setEncryptionKey('lxZFUEsBCJ2Yb14IF2ygAHI5N4+ZAUXXaSeeJm6+twsUmIen'); $grant = new PasswordGrant( new UserRepository(), // instance of UserRepositoryInterface diff --git a/examples/public/refresh_token.php b/examples/public/refresh_token.php index 25c32100..39be0826 100644 --- a/examples/public/refresh_token.php +++ b/examples/public/refresh_token.php @@ -32,7 +32,6 @@ $app = new App([ $refreshTokenRepository = new RefreshTokenRepository(); $privateKeyPath = 'file://' . __DIR__ . '/../private.key'; - $publicKeyPath = 'file://' . __DIR__ . '/../public.key'; // Setup the authorization server $server = new AuthorizationServer( @@ -40,9 +39,8 @@ $app = new App([ $accessTokenRepository, $scopeRepository, $privateKeyPath, - $publicKeyPath + 'lxZFUEsBCJ2Yb14IF2ygAHI5N4+ZAUXXaSeeJm6+twsUmIen' ); - $server->setEncryptionKey('lxZFUEsBCJ2Yb14IF2ygAHI5N4+ZAUXXaSeeJm6+twsUmIen'); // Enable the refresh token grant on the server $grant = new RefreshTokenGrant($refreshTokenRepository); From 315d079033df8f14e18860d9a56ff8f9653eeb22 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sun, 2 Jul 2017 18:44:55 +0100 Subject: [PATCH 37/55] Added link to security release information page --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e63865d8..e3d88169 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ### :warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning: ### Security Notice -### Please upgrade to version `>=5.1.4` (backwards compatible) or `6.x` (one tiny breaking change) to fix some potential security vulnerabilities +### Please upgrade to version `>=5.1.4` (backwards compatible) or `6.x` (one tiny breaking change) to fix some potential security vulnerabilities - [visit this page for more information](https://oauth2.thephpleague.com/v5-security-improvements/) ### :warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning::warning: [![Latest Version](http://img.shields.io/packagist/v/league/oauth2-server.svg?style=flat-square)](https://github.com/thephpleague/oauth2-server/releases) From 88bf8b236781439cf52877ab59c1adb6166a8b74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Parmentier?= Date: Mon, 3 Jul 2017 20:28:28 +0200 Subject: [PATCH 38/55] Fix missing sprintf --- src/CryptKey.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/CryptKey.php b/src/CryptKey.php index f3051d04..c707b223 100644 --- a/src/CryptKey.php +++ b/src/CryptKey.php @@ -79,19 +79,19 @@ class CryptKey if (!file_exists($keyPath) && !touch($keyPath)) { // @codeCoverageIgnoreStart - throw new \RuntimeException('"%s" key file could not be created', $keyPath); + throw new \RuntimeException(sprintf('"%s" key file could not be created', $keyPath)); // @codeCoverageIgnoreEnd } if (file_put_contents($keyPath, $key) === false) { // @codeCoverageIgnoreStart - throw new \RuntimeException('Unable to write key file to temporary directory "%s"', $tmpDir); + throw new \RuntimeException(sprintf('Unable to write key file to temporary directory "%s"', $tmpDir)); // @codeCoverageIgnoreEnd } if (chmod($keyPath, 0600) === false) { // @codeCoverageIgnoreStart - throw new \RuntimeException('The key file "%s" file mode could not be changed with chmod to 600', $keyPath); + throw new \RuntimeException(sprintf('The key file "%s" file mode could not be changed with chmod to 600', $keyPath)); // @codeCoverageIgnoreEnd } From 80fc8e654b6ab6ba66000ddd7b95f8d7203c2443 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Wed, 19 Jul 2017 07:57:47 +0100 Subject: [PATCH 39/55] Trigger E_USER_NOTICE instead of throwing an exception if key cannot be chmod to 600 --- src/CryptKey.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/CryptKey.php b/src/CryptKey.php index c707b223..557d6dc7 100644 --- a/src/CryptKey.php +++ b/src/CryptKey.php @@ -50,12 +50,13 @@ class CryptKey // Attempt to correct the permissions if (chmod($keyPath, 0600) === false) { // @codeCoverageIgnoreStart - throw new \LogicException( + trigger_error( sprintf( 'Key file "%s" permissions are not correct, should be 600 instead of %s, unable to automatically resolve the issue', $keyPath, $keyPathPerms - ) + ), + E_USER_NOTICE ); // @codeCoverageIgnoreEnd } From a1b8d87b473e9b956b80e7e20b31ae20dc670d30 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Wed, 19 Jul 2017 07:58:56 +0100 Subject: [PATCH 40/55] Updated changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ca978bc7..2b532e9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 6.0.1 (released 2017-07-19) + +To address feedback from the security release the following change has been made: + +* If an RSA key cannot be chmod'ed to 600 then it will now throw a E_USER_NOTICE instead of an exception. + ## 6.0.0 (released 2017-07-01) * Breaking change: The `AuthorizationServer` constructor now expects an encryption key string instead of a public key From ecc07abb3367e34c3090aa67212421dee9bac905 Mon Sep 17 00:00:00 2001 From: Benjamin Dieleman Date: Thu, 27 Jul 2017 17:27:36 +0200 Subject: [PATCH 41/55] Updated PHPDoc about the unicity violation exception throwing UniqueTokenIdentifierConstraintViolationException can be thrown when persisting tokens --- src/Repositories/AccessTokenRepositoryInterface.php | 3 +++ src/Repositories/AuthCodeRepositoryInterface.php | 3 +++ src/Repositories/RefreshTokenRepositoryInterface.php | 3 +++ 3 files changed, 9 insertions(+) diff --git a/src/Repositories/AccessTokenRepositoryInterface.php b/src/Repositories/AccessTokenRepositoryInterface.php index 04e98bc6..72ddf1f4 100644 --- a/src/Repositories/AccessTokenRepositoryInterface.php +++ b/src/Repositories/AccessTokenRepositoryInterface.php @@ -12,6 +12,7 @@ namespace League\OAuth2\Server\Repositories; use League\OAuth2\Server\Entities\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\ClientEntityInterface; use League\OAuth2\Server\Entities\ScopeEntityInterface; +use League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException; /** * Access token interface. @@ -33,6 +34,8 @@ interface AccessTokenRepositoryInterface extends RepositoryInterface * Persists a new access token to permanent storage. * * @param AccessTokenEntityInterface $accessTokenEntity + * + * @throws UniqueTokenIdentifierConstraintViolationException */ public function persistNewAccessToken(AccessTokenEntityInterface $accessTokenEntity); diff --git a/src/Repositories/AuthCodeRepositoryInterface.php b/src/Repositories/AuthCodeRepositoryInterface.php index 4d23439a..2dc285b8 100644 --- a/src/Repositories/AuthCodeRepositoryInterface.php +++ b/src/Repositories/AuthCodeRepositoryInterface.php @@ -10,6 +10,7 @@ namespace League\OAuth2\Server\Repositories; use League\OAuth2\Server\Entities\AuthCodeEntityInterface; +use League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException; /** * Auth code storage interface. @@ -27,6 +28,8 @@ interface AuthCodeRepositoryInterface extends RepositoryInterface * Persists a new auth code to permanent storage. * * @param AuthCodeEntityInterface $authCodeEntity + * + * @throws UniqueTokenIdentifierConstraintViolationException */ public function persistNewAuthCode(AuthCodeEntityInterface $authCodeEntity); diff --git a/src/Repositories/RefreshTokenRepositoryInterface.php b/src/Repositories/RefreshTokenRepositoryInterface.php index d7e686cc..0c0697bf 100644 --- a/src/Repositories/RefreshTokenRepositoryInterface.php +++ b/src/Repositories/RefreshTokenRepositoryInterface.php @@ -10,6 +10,7 @@ namespace League\OAuth2\Server\Repositories; use League\OAuth2\Server\Entities\RefreshTokenEntityInterface; +use League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException; /** * Refresh token interface. @@ -27,6 +28,8 @@ interface RefreshTokenRepositoryInterface extends RepositoryInterface * Create a new refresh token_name. * * @param RefreshTokenEntityInterface $refreshTokenEntity + * + * @throws UniqueTokenIdentifierConstraintViolationException */ public function persistNewRefreshToken(RefreshTokenEntityInterface $refreshTokenEntity); From 0f1ddaaacf2018002f2f7840555e47982c200ac2 Mon Sep 17 00:00:00 2001 From: Mathieu Alorent Date: Sat, 29 Jul 2017 17:41:44 +0200 Subject: [PATCH 42/55] Fix #772 - PR should be based on master branch --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0391ae5e..af439e0a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,7 +1,7 @@ Thanks for contributing to this project. -**Please submit your pull request against the `develop` branch only.** +**Please submit your pull request against the `master` branch only.** Please ensure that you run `phpunit` from the project root after you've made any changes. From 79038ced785e3fc733408b6ba8a88be7d0c30b59 Mon Sep 17 00:00:00 2001 From: Hugo Hamon Date: Wed, 2 Aug 2017 17:55:11 +0200 Subject: [PATCH 43/55] [BC Break] Fixes invalid code challenge method payload key name I guess this change might be a BC break for existing and active authorization tokens when they're validated by the server. The good thing is that an authorization token has a very short expiration time and is used once to request an access token. --- src/Grant/AuthCodeGrant.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Grant/AuthCodeGrant.php b/src/Grant/AuthCodeGrant.php index 594bc7ab..a138366f 100644 --- a/src/Grant/AuthCodeGrant.php +++ b/src/Grant/AuthCodeGrant.php @@ -312,14 +312,14 @@ class AuthCodeGrant extends AbstractAuthorizeGrant ); $payload = [ - 'client_id' => $authCode->getClient()->getIdentifier(), - 'redirect_uri' => $authCode->getRedirectUri(), - 'auth_code_id' => $authCode->getIdentifier(), - 'scopes' => $authCode->getScopes(), - 'user_id' => $authCode->getUserIdentifier(), - 'expire_time' => (new \DateTime())->add($this->authCodeTTL)->format('U'), - 'code_challenge' => $authorizationRequest->getCodeChallenge(), - 'code_challenge_method ' => $authorizationRequest->getCodeChallengeMethod(), + 'client_id' => $authCode->getClient()->getIdentifier(), + 'redirect_uri' => $authCode->getRedirectUri(), + 'auth_code_id' => $authCode->getIdentifier(), + 'scopes' => $authCode->getScopes(), + 'user_id' => $authCode->getUserIdentifier(), + 'expire_time' => (new \DateTime())->add($this->authCodeTTL)->format('U'), + 'code_challenge' => $authorizationRequest->getCodeChallenge(), + 'code_challenge_method' => $authorizationRequest->getCodeChallengeMethod(), ]; $response = new RedirectResponse(); From 2aca909d203e8a925da8c3a3f16a803683cecf04 Mon Sep 17 00:00:00 2001 From: Yannick de Lange Date: Tue, 1 Aug 2017 14:59:21 +0200 Subject: [PATCH 44/55] Removed chmod from CryptKey and add toggle to disable checking --- src/CryptKey.php | 27 +++++++++++---------------- tests/AuthorizationServerTest.php | 7 +++++++ 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/CryptKey.php b/src/CryptKey.php index 557d6dc7..2ede9e33 100644 --- a/src/CryptKey.php +++ b/src/CryptKey.php @@ -29,8 +29,9 @@ class CryptKey /** * @param string $keyPath * @param null|string $passPhrase + * @param bool $keyPermissionsCheck */ - public function __construct($keyPath, $passPhrase = null) + public function __construct($keyPath, $passPhrase = null, $keyPermissionsCheck = true) { if (preg_match(self::RSA_KEY_PATTERN, $keyPath)) { $keyPath = $this->saveKeyToFile($keyPath); @@ -44,21 +45,15 @@ class CryptKey throw new \LogicException(sprintf('Key path "%s" does not exist or is not readable', $keyPath)); } - // Verify the permissions of the key - $keyPathPerms = decoct(fileperms($keyPath) & 0777); - if ($keyPathPerms !== '600') { - // Attempt to correct the permissions - if (chmod($keyPath, 0600) === false) { - // @codeCoverageIgnoreStart - trigger_error( - sprintf( - 'Key file "%s" permissions are not correct, should be 600 instead of %s, unable to automatically resolve the issue', - $keyPath, - $keyPathPerms - ), - E_USER_NOTICE - ); - // @codeCoverageIgnoreEnd + if ($keyPermissionsCheck === true) { + // Verify the permissions of the key + $keyPathPerms = decoct(fileperms($keyPath) & 0777); + if (in_array($keyPathPerms, ['600', '660'], true) === false) { + trigger_error(sprintf( + 'Key file "%s" permissions are not correct, should be 600 or 660 instead of %s', + $keyPath, + $keyPathPerms + ), E_USER_NOTICE); } } diff --git a/tests/AuthorizationServerTest.php b/tests/AuthorizationServerTest.php index 7b921ff9..91ca9e4b 100644 --- a/tests/AuthorizationServerTest.php +++ b/tests/AuthorizationServerTest.php @@ -26,6 +26,13 @@ use Zend\Diactoros\ServerRequestFactory; class AuthorizationServerTest extends \PHPUnit_Framework_TestCase { + public function setUp() + { + // Make sure the keys have the correct permissions. + chmod(__DIR__ . '/Stubs/private.key', 0600); + chmod(__DIR__ . '/Stubs/public.key', 0600); + } + public function testRespondToRequestInvalidGrantType() { $server = new AuthorizationServer( From c86c7dde70cecc459cb3592f8a862389e3d841d0 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 3 Aug 2017 16:07:11 +0100 Subject: [PATCH 45/55] Fix #759 --- src/Exception/OAuthServerException.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Exception/OAuthServerException.php b/src/Exception/OAuthServerException.php index 6cd82bb3..45e03c07 100644 --- a/src/Exception/OAuthServerException.php +++ b/src/Exception/OAuthServerException.php @@ -152,7 +152,7 @@ class OAuthServerException extends \Exception */ public static function invalidRefreshToken($hint = null) { - return new static('The refresh token is invalid.', 8, 'invalid_request', 400, $hint); + return new static('The refresh token is invalid.', 8, 'invalid_request', 401, $hint); } /** From 925776958fc3f5278e74363663c20147af32b668 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Thu, 3 Aug 2017 16:09:23 +0100 Subject: [PATCH 46/55] Updated changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b532e9c..958a941e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 6.0.2 (released 2017-08-03) + +* An invalid refresh token that can't be decrypted now returns a HTTP 401 error instead of HTTP 400 (Issue #759) +* Removed chmod from CryptKey and add toggle to disable checking (Issue #776) +* Fixes invalid code challenge method payload key name (Issue #777) + ## 6.0.1 (released 2017-07-19) To address feedback from the security release the following change has been made: From 5b223a9501f882bb0ebadfee9fd92778ffe8b5ae Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Wed, 11 Oct 2017 10:33:10 +0100 Subject: [PATCH 47/55] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index e3d88169..0cf7b95b 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,10 @@ Bugs and feature request are tracked on [GitHub](https://github.com/thephpleague If you have any questions about OAuth _please_ open a ticket here; please **don't** email the address below. + + Sponsor + + ## Commercial Support If you would like help implementing this library into your existing platform, or would be interested in OAuth advice or training for you and your team please get in touch with [Glynde Labs](https://glyndelabs.com). From e7ee483d11afc5658e3b2e51f1bff24406431848 Mon Sep 17 00:00:00 2001 From: Andrew Millington Date: Fri, 13 Oct 2017 23:02:29 +0100 Subject: [PATCH 48/55] Changed function comment to reflect we are setting the public, instead of private key --- src/AuthorizationValidators/BearerTokenValidator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AuthorizationValidators/BearerTokenValidator.php b/src/AuthorizationValidators/BearerTokenValidator.php index 1547f6bf..6f299ce4 100644 --- a/src/AuthorizationValidators/BearerTokenValidator.php +++ b/src/AuthorizationValidators/BearerTokenValidator.php @@ -41,7 +41,7 @@ class BearerTokenValidator implements AuthorizationValidatorInterface } /** - * Set the private key + * Set the public key * * @param \League\OAuth2\Server\CryptKey $key */ From 203be5ca20de4a0a3520513b7507d7e2dc5fc0f8 Mon Sep 17 00:00:00 2001 From: Diogo Oliveira de Melo Date: Fri, 20 Oct 2017 09:23:36 -0200 Subject: [PATCH 49/55] Revert comparison order, as suggested by @Sephster --- src/Grant/ImplicitGrant.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Grant/ImplicitGrant.php b/src/Grant/ImplicitGrant.php index 2ec9aed7..693880b4 100644 --- a/src/Grant/ImplicitGrant.php +++ b/src/Grant/ImplicitGrant.php @@ -96,7 +96,7 @@ class ImplicitGrant extends AbstractAuthorizeGrant { return ( isset($request->getQueryParams()['response_type']) - && 'token' === $request->getQueryParams()['response_type'] + && $request->getQueryParams()['response_type'] === 'token' && isset($request->getQueryParams()['client_id']) ); } From 23c7138d48f0d760d3faeb2ef4eb2c9186ee293d Mon Sep 17 00:00:00 2001 From: Brian Retterer Date: Mon, 23 Oct 2017 15:26:10 +0000 Subject: [PATCH 50/55] Apply fixes from StyleCI --- src/AuthorizationServer.php | 1 + src/CryptTrait.php | 4 ++++ src/ResponseTypes/AbstractResponseType.php | 1 - tests/AuthorizationServerTest.php | 1 - tests/CryptTraitTest.php | 1 - tests/Grant/AbstractGrantTest.php | 1 - tests/Grant/AuthCodeGrantTest.php | 1 - tests/Stubs/CryptTraitStub.php | 1 - 8 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/AuthorizationServer.php b/src/AuthorizationServer.php index 46a9b27a..35e745d3 100644 --- a/src/AuthorizationServer.php +++ b/src/AuthorizationServer.php @@ -3,6 +3,7 @@ * @author Alex Bilbie * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ + * * @link https://github.com/thephpleague/oauth2-server */ diff --git a/src/CryptTrait.php b/src/CryptTrait.php index 805969b0..125a757e 100644 --- a/src/CryptTrait.php +++ b/src/CryptTrait.php @@ -1,9 +1,11 @@ * @copyright Copyright (c) Alex Bilbie * @license http://mit-license.org/ + * * @link https://github.com/thephpleague/oauth2-server */ @@ -24,6 +26,7 @@ trait CryptTrait * @param string $unencryptedData * * @throws \LogicException + * * @return string */ protected function encrypt($unencryptedData) @@ -41,6 +44,7 @@ trait CryptTrait * @param string $encryptedData * * @throws \LogicException + * * @return string */ protected function decrypt($encryptedData) diff --git a/src/ResponseTypes/AbstractResponseType.php b/src/ResponseTypes/AbstractResponseType.php index 0c256f17..d013bab0 100644 --- a/src/ResponseTypes/AbstractResponseType.php +++ b/src/ResponseTypes/AbstractResponseType.php @@ -60,5 +60,4 @@ abstract class AbstractResponseType implements ResponseTypeInterface { $this->privateKey = $key; } - } diff --git a/tests/AuthorizationServerTest.php b/tests/AuthorizationServerTest.php index 91ca9e4b..4571c5e1 100644 --- a/tests/AuthorizationServerTest.php +++ b/tests/AuthorizationServerTest.php @@ -3,7 +3,6 @@ namespace LeagueTests; use League\OAuth2\Server\AuthorizationServer; -use League\OAuth2\Server\CryptKey; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Grant\AuthCodeGrant; use League\OAuth2\Server\Grant\ClientCredentialsGrant; diff --git a/tests/CryptTraitTest.php b/tests/CryptTraitTest.php index 8c7d2642..3d60ec9d 100644 --- a/tests/CryptTraitTest.php +++ b/tests/CryptTraitTest.php @@ -2,7 +2,6 @@ namespace LeagueTests\Utils; -use League\OAuth2\Server\CryptKey; use LeagueTests\Stubs\CryptTraitStub; class CryptTraitTest extends \PHPUnit_Framework_TestCase diff --git a/tests/Grant/AbstractGrantTest.php b/tests/Grant/AbstractGrantTest.php index 542c78dc..4cd490e3 100644 --- a/tests/Grant/AbstractGrantTest.php +++ b/tests/Grant/AbstractGrantTest.php @@ -3,7 +3,6 @@ namespace LeagueTests\Grant; use League\Event\Emitter; -use League\OAuth2\Server\CryptKey; use League\OAuth2\Server\Entities\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\AuthCodeEntityInterface; use League\OAuth2\Server\Entities\RefreshTokenEntityInterface; diff --git a/tests/Grant/AuthCodeGrantTest.php b/tests/Grant/AuthCodeGrantTest.php index 3bccba0a..d63aec29 100644 --- a/tests/Grant/AuthCodeGrantTest.php +++ b/tests/Grant/AuthCodeGrantTest.php @@ -2,7 +2,6 @@ namespace LeagueTests\Grant; -use League\OAuth2\Server\CryptKey; use League\OAuth2\Server\Entities\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\RefreshTokenEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; diff --git a/tests/Stubs/CryptTraitStub.php b/tests/Stubs/CryptTraitStub.php index a481a849..3fe02199 100644 --- a/tests/Stubs/CryptTraitStub.php +++ b/tests/Stubs/CryptTraitStub.php @@ -2,7 +2,6 @@ namespace LeagueTests\Stubs; -use League\OAuth2\Server\CryptKey; use League\OAuth2\Server\CryptTrait; class CryptTraitStub From 63c2c21ee66a37fe4f42f35676294a99983d1419 Mon Sep 17 00:00:00 2001 From: Brian Retterer Date: Mon, 23 Oct 2017 11:26:21 -0400 Subject: [PATCH 51/55] Update readme file to bring in Andy, Brian, and Simon --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0cf7b95b..4f8b0906 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,8 @@ This package is released under the MIT License. See the bundled [LICENSE](https: ## Credits -This code is principally developed and maintained by [Alex Bilbie](https://twitter.com/alexbilbie). +This code is principally developed and maintained by [Andy Millington](https://twitter.com/Sephster), [Brian +Retterer](https://twitter.com/bretterer), and [Simon Hamp](https://twitter.com/simonhamp). Special thanks to [all of these awesome contributors](https://github.com/thephpleague/oauth2-server/contributors). From 825017f27ecd20f101bcf864769222e24a92f886 Mon Sep 17 00:00:00 2001 From: Luca Santarella Date: Wed, 25 Oct 2017 18:30:17 -0400 Subject: [PATCH 52/55] Ability to specify query delimiter, such as `?` instead of the hard-coded `#` --- src/Grant/ImplicitGrant.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Grant/ImplicitGrant.php b/src/Grant/ImplicitGrant.php index 2f7ea51f..4ed2de63 100644 --- a/src/Grant/ImplicitGrant.php +++ b/src/Grant/ImplicitGrant.php @@ -27,11 +27,18 @@ class ImplicitGrant extends AbstractAuthorizeGrant private $accessTokenTTL; /** - * @param \DateInterval $accessTokenTTL + * @var string */ - public function __construct(\DateInterval $accessTokenTTL) + private $queryDelimiter; + + /** + * @param \DateInterval $accessTokenTTL + * @param string $queryDelimiter + */ + public function __construct(\DateInterval $accessTokenTTL, $queryDelimiter = '#') { $this->accessTokenTTL = $accessTokenTTL; + $this->queryDelimiter = $queryDelimiter; } /** @@ -204,7 +211,7 @@ class ImplicitGrant extends AbstractAuthorizeGrant 'expires_in' => $accessToken->getExpiryDateTime()->getTimestamp() - (new \DateTime())->getTimestamp(), 'state' => $authorizationRequest->getState(), ], - '#' + $this->queryDelimiter ) ); From 606f69e6cd8f1746f2ef5c9d539b303d569d27ef Mon Sep 17 00:00:00 2001 From: Luca Santarella Date: Wed, 25 Oct 2017 18:33:26 -0400 Subject: [PATCH 53/55] Fixed indentation in comment to match code style --- src/Grant/ImplicitGrant.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Grant/ImplicitGrant.php b/src/Grant/ImplicitGrant.php index 4ed2de63..ed2f4b5d 100644 --- a/src/Grant/ImplicitGrant.php +++ b/src/Grant/ImplicitGrant.php @@ -32,9 +32,9 @@ class ImplicitGrant extends AbstractAuthorizeGrant private $queryDelimiter; /** - * @param \DateInterval $accessTokenTTL - * @param string $queryDelimiter - */ + * @param \DateInterval $accessTokenTTL + * @param string $queryDelimiter + */ public function __construct(\DateInterval $accessTokenTTL, $queryDelimiter = '#') { $this->accessTokenTTL = $accessTokenTTL; From a4fc05c31e8463ca984743749de2366131b9ae5b Mon Sep 17 00:00:00 2001 From: Luca Santarella Date: Wed, 25 Oct 2017 18:33:26 -0400 Subject: [PATCH 54/55] Fixed indentation in comment to match code style --- src/Grant/ImplicitGrant.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Grant/ImplicitGrant.php b/src/Grant/ImplicitGrant.php index 4ed2de63..4a16314f 100644 --- a/src/Grant/ImplicitGrant.php +++ b/src/Grant/ImplicitGrant.php @@ -31,10 +31,10 @@ class ImplicitGrant extends AbstractAuthorizeGrant */ private $queryDelimiter; - /** - * @param \DateInterval $accessTokenTTL - * @param string $queryDelimiter - */ + /** + * @param \DateInterval $accessTokenTTL + * @param string $queryDelimiter + */ public function __construct(\DateInterval $accessTokenTTL, $queryDelimiter = '#') { $this->accessTokenTTL = $accessTokenTTL; From 4d77aee4a9eef4c7523a24cf7512463f5cea23f7 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Sat, 28 Oct 2017 18:29:55 +0700 Subject: [PATCH 55/55] =?UTF-8?q?Added=20a=20reference=20to=20myself=C2=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 4f8b0906..93e3341e 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,8 @@ This package is released under the MIT License. See the bundled [LICENSE](https: This code is principally developed and maintained by [Andy Millington](https://twitter.com/Sephster), [Brian Retterer](https://twitter.com/bretterer), and [Simon Hamp](https://twitter.com/simonhamp). +Between 2012 and 2017 this library was developed and maintained by [Alex Bilbie](https://alexbilbie.com/). + Special thanks to [all of these awesome contributors](https://github.com/thephpleague/oauth2-server/contributors). Additional thanks go to the [Mozilla Secure Open Source Fund](https://wiki.mozilla.org/MOSS/Secure_Open_Source) for funding a security audit of this library.