From 6bdd108145d16af2f0493d29c45eef988088bd87 Mon Sep 17 00:00:00 2001 From: Alex Bilbie Date: Fri, 16 Jun 2017 16:51:16 +0100 Subject: [PATCH 01/32] 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 02/32] 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 03/32] 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 04/32] 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 05/32] 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 06/32] 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 07/32] 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 08/32] 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 09/32] 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 10/32] 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 11/32] 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 12/32] =?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 13/32] 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 14/32] 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 15/32] 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 16/32] 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 17/32] 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 18/32] 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 19/32] 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 20/32] 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 21/32] 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 22/32] 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 23/32] 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 24/32] 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 25/32] 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 26/32] 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 27/32] 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 28/32] 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 29/32] 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 30/32] 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 31/32] 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 32/32] 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 }