From d6afe436e1057b5e807c26ebcf2c8aea6ef07fe1 Mon Sep 17 00:00:00 2001 From: Westin Shafer Date: Mon, 2 Apr 2018 09:39:58 -0600 Subject: [PATCH 01/99] Added docs for grant configuration --- docs/book/intro.md | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/docs/book/intro.md b/docs/book/intro.md index cbc6b21..6c13cfe 100644 --- a/docs/book/intro.md +++ b/docs/book/intro.md @@ -62,7 +62,21 @@ return [ 'dsn' => '', 'username' => '', 'password' => '' - ] + ], + + // Set value to null to disable a grant + 'grants' => [ + \League\OAuth2\Server\Grant\ClientCredentialsGrant::class + => \League\OAuth2\Server\Grant\ClientCredentialsGrant::class, + \League\OAuth2\Server\Grant\PasswordGrant::class + => \League\OAuth2\Server\Grant\PasswordGrant::class, + \League\OAuth2\Server\Grant\AuthCodeGrant::class + => \League\OAuth2\Server\Grant\AuthCodeGrant::class, + \League\OAuth2\Server\Grant\ImplicitGrant::class + => \League\OAuth2\Server\Grant\ImplicitGrant::class, + \League\OAuth2\Server\Grant\RefreshTokenGrant::class + => \League\OAuth2\Server\Grant\RefreshTokenGrant::class + ], ]; ``` @@ -77,16 +91,21 @@ format in PHP. The default value is `P1D` (1 day). The `refresh_token_expire` value is the TTL used for the refresh token. The default value is 1 month. -The `auth_code_expire` value is th TTL of the authentication code, used in +The `auth_code_expire` value is the TTL of the authentication code, used in the [authorization code grant](https://oauth2.thephpleague.com/authorization-server/auth-code-grant/) scenario. The default value is 10 minutes. -The last parameter is the PDO database configuration. Here we need to insert +The `pdo` value is for the PDO database configuration. Here we need to insert the parameters to access the OAuth2 database. These parameters are the `dsn`, the `username`, and the `password`, if required. The SQL structure of this database is stored in the [data/oauth2.sql](https://github.com/zendframework/zend-expressive-authentication-oauth2/blob/master/data/oauth2.sql) file. +The `grants` array is for enabling/disabling grants. By default all the supported +grants are configured to be available. If you would like to disable any of the +supplied grants, simply change the value for the grant to NULL. Additionally, +you can extend this array to add your own custom grants. + You need to provide an OAuth2 database yourself, or generate a [SQLite](https://www.sqlite.org) database with the following command (using `sqlite3` for GNU/Linux): From be9b79efc6527929482161676813a7b3a5dfa4dd Mon Sep 17 00:00:00 2001 From: Westin Shafer Date: Mon, 2 Apr 2018 10:05:08 -0600 Subject: [PATCH 02/99] Allow existing PDO service to be used --- src/Repository/Pdo/AbstractRepository.php | 4 +-- src/Repository/Pdo/PdoServiceFactory.php | 13 ++++++- test/Repository/Pdo/PdoServiceFactoryTest.php | 35 +++++++++++++++++++ 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/src/Repository/Pdo/AbstractRepository.php b/src/Repository/Pdo/AbstractRepository.php index 7cce630..ebd21c8 100644 --- a/src/Repository/Pdo/AbstractRepository.php +++ b/src/Repository/Pdo/AbstractRepository.php @@ -23,9 +23,9 @@ class AbstractRepository /** * Constructor * - * @param PdoService $pdo + * @param \PDO $pdo */ - public function __construct(PdoService $pdo) + public function __construct(\PDO $pdo) { $this->pdo = $pdo; } diff --git a/src/Repository/Pdo/PdoServiceFactory.php b/src/Repository/Pdo/PdoServiceFactory.php index 4da0057..eda23cc 100644 --- a/src/Repository/Pdo/PdoServiceFactory.php +++ b/src/Repository/Pdo/PdoServiceFactory.php @@ -15,7 +15,7 @@ class PdoServiceFactory { - public function __invoke(ContainerInterface $container) : PdoService + public function __invoke(ContainerInterface $container) : \PDO { $config = $container->has('config') ? $container->get('config') : []; $config = $config['authentication']['pdo'] ?? null; @@ -24,6 +24,17 @@ public function __invoke(ContainerInterface $container) : PdoService 'The PDO configuration is missing' ); } + + if (is_string($config) && !$container->has($config)) { + throw new Exception\InvalidConfigException( + 'Invalid service for PDO' + ); + } + + if (is_string($config) && $container->has($config)) { + return $container->get($config); + } + if (! isset($config['dsn'])) { throw new Exception\InvalidConfigException( 'The DSN configuration is missing for PDO' diff --git a/test/Repository/Pdo/PdoServiceFactoryTest.php b/test/Repository/Pdo/PdoServiceFactoryTest.php index 6a37479..5e60c7c 100644 --- a/test/Repository/Pdo/PdoServiceFactoryTest.php +++ b/test/Repository/Pdo/PdoServiceFactoryTest.php @@ -73,4 +73,39 @@ public function testValidConfigurationResultsInReturnedPdoServiceInstance() $this->assertInstanceOf(PdoService::class, $pdo); } + + public function testValidServiceInConfigurationReturnsPdoService() + { + $mockPdo = $this->prophesize(\PDO::class); + + $this->container->has('config')->willReturn(true); + $this->container->get('config')->willReturn([ + 'authentication' => [ + 'pdo' => 'My\Pdo\Service', + ], + ]); + + $this->container->has('My\Pdo\Service')->willReturn(true); + $this->container->get('My\Pdo\Service')->willReturn($mockPdo->reveal()); + + $pdo = ($this->factory)($this->container->reveal()); + + $this->assertInstanceOf(\PDO::class, $pdo); + } + + public function testRaisesExceptionIfPdoServiceIsInvalid() + { + $this->container->has('config')->willReturn(true); + $this->container->get('config')->willReturn([ + 'authentication' => [ + 'pdo' => 'My\Invalid\Service', + ], + ]); + + $this->container->has('My\Invalid\Service')->willReturn(false); + + $this->expectException(Exception\InvalidConfigException::class); + + ($this->factory)($this->container->reveal()); + } } From 2fb725df124d8c8ed35cd814c804a7bfef0ec681 Mon Sep 17 00:00:00 2001 From: Westin Shafer Date: Mon, 2 Apr 2018 10:18:09 -0600 Subject: [PATCH 03/99] sytle fix --- src/Repository/Pdo/PdoServiceFactory.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Repository/Pdo/PdoServiceFactory.php b/src/Repository/Pdo/PdoServiceFactory.php index eda23cc..25e19dc 100644 --- a/src/Repository/Pdo/PdoServiceFactory.php +++ b/src/Repository/Pdo/PdoServiceFactory.php @@ -25,7 +25,7 @@ public function __invoke(ContainerInterface $container) : \PDO ); } - if (is_string($config) && !$container->has($config)) { + if (is_string($config) && ! $container->has($config)) { throw new Exception\InvalidConfigException( 'Invalid service for PDO' ); From cc2a36ef83245efd0357b24440fa101cdd7029d1 Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Wed, 9 May 2018 15:44:03 -0500 Subject: [PATCH 04/99] Use paths relative to current working directory Previously, using the construct `__DIR__ . '/../data/' for paths to keys causes fatal errors immediately when the user does not override the configuration, and instead uses the default configuration. This is particularly problematic because the documentation suggests that running `vendor/bin/generate-oauth2-keys` should be sufficient. This patch modifies those paths to be relative to the current working directory, `getcwd() . '/data'`, fixing those issues. --- config/oauth2.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config/oauth2.php b/config/oauth2.php index 2a9b9a9..5216f0c 100644 --- a/config/oauth2.php +++ b/config/oauth2.php @@ -10,9 +10,9 @@ * @see http://php.net/manual/en/class.dateinterval.php */ return [ - 'private_key' => __DIR__ . '/../data/private.key', - 'public_key' => __DIR__ . '/../data/public.key', - 'encryption_key' => require __DIR__ . '/../data/encryption.key', + 'private_key' => getcwd() . '/data/private.key', + 'public_key' => getcwd() . '/data/public.key', + 'encryption_key' => require getcwd() . '/data/encryption.key', 'access_token_expire' => 'P1D', // 1 day in DateInterval format 'refresh_token_expire' => 'P1M', // 1 month in DateInterval format 'auth_code_expire' => 'PT10M', // 10 minutes in DateInterval format From 574bec869d8f68045ad52cabc5ec8f90f2f5be5b Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Wed, 9 May 2018 15:45:09 -0500 Subject: [PATCH 05/99] Creates changelog for 0.4.2 release. --- CHANGELOG.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8fe7c5e..d7e99b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,29 @@ All notable changes to this project will be documented in this file, in reverse chronological order by release. +## 0.4.2 - 2018-05-09 + +### Added + +- Nothing. + +### Changed + +- Nothing. + +### Deprecated + +- Nothing. + +### Removed + +- Nothing. + +### Fixed + +- Fixes an issue in the default configuration paths for public, private, and encryption keys, + ensuring they will be based on the current working directory, and not the package directory. + ## 0.4.1 - 2018-05-09 ### Added From e5c8e58db4153e880ff36662133fe81d56a3de1e Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Wed, 9 May 2018 15:58:08 -0500 Subject: [PATCH 06/99] Modifies the configuration to conditionally include the encryption key Previously, we ran a `require` regardless of whether or not the file existed. This causes issues if you configure the location to be elsewhere, as this configuration file is still processed on every single request. We now conditionally require it instead. --- config/oauth2.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/config/oauth2.php b/config/oauth2.php index 5216f0c..9abb090 100644 --- a/config/oauth2.php +++ b/config/oauth2.php @@ -9,10 +9,10 @@ * The expire values must be a valid DateInterval format * @see http://php.net/manual/en/class.dateinterval.php */ -return [ + +$config = [ 'private_key' => getcwd() . '/data/private.key', 'public_key' => getcwd() . '/data/public.key', - 'encryption_key' => require getcwd() . '/data/encryption.key', 'access_token_expire' => 'P1D', // 1 day in DateInterval format 'refresh_token_expire' => 'P1M', // 1 month in DateInterval format 'auth_code_expire' => 'PT10M', // 10 minutes in DateInterval format @@ -36,3 +36,11 @@ => \League\OAuth2\Server\Grant\RefreshTokenGrant::class ], ]; + +// Conditionally include the encryption_key config setting, based on presence of file. +$encryptionKeyFile = getcwd() . '/data/encryption.key'; +if (is_readable($encryptionKeyFile)) { + $config['encryption_key'] = require $encryptionKeyFile; +} + +return $config; From 10f5fcc9eb502eb4e8b0d072b035e9932b644cf1 Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Wed, 9 May 2018 15:59:43 -0500 Subject: [PATCH 07/99] Adds CHANGELOG for 0.4.3. --- CHANGELOG.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d7e99b7..a28c5e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,30 @@ All notable changes to this project will be documented in this file, in reverse chronological order by release. +## 0.4.3 - 2018-05-09 + +### Added + +- Nothing. + +### Changed + +- Nothing. + +### Deprecated + +- Nothing. + +### Removed + +- Nothing. + +### Fixed + +- Removes auto-requiring of the encryption key via the configuration unless the default file + actually exists and is readable. As the configuration is processed in every request, this is necessary + to prevent issues when the file does not exist (e.g., if the user has specified an alternate location). + ## 0.4.2 - 2018-05-09 ### Added From ec9770495021bc4047907aa091a795272c24906a Mon Sep 17 00:00:00 2001 From: tux-rampage Date: Fri, 25 May 2018 00:24:03 +0200 Subject: [PATCH 08/99] Separate authorization and token endpoints --- ...reFactory.php => AuthFlowFactoryTrait.php} | 19 +- src/AuthorizationHanderFactory.php | 27 ++ src/AuthorizationHandler.php | 54 ++++ src/AuthorizationMiddleware.php | 82 +++++ src/AuthorizationMiddlewareFactory.php | 29 ++ src/ConfigProvider.php | 4 +- src/OAuth2Middleware.php | 125 -------- src/TokenEndpointHandler.php | 83 ++++++ src/TokenEndpointHandlerFactory.php | 29 ++ ...=> AuthorizationMiddlewareFactoryTest.php} | 26 +- test/AuthorizationMiddlewareTest.php | 171 +++++++++++ test/OAuth2MiddlewareTest.php | 282 ------------------ test/Pdo/OAuth2PdoMiddlewareTest.php | 18 +- 13 files changed, 508 insertions(+), 441 deletions(-) rename src/{OAuth2MiddlewareFactory.php => AuthFlowFactoryTrait.php} (69%) create mode 100644 src/AuthorizationHanderFactory.php create mode 100644 src/AuthorizationHandler.php create mode 100644 src/AuthorizationMiddleware.php create mode 100644 src/AuthorizationMiddlewareFactory.php delete mode 100644 src/OAuth2Middleware.php create mode 100644 src/TokenEndpointHandler.php create mode 100644 src/TokenEndpointHandlerFactory.php rename test/{OAuth2MiddlewareFactoryTest.php => AuthorizationMiddlewareFactoryTest.php} (78%) create mode 100644 test/AuthorizationMiddlewareTest.php delete mode 100644 test/OAuth2MiddlewareTest.php diff --git a/src/OAuth2MiddlewareFactory.php b/src/AuthFlowFactoryTrait.php similarity index 69% rename from src/OAuth2MiddlewareFactory.php rename to src/AuthFlowFactoryTrait.php index 4a71861..4e32fdb 100644 --- a/src/OAuth2MiddlewareFactory.php +++ b/src/AuthFlowFactoryTrait.php @@ -1,7 +1,7 @@ has(AuthorizationServer::class) ? $container->get(AuthorizationServer::class) @@ -31,9 +33,6 @@ public function __invoke(ContainerInterface $container) : OAuth2Middleware )); } - return new OAuth2Middleware( - $authServer, - $container->get(ResponseInterface::class) - ); + return $authServer; } -} +} \ No newline at end of file diff --git a/src/AuthorizationHanderFactory.php b/src/AuthorizationHanderFactory.php new file mode 100644 index 0000000..093a592 --- /dev/null +++ b/src/AuthorizationHanderFactory.php @@ -0,0 +1,27 @@ +getAuthorizationServer($container), + $container->get(ResponseInterface::class) + ); + } +} \ No newline at end of file diff --git a/src/AuthorizationHandler.php b/src/AuthorizationHandler.php new file mode 100644 index 0000000..e58065c --- /dev/null +++ b/src/AuthorizationHandler.php @@ -0,0 +1,54 @@ +server = $server; + $this->responseFactory = function() use ($responseFactory): ResponseInterface { + return $responseFactory(); + }; + } + + public function handle(ServerRequestInterface $request): ResponseInterface + { + $authRequest = $request->getAttribute(AuthorizationRequest::class); + return $this->server->completeAuthorizationRequest($authRequest, ($this->responseFactory)()); + } +} \ No newline at end of file diff --git a/src/AuthorizationMiddleware.php b/src/AuthorizationMiddleware.php new file mode 100644 index 0000000..302fc98 --- /dev/null +++ b/src/AuthorizationMiddleware.php @@ -0,0 +1,82 @@ +server = $server; + $this->responseFactory = function () use ($responseFactory) : ResponseInterface { + return $responseFactory(); + }; + } + + /** + * {@inheritDoc} + */ + public function process(ServerRequestInterface $request, RequestHandlerInterface $handler) : ResponseInterface + { + $response = ($this->responseFactory)(); + + try { + $authRequest = $this->server->validateAuthorizationRequest($request); + + // The next handler must take care of providing the + // authenticated user and the approval + $authRequest->setAuthorizationApproved(false); + + return $handler->handle($request->withAttribute(AuthorizationRequest::class, $authRequest)); + } catch (OAuthServerException $exception) { + // The validation throws this exception if the request is not valid + // for example when the client id is invalid + return $exception->generateHttpResponse($response); + } catch (\Exception $exception) { + return (new OAuthServerException($exception->getMessage(), 0, 'unknown_error', 500)) + ->generateHttpResponse($response); + } + } +} diff --git a/src/AuthorizationMiddlewareFactory.php b/src/AuthorizationMiddlewareFactory.php new file mode 100644 index 0000000..07f6e20 --- /dev/null +++ b/src/AuthorizationMiddlewareFactory.php @@ -0,0 +1,29 @@ +getAuthorizationServer($container), + $container->get(ResponseInterface::class) + ); + } +} diff --git a/src/ConfigProvider.php b/src/ConfigProvider.php index 4a7aaf5..61da355 100644 --- a/src/ConfigProvider.php +++ b/src/ConfigProvider.php @@ -62,7 +62,7 @@ public function getDependencies() : array AuthenticationInterface::class => OAuth2Adapter::class ], 'factories' => [ - OAuth2Middleware::class => OAuth2MiddlewareFactory::class, + AuthorizationMiddleware::class => AuthorizationMiddlewareFactory::class, OAuth2Adapter::class => OAuth2AdapterFactory::class, AuthorizationServer::class => AuthorizationServerFactory::class, ResourceServer::class => ResourceServerFactory::class, @@ -90,7 +90,7 @@ public function getRoutes() : array [ 'name' => 'oauth', 'path' => '/oauth', - 'middleware' => OAuth2Middleware::class, + 'middleware' => AuthorizationMiddleware::class, 'allowed_methods' => ['GET', 'POST'] ], ]; diff --git a/src/OAuth2Middleware.php b/src/OAuth2Middleware.php deleted file mode 100644 index e3d1acd..0000000 --- a/src/OAuth2Middleware.php +++ /dev/null @@ -1,125 +0,0 @@ -server = $server; - $this->responseFactory = function () use ($responseFactory) : ResponseInterface { - return $responseFactory(); - }; - } - - /** - * {@inheritDoc} - */ - public function process(ServerRequestInterface $request, RequestHandlerInterface $handler) : ResponseInterface - { - $method = $request->getMethod(); - switch (strtoupper($method)) { - case 'GET': - return $this->authorizationRequest($request); - case 'POST': - return $this->accessTokenRequest($request); - } - return ($this->responseFactory)()->withStatus(501); // Method not implemented - } - - /** - * Authorize the request and return an authorization code - * Used for authorization code grant and implicit grant - * - * @see https://oauth2.thephpleague.com/authorization-server/auth-code-grant/ - * @see https://oauth2.thephpleague.com/authorization-server/implicit-grant/ - * - * @param ServerRequestInterface $request - * @return ResponseInterface - */ - protected function authorizationRequest(ServerRequestInterface $request) : ResponseInterface - { - // Create a new response for the request - $response = ($this->responseFactory)(); - - try { - // Validate the HTTP request and return an AuthorizationRequest object. - $authRequest = $this->server->validateAuthorizationRequest($request); - - // The auth request object can be serialized and saved into a user's session. - // You will probably want to redirect the user at this point to a login endpoint. - - // Once the user has logged in set the user on the AuthorizationRequest - $authRequest->setUser(new UserEntity('guest')); // an instance of UserEntityInterface - - // At this point you should redirect the user to an authorization page. - // This form will ask the user to approve the client and the scopes requested. - - // Once the user has approved or denied the client update the status - // (true = approved, false = denied) - $authRequest->setAuthorizationApproved(true); - - // Return the HTTP redirect response - return $this->server->completeAuthorizationRequest($authRequest, $response); - } catch (OAuthServerException $exception) { - return $exception->generateHttpResponse($response); - } catch (\Exception $exception) { - return (new OAuthServerException($exception->getMessage(), 0, 'unknown_error', 500)) - ->generateHttpResponse($response); - } - } - - /** - * Request an access token - * Used for client credential grant, password grant, and refresh token grant - * - * @see https://oauth2.thephpleague.com/authorization-server/client-credentials-grant/ - * @see https://oauth2.thephpleague.com/authorization-server/resource-owner-password-credentials-grant/ - * @see https://oauth2.thephpleague.com/authorization-server/refresh-token-grant/ - * - * @param ServerRequestInterface $request - * @return ResponseInterface - */ - protected function accessTokenRequest(ServerRequestInterface $request) : ResponseInterface - { - // Create a new response for the request - $response = ($this->responseFactory)(); - - try { - return $this->server->respondToAccessTokenRequest($request, $response); - } catch (OAuthServerException $exception) { - return $exception->generateHttpResponse($response); - } catch (\Exception $exception) { - return (new OAuthServerException($exception->getMessage(), 0, 'unknown_error', 500)) - ->generateHttpResponse($response); - } - } -} diff --git a/src/TokenEndpointHandler.php b/src/TokenEndpointHandler.php new file mode 100644 index 0000000..0590e8a --- /dev/null +++ b/src/TokenEndpointHandler.php @@ -0,0 +1,83 @@ +server = $server; + $this->responseFactory = $responseFactory; + } + + private function createResponse(): ResponseInterface + { + return ($this->responseFactory)(); + } + + /** + * Request an access token + * + * Used for client credential grant, password grant, and refresh token grant + * + * @see https://oauth2.thephpleague.com/authorization-server/client-credentials-grant/ + * @see https://oauth2.thephpleague.com/authorization-server/resource-owner-password-credentials-grant/ + * @see https://oauth2.thephpleague.com/authorization-server/refresh-token-grant/ + * @see https://tools.ietf.org/html/rfc6749#section-3.2 + */ + public function handle(ServerRequestInterface $request): ResponseInterface + { + $response = $this->createResponse(); + + if (strtoupper($request->getMethod()) !== 'POST') { + return $response->withStatus(501); // Method not implemented + } + + try { + return $this->server->respondToAccessTokenRequest($request, $response); + } catch (OAuthServerException $exception) { + return $exception->generateHttpResponse($response); + } catch (\Exception $exception) { + return (new OAuthServerException($exception->getMessage(), 0, 'unknown_error', 500)) + ->generateHttpResponse($response); + } + } +} diff --git a/src/TokenEndpointHandlerFactory.php b/src/TokenEndpointHandlerFactory.php new file mode 100644 index 0000000..4e3a6e6 --- /dev/null +++ b/src/TokenEndpointHandlerFactory.php @@ -0,0 +1,29 @@ +getAuthorizationServer($container); + + return new TokenEndpointHandler( + $authServer, + $container->get(ResponseInterface::class) + ); + } +} \ No newline at end of file diff --git a/test/OAuth2MiddlewareFactoryTest.php b/test/AuthorizationMiddlewareFactoryTest.php similarity index 78% rename from test/OAuth2MiddlewareFactoryTest.php rename to test/AuthorizationMiddlewareFactoryTest.php index 021938a..5809276 100644 --- a/test/OAuth2MiddlewareFactoryTest.php +++ b/test/AuthorizationMiddlewareFactoryTest.php @@ -18,18 +18,18 @@ use stdClass; use TypeError; use Zend\Expressive\Authentication\OAuth2\Exception\InvalidConfigException; -use Zend\Expressive\Authentication\OAuth2\OAuth2Middleware; -use Zend\Expressive\Authentication\OAuth2\OAuth2MiddlewareFactory; +use Zend\Expressive\Authentication\OAuth2\AuthorizationMiddleware; +use Zend\Expressive\Authentication\OAuth2\AuthorizationMiddlewareFactory; /** - * @covers \Zend\Expressive\Authentication\OAuth2\OAuth2MiddlewareFactory + * @covers \Zend\Expressive\Authentication\OAuth2\AuthorizationMiddlewareFactory */ -class OAuth2MiddlewareFactoryTest extends TestCase +class AuthorizationMiddlewareFactoryTest extends TestCase { /** @var AuthorizationServer|ObjectProphecy */ private $authServer; - /** @var AuthServer|ObjectProphecy */ + /** @var ContainerInterface|ObjectProphecy */ private $container; /** @var ResponseInterface|ObjectProphecy */ @@ -44,16 +44,16 @@ public function setUp() public function testConstructor() { - $factory = new OAuth2MiddlewareFactory(); - $this->assertInstanceOf(OAuth2MiddlewareFactory::class, $factory); + $factory = new AuthorizationMiddlewareFactory(); + $this->assertInstanceOf(AuthorizationMiddlewareFactory::class, $factory); } public function testInvokeWithEmptyContainer() { - $factory = new OAuth2MiddlewareFactory(); + $factory = new AuthorizationMiddlewareFactory(); $this->expectException(InvalidConfigException::class); - $middleware = $factory($this->container->reveal()); + $factory($this->container->reveal()); } public function testFactoryRaisesTypeErrorForNonCallableResponseFactory() @@ -68,7 +68,7 @@ public function testFactoryRaisesTypeErrorForNonCallableResponseFactory() ->get(ResponseInterface::class) ->willReturn(new stdClass()); - $factory = new OAuth2MiddlewareFactory(); + $factory = new AuthorizationMiddlewareFactory(); $this->expectException(TypeError::class); $factory($this->container->reveal()); @@ -86,7 +86,7 @@ public function testFactoryRaisesTypeErrorWhenResponseServiceProvidesResponseIns ->get(ResponseInterface::class) ->will([$this->response, 'reveal']); - $factory = new OAuth2MiddlewareFactory(); + $factory = new AuthorizationMiddlewareFactory(); $this->expectException(TypeError::class); $factory($this->container->reveal()); @@ -106,8 +106,8 @@ public function testFactoryReturnsInstanceWhenAppropriateDependenciesArePresentI return $this->response->reveal(); }); - $factory = new OAuth2MiddlewareFactory(); + $factory = new AuthorizationMiddlewareFactory(); $middleware = $factory($this->container->reveal()); - $this->assertInstanceOf(OAuth2Middleware::class, $middleware); + $this->assertInstanceOf(AuthorizationMiddleware::class, $middleware); } } diff --git a/test/AuthorizationMiddlewareTest.php b/test/AuthorizationMiddlewareTest.php new file mode 100644 index 0000000..d5d0eb7 --- /dev/null +++ b/test/AuthorizationMiddlewareTest.php @@ -0,0 +1,171 @@ +authServer = $this->prophesize(AuthorizationServer::class); + $this->response = $this->prophesize(ResponseInterface::class); + $this->serverRequest = $this->prophesize(ServerRequestInterface::class); + $this->authRequest = $this->prophesize(AuthorizationRequest::class); + $this->handler = $this->prophesize(RequestHandlerInterface::class); + $this->responseFactory = function () { + return $this->response->reveal(); + }; + } + + public function testConstructor() + { + $middleware = new AuthorizationMiddleware( + $this->authServer->reveal(), + $this->responseFactory + ); + + $this->assertInstanceOf(AuthorizationMiddleware::class, $middleware); + $this->assertInstanceOf(MiddlewareInterface::class, $middleware); + } + + public function testProcess() + { + $this->authRequest + ->setUser(Argument::any()) + ->shouldNotBeCalled(); // Ths middleware must not provide a user entity + $this->authRequest + ->setAuthorizationApproved(false) // Expect approval to be set to false only + ->willReturn(null); + + // Mock a valid authorization request + $this->authServer + ->validateAuthorizationRequest($this->serverRequest->reveal()) + ->willReturn($this->authRequest->reveal()); + + // Mock a instance immutability when the authorization request + // is populated + $newRequest = $this->prophesize(ServerRequestInterface::class); + $this->serverRequest + ->withAttribute(AuthorizationRequest::class, $this->authRequest->reveal()) + ->willReturn($newRequest->reveal()); + + // Expect the handler to be called with the new modified request, + // that contains the auth request attribute + $handlerResponse = $this->prophesize(ResponseInterface::class)->reveal(); + $this->handler + ->handle($newRequest->reveal()) + ->willReturn($handlerResponse); + + + $middleware = new AuthorizationMiddleware( + $this->authServer->reveal(), + $this->responseFactory + ); + $response = $middleware->process( + $this->serverRequest->reveal(), + $this->handler->reveal() + ); + + $this->assertSame($handlerResponse, $response); + } + + public function testAuthorizationRequestRaisingOAuthServerExceptionGeneratesResponseFromException() + { + $response = $this->prophesize(ResponseInterface::class); + $oauthServerException = $this->prophesize(OAuthServerException::class); + $oauthServerException + ->generateHttpResponse(Argument::type(ResponseInterface::class)) + ->willReturn($response->reveal()); + + $this->authServer + ->validateAuthorizationRequest($this->serverRequest->reveal()) + ->willThrow($oauthServerException->reveal()); + + $middleware = new AuthorizationMiddleware( + $this->authServer->reveal(), + $this->responseFactory + ); + + $result = $middleware->process( + $this->serverRequest->reveal(), + $this->handler->reveal() + ); + + $this->assertSame($response->reveal(), $result); + } + + public function testAuthorizationRequestRaisingUnknownExceptionGeneratesResponseFromException() + { + $body = $this->prophesize(StreamInterface::class); + $body + ->write(Argument::containingString('oauth2 server error')) + ->shouldBeCalled(); + + $this->response->getBody()->willReturn($body->reveal())->shouldBeCalled(); + $this->response + ->withHeader(Argument::type('string'), Argument::type('string')) + ->willReturn($this->response->reveal()) + ->shouldBeCalled(); + $this->response + ->withStatus(500) + ->willReturn($this->response->reveal()) + ->shouldBeCalled(); + + $exception = new RuntimeException('oauth2 server error'); + + $this->authServer + ->validateAuthorizationRequest($this->serverRequest->reveal()) + ->willThrow($exception); + + $middleware = new AuthorizationMiddleware( + $this->authServer->reveal(), + $this->responseFactory + ); + + $response = $middleware->process( + $this->serverRequest->reveal(), + $this->handler->reveal() + ); + + $this->assertSame($this->response->reveal(), $response); + } +} diff --git a/test/OAuth2MiddlewareTest.php b/test/OAuth2MiddlewareTest.php deleted file mode 100644 index b84a213..0000000 --- a/test/OAuth2MiddlewareTest.php +++ /dev/null @@ -1,282 +0,0 @@ -authServer = $this->prophesize(AuthorizationServer::class); - $this->response = $this->prophesize(ResponseInterface::class); - $this->serverRequest = $this->prophesize(ServerRequestInterface::class); - $this->authRequest = $this->prophesize(AuthorizationRequest::class); - $this->handler = $this->prophesize(RequestHandlerInterface::class); - $this->responseFactory = function () { - return $this->response->reveal(); - }; - } - - public function testConstructor() - { - $middleware = new OAuth2Middleware( - $this->authServer->reveal(), - $this->responseFactory - ); - $this->assertInstanceOf(OAuth2Middleware::class, $middleware); - $this->assertInstanceOf(MiddlewareInterface::class, $middleware); - } - - public function testProcessWithGet() - { - $this->authRequest - ->setUser(Argument::any()) - ->willReturn(null); - $this->authRequest - ->setAuthorizationApproved(true) - ->willReturn(null); - - $this->serverRequest - ->getMethod() - ->willReturn('GET'); - - $this->authServer - ->completeAuthorizationRequest( - $this->authRequest->reveal(), - $this->response->reveal() - ) - ->willReturn($this->response->reveal()); - $this->authServer - ->validateAuthorizationRequest($this->serverRequest->reveal()) - ->willReturn($this->authRequest); - - $middleware = new OAuth2Middleware( - $this->authServer->reveal(), - $this->responseFactory - ); - $response = $middleware->process( - $this->serverRequest->reveal(), - $this->handler->reveal() - ); - $this->assertInstanceOf(ResponseInterface::class, $response); - } - - public function testProcessWithPost() - { - $this->serverRequest->getMethod() - ->willReturn('POST'); - - $this->authServer - ->respondToAccessTokenRequest( - $this->serverRequest->reveal(), - $this->response->reveal() - ) - ->willReturn($this->response->reveal()); - - $middleware = new OAuth2Middleware( - $this->authServer->reveal(), - $this->responseFactory - ); - $response = $middleware->process( - $this->serverRequest->reveal(), - $this->handler->reveal() - ); - $this->assertInstanceOf(ResponseInterface::class, $response); - } - - public function testAuthorizationRequestRaisingOAuthServerExceptionGeneratesResponseFromException() - { - $response = $this->prophesize(ResponseInterface::class); - $oauthServerException = $this->prophesize(OAuthServerException::class); - $oauthServerException - ->generateHttpResponse(Argument::type(ResponseInterface::class)) - ->will([$response, 'reveal']); - - $this->authServer - ->validateAuthorizationRequest( - Argument::that([$this->serverRequest, 'reveal']) - ) - ->willThrow($oauthServerException->reveal()); - - $middleware = new OAuth2Middleware( - $this->authServer->reveal(), - $this->responseFactory - ); - - $this->serverRequest->getMethod()->willReturn('GET'); - - $result = $middleware->process( - $this->serverRequest->reveal(), - $this->handler->reveal() - ); - - $this->assertSame($response->reveal(), $result); - } - - public function testAuthorizationRequestRaisingUnknownExceptionGeneratesResponseFromException() - { - $body = $this->prophesize(StreamInterface::class); - $body - ->write(Argument::containingString('oauth2 server error')) - ->shouldBeCalled(); - - $this->response->getBody()->will([$body, 'reveal'])->shouldBeCalled(); - $this->response - ->withHeader(Argument::type('string'), Argument::type('string')) - ->will([$this->response, 'reveal']) - ->shouldBeCalled(); - $this->response - ->withStatus(500) - ->will([$this->response, 'reveal']) - ->shouldBeCalled(); - - $exception = new RuntimeException('oauth2 server error'); - - $this->authServer - ->validateAuthorizationRequest( - Argument::that([$this->serverRequest, 'reveal']) - ) - ->willThrow($exception); - - $middleware = new OAuth2Middleware( - $this->authServer->reveal(), - $this->responseFactory - ); - - $this->serverRequest->getMethod()->willReturn('GET'); - - $response = $middleware->process( - $this->serverRequest->reveal(), - $this->handler->reveal() - ); - - $this->assertSame($this->response->reveal(), $response); - } - - public function testReturns501ResponseForInvalidMethods() - { - $this->serverRequest->getMethod()->willReturn('UNKNOWN'); - $this->response->withStatus(501)->will([$this->response, 'reveal']); - - $middleware = new OAuth2Middleware( - $this->authServer->reveal(), - $this->responseFactory - ); - - $response = $middleware->process( - $this->serverRequest->reveal(), - $this->handler->reveal() - ); - - $this->assertSame($this->response->reveal(), $response); - } - - public function testPostRequestResultingInOAuthServerExceptionUsesExceptionToGenerateResponse() - { - $this->serverRequest->getMethod()->willReturn('POST'); - - $exception = $this->prophesize(OAuthServerException::class); - $exception - ->generateHttpResponse(Argument::that([$this->response, 'reveal'])) - ->will([$this->response, 'reveal']); - - $this->authServer - ->respondToAccessTokenRequest( - Argument::that([$this->serverRequest, 'reveal']), - Argument::that([$this->response, 'reveal']) - ) - ->willThrow($exception->reveal()); - - $middleware = new OAuth2Middleware( - $this->authServer->reveal(), - $this->responseFactory - ); - - $response = $middleware->process( - $this->serverRequest->reveal(), - $this->handler->reveal() - ); - - $this->assertSame($this->response->reveal(), $response); - } - - public function testPostRequestResultingInGenericExceptionCastsExceptionToOauthServerExceptionToGenerateResponse() - { - $this->serverRequest->getMethod()->willReturn('POST'); - - $exception = new RuntimeException('runtime-exception', 500); - - $body = $this->prophesize(StreamInterface::class); - $body->write(Argument::containingString('runtime-exception'))->shouldBeCalled(); - - $this->response - ->withHeader('Content-type', 'application/json') - ->will([$this->response, 'reveal']); - - $this->response - ->getBody() - ->will([$body, 'reveal']); - - $this->response - ->withStatus(500) - ->will([$this->response, 'reveal']); - - $this->authServer - ->respondToAccessTokenRequest( - Argument::that([$this->serverRequest, 'reveal']), - Argument::that([$this->response, 'reveal']) - ) - ->willThrow($exception); - - $middleware = new OAuth2Middleware( - $this->authServer->reveal(), - $this->responseFactory - ); - - $response = $middleware->process( - $this->serverRequest->reveal(), - $this->handler->reveal() - ); - - $this->assertSame($this->response->reveal(), $response); - } -} diff --git a/test/Pdo/OAuth2PdoMiddlewareTest.php b/test/Pdo/OAuth2PdoMiddlewareTest.php index dfec773..0c8c7e8 100644 --- a/test/Pdo/OAuth2PdoMiddlewareTest.php +++ b/test/Pdo/OAuth2PdoMiddlewareTest.php @@ -24,7 +24,7 @@ use Zend\Diactoros\Response; use Zend\Diactoros\ServerRequest; use Zend\Diactoros\Stream; -use Zend\Expressive\Authentication\OAuth2\OAuth2Middleware; +use Zend\Expressive\Authentication\OAuth2\AuthorizationMiddleware; use Zend\Expressive\Authentication\OAuth2\Repository\Pdo\AccessTokenRepository; use Zend\Expressive\Authentication\OAuth2\Repository\Pdo\AuthCodeRepository; use Zend\Expressive\Authentication\OAuth2\Repository\Pdo\ClientRepository; @@ -141,11 +141,11 @@ public function setUp() public function testConstructor() { - $authMiddleware = new OAuth2Middleware( + $authMiddleware = new AuthorizationMiddleware( $this->authServer, $this->responseFactory ); - $this->assertInstanceOf(OAuth2Middleware::class, $authMiddleware); + $this->assertInstanceOf(AuthorizationMiddleware::class, $authMiddleware); } /** @@ -176,7 +176,7 @@ public function testProcessClientCredentialGrant() [ 'Content-Type' => 'application/x-www-form-urlencoded' ] ); - $authMiddleware = new OAuth2Middleware( + $authMiddleware = new AuthorizationMiddleware( $this->authServer, $this->responseFactory ); @@ -224,7 +224,7 @@ public function testProcessPasswordGrant() [ 'Content-Type' => 'application/x-www-form-urlencoded' ] ); - $authMiddleware = new OAuth2Middleware( + $authMiddleware = new AuthorizationMiddleware( $this->authServer, $this->responseFactory ); @@ -276,7 +276,7 @@ public function testProcessGetAuthorizationCode() $params ); - $authMiddleware = new OAuth2Middleware( + $authMiddleware = new AuthorizationMiddleware( $this->authServer, $this->responseFactory ); @@ -332,7 +332,7 @@ public function testProcessFromAuthorizationCode(string $code) [ 'Content-Type' => 'application/x-www-form-urlencoded' ] ); - $authMiddleware = new OAuth2Middleware( + $authMiddleware = new AuthorizationMiddleware( $this->authServer, $this->responseFactory ); @@ -379,7 +379,7 @@ public function testProcessImplicitGrant() $params ); - $authMiddleware = new OAuth2Middleware( + $authMiddleware = new AuthorizationMiddleware( $this->authServer, $this->responseFactory ); @@ -432,7 +432,7 @@ public function testProcessRefreshTokenGrant(string $refreshToken) [ 'Content-Type' => 'application/x-www-form-urlencoded' ] ); - $authMiddleware = new OAuth2Middleware( + $authMiddleware = new AuthorizationMiddleware( $this->authServer, $this->responseFactory ); From 1215cd6cc690b94a4889998cd07d8f27b52daa97 Mon Sep 17 00:00:00 2001 From: Westin Shafer Date: Wed, 30 May 2018 13:09:52 -0600 Subject: [PATCH 09/99] Added documentaion for passing in existing pdo service --- .gitignore | 1 + docs/book/intro.md | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/.gitignore b/.gitignore index 245087a..8d7f3f7 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ /vendor/ /zf-mkdoc-theme.tgz /zf-mkdoc-theme/ +.idea diff --git a/docs/book/intro.md b/docs/book/intro.md index e7747cc..f7b0789 100644 --- a/docs/book/intro.md +++ b/docs/book/intro.md @@ -87,6 +87,15 @@ the `username`, and the `password`, if required. The SQL structure of this database is stored in the [data/oauth2.sql](https://github.com/zendframework/zend-expressive-authentication-oauth2/blob/master/data/oauth2.sql) file. +If you already have a PDO service configured, you can simply pass in the service +name to the `pdo` key as follows: + +```php +return [ + 'pdo' => 'myServiceName', +]; +``` + You need to provide an OAuth2 database yourself, or generate a [SQLite](https://www.sqlite.org) database with the following command (using `sqlite3` for GNU/Linux): From 4178d4553dcea85a7780fc7988fa3cda025b64a9 Mon Sep 17 00:00:00 2001 From: Axel Helmert Date: Fri, 1 Jun 2018 10:58:42 +0200 Subject: [PATCH 10/99] Update test cases --- test/AuthorizationHandlerFactoryTest.php | 110 ++++++++++++++++++++ test/AuthorizationMiddlewareFactoryTest.php | 21 ++-- test/Pdo/OAuth2PdoMiddlewareTest.php | 90 ++++++++++------ 3 files changed, 179 insertions(+), 42 deletions(-) create mode 100644 test/AuthorizationHandlerFactoryTest.php diff --git a/test/AuthorizationHandlerFactoryTest.php b/test/AuthorizationHandlerFactoryTest.php new file mode 100644 index 0000000..86a32f8 --- /dev/null +++ b/test/AuthorizationHandlerFactoryTest.php @@ -0,0 +1,110 @@ +container = $this->prophesize(ContainerInterface::class); + $this->authServer = $this->prophesize(AuthorizationServer::class); + $this->response = $this->prophesize(ResponseInterface::class); + } + + public function testConstructor() + { + $factory = new AuthorizationHandlerFactory(); + $this->assertInstanceOf(AuthorizationHandlerFactory::class, $factory); + } + + public function testRaisesTypeErrorForInvalidAuthorizationServer() + { + $this->container + ->get(AuthorizationServer::class) + ->willReturn(new stdClass()); + $this->container + ->get(ResponseInterface::class) + ->willReturn(function() {}); + + $factory = new AuthorizationHandlerFactory(); + + $this->expectException(TypeError::class); + $factory($this->container->reveal()); + } + + public function testFactoryRaisesTypeErrorForNonCallableResponseFactory() + { + $this->container + ->get(AuthorizationServer::class) + ->willReturn($this->authServer->reveal()); + $this->container + ->get(ResponseInterface::class) + ->willReturn(new stdClass()); + + $factory = new AuthorizationHandlerFactory(); + + $this->expectException(TypeError::class); + $factory($this->container->reveal()); + } + + public function testFactoryRaisesTypeErrorWhenResponseServiceProvidesResponseInstance() + { + $this->container + ->get(AuthorizationServer::class) + ->willReturn($this->authServer->reveal()); + $this->container + ->get(ResponseInterface::class) + ->will([$this->response, 'reveal']); + + $factory = new AuthorizationHandlerFactory(); + + $this->expectException(TypeError::class); + $factory($this->container->reveal()); + } + + public function testFactoryReturnsInstanceWhenAppropriateDependenciesArePresentInContainer() + { + $this->container + ->get(AuthorizationServer::class) + ->willReturn($this->authServer->reveal()); + $this->container + ->get(ResponseInterface::class) + ->willReturn(function () { + return $this->response->reveal(); + }); + + $factory = new AuthorizationHandlerFactory(); + $middleware = $factory($this->container->reveal()); + $this->assertInstanceOf(AuthorizationHandler::class, $middleware); + } +} diff --git a/test/AuthorizationMiddlewareFactoryTest.php b/test/AuthorizationMiddlewareFactoryTest.php index 5809276..f274c01 100644 --- a/test/AuthorizationMiddlewareFactoryTest.php +++ b/test/AuthorizationMiddlewareFactoryTest.php @@ -17,7 +17,6 @@ use Psr\Http\Message\ResponseInterface; use stdClass; use TypeError; -use Zend\Expressive\Authentication\OAuth2\Exception\InvalidConfigException; use Zend\Expressive\Authentication\OAuth2\AuthorizationMiddleware; use Zend\Expressive\Authentication\OAuth2\AuthorizationMiddlewareFactory; @@ -48,19 +47,23 @@ public function testConstructor() $this->assertInstanceOf(AuthorizationMiddlewareFactory::class, $factory); } - public function testInvokeWithEmptyContainer() + public function testRaisesTypeErrorForInvalidAuthorizationServer() { + $this->container + ->get(AuthorizationServer::class) + ->willReturn(new stdClass()); + $this->container + ->get(ResponseInterface::class) + ->willReturn(function() {}); + $factory = new AuthorizationMiddlewareFactory(); - $this->expectException(InvalidConfigException::class); + $this->expectException(TypeError::class); $factory($this->container->reveal()); } public function testFactoryRaisesTypeErrorForNonCallableResponseFactory() { - $this->container - ->has(AuthorizationServer::class) - ->willReturn(true); $this->container ->get(AuthorizationServer::class) ->willReturn($this->authServer->reveal()); @@ -76,9 +79,6 @@ public function testFactoryRaisesTypeErrorForNonCallableResponseFactory() public function testFactoryRaisesTypeErrorWhenResponseServiceProvidesResponseInstance() { - $this->container - ->has(AuthorizationServer::class) - ->willReturn(true); $this->container ->get(AuthorizationServer::class) ->willReturn($this->authServer->reveal()); @@ -94,9 +94,6 @@ public function testFactoryRaisesTypeErrorWhenResponseServiceProvidesResponseIns public function testFactoryReturnsInstanceWhenAppropriateDependenciesArePresentInContainer() { - $this->container - ->has(AuthorizationServer::class) - ->willReturn(true); $this->container ->get(AuthorizationServer::class) ->willReturn($this->authServer->reveal()); diff --git a/test/Pdo/OAuth2PdoMiddlewareTest.php b/test/Pdo/OAuth2PdoMiddlewareTest.php index 0c8c7e8..e1858f4 100644 --- a/test/Pdo/OAuth2PdoMiddlewareTest.php +++ b/test/Pdo/OAuth2PdoMiddlewareTest.php @@ -17,14 +17,19 @@ use League\OAuth2\Server\Grant\ImplicitGrant; use League\OAuth2\Server\Grant\PasswordGrant; use League\OAuth2\Server\Grant\RefreshTokenGrant; +use League\OAuth2\Server\RequestTypes\AuthorizationRequest; use PDO; use PHPUnit\Framework\TestCase; use Prophecy\Prophecy\ObjectProphecy; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; use Zend\Diactoros\Response; use Zend\Diactoros\ServerRequest; use Zend\Diactoros\Stream; +use Zend\Expressive\Authentication\OAuth2\AuthorizationHandler; use Zend\Expressive\Authentication\OAuth2\AuthorizationMiddleware; +use Zend\Expressive\Authentication\OAuth2\Entity\UserEntity; use Zend\Expressive\Authentication\OAuth2\Repository\Pdo\AccessTokenRepository; use Zend\Expressive\Authentication\OAuth2\Repository\Pdo\AuthCodeRepository; use Zend\Expressive\Authentication\OAuth2\Repository\Pdo\ClientRepository; @@ -32,7 +37,8 @@ use Zend\Expressive\Authentication\OAuth2\Repository\Pdo\RefreshTokenRepository; use Zend\Expressive\Authentication\OAuth2\Repository\Pdo\ScopeRepository; use Zend\Expressive\Authentication\OAuth2\Repository\Pdo\UserRepository; - +use Zend\Expressive\Authentication\OAuth2\TokenEndpointHandler; +use function assert; use function bin2hex; use function explode; use function file_exists; @@ -45,6 +51,11 @@ use function strtolower; use function unlink; +/** + * Integration test for the authorization flows with PDO + * + * @coversNothing + */ class OAuth2PdoMiddlewareTest extends TestCase { const DB_FILE = __DIR__ . '/TestAsset/test_oauth2.sq3'; @@ -59,7 +70,7 @@ class OAuth2PdoMiddlewareTest extends TestCase /** @var AuthCodeRepository */ private $authCodeRepository; - /** @var AuthServer */ + /** @var AuthorizationServer */ private $authServer; /** @var ClientRepository */ @@ -139,15 +150,6 @@ public function setUp() }; } - public function testConstructor() - { - $authMiddleware = new AuthorizationMiddleware( - $this->authServer, - $this->responseFactory - ); - $this->assertInstanceOf(AuthorizationMiddleware::class, $authMiddleware); - } - /** * Test the Client Credential Grant * @@ -176,12 +178,12 @@ public function testProcessClientCredentialGrant() [ 'Content-Type' => 'application/x-www-form-urlencoded' ] ); - $authMiddleware = new AuthorizationMiddleware( + $handler = new TokenEndpointHandler( $this->authServer, $this->responseFactory ); - $response = $authMiddleware->process($request, $this->handler->reveal()); + $response = $handler->handle($request); $this->assertEquals(200, $response->getStatusCode()); $content = json_decode((string) $response->getBody()); @@ -224,12 +226,12 @@ public function testProcessPasswordGrant() [ 'Content-Type' => 'application/x-www-form-urlencoded' ] ); - $authMiddleware = new AuthorizationMiddleware( + $handler = new TokenEndpointHandler( $this->authServer, $this->responseFactory ); - $response = $authMiddleware->process($request, $this->handler->reveal()); + $response = $handler->handle($request); $this->assertEquals(200, $response->getStatusCode()); $content = json_decode((string) $response->getBody()); @@ -240,7 +242,7 @@ public function testProcessPasswordGrant() } /** - * Test the Authorization Code Grant (Part One) + * Test the Authorization Code Grant flow (Part One) * * @see https://oauth2.thephpleague.com/authorization-server/auth-code-grant/ */ @@ -276,12 +278,12 @@ public function testProcessGetAuthorizationCode() $params ); - $authMiddleware = new AuthorizationMiddleware( - $this->authServer, - $this->responseFactory - ); + // mocks the authorization endpoint pipe + $authMiddleware = new AuthorizationMiddleware($this->authServer, $this->responseFactory); + $authHandler = new AuthorizationHandler($this->authServer, $this->responseFactory); + $consumerHandler = $this->buildConsumerAuthMiddleware($authHandler); - $response = $authMiddleware->process($request, $this->handler->reveal()); + $response = $authMiddleware->process($request, $consumerHandler); $this->assertEquals(302, $response->getStatusCode()); $this->assertTrue($response->hasHeader('Location')); @@ -332,12 +334,12 @@ public function testProcessFromAuthorizationCode(string $code) [ 'Content-Type' => 'application/x-www-form-urlencoded' ] ); - $authMiddleware = new AuthorizationMiddleware( + $handler = new TokenEndpointHandler( $this->authServer, $this->responseFactory ); - $response = $authMiddleware->process($request, $this->handler->reveal()); + $response = $handler->handle($request); $this->assertEquals(200, $response->getStatusCode()); $content = json_decode((string) $response->getBody()); @@ -379,12 +381,11 @@ public function testProcessImplicitGrant() $params ); - $authMiddleware = new AuthorizationMiddleware( - $this->authServer, - $this->responseFactory - ); + $authMiddleware = new AuthorizationMiddleware($this->authServer, $this->responseFactory); + $authHandler = new AuthorizationHandler($this->authServer, $this->responseFactory); + $consumerHandler = $this->buildConsumerAuthMiddleware($authHandler); - $response = $authMiddleware->process($request, $this->handler->reveal()); + $response = $authMiddleware->process($request, $consumerHandler); $this->assertEquals(302, $response->getStatusCode()); $this->assertTrue($response->hasHeader('Location')); @@ -432,12 +433,12 @@ public function testProcessRefreshTokenGrant(string $refreshToken) [ 'Content-Type' => 'application/x-www-form-urlencoded' ] ); - $authMiddleware = new AuthorizationMiddleware( + $handler = new TokenEndpointHandler( $this->authServer, $this->responseFactory ); - $response = $authMiddleware->process($request, $this->handler->reveal()); + $response = $handler->handle($request); $this->assertEquals(200, $response->getStatusCode()); $content = json_decode((string) $response->getBody()); @@ -447,6 +448,35 @@ public function testProcessRefreshTokenGrant(string $refreshToken) $this->assertNotEmpty($content->refresh_token); } + private function buildConsumerAuthMiddleware(AuthorizationHandler $authHandler) + { + return new class($authHandler) implements RequestHandlerInterface + { + /** + * @var AuthorizationHandler + */ + private $handler; + + public function __construct(AuthorizationHandler $handler) + { + $this->handler = $handler; + } + + public function handle( + ServerRequestInterface $request + ): ResponseInterface { + $authRequest = $request->getAttribute(AuthorizationRequest::class); + assert($authRequest instanceof AuthorizationRequest); + $authRequest->setUser(new UserEntity('test')); + $authRequest->setAuthorizationApproved(true); + + return $this->handler->handle( + $request->withAttribute(AuthorizationRequest::class, $authRequest) + ); + } + }; + } + /** * Build a ServerRequest object */ From f71faf485c21ec52044f000a0f1f9a3fb79d0a45 Mon Sep 17 00:00:00 2001 From: Axel Helmert Date: Fri, 1 Jun 2018 10:59:12 +0200 Subject: [PATCH 11/99] Remove trait --- src/AuthFlowFactoryTrait.php | 38 ------------------- ...ry.php => AuthorizationHandlerFactory.php} | 9 ++--- src/AuthorizationMiddlewareFactory.php | 7 +--- src/TokenEndpointHandlerFactory.php | 9 ++--- 4 files changed, 9 insertions(+), 54 deletions(-) delete mode 100644 src/AuthFlowFactoryTrait.php rename src/{AuthorizationHanderFactory.php => AuthorizationHandlerFactory.php} (82%) diff --git a/src/AuthFlowFactoryTrait.php b/src/AuthFlowFactoryTrait.php deleted file mode 100644 index 4e32fdb..0000000 --- a/src/AuthFlowFactoryTrait.php +++ /dev/null @@ -1,38 +0,0 @@ -has(AuthorizationServer::class) - ? $container->get(AuthorizationServer::class) - : null; - - if (null === $authServer) { - throw new Exception\InvalidConfigException(sprintf( - "The %s service is missing", - AuthorizationServer::class - )); - } - - return $authServer; - } -} \ No newline at end of file diff --git a/src/AuthorizationHanderFactory.php b/src/AuthorizationHandlerFactory.php similarity index 82% rename from src/AuthorizationHanderFactory.php rename to src/AuthorizationHandlerFactory.php index 093a592..ca28a7b 100644 --- a/src/AuthorizationHanderFactory.php +++ b/src/AuthorizationHandlerFactory.php @@ -10,18 +10,17 @@ namespace Zend\Expressive\Authentication\OAuth2; +use League\OAuth2\Server\AuthorizationServer; use Psr\Container\ContainerInterface; use Psr\Http\Message\ResponseInterface; -class AuthorizationHanderFactory +final class AuthorizationHandlerFactory { - use AuthFlowFactoryTrait; - public function __invoke(ContainerInterface $container) { return new AuthorizationHandler( - $this->getAuthorizationServer($container), + $container->get(AuthorizationServer::class), $container->get(ResponseInterface::class) ); } -} \ No newline at end of file +} diff --git a/src/AuthorizationMiddlewareFactory.php b/src/AuthorizationMiddlewareFactory.php index 07f6e20..c27d922 100644 --- a/src/AuthorizationMiddlewareFactory.php +++ b/src/AuthorizationMiddlewareFactory.php @@ -13,16 +13,13 @@ use League\OAuth2\Server\AuthorizationServer; use Psr\Container\ContainerInterface; use Psr\Http\Message\ResponseInterface; -use function sprintf; -class AuthorizationMiddlewareFactory +final class AuthorizationMiddlewareFactory { - use AuthFlowFactoryTrait; - public function __invoke(ContainerInterface $container) : AuthorizationMiddleware { return new AuthorizationMiddleware( - $this->getAuthorizationServer($container), + $container->get(AuthorizationServer::class), $container->get(ResponseInterface::class) ); } diff --git a/src/TokenEndpointHandlerFactory.php b/src/TokenEndpointHandlerFactory.php index 4e3a6e6..59fee29 100644 --- a/src/TokenEndpointHandlerFactory.php +++ b/src/TokenEndpointHandlerFactory.php @@ -10,20 +10,17 @@ namespace Zend\Expressive\Authentication\OAuth2; +use League\OAuth2\Server\AuthorizationServer; use Psr\Container\ContainerInterface; use Psr\Http\Message\ResponseInterface; final class TokenEndpointHandlerFactory { - use AuthFlowFactoryTrait; - public function __invoke(ContainerInterface $container): TokenEndpointHandler { - $authServer = $this->getAuthorizationServer($container); - return new TokenEndpointHandler( - $authServer, + $container->get(AuthorizationServer::class), $container->get(ResponseInterface::class) ); } -} \ No newline at end of file +} From bac7c6a45ed4f7bc5bfefc3eba36ddb631a7ace4 Mon Sep 17 00:00:00 2001 From: Axel Helmert Date: Fri, 1 Jun 2018 10:59:39 +0200 Subject: [PATCH 12/99] Remove HTTP method check --- src/TokenEndpointHandler.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/TokenEndpointHandler.php b/src/TokenEndpointHandler.php index 0590e8a..6493f6a 100644 --- a/src/TokenEndpointHandler.php +++ b/src/TokenEndpointHandler.php @@ -67,10 +67,6 @@ public function handle(ServerRequestInterface $request): ResponseInterface { $response = $this->createResponse(); - if (strtoupper($request->getMethod()) !== 'POST') { - return $response->withStatus(501); // Method not implemented - } - try { return $this->server->respondToAccessTokenRequest($request, $response); } catch (OAuthServerException $exception) { From 2a74fa5f73550fe73429b9886a509afb13084c13 Mon Sep 17 00:00:00 2001 From: Axel Helmert Date: Fri, 1 Jun 2018 11:01:47 +0200 Subject: [PATCH 13/99] Add missing service config --- src/ConfigProvider.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ConfigProvider.php b/src/ConfigProvider.php index 61da355..d59fc0a 100644 --- a/src/ConfigProvider.php +++ b/src/ConfigProvider.php @@ -63,6 +63,8 @@ public function getDependencies() : array ], 'factories' => [ AuthorizationMiddleware::class => AuthorizationMiddlewareFactory::class, + AuthorizationHandler::class => AuthorizationServerFactory::class, + TokenEndpointHandler::class => TokenEndpointHandlerFactory::class, OAuth2Adapter::class => OAuth2AdapterFactory::class, AuthorizationServer::class => AuthorizationServerFactory::class, ResourceServer::class => ResourceServerFactory::class, From 755b8aaffabb9cacb95485388fcdf55c4ab2dc6e Mon Sep 17 00:00:00 2001 From: Axel Helmert Date: Fri, 1 Jun 2018 11:27:37 +0200 Subject: [PATCH 14/99] Fix coding style --- src/AuthorizationHandler.php | 4 ++-- test/AuthorizationHandlerFactoryTest.php | 3 ++- test/AuthorizationMiddlewareFactoryTest.php | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/AuthorizationHandler.php b/src/AuthorizationHandler.php index e58065c..98478cb 100644 --- a/src/AuthorizationHandler.php +++ b/src/AuthorizationHandler.php @@ -41,7 +41,7 @@ class AuthorizationHandler implements RequestHandlerInterface public function __construct(AuthorizationServer $server, callable $responseFactory) { $this->server = $server; - $this->responseFactory = function() use ($responseFactory): ResponseInterface { + $this->responseFactory = function () use ($responseFactory): ResponseInterface { return $responseFactory(); }; } @@ -51,4 +51,4 @@ public function handle(ServerRequestInterface $request): ResponseInterface $authRequest = $request->getAttribute(AuthorizationRequest::class); return $this->server->completeAuthorizationRequest($authRequest, ($this->responseFactory)()); } -} \ No newline at end of file +} diff --git a/test/AuthorizationHandlerFactoryTest.php b/test/AuthorizationHandlerFactoryTest.php index 86a32f8..ca238a3 100644 --- a/test/AuthorizationHandlerFactoryTest.php +++ b/test/AuthorizationHandlerFactoryTest.php @@ -54,7 +54,8 @@ public function testRaisesTypeErrorForInvalidAuthorizationServer() ->willReturn(new stdClass()); $this->container ->get(ResponseInterface::class) - ->willReturn(function() {}); + ->willReturn(function () { + }); $factory = new AuthorizationHandlerFactory(); diff --git a/test/AuthorizationMiddlewareFactoryTest.php b/test/AuthorizationMiddlewareFactoryTest.php index f274c01..32c536e 100644 --- a/test/AuthorizationMiddlewareFactoryTest.php +++ b/test/AuthorizationMiddlewareFactoryTest.php @@ -54,7 +54,8 @@ public function testRaisesTypeErrorForInvalidAuthorizationServer() ->willReturn(new stdClass()); $this->container ->get(ResponseInterface::class) - ->willReturn(function() {}); + ->willReturn(function () { + }); $factory = new AuthorizationMiddlewareFactory(); From 79f41d9c29830ffc448e99662f5c72b85257cd25 Mon Sep 17 00:00:00 2001 From: Andrey Yanakov Date: Fri, 29 Jun 2018 22:29:35 +0300 Subject: [PATCH 15/99] Revocation of access token was fixed --- src/Repository/Pdo/AccessTokenRepository.php | 2 +- .../Pdo/AccessTokenRepositoryTest.php | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/Repository/Pdo/AccessTokenRepository.php b/src/Repository/Pdo/AccessTokenRepository.php index b1d1f90..cac3249 100644 --- a/src/Repository/Pdo/AccessTokenRepository.php +++ b/src/Repository/Pdo/AccessTokenRepository.php @@ -94,7 +94,7 @@ public function revokeAccessToken($tokenId) $sth = $this->pdo->prepare( 'UPDATE oauth_access_tokens SET revoked=:revoked WHERE id = :tokenId' ); - $sth->bindValue(':revoked', 0); + $sth->bindValue(':revoked', 1); $sth->bindParam(':tokenId', $tokenId); $sth->execute(); diff --git a/test/Repository/Pdo/AccessTokenRepositoryTest.php b/test/Repository/Pdo/AccessTokenRepositoryTest.php index fc7c083..9e97186 100644 --- a/test/Repository/Pdo/AccessTokenRepositoryTest.php +++ b/test/Repository/Pdo/AccessTokenRepositoryTest.php @@ -25,6 +25,11 @@ class AccessTokenRepositoryTest extends TestCase { + /** + * @var AccessTokenRepository + */ + private $repo; + public function setUp() { $this->pdo = $this->prophesize(PdoService::class); @@ -125,4 +130,18 @@ public function testIsAccessTokenRevokedReturnsTrueWhenRowRevokedFlagIsTrue() $this->assertTrue($this->repo->isAccessTokenRevoked('token_id')); } + + public function testRevokeAccessToken() + { + $statement = $this->prophesize(PDOStatement::class); + $statement->bindParam(':tokenId', 'token_id')->shouldBeCalled(); + $statement->bindValue(':revoked', 1)->shouldBeCalled(); + $statement->execute()->willReturn(null)->shouldBeCalled(); + + $this->pdo + ->prepare(Argument::containingString('UPDATE oauth_access_tokens SET revoked=:revoked')) + ->will([$statement, 'reveal']); + + $this->repo->revokeAccessToken('token_id'); + } } From 454781125ce9683ec0a431077fae2123f0682b33 Mon Sep 17 00:00:00 2001 From: tux-rampage Date: Mon, 9 Jul 2018 21:22:46 +0200 Subject: [PATCH 16/99] Add auth handler test (wip) --- src/AuthorizationHandlerTest.php | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/AuthorizationHandlerTest.php diff --git a/src/AuthorizationHandlerTest.php b/src/AuthorizationHandlerTest.php new file mode 100644 index 0000000..289ecb5 --- /dev/null +++ b/src/AuthorizationHandlerTest.php @@ -0,0 +1,20 @@ + Date: Tue, 10 Jul 2018 22:49:13 +0200 Subject: [PATCH 17/99] Add missing authorization handler tests --- src/AuthorizationHandlerTest.php | 20 ------- test/AuthorizationHandlerFactoryTest.php | 2 +- test/AuthorizationHandlerTest.php | 68 ++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 21 deletions(-) delete mode 100644 src/AuthorizationHandlerTest.php create mode 100644 test/AuthorizationHandlerTest.php diff --git a/src/AuthorizationHandlerTest.php b/src/AuthorizationHandlerTest.php deleted file mode 100644 index 289ecb5..0000000 --- a/src/AuthorizationHandlerTest.php +++ /dev/null @@ -1,20 +0,0 @@ -prophesize(AuthorizationServer::class); + $response = $this->prophesize(ResponseInterface::class); + $authRequest = $this->prophesize(AuthorizationRequest::class); + $request = $this->prophesize(ServerRequestInterface::class); + $expectedResponse = $response->reveal(); + + $request->getAttribute(AuthorizationRequest::class) + ->willReturn($authRequest->reveal()); + + $server->completeAuthorizationRequest($authRequest->reveal(), $expectedResponse) + ->shouldBeCalled() + ->willReturn($expectedResponse); + + $subject = new AuthorizationHandler($server->reveal(), function() use ($expectedResponse): ResponseInterface { + return $expectedResponse; + }); + + self::assertSame($expectedResponse, $subject->handle($request->reveal())); + } + + public function testInvalidResponseFactoryThrowsTypeError() + { + $server = $this->prophesize(AuthorizationServer::class); + $authRequest = $this->prophesize(AuthorizationRequest::class); + $request = $this->prophesize(ServerRequestInterface::class); + + $request->getAttribute(AuthorizationRequest::class) + ->willReturn($authRequest->reveal()); + + $server->completeAuthorizationRequest(Argument::any()) + ->shouldNotBeCalled(); + + $subject = new AuthorizationHandler($server->reveal(), function() { + return new stdClass(); + }); + + $this->expectException(TypeError::class); + $subject->handle($request->reveal()); + } +} From 28497b23c29a68b058a85ba766ce1f5bea2d72c9 Mon Sep 17 00:00:00 2001 From: tux-rampage Date: Tue, 10 Jul 2018 23:30:52 +0200 Subject: [PATCH 18/99] Add token endpoint handler tests --- src/TokenEndpointHandler.php | 3 - test/TokenEndpointHandlerFactoryTest.php | 74 +++++++++++++++++++++ test/TokenEndpointHandlerTest.php | 83 ++++++++++++++++++++++++ 3 files changed, 157 insertions(+), 3 deletions(-) create mode 100644 test/TokenEndpointHandlerFactoryTest.php create mode 100644 test/TokenEndpointHandlerTest.php diff --git a/src/TokenEndpointHandler.php b/src/TokenEndpointHandler.php index 6493f6a..4c043dc 100644 --- a/src/TokenEndpointHandler.php +++ b/src/TokenEndpointHandler.php @@ -71,9 +71,6 @@ public function handle(ServerRequestInterface $request): ResponseInterface return $this->server->respondToAccessTokenRequest($request, $response); } catch (OAuthServerException $exception) { return $exception->generateHttpResponse($response); - } catch (\Exception $exception) { - return (new OAuthServerException($exception->getMessage(), 0, 'unknown_error', 500)) - ->generateHttpResponse($response); } } } diff --git a/test/TokenEndpointHandlerFactoryTest.php b/test/TokenEndpointHandlerFactoryTest.php new file mode 100644 index 0000000..60da57b --- /dev/null +++ b/test/TokenEndpointHandlerFactoryTest.php @@ -0,0 +1,74 @@ +subject = new TokenEndpointHandlerFactory(); + parent::setUp(); + } + + public function testEmptyContainerThrowsTypeError() + { + $container = $this->prophesize(ContainerInterface::class); + + $this->expectException(TypeError::class); + ($this->subject)($container); + } + + public function testCreatesTokenEndpointHandler() + { + $server = $this->prophesize(AuthorizationServer::class); + $responseFactory = function() {}; + $container = $this->prophesize(ContainerInterface::class); + + $container->get(AuthorizationServer::class) + ->willReturn($server->reveal()); + $container->get(ResponseInterface::class) + ->willReturn($responseFactory); + + self::assertInstanceOf(TokenEndpointHandler::class, ($this->subject)($container->reveal())); + } + + public function testDirectResponseInstanceFromContainerThrowsTypeError() + { + $server = $this->prophesize(AuthorizationServer::class); + $container = $this->prophesize(ContainerInterface::class); + + $container->get(AuthorizationServer::class) + ->willReturn($server->reveal()); + $container->get(ResponseInterface::class) + ->willReturn($this->prophesize(ResponseInterface::class)->reveal()); + + $this->expectException(TypeError::class); + ($this->subject)($container->reveal()); + } +} diff --git a/test/TokenEndpointHandlerTest.php b/test/TokenEndpointHandlerTest.php new file mode 100644 index 0000000..9e9543d --- /dev/null +++ b/test/TokenEndpointHandlerTest.php @@ -0,0 +1,83 @@ +prophesize(ResponseInterface::class)->reveal(); + }; + } + + public function testHandleUsesAuthorizationServer() + { + $server = $this->prophesize(AuthorizationServer::class); + $request = $this->prophesize(ServerRequestInterface::class); + $response = $this->prophesize(ResponseInterface::class); + $expectedResponse = $response->reveal(); + + $server->respondToAccessTokenRequest($request->reveal(), $expectedResponse) + ->shouldBeCalled() + ->willReturn($expectedResponse); + + $subject = new TokenEndpointHandler($server->reveal(), $this->createResponseFactory($expectedResponse)); + self::assertSame($expectedResponse, $subject->handle($request->reveal())); + } + + public function testOAuthExceptionProducesResult() + { + $server = $this->prophesize(AuthorizationServer::class); + $request = $this->prophesize(ServerRequestInterface::class); + $response = $this->prophesize(ResponseInterface::class); + $exception = $this->prophesize(OAuthServerException::class); + $expectedResponse = $response->reveal(); + + $server->respondToAccessTokenRequest(Argument::cetera()) + ->willThrow($exception->reveal()); + + $exception->generateHttpResponse($expectedResponse, Argument::cetera()) + ->shouldBeCalled() + ->willReturn($expectedResponse); + + $subject = new TokenEndpointHandler($server->reveal(), $this->createResponseFactory($expectedResponse)); + self::assertSame($expectedResponse, $subject->handle($request->reveal())); + } + + public function testGenericExceptionsFallsThrough() + { + $server = $this->prophesize(AuthorizationServer::class); + $request = $this->prophesize(ServerRequestInterface::class); + $exception = new RuntimeException(); + + $server->respondToAccessTokenRequest(Argument::cetera()) + ->willThrow($exception); + + $subject = new TokenEndpointHandler($server->reveal(), $this->createResponseFactory()); + + $this->expectException(RuntimeException::class); + $subject->handle($request->reveal()); + + } +} From b9f37758ebb0da4b4105abe60641884efa9f1854 Mon Sep 17 00:00:00 2001 From: tux-rampage Date: Tue, 10 Jul 2018 23:33:22 +0200 Subject: [PATCH 19/99] fix coding style --- test/AuthorizationHandlerTest.php | 4 ++-- test/TokenEndpointHandlerFactoryTest.php | 3 ++- test/TokenEndpointHandlerTest.php | 3 +-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/AuthorizationHandlerTest.php b/test/AuthorizationHandlerTest.php index cd28607..4e8987a 100644 --- a/test/AuthorizationHandlerTest.php +++ b/test/AuthorizationHandlerTest.php @@ -39,7 +39,7 @@ public function testHandleUsesAuthorizationServerService(): void ->shouldBeCalled() ->willReturn($expectedResponse); - $subject = new AuthorizationHandler($server->reveal(), function() use ($expectedResponse): ResponseInterface { + $subject = new AuthorizationHandler($server->reveal(), function () use ($expectedResponse): ResponseInterface { return $expectedResponse; }); @@ -58,7 +58,7 @@ public function testInvalidResponseFactoryThrowsTypeError() $server->completeAuthorizationRequest(Argument::any()) ->shouldNotBeCalled(); - $subject = new AuthorizationHandler($server->reveal(), function() { + $subject = new AuthorizationHandler($server->reveal(), function () { return new stdClass(); }); diff --git a/test/TokenEndpointHandlerFactoryTest.php b/test/TokenEndpointHandlerFactoryTest.php index 60da57b..f706b21 100644 --- a/test/TokenEndpointHandlerFactoryTest.php +++ b/test/TokenEndpointHandlerFactoryTest.php @@ -47,7 +47,8 @@ public function testEmptyContainerThrowsTypeError() public function testCreatesTokenEndpointHandler() { $server = $this->prophesize(AuthorizationServer::class); - $responseFactory = function() {}; + $responseFactory = function () { + }; $container = $this->prophesize(ContainerInterface::class); $container->get(AuthorizationServer::class) diff --git a/test/TokenEndpointHandlerTest.php b/test/TokenEndpointHandlerTest.php index 9e9543d..99833e9 100644 --- a/test/TokenEndpointHandlerTest.php +++ b/test/TokenEndpointHandlerTest.php @@ -26,7 +26,7 @@ class TokenEndpointHandlerTest extends TestCase { private function createResponseFactory(ResponseInterface $response = null): callable { - return function() use ($response): ResponseInterface { + return function () use ($response): ResponseInterface { return $response ?? $this->prophesize(ResponseInterface::class)->reveal(); }; } @@ -78,6 +78,5 @@ public function testGenericExceptionsFallsThrough() $this->expectException(RuntimeException::class); $subject->handle($request->reveal()); - } } From 885d462124ed820ebde6e26268af4e216ac4b78f Mon Sep 17 00:00:00 2001 From: tux-rampage Date: Wed, 11 Jul 2018 00:35:46 +0200 Subject: [PATCH 20/99] Update docs --- docs/book/authorization-server.md | 113 ++++++++++++++++++++++++++++++ docs/book/usage.md | 5 ++ mkdocs.yml | 1 + 3 files changed, 119 insertions(+) create mode 100644 docs/book/authorization-server.md diff --git a/docs/book/authorization-server.md b/docs/book/authorization-server.md new file mode 100644 index 0000000..3eb298c --- /dev/null +++ b/docs/book/authorization-server.md @@ -0,0 +1,113 @@ +# Implement an authorization server + +This library provides the basics to implement an authorization server +for your application. + +Since there are authorization flows that require user interaction, +your application is expected to provide the middleware to handle this. + +## Add the token endpoint + +This is the most simple part, since this library provides +`Zend\Expressive\Authentication\OAuth2\TokenHandler` to deal with it. + +This endpoint must accept POST requests. + +For example: + +```php +use Zend\Expressive\Authentication\OAuth2; + +$app->route('/oauth2/token', OAuth2\TokenHandler::class, ['POST']); +``` + +## Add the authorization endpoint + +The authorization endpoint is an url of to which the client redirects +to obtain an access token or authorization code. + +This endpoint must accept GET requests and should: + + - Validate the request (especially for a valid client id and redirect url) + - Make sure the User is authenticated (for example by showing a login + prompt if needed) + - Optionally request the users consent to grant access to the client + - Redirect to a specified url of the client with success or error information + +The first and the last part is provided by this library. + +For example, to add the authorization endpoint you can declare a middleware pipe +to compose these parts: + +```php +use Zend\Expressive\Authentication\OAuth2; + +$app->route('/oauth2/authorize', [ + OAuth2\AuthorizatonMiddleware, + + // The followig middleware is provided by your application (see below) + Application\OAuthAuthorizationMiddleware::class, + + OAuth2\AuthorizationHandler +], ['GET', 'POST']); +``` + +In your `Application\OAuthAuthorizationMiddleware`, you'll have access +to the `League\OAuth2\Server\RequestTypes\AuthorizationRequest` via the +psr-7 request. Your middleware should populate the user entity with `setUser()` and the +user's consent decision with `setAuthorizationApproved()` to this authorization +request instance. + +```php +getAttribute('authenticated_user'); + + // Assume some middleware handles and populates a session + // container + $session = $request->getAttribute('session'); + + // This is populated by the previous middleware + /** @var AuthorizationRequest $authRequest */ + $authRequest = $request->getAttribute(AuthorizationRequest::class); + + // the user is authenticated + if ($user) { + $authRequest->setUser($user); + + // Assume all clients are trusted, but you could + // handle consent here or within the next middleware + // as needed + $authRequest->setAuthorizationApproved(true); + + return $handler->handle($request); + } + + // The user is not authenticated, show login form ... + + // Store the auth request state + // NOTE: Do not attempt to serialize or store the authorization + // request object. Store the query parameters instead and redirect + // with these to this endpoint again to replay the request. + $session['oauth2_request_params'] = $request->getQueryParams(); + + return new RedirectResponse('/oauth2/login'); + } +} +``` + diff --git a/docs/book/usage.md b/docs/book/usage.md index 1d34e15..2d47cd1 100644 --- a/docs/book/usage.md +++ b/docs/book/usage.md @@ -53,3 +53,8 @@ $app->post('/api/users', [ App\Action\AddUserAction::class, ], 'api.add.user'); ``` + +# Providing an authorization server + +See the chapter [Authorization server](authorization-server.md) for details on how +to implement this. \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 105ee8e..bb56eee 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -4,6 +4,7 @@ pages: - index.md - Introduction: intro.md - Usage: usage.md + - "Authorization server": authorization-server.md - Grant: - "Client credentials": grant/client_credentials.md - "Password": grant/password.md From e315586bfbc6244b9492b906b03cef6776771baf Mon Sep 17 00:00:00 2001 From: tux-rampage Date: Wed, 11 Jul 2018 00:36:11 +0200 Subject: [PATCH 21/99] Remove unused imports --- src/AuthorizationMiddleware.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/AuthorizationMiddleware.php b/src/AuthorizationMiddleware.php index 302fc98..5a4502f 100644 --- a/src/AuthorizationMiddleware.php +++ b/src/AuthorizationMiddleware.php @@ -17,9 +17,6 @@ use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\MiddlewareInterface; use Psr\Http\Server\RequestHandlerInterface; -use Zend\Expressive\Authentication\OAuth2\Entity\UserEntity; - -use function strtoupper; /** * Implements OAuth2 authorization request validation From cee014a703b0772aaf1bc698a1de5fc874816f1a Mon Sep 17 00:00:00 2001 From: tux-rampage Date: Wed, 11 Jul 2018 00:48:29 +0200 Subject: [PATCH 22/99] Add changelog entries --- CHANGELOG.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a28c5e7..82c399d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,15 @@ All notable changes to this project will be documented in this file, in reverse ### Added -- Nothing. +- [#42](https://github.com/zendframework/zend-expressive-authentication-oauth2/pull/42) Adds `TokenEndpointHandler`, + `AuthorizationMiddleware` and `AuthorizationHandler` in the `Zend\Expressive\Authentication\OAuth2` namespace + to [implement an authorization server](docs/book/authorization-server.md). ### Changed -- Nothing. +- [#42](https://github.com/zendframework/zend-expressive-authentication-oauth2/pull/42) Splits + `Zend\Expressive\Authentication\OAuth2\OAuth2Middleware` into individual implementations that allow + [OAuth RFC-6749](https://tools.ietf.org/html/rfc6749) compliant authorization server implementations. ### Deprecated @@ -18,7 +22,8 @@ All notable changes to this project will be documented in this file, in reverse ### Removed -- Nothing. +- [#42](https://github.com/zendframework/zend-expressive-authentication-oauth2/pull/42) Removes + `Zend\Expressive\Authentication\OAuth2\OAuth2Middleware`. ### Fixed From 356c692b16faf7a748febe363e270cdbeabdd5f0 Mon Sep 17 00:00:00 2001 From: Sam Sheridan Date: Wed, 11 Jul 2018 16:13:18 +0100 Subject: [PATCH 23/99] Fixed issue with empty scope being passed throwing exception --- src/Repository/Pdo/AbstractRepository.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Repository/Pdo/AbstractRepository.php b/src/Repository/Pdo/AbstractRepository.php index 7cce630..aae4434 100644 --- a/src/Repository/Pdo/AbstractRepository.php +++ b/src/Repository/Pdo/AbstractRepository.php @@ -39,6 +39,10 @@ public function __construct(PdoService $pdo) */ protected function scopesToString(array $scopes) : string { + if (empty($scopes)) { + return ''; + } + return trim(array_reduce($scopes, function ($result, $item) { return $result . ' ' . $item->getIdentifier(); })); From 8215fede2172f98472483a53408e5f1472ad0a5f Mon Sep 17 00:00:00 2001 From: Enrico Zimuel Date: Fri, 21 Sep 2018 15:48:50 +0200 Subject: [PATCH 24/99] Added test for PDO AbstractRepository --- .../Repository/Pdo/AbstractRepositoryTest.php | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 test/Repository/Pdo/AbstractRepositoryTest.php diff --git a/test/Repository/Pdo/AbstractRepositoryTest.php b/test/Repository/Pdo/AbstractRepositoryTest.php new file mode 100644 index 0000000..6d93b25 --- /dev/null +++ b/test/Repository/Pdo/AbstractRepositoryTest.php @@ -0,0 +1,41 @@ +pdo = $this->prophesize(PdoService::class); + } + + public function testConstructor() + { + $abstract = new AbstractRepository($this->pdo->reveal()); + $this->assertInstanceOf(AbstractRepository::class, $abstract); + } + + public function testScopesToString() + { + $proxy = new class($this->pdo->reveal()) extends AbstractRepository { + public function scopesToString(array $scopes): string + { + return parent::scopesToString($scopes); + } + }; + $result = $proxy->scopesToString([]); + $this->assertEquals('', $result); + } +} From 1911c3d47fe4b6d153f1183ff859952e712f239e Mon Sep 17 00:00:00 2001 From: Enrico Zimuel Date: Fri, 21 Sep 2018 17:04:25 +0200 Subject: [PATCH 25/99] WIP: improving unit tests --- test/Entity/AccessTokenEntityTest.php | 24 +++++++++ test/Entity/AuthCodeEntityTest.php | 24 +++++++++ test/Entity/ClientEntityTest.php | 51 +++++++++++++++++++ test/Entity/RefreshTokenEntityTest.php | 24 +++++++++ test/Entity/RevokableTraitTest.php | 27 ++++++++++ test/Entity/ScopeEntityTest.php | 34 +++++++++++++ test/Entity/TimestampableTraitTest.php | 43 ++++++++++++++++ test/Entity/UserEntityTest.php | 37 ++++++++++++++ .../Repository/Pdo/AbstractRepositoryTest.php | 2 +- .../Pdo/AccessTokenRepositoryFactoryTest.php | 40 +++++++++++++++ .../Pdo/AuthCodeRepositoryFactoryTest.php | 40 +++++++++++++++ .../Pdo/ClientRepositoryFactoryTest.php | 40 +++++++++++++++ .../Pdo/RefreshTokenRepositoryFactoryTest.php | 40 +++++++++++++++ .../Pdo/ScopeRepositoryFactoryTest.php | 40 +++++++++++++++ 14 files changed, 465 insertions(+), 1 deletion(-) create mode 100644 test/Entity/AccessTokenEntityTest.php create mode 100644 test/Entity/AuthCodeEntityTest.php create mode 100644 test/Entity/ClientEntityTest.php create mode 100644 test/Entity/RefreshTokenEntityTest.php create mode 100644 test/Entity/RevokableTraitTest.php create mode 100644 test/Entity/ScopeEntityTest.php create mode 100644 test/Entity/TimestampableTraitTest.php create mode 100644 test/Entity/UserEntityTest.php create mode 100644 test/Repository/Pdo/AccessTokenRepositoryFactoryTest.php create mode 100644 test/Repository/Pdo/AuthCodeRepositoryFactoryTest.php create mode 100644 test/Repository/Pdo/ClientRepositoryFactoryTest.php create mode 100644 test/Repository/Pdo/RefreshTokenRepositoryFactoryTest.php create mode 100644 test/Repository/Pdo/ScopeRepositoryFactoryTest.php diff --git a/test/Entity/AccessTokenEntityTest.php b/test/Entity/AccessTokenEntityTest.php new file mode 100644 index 0000000..7be3ca7 --- /dev/null +++ b/test/Entity/AccessTokenEntityTest.php @@ -0,0 +1,24 @@ +assertInstanceOf(AccessTokenEntityInterface::class, $entity); + } +} diff --git a/test/Entity/AuthCodeEntityTest.php b/test/Entity/AuthCodeEntityTest.php new file mode 100644 index 0000000..2ab7530 --- /dev/null +++ b/test/Entity/AuthCodeEntityTest.php @@ -0,0 +1,24 @@ +assertInstanceOf(AuthCodeEntityInterface::class, $entity); + } +} diff --git a/test/Entity/ClientEntityTest.php b/test/Entity/ClientEntityTest.php new file mode 100644 index 0000000..4ea2ba7 --- /dev/null +++ b/test/Entity/ClientEntityTest.php @@ -0,0 +1,51 @@ +entity = new ClientEntity('foo', 'bar', 'http://localhost'); + } + public function testConstructor() + { + $this->assertInstanceOf(ClientEntityInterface::class, $this->entity); + } + + public function testSecret() + { + $this->entity->setSecret('secret'); + $this->assertEquals('secret', $this->entity->getSecret()); + } + + public function testPersonalAccessClient() + { + $this->entity->setPersonalAccessClient(true); + $this->assertTrue($this->entity->hasPersonalAccessClient()); + + $this->entity->setPersonalAccessClient(false); + $this->assertFalse($this->entity->hasPersonalAccessClient()); + } + + public function testPasswordClient() + { + $this->entity->setPasswordClient(true); + $this->assertTrue($this->entity->hasPasswordClient()); + + $this->entity->setPasswordClient(false); + $this->assertFalse($this->entity->hasPasswordClient()); + } +} diff --git a/test/Entity/RefreshTokenEntityTest.php b/test/Entity/RefreshTokenEntityTest.php new file mode 100644 index 0000000..06f8a2c --- /dev/null +++ b/test/Entity/RefreshTokenEntityTest.php @@ -0,0 +1,24 @@ +assertInstanceOf(RefreshTokenEntityInterface::class, $entity); + } +} diff --git a/test/Entity/RevokableTraitTest.php b/test/Entity/RevokableTraitTest.php new file mode 100644 index 0000000..60e0931 --- /dev/null +++ b/test/Entity/RevokableTraitTest.php @@ -0,0 +1,27 @@ +getMockForTrait(RevokableTrait::class); + + $mock->setRevoked(true); + $this->assertTrue($mock->isRevoked()); + $mock->setRevoked(false); + $this->assertFalse($mock->isRevoked()); + } +} diff --git a/test/Entity/ScopeEntityTest.php b/test/Entity/ScopeEntityTest.php new file mode 100644 index 0000000..0cfa65c --- /dev/null +++ b/test/Entity/ScopeEntityTest.php @@ -0,0 +1,34 @@ +entity = new ScopeEntity(); + } + + public function testConstructor() + { + $this->assertInstanceOf(ScopeEntityInterface::class, $this->entity); + } + + public function testJsonSerialize() + { + $this->entity->setIdentifier('foo'); + $this->assertEquals('"foo"', json_encode($this->entity)); + } +} diff --git a/test/Entity/TimestampableTraitTest.php b/test/Entity/TimestampableTraitTest.php new file mode 100644 index 0000000..59c6a94 --- /dev/null +++ b/test/Entity/TimestampableTraitTest.php @@ -0,0 +1,43 @@ +trait = $this->getMockForTrait(TimestampableTrait::class); + } + + public function testCreatedAt() + { + $now = new DateTime(); + $this->trait->setCreatedAt($now); + $this->assertEquals($now, $this->trait->getCreatedAt()); + } + + public function testUpdatedAt() + { + $now = new DateTime(); + $this->trait->setUpdatedAt($now); + $this->assertEquals($now, $this->trait->getUpdatedAt()); + } + + public function testTimestampOnCreate() + { + $this->trait->timestampOnCreate(); + $this->assertNotEmpty($this->trait->getCreatedAt()); + } +} diff --git a/test/Entity/UserEntityTest.php b/test/Entity/UserEntityTest.php new file mode 100644 index 0000000..c7b10bd --- /dev/null +++ b/test/Entity/UserEntityTest.php @@ -0,0 +1,37 @@ +entity = new UserEntity('foo'); + } + + /** + * @expectedException ArgumentCountError + */ + public function testConstructorWithoutParam() + { + $entity = new UserEntity(); + } + + public function testConstructor() + { + $this->assertInstanceOf(UserEntityInterface::class, $this->entity); + $this->assertEquals('foo', $this->entity->getIdentifier()); + } +} diff --git a/test/Repository/Pdo/AbstractRepositoryTest.php b/test/Repository/Pdo/AbstractRepositoryTest.php index 6d93b25..8317661 100644 --- a/test/Repository/Pdo/AbstractRepositoryTest.php +++ b/test/Repository/Pdo/AbstractRepositoryTest.php @@ -27,7 +27,7 @@ public function testConstructor() $this->assertInstanceOf(AbstractRepository::class, $abstract); } - public function testScopesToString() + public function testScopesToStringWithEmptyArray() { $proxy = new class($this->pdo->reveal()) extends AbstractRepository { public function scopesToString(array $scopes): string diff --git a/test/Repository/Pdo/AccessTokenRepositoryFactoryTest.php b/test/Repository/Pdo/AccessTokenRepositoryFactoryTest.php new file mode 100644 index 0000000..d30f058 --- /dev/null +++ b/test/Repository/Pdo/AccessTokenRepositoryFactoryTest.php @@ -0,0 +1,40 @@ +container = $this->prophesize(ContainerInterface::class); + $this->pdo = $this->prophesize(PdoService::class); + } + + public function testFactory() + { + $this->container->get(PdoService::class) + ->willReturn($this->pdo->reveal()); + + $factory = (new AccessTokenRepositoryFactory)($this->container->reveal()); + $this->assertInstanceOf(AccessTokenRepository::class, $factory); + } +} diff --git a/test/Repository/Pdo/AuthCodeRepositoryFactoryTest.php b/test/Repository/Pdo/AuthCodeRepositoryFactoryTest.php new file mode 100644 index 0000000..25d215c --- /dev/null +++ b/test/Repository/Pdo/AuthCodeRepositoryFactoryTest.php @@ -0,0 +1,40 @@ +container = $this->prophesize(ContainerInterface::class); + $this->pdo = $this->prophesize(PdoService::class); + } + + public function testFactory() + { + $this->container->get(PdoService::class) + ->willReturn($this->pdo->reveal()); + + $factory = (new AuthCodeRepositoryFactory)($this->container->reveal()); + $this->assertInstanceOf(AuthCodeRepository::class, $factory); + } +} diff --git a/test/Repository/Pdo/ClientRepositoryFactoryTest.php b/test/Repository/Pdo/ClientRepositoryFactoryTest.php new file mode 100644 index 0000000..cfd49a6 --- /dev/null +++ b/test/Repository/Pdo/ClientRepositoryFactoryTest.php @@ -0,0 +1,40 @@ +container = $this->prophesize(ContainerInterface::class); + $this->pdo = $this->prophesize(PdoService::class); + } + + public function testFactory() + { + $this->container->get(PdoService::class) + ->willReturn($this->pdo->reveal()); + + $factory = (new ClientRepositoryFactory)($this->container->reveal()); + $this->assertInstanceOf(ClientRepository::class, $factory); + } +} diff --git a/test/Repository/Pdo/RefreshTokenRepositoryFactoryTest.php b/test/Repository/Pdo/RefreshTokenRepositoryFactoryTest.php new file mode 100644 index 0000000..35b441d --- /dev/null +++ b/test/Repository/Pdo/RefreshTokenRepositoryFactoryTest.php @@ -0,0 +1,40 @@ +container = $this->prophesize(ContainerInterface::class); + $this->pdo = $this->prophesize(PdoService::class); + } + + public function testFactory() + { + $this->container->get(PdoService::class) + ->willReturn($this->pdo->reveal()); + + $factory = (new RefreshTokenRepositoryFactory)($this->container->reveal()); + $this->assertInstanceOf(RefreshTokenRepository::class, $factory); + } +} diff --git a/test/Repository/Pdo/ScopeRepositoryFactoryTest.php b/test/Repository/Pdo/ScopeRepositoryFactoryTest.php new file mode 100644 index 0000000..30c99e2 --- /dev/null +++ b/test/Repository/Pdo/ScopeRepositoryFactoryTest.php @@ -0,0 +1,40 @@ +container = $this->prophesize(ContainerInterface::class); + $this->pdo = $this->prophesize(PdoService::class); + } + + public function testFactory() + { + $this->container->get(PdoService::class) + ->willReturn($this->pdo->reveal()); + + $factory = (new ScopeRepositoryFactory)($this->container->reveal()); + $this->assertInstanceOf(ScopeRepository::class, $factory); + } +} From a03545a4221fc913b5d0f424affcecdd4a821eb7 Mon Sep 17 00:00:00 2001 From: Enrico Zimuel Date: Mon, 24 Sep 2018 17:33:44 +0200 Subject: [PATCH 26/99] Improve unit tests completed --- src/ConfigTrait.php | 7 +- test/ConfigTraitTest.php | 154 +++++++++++++++++ test/Entity/RevokableTraitTest.php | 2 +- .../Pdo/AccessTokenRepositoryTest.php | 24 +++ .../Repository/Pdo/AuthCodeRepositoryTest.php | 36 +++- .../Pdo/RefreshTokenRepositoryTest.php | 38 ++++ test/Repository/Pdo/ScopeRepositoryTest.php | 27 +++ test/Repository/Pdo/UserRepositoryTest.php | 26 +++ test/RepositoryTraitTest.php | 163 ++++++++++++++++++ 9 files changed, 474 insertions(+), 3 deletions(-) create mode 100644 test/ConfigTraitTest.php create mode 100644 test/RepositoryTraitTest.php diff --git a/src/ConfigTrait.php b/src/ConfigTrait.php index 0f1c358..401b758 100644 --- a/src/ConfigTrait.php +++ b/src/ConfigTrait.php @@ -90,11 +90,16 @@ protected function getGrantsConfig(ContainerInterface $container) : array { $config = $container->get('config')['authentication'] ?? []; - if (empty($config['grants']) || ! is_array($config['grants'])) { + if (empty($config['grants'])) { throw new InvalidConfigException( 'The grant value is missing in config authentication' ); } + if (! is_array($config['grants'])) { + throw new InvalidConfigException( + 'The grant must be an array value' + ); + } return $config['grants']; } diff --git a/test/ConfigTraitTest.php b/test/ConfigTraitTest.php new file mode 100644 index 0000000..c973104 --- /dev/null +++ b/test/ConfigTraitTest.php @@ -0,0 +1,154 @@ +trait = $trait = new class { + use ConfigTrait; + + public function proxy(string $name, ContainerInterface $container) + { + return $this->$name($container); + } + }; + $this->config = [ + 'authentication' => [ + 'private_key' => 'xxx', + 'encryption_key' => 'xxx', + 'access_token_expire' => '3600', + 'refresh_token_expire' => '3600', + 'auth_code_expire' => '120', + 'grants' => ['xxx'] + ] + ]; + $this->container = $this->prophesize(ContainerInterface::class); + $this->container->get('config') + ->willReturn($this->config); + } + + /** + * @expectedException Zend\Expressive\Authentication\OAuth2\Exception\InvalidConfigException + */ + public function testGetPrivateKeyNoConfig() + { + $this->container->get('config') + ->willReturn([]); + $this->trait->proxy('getPrivateKey', $this->container->reveal()); + } + + public function testGetPrivateKey() + { + $result = $this->trait->proxy('getPrivateKey', $this->container->reveal()); + $this->assertEquals($this->config['authentication']['private_key'], $result); + } + + /** + * @expectedException Zend\Expressive\Authentication\OAuth2\Exception\InvalidConfigException + */ + public function testGetEncryptionKeyNoConfig() + { + $this->container->get('config') + ->willReturn([]); + $this->trait->proxy('getEncryptionKey', $this->container->reveal()); + } + + public function testGetEncryptionKey() + { + $result = $this->trait->proxy('getEncryptionKey', $this->container->reveal()); + $this->assertEquals($this->config['authentication']['encryption_key'], $result); + } + + /** + * @expectedException Zend\Expressive\Authentication\OAuth2\Exception\InvalidConfigException + */ + public function testGetAccessTokenExpireNoConfig() + { + $this->container->get('config') + ->willReturn([]); + $this->trait->proxy('getAccessTokenExpire', $this->container->reveal()); + } + + public function testGetAccessTokenExpire() + { + $result = $this->trait->proxy('getAccessTokenExpire', $this->container->reveal()); + $this->assertEquals($this->config['authentication']['access_token_expire'], $result); + } + + /** + * @expectedException Zend\Expressive\Authentication\OAuth2\Exception\InvalidConfigException + */ + public function testGetRefreshTokenExpireNoConfig() + { + $this->container->get('config') + ->willReturn([]); + $this->trait->proxy('getRefreshTokenExpire', $this->container->reveal()); + } + + public function testGetRefreshTokenExpire() + { + $result = $this->trait->proxy('getRefreshTokenExpire', $this->container->reveal()); + $this->assertEquals($this->config['authentication']['refresh_token_expire'], $result); + } + + /** + * @expectedException Zend\Expressive\Authentication\OAuth2\Exception\InvalidConfigException + */ + public function testGetAuthCodeExpireNoConfig() + { + $this->container->get('config') + ->willReturn([]); + $this->trait->proxy('getAuthCodeExpire', $this->container->reveal()); + } + + public function testGetAuthCodeExpire() + { + $result = $this->trait->proxy('getAuthCodeExpire', $this->container->reveal()); + $this->assertEquals($this->config['authentication']['auth_code_expire'], $result); + } + + /** + * @expectedException Zend\Expressive\Authentication\OAuth2\Exception\InvalidConfigException + */ + public function testGetGrantsConfigNoConfig() + { + $this->container->get('config') + ->willReturn([]); + $this->trait->proxy('getGrantsConfig', $this->container->reveal()); + } + + /** + * @expectedException Zend\Expressive\Authentication\OAuth2\Exception\InvalidConfigException + */ + public function testGetGrantsConfigNoArrayValue() + { + $this->container->get('config') + ->willReturn([ + 'authentication' => [ + 'grants' => 'xxx' + ] + ]); + + $this->trait->proxy('getGrantsConfig', $this->container->reveal()); + } + + public function testGetGrantsConfig() + { + $result = $this->trait->proxy('getGrantsConfig', $this->container->reveal()); + $this->assertEquals($this->config['authentication']['grants'], $result); + } +} diff --git a/test/Entity/RevokableTraitTest.php b/test/Entity/RevokableTraitTest.php index 60e0931..1255f26 100644 --- a/test/Entity/RevokableTraitTest.php +++ b/test/Entity/RevokableTraitTest.php @@ -18,7 +18,7 @@ class RevokableTraitTest extends TestCase public function testRevoked() { $mock = $this->getMockForTrait(RevokableTrait::class); - + $mock->setRevoked(true); $this->assertTrue($mock->isRevoked()); $mock->setRevoked(false); diff --git a/test/Repository/Pdo/AccessTokenRepositoryTest.php b/test/Repository/Pdo/AccessTokenRepositoryTest.php index 9e97186..07f9f4c 100644 --- a/test/Repository/Pdo/AccessTokenRepositoryTest.php +++ b/test/Repository/Pdo/AccessTokenRepositoryTest.php @@ -14,10 +14,12 @@ use League\OAuth2\Server\Entities\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\ClientEntityInterface; use League\OAuth2\Server\Entities\ScopeEntityInterface; +use League\OAuth2\Server\Entities\Traits\AccessTokenTrait; use League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException; use PDOStatement; use PHPUnit\Framework\TestCase; use Prophecy\Argument; +use Zend\Expressive\Authentication\OAuth2\Entity\AccessTokenEntity; use Zend\Expressive\Authentication\OAuth2\Repository\Pdo\AccessTokenRepository; use Zend\Expressive\Authentication\OAuth2\Repository\Pdo\PdoService; @@ -144,4 +146,26 @@ public function testRevokeAccessToken() $this->repo->revokeAccessToken('token_id'); } + + public function testGetNewToken() + { + $client = $this->prophesize(ClientEntityInterface::class)->reveal(); + $accessToken = $this->repo->getNewToken($client, []); + $this->assertInstanceOf(AccessTokenEntity::class, $accessToken); + $this->assertEquals($client, $accessToken->getClient()); + $this->assertEquals([], $accessToken->getScopes()); + } + + public function testGetNewTokenWithScopeAndIndentifier() + { + $client = $this->prophesize(ClientEntityInterface::class)->reveal(); + $scopes = [ $this->prophesize(ScopeEntityInterface::class)->reveal() ]; + $userIdentifier = 'foo'; + + $accessToken = $this->repo->getNewToken($client, $scopes, $userIdentifier); + $this->assertInstanceOf(AccessTokenEntity::class, $accessToken); + $this->assertEquals($client, $accessToken->getClient()); + $this->assertEquals($scopes, $accessToken->getScopes()); + $this->assertEquals($userIdentifier, $accessToken->getUserIdentifier()); + } } diff --git a/test/Repository/Pdo/AuthCodeRepositoryTest.php b/test/Repository/Pdo/AuthCodeRepositoryTest.php index d960fb0..0605a0f 100644 --- a/test/Repository/Pdo/AuthCodeRepositoryTest.php +++ b/test/Repository/Pdo/AuthCodeRepositoryTest.php @@ -31,7 +31,7 @@ public function setUp() $this->repo = new AuthCodeRepository($this->pdo->reveal()); } - public function testPeristNewAuthCodeRaisesExceptionWhenStatementExecutionFails() + public function testPersistNewAuthCodeRaisesExceptionWhenStatementExecutionFails() { $client = $this->prophesize(ClientEntityInterface::class); $client->getIdentifier()->willReturn('client_id'); @@ -81,4 +81,38 @@ public function testIsAuthCodeRevokedReturnsFalseForStatementExecutionFailure() $this->assertFalse($this->repo->isAuthCodeRevoked('code_identifier')); } + + public function testIsAuthCodeRevokedReturnsTrue() + { + $statement = $this->prophesize(PDOStatement::class); + $statement->bindParam(':codeId', 'code_identifier')->shouldBeCalled(); + $statement->execute()->willReturn(true); + $statement->fetch()->willReturn(['revoked' => true]); + + $this->pdo + ->prepare(Argument::containingString('SELECT revoked FROM oauth_auth_codes')) + ->will([$statement, 'reveal']); + + $this->assertTrue($this->repo->isAuthCodeRevoked('code_identifier')); + } + + public function testNewAuthCode() + { + $result = $this->repo->getNewAuthCode(); + $this->assertInstanceOf(AuthCodeEntity::class, $result); + } + + public function testRevokeAuthCode() + { + $statement = $this->prophesize(PDOStatement::class); + $statement->bindParam(':codeId', 'code_identifier')->shouldBeCalled(); + $statement->bindValue(':revoked', 1)->shouldBeCalled(); + $statement->execute()->willReturn(true); + + $this->pdo + ->prepare(Argument::containingString('UPDATE oauth_auth_codes SET revoked=:revoked WHERE id = :codeId')) + ->will([$statement, 'reveal']); + + $this->repo->revokeAuthCode('code_identifier'); + } } diff --git a/test/Repository/Pdo/RefreshTokenRepositoryTest.php b/test/Repository/Pdo/RefreshTokenRepositoryTest.php index f00ccf6..53ef3d6 100644 --- a/test/Repository/Pdo/RefreshTokenRepositoryTest.php +++ b/test/Repository/Pdo/RefreshTokenRepositoryTest.php @@ -17,6 +17,7 @@ use PDOStatement; use PHPUnit\Framework\TestCase; use Prophecy\Argument; +use Zend\Expressive\Authentication\OAuth2\Entity\RefreshTokenEntity; use Zend\Expressive\Authentication\OAuth2\Repository\Pdo\PdoService; use Zend\Expressive\Authentication\OAuth2\Repository\Pdo\RefreshTokenRepository; @@ -73,4 +74,41 @@ public function testIsRefreshTokenRevokedReturnsFalseWhenStatementFailsExecution $this->assertFalse($this->repo->isRefreshTokenRevoked('token_id')); } + + public function testIsRefreshTokenRevokedReturnsTrue() + { + $statement = $this->prophesize(PDOStatement::class); + $statement->bindParam(':tokenId', 'token_id')->shouldBeCalled(); + $statement->execute()->willReturn(true)->shouldBeCalled(); + $statement->fetch()->willReturn(['revoked' => true]); + + $this->pdo + ->prepare(Argument::containingString('SELECT revoked FROM oauth_refresh_tokens')) + ->will([$statement, 'reveal']); + + $this->assertTrue($this->repo->isRefreshTokenRevoked('token_id')); + } + + public function testGetNewRefreshToken() + { + $result = $this->repo->getNewRefreshToken(); + $this->assertInstanceOf(RefreshTokenEntity::class, $result); + } + + public function testRevokeRefreshToken() + { + $statement = $this->prophesize(PDOStatement::class); + $statement->bindParam(':tokenId', 'token_id')->shouldBeCalled(); + $statement->bindValue(':revoked', 1)->shouldBeCalled(); + $statement->execute()->willReturn(true)->shouldBeCalled(); + $statement->fetch()->shouldNotBeCalled(); + + $this->pdo + ->prepare(Argument::containingString( + 'UPDATE oauth_refresh_tokens SET revoked=:revoked WHERE id = :tokenId' + )) + ->will([$statement, 'reveal']); + + $this->repo->revokeRefreshToken('token_id'); + } } diff --git a/test/Repository/Pdo/ScopeRepositoryTest.php b/test/Repository/Pdo/ScopeRepositoryTest.php index fce2cc1..985d78e 100644 --- a/test/Repository/Pdo/ScopeRepositoryTest.php +++ b/test/Repository/Pdo/ScopeRepositoryTest.php @@ -10,9 +10,11 @@ namespace ZendTest\Expressive\Authentication\OAuth2\Repository\Pdo; +use League\OAuth2\Server\Entities\ClientEntityInterface; use PDOStatement; use PHPUnit\Framework\TestCase; use Prophecy\Argument; +use Zend\Expressive\Authentication\OAuth2\Entity\ScopeEntity; use Zend\Expressive\Authentication\OAuth2\Repository\Pdo\PdoService; use Zend\Expressive\Authentication\OAuth2\Repository\Pdo\ScopeRepository; @@ -51,4 +53,29 @@ public function testGetScopeEntityByIdentifierReturnsNullWhenReturnedRowDoesNotH $this->assertNull($this->repo->getScopeEntityByIdentifier('id')); } + + public function testGetScopeEntityByIndentifierReturnsScopes() + { + $statement = $this->prophesize(PDOStatement::class); + $statement->bindParam(':identifier', 'id')->shouldBeCalled(); + $statement->execute()->shouldBeCalled(); + $statement->fetch()->willReturn([ + 'id' => 'foo' + ])->shouldBeCalled(); + + $this->pdo + ->prepare(Argument::containingString('SELECT id FROM oauth_scopes')) + ->will([$statement, 'reveal']); + + $scope = $this->repo->getScopeEntityByIdentifier('id'); + $this->assertInstanceOf(ScopeEntity::class, $scope); + $this->assertEquals('foo', $scope->getIdentifier()); + } + + public function testFinalizeScopesWithEmptyScopes() + { + $clientEntity = $this->prophesize(ClientEntityInterface::class); + $scopes = $this->repo->finalizeScopes([], 'foo', $clientEntity->reveal()); + $this->assertEquals([], $scopes); + } } diff --git a/test/Repository/Pdo/UserRepositoryTest.php b/test/Repository/Pdo/UserRepositoryTest.php index 6cd1e4e..35f4ca1 100644 --- a/test/Repository/Pdo/UserRepositoryTest.php +++ b/test/Repository/Pdo/UserRepositoryTest.php @@ -14,6 +14,7 @@ use PDOStatement; use PHPUnit\Framework\TestCase; use Prophecy\Argument; +use Zend\Expressive\Authentication\OAuth2\Entity\UserEntity; use Zend\Expressive\Authentication\OAuth2\Repository\Pdo\PdoService; use Zend\Expressive\Authentication\OAuth2\Repository\Pdo\UserRepository; @@ -98,4 +99,29 @@ public function testGetUserEntityByCredentialsReturnsNullIfUserIsNotFound() ) ); } + + public function testGetUserEntityByCredentialsReturnsEntity() + { + $statement = $this->prophesize(PDOStatement::class); + $statement->bindParam(':username', 'username')->shouldBeCalled(); + $statement->execute()->willReturn(true); + $statement->fetch()->willReturn([ + 'password' => password_hash('password', PASSWORD_DEFAULT) + ]); + + $this->pdo + ->prepare(Argument::containingString('SELECT password FROM oauth_users WHERE username = :username')) + ->will([$statement, 'reveal']); + + $client = $this->prophesize(ClientEntityInterface::class); + + $entity = $this->repo->getUserEntityByUserCredentials( + 'username', + 'password', + 'auth', + $client->reveal() + ); + $this->assertInstanceOf(UserEntity::class, $entity); + $this->assertEquals('username', $entity->getIdentifier()); + } } diff --git a/test/RepositoryTraitTest.php b/test/RepositoryTraitTest.php new file mode 100644 index 0000000..cad42ce --- /dev/null +++ b/test/RepositoryTraitTest.php @@ -0,0 +1,163 @@ +trait = $trait = new class { + use RepositoryTrait; + + public function proxy(string $name, ContainerInterface $container) + { + return $this->$name($container); + } + }; + $this->container = $this->prophesize(ContainerInterface::class); + } + + /** + * @expectedException Zend\Expressive\Authentication\OAuth2\Exception\InvalidConfigException + */ + public function testGetUserRepositoryWithoutService() + { + $this->container->has(UserRepositoryInterface::class) + ->willReturn(false); + $this->trait->proxy('getUserRepository', $this->container->reveal()); + } + + public function testGetUserRepository() + { + $this->container->has(UserRepositoryInterface::class) + ->willReturn(true); + $this->container->get(UserRepositoryInterface::class) + ->willReturn($this->prophesize(UserRepositoryInterface::class)->reveal()); + + $result = $this->trait->proxy('getUserRepository', $this->container->reveal()); + $this->assertInstanceOf(UserRepositoryInterface::class, $result); + } + + /** + * @expectedException Zend\Expressive\Authentication\OAuth2\Exception\InvalidConfigException + */ + public function testGetScopeRepositoryWithoutService() + { + $this->container->has(ScopeRepositoryInterface::class) + ->willReturn(false); + $this->trait->proxy('getScopeRepository', $this->container->reveal()); + } + + public function testGetScopeRepository() + { + $this->container->has(ScopeRepositoryInterface::class) + ->willReturn(true); + $this->container->get(ScopeRepositoryInterface::class) + ->willReturn($this->prophesize(ScopeRepositoryInterface::class)->reveal()); + + $result = $this->trait->proxy('getScopeRepository', $this->container->reveal()); + $this->assertInstanceOf(ScopeRepositoryInterface::class, $result); + } + + /** + * @expectedException Zend\Expressive\Authentication\OAuth2\Exception\InvalidConfigException + */ + public function testGetAccessTokenRepositoryWithoutService() + { + $this->container->has(AccessTokenRepositoryInterface::class) + ->willReturn(false); + $this->trait->proxy('getAccessTokenRepository', $this->container->reveal()); + } + + public function testGetAccessTokenRepository() + { + $this->container->has(AccessTokenRepositoryInterface::class) + ->willReturn(true); + $this->container->get(AccessTokenRepositoryInterface::class) + ->willReturn($this->prophesize(AccessTokenRepositoryInterface::class)->reveal()); + + $result = $this->trait->proxy('getAccessTokenRepository', $this->container->reveal()); + $this->assertInstanceOf(AccessTokenRepositoryInterface::class, $result); + } + + /** + * @expectedException Zend\Expressive\Authentication\OAuth2\Exception\InvalidConfigException + */ + public function testGetClientRepositoryWithoutService() + { + $this->container->has(ClientRepositoryInterface::class) + ->willReturn(false); + $this->trait->proxy('getClientRepository', $this->container->reveal()); + } + + public function testGetClientRepository() + { + $this->container->has(ClientRepositoryInterface::class) + ->willReturn(true); + $this->container->get(ClientRepositoryInterface::class) + ->willReturn($this->prophesize(ClientRepositoryInterface::class)->reveal()); + + $result = $this->trait->proxy('getClientRepository', $this->container->reveal()); + $this->assertInstanceOf(ClientRepositoryInterface::class, $result); + } + + /** + * @expectedException Zend\Expressive\Authentication\OAuth2\Exception\InvalidConfigException + */ + public function testGetRefreshTokenRepositoryWithoutService() + { + $this->container->has(RefreshTokenRepositoryInterface::class) + ->willReturn(false); + $this->trait->proxy('getRefreshTokenRepository', $this->container->reveal()); + } + + public function testGetRefreshTokenRepository() + { + $this->container->has(RefreshTokenRepositoryInterface::class) + ->willReturn(true); + $this->container->get(RefreshTokenRepositoryInterface::class) + ->willReturn($this->prophesize(RefreshTokenRepositoryInterface::class)->reveal()); + + $result = $this->trait->proxy('getRefreshTokenRepository', $this->container->reveal()); + $this->assertInstanceOf(RefreshTokenRepositoryInterface::class, $result); + } + + /** + * @expectedException Zend\Expressive\Authentication\OAuth2\Exception\InvalidConfigException + */ + public function testGetAuthCodeRepositoryWithoutService() + { + $this->container->has(AuthCodeRepositoryInterface::class) + ->willReturn(false); + $this->trait->proxy('getAuthCodeRepository', $this->container->reveal()); + } + + public function testGetAuthCodeRepository() + { + $this->container->has(AuthCodeRepositoryInterface::class) + ->willReturn(true); + $this->container->get(AuthCodeRepositoryInterface::class) + ->willReturn($this->prophesize(AuthCodeRepositoryInterface::class)->reveal()); + + $result = $this->trait->proxy('getAuthCodeRepository', $this->container->reveal()); + $this->assertInstanceOf(AuthCodeRepositoryInterface::class, $result); + } +} From bba9b21160527f727e1c34da38e8966940d77004 Mon Sep 17 00:00:00 2001 From: Enrico Zimuel Date: Wed, 26 Sep 2018 15:13:26 +0200 Subject: [PATCH 27/99] Resolved comments on PR #49 --- src/ConfigProvider.php | 3 +++ src/ConfigTrait.php | 4 ++-- src/Entity/TimestampableTrait.php | 16 +++++++++------- test/ConfigTraitTest.php | 4 ++-- test/Entity/AccessTokenEntityTest.php | 2 +- test/Entity/AuthCodeEntityTest.php | 2 +- test/Entity/ClientEntityTest.php | 2 +- test/Entity/RefreshTokenEntityTest.php | 2 +- test/Entity/RevokableTraitTest.php | 19 +++++++++++++------ test/Entity/ScopeEntityTest.php | 2 +- test/Entity/TimestampableTraitTest.php | 6 +++--- test/Entity/UserEntityTest.php | 8 ++++++-- 12 files changed, 43 insertions(+), 27 deletions(-) diff --git a/src/ConfigProvider.php b/src/ConfigProvider.php index d59fc0a..14190f7 100644 --- a/src/ConfigProvider.php +++ b/src/ConfigProvider.php @@ -31,6 +31,9 @@ use Zend\Expressive\Authentication\OAuth2\Grant\RefreshTokenGrantFactory; use Zend\Expressive\Authentication\OAuth2\Repository\Pdo; +/** + * @codeCoverageIgnore + */ class ConfigProvider { /** diff --git a/src/ConfigTrait.php b/src/ConfigTrait.php index 401b758..1c01e51 100644 --- a/src/ConfigTrait.php +++ b/src/ConfigTrait.php @@ -92,12 +92,12 @@ protected function getGrantsConfig(ContainerInterface $container) : array if (empty($config['grants'])) { throw new InvalidConfigException( - 'The grant value is missing in config authentication' + 'The grants value is missing in config authentication and must be an array' ); } if (! is_array($config['grants'])) { throw new InvalidConfigException( - 'The grant must be an array value' + 'The grants must be an array value' ); } diff --git a/src/Entity/TimestampableTrait.php b/src/Entity/TimestampableTrait.php index 4f710ba..fdf54ff 100644 --- a/src/Entity/TimestampableTrait.php +++ b/src/Entity/TimestampableTrait.php @@ -10,7 +10,8 @@ namespace Zend\Expressive\Authentication\OAuth2\Entity; -use DateTime; +use DateTimeImmutable; +use DateTimeInterface; use DateTimeZone; use function method_exists; @@ -27,22 +28,22 @@ trait TimestampableTrait */ protected $updatedAt; - public function getCreatedAt() : DateTime + public function getCreatedAt() : DateTimeInterface { return $this->createdAt; } - public function setCreatedAt(DateTime $createdAt) : void + public function setCreatedAt(DateTimeInterface $createdAt) : void { $this->createdAt = $createdAt; } - public function getUpdatedAt() : DateTime + public function getUpdatedAt() : DateTimeInterface { return $this->updatedAt; } - public function setUpdatedAt(DateTime $updatedAt) : void + public function setUpdatedAt(DateTimeInterface $updatedAt) : void { $this->updatedAt = $updatedAt; } @@ -54,9 +55,10 @@ public function setUpdatedAt(DateTime $updatedAt) : void public function timestampOnCreate() : void { if (! $this->createdAt) { - $this->createdAt = new DateTime(); if (method_exists($this, 'getTimezone')) { - $this->createdAt->setTimezone(new DateTimeZone($this->getTimezone()->getValue())); + $this->createdAt = new DateTimeImmutable('now', new DateTimeZone($this->getTimezone()->getValue())); + } else { + $this->createdAt = new DateTimeImmutable(); } } } diff --git a/test/ConfigTraitTest.php b/test/ConfigTraitTest.php index c973104..cbaa883 100644 --- a/test/ConfigTraitTest.php +++ b/test/ConfigTraitTest.php @@ -1,7 +1,7 @@ container->get('config') ->willReturn([]); diff --git a/test/Entity/AccessTokenEntityTest.php b/test/Entity/AccessTokenEntityTest.php index 7be3ca7..a2965ff 100644 --- a/test/Entity/AccessTokenEntityTest.php +++ b/test/Entity/AccessTokenEntityTest.php @@ -16,7 +16,7 @@ class AccessTokenEntityTest extends TestCase { - public function testConstructor() + public function testImplementsInstanceAccessTokenEntityInterface() { $entity = new AccessTokenEntity(); $this->assertInstanceOf(AccessTokenEntityInterface::class, $entity); diff --git a/test/Entity/AuthCodeEntityTest.php b/test/Entity/AuthCodeEntityTest.php index 2ab7530..d5a10c6 100644 --- a/test/Entity/AuthCodeEntityTest.php +++ b/test/Entity/AuthCodeEntityTest.php @@ -16,7 +16,7 @@ class AuthCodeEntityTest extends TestCase { - public function testConstructor() + public function testImplementsInstanceAuthCodeEntityInterface() { $entity = new AuthCodeEntity(); $this->assertInstanceOf(AuthCodeEntityInterface::class, $entity); diff --git a/test/Entity/ClientEntityTest.php b/test/Entity/ClientEntityTest.php index 4ea2ba7..e77782b 100644 --- a/test/Entity/ClientEntityTest.php +++ b/test/Entity/ClientEntityTest.php @@ -20,7 +20,7 @@ public function setUp() { $this->entity = new ClientEntity('foo', 'bar', 'http://localhost'); } - public function testConstructor() + public function testImplementsAuthCodeEntityInterface() { $this->assertInstanceOf(ClientEntityInterface::class, $this->entity); } diff --git a/test/Entity/RefreshTokenEntityTest.php b/test/Entity/RefreshTokenEntityTest.php index 06f8a2c..8f00bc7 100644 --- a/test/Entity/RefreshTokenEntityTest.php +++ b/test/Entity/RefreshTokenEntityTest.php @@ -16,7 +16,7 @@ class RefreshTokenEntityTest extends TestCase { - public function testConstructor() + public function testImplementsRefreshTokenEntityInterface() { $entity = new RefreshTokenEntity(); $this->assertInstanceOf(RefreshTokenEntityInterface::class, $entity); diff --git a/test/Entity/RevokableTraitTest.php b/test/Entity/RevokableTraitTest.php index 1255f26..a16dc8c 100644 --- a/test/Entity/RevokableTraitTest.php +++ b/test/Entity/RevokableTraitTest.php @@ -15,13 +15,20 @@ class RevokableTraitTest extends TestCase { - public function testRevoked() + public function setUp() { - $mock = $this->getMockForTrait(RevokableTrait::class); + $this->trait = $this->getMockForTrait(RevokableTrait::class); + } - $mock->setRevoked(true); - $this->assertTrue($mock->isRevoked()); - $mock->setRevoked(false); - $this->assertFalse($mock->isRevoked()); + public function testSetRevokedToTrue() + { + $this->trait->setRevoked(true); + $this->assertTrue($this->trait->isRevoked()); + } + + public function testSetREvokedToFalse() + { + $this->trait->setRevoked(false); + $this->assertFalse($this->trait->isRevoked()); } } diff --git a/test/Entity/ScopeEntityTest.php b/test/Entity/ScopeEntityTest.php index 0cfa65c..bf586cd 100644 --- a/test/Entity/ScopeEntityTest.php +++ b/test/Entity/ScopeEntityTest.php @@ -21,7 +21,7 @@ public function setUp() $this->entity = new ScopeEntity(); } - public function testConstructor() + public function testImplementsScopeEntityInterface() { $this->assertInstanceOf(ScopeEntityInterface::class, $this->entity); } diff --git a/test/Entity/TimestampableTraitTest.php b/test/Entity/TimestampableTraitTest.php index 59c6a94..0b3769c 100644 --- a/test/Entity/TimestampableTraitTest.php +++ b/test/Entity/TimestampableTraitTest.php @@ -10,7 +10,7 @@ namespace ZendTest\Expressive\Authentication\OAuth2\Entity; -use DateTime; +use DateTimeImmutable; use PHPUnit\Framework\TestCase; use Zend\Expressive\Authentication\OAuth2\Entity\TimestampableTrait; @@ -23,14 +23,14 @@ public function setUp() public function testCreatedAt() { - $now = new DateTime(); + $now = new DateTimeImmutable(); $this->trait->setCreatedAt($now); $this->assertEquals($now, $this->trait->getCreatedAt()); } public function testUpdatedAt() { - $now = new DateTime(); + $now = new DateTimeImmutable(); $this->trait->setUpdatedAt($now); $this->assertEquals($now, $this->trait->getUpdatedAt()); } diff --git a/test/Entity/UserEntityTest.php b/test/Entity/UserEntityTest.php index c7b10bd..0957993 100644 --- a/test/Entity/UserEntityTest.php +++ b/test/Entity/UserEntityTest.php @@ -24,14 +24,18 @@ public function setUp() /** * @expectedException ArgumentCountError */ - public function testConstructorWithoutParam() + public function testConstructorWithoutParamWillResultInAnException() { $entity = new UserEntity(); } - public function testConstructor() + public function testImplementsUserEntityInterface() { $this->assertInstanceOf(UserEntityInterface::class, $this->entity); + } + + public function testGetIdentifier() + { $this->assertEquals('foo', $this->entity->getIdentifier()); } } From 458d26a49f2279ab591f73f5948f39cec666e8f1 Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Wed, 26 Sep 2018 11:19:21 -0500 Subject: [PATCH 28/99] Minor CS/consistency changes - Commas after all array entries - When splitting to multiple lines, move all arrow operations to their own lines when operating on an object --- test/ConfigTraitTest.php | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/test/ConfigTraitTest.php b/test/ConfigTraitTest.php index cbaa883..f1e9659 100644 --- a/test/ConfigTraitTest.php +++ b/test/ConfigTraitTest.php @@ -37,7 +37,8 @@ public function proxy(string $name, ContainerInterface $container) ] ]; $this->container = $this->prophesize(ContainerInterface::class); - $this->container->get('config') + $this->container + ->get('config') ->willReturn($this->config); } @@ -46,7 +47,8 @@ public function proxy(string $name, ContainerInterface $container) */ public function testGetPrivateKeyWhenNoConfigPresentWillResultInAnException() { - $this->container->get('config') + $this->container + ->get('config') ->willReturn([]); $this->trait->proxy('getPrivateKey', $this->container->reveal()); } @@ -62,7 +64,8 @@ public function testGetPrivateKey() */ public function testGetEncryptionKeyNoConfig() { - $this->container->get('config') + $this->container + ->get('config') ->willReturn([]); $this->trait->proxy('getEncryptionKey', $this->container->reveal()); } @@ -78,7 +81,8 @@ public function testGetEncryptionKey() */ public function testGetAccessTokenExpireNoConfig() { - $this->container->get('config') + $this->container + ->get('config') ->willReturn([]); $this->trait->proxy('getAccessTokenExpire', $this->container->reveal()); } @@ -94,7 +98,8 @@ public function testGetAccessTokenExpire() */ public function testGetRefreshTokenExpireNoConfig() { - $this->container->get('config') + $this->container + ->get('config') ->willReturn([]); $this->trait->proxy('getRefreshTokenExpire', $this->container->reveal()); } @@ -110,7 +115,8 @@ public function testGetRefreshTokenExpire() */ public function testGetAuthCodeExpireNoConfig() { - $this->container->get('config') + $this->container + ->get('config') ->willReturn([]); $this->trait->proxy('getAuthCodeExpire', $this->container->reveal()); } @@ -126,7 +132,8 @@ public function testGetAuthCodeExpire() */ public function testGetGrantsConfigNoConfig() { - $this->container->get('config') + $this->container + ->get('config') ->willReturn([]); $this->trait->proxy('getGrantsConfig', $this->container->reveal()); } @@ -136,11 +143,12 @@ public function testGetGrantsConfigNoConfig() */ public function testGetGrantsConfigNoArrayValue() { - $this->container->get('config') + $this->container + ->get('config') ->willReturn([ 'authentication' => [ - 'grants' => 'xxx' - ] + 'grants' => 'xxx', + ], ]); $this->trait->proxy('getGrantsConfig', $this->container->reveal()); From c569c1cbda8ea33d4cb97f0c3e74437ca6e432d7 Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Wed, 26 Sep 2018 11:23:25 -0500 Subject: [PATCH 29/99] Write tests for ClientEntity constructor Writes three test methods that ensure the arguments passed to the constructor affect the instance state. --- test/Entity/ClientEntityTest.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/Entity/ClientEntityTest.php b/test/Entity/ClientEntityTest.php index e77782b..afa3938 100644 --- a/test/Entity/ClientEntityTest.php +++ b/test/Entity/ClientEntityTest.php @@ -20,11 +20,27 @@ public function setUp() { $this->entity = new ClientEntity('foo', 'bar', 'http://localhost'); } + public function testImplementsAuthCodeEntityInterface() { $this->assertInstanceOf(ClientEntityInterface::class, $this->entity); } + public function testConstructorSetsIdentifier() + { + $this->assertSame('foo', $this->entity->getIdentifier()); + } + + public function testConstructorSetsName() + { + $this->assertSame('bar', $this->entity->getName()); + } + + public function testConstructorSetsRedirectUri() + { + $this->assertSame(['http://localhost'], $this->entity->getRedirectUri()); + } + public function testSecret() { $this->entity->setSecret('secret'); From c64113861b74d12d6db7b0a12eeb5c88d1a6a863 Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Wed, 26 Sep 2018 11:24:01 -0500 Subject: [PATCH 30/99] Fixes typo in method name of RevokableTraitTest --- test/Entity/RevokableTraitTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Entity/RevokableTraitTest.php b/test/Entity/RevokableTraitTest.php index a16dc8c..dade9ba 100644 --- a/test/Entity/RevokableTraitTest.php +++ b/test/Entity/RevokableTraitTest.php @@ -26,7 +26,7 @@ public function testSetRevokedToTrue() $this->assertTrue($this->trait->isRevoked()); } - public function testSetREvokedToFalse() + public function testSetRevokedToFalse() { $this->trait->setRevoked(false); $this->assertFalse($this->trait->isRevoked()); From 3c4a3561bcda3968f7fd7e74e1f65d813c30ade8 Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Wed, 26 Sep 2018 11:25:11 -0500 Subject: [PATCH 31/99] Better test method name in ScopeEntityTest s/testJsonSerialize/testEntityIsJsonSerializable/ --- test/Entity/ScopeEntityTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Entity/ScopeEntityTest.php b/test/Entity/ScopeEntityTest.php index bf586cd..ef62884 100644 --- a/test/Entity/ScopeEntityTest.php +++ b/test/Entity/ScopeEntityTest.php @@ -26,7 +26,7 @@ public function testImplementsScopeEntityInterface() $this->assertInstanceOf(ScopeEntityInterface::class, $this->entity); } - public function testJsonSerialize() + public function testEntityIsJsonSerializable() { $this->entity->setIdentifier('foo'); $this->assertEquals('"foo"', json_encode($this->entity)); From 0a83f1259e89c3311cadecce34298f0a6713bc8a Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Wed, 26 Sep 2018 11:26:34 -0500 Subject: [PATCH 32/99] One line per object operation --- .../Pdo/AccessTokenRepositoryFactoryTest.php | 3 +- .../Pdo/AuthCodeRepositoryFactoryTest.php | 3 +- .../Pdo/ClientRepositoryFactoryTest.php | 3 +- .../Pdo/RefreshTokenRepositoryFactoryTest.php | 3 +- .../Pdo/ScopeRepositoryFactoryTest.php | 3 +- test/RepositoryTraitTest.php | 54 ++++++++++++------- 6 files changed, 46 insertions(+), 23 deletions(-) diff --git a/test/Repository/Pdo/AccessTokenRepositoryFactoryTest.php b/test/Repository/Pdo/AccessTokenRepositoryFactoryTest.php index d30f058..1c9ef49 100644 --- a/test/Repository/Pdo/AccessTokenRepositoryFactoryTest.php +++ b/test/Repository/Pdo/AccessTokenRepositoryFactoryTest.php @@ -31,7 +31,8 @@ public function setUp() public function testFactory() { - $this->container->get(PdoService::class) + $this->container + ->get(PdoService::class) ->willReturn($this->pdo->reveal()); $factory = (new AccessTokenRepositoryFactory)($this->container->reveal()); diff --git a/test/Repository/Pdo/AuthCodeRepositoryFactoryTest.php b/test/Repository/Pdo/AuthCodeRepositoryFactoryTest.php index 25d215c..7c32774 100644 --- a/test/Repository/Pdo/AuthCodeRepositoryFactoryTest.php +++ b/test/Repository/Pdo/AuthCodeRepositoryFactoryTest.php @@ -31,7 +31,8 @@ public function setUp() public function testFactory() { - $this->container->get(PdoService::class) + $this->container + ->get(PdoService::class) ->willReturn($this->pdo->reveal()); $factory = (new AuthCodeRepositoryFactory)($this->container->reveal()); diff --git a/test/Repository/Pdo/ClientRepositoryFactoryTest.php b/test/Repository/Pdo/ClientRepositoryFactoryTest.php index cfd49a6..4e2574a 100644 --- a/test/Repository/Pdo/ClientRepositoryFactoryTest.php +++ b/test/Repository/Pdo/ClientRepositoryFactoryTest.php @@ -31,7 +31,8 @@ public function setUp() public function testFactory() { - $this->container->get(PdoService::class) + $this->container + ->get(PdoService::class) ->willReturn($this->pdo->reveal()); $factory = (new ClientRepositoryFactory)($this->container->reveal()); diff --git a/test/Repository/Pdo/RefreshTokenRepositoryFactoryTest.php b/test/Repository/Pdo/RefreshTokenRepositoryFactoryTest.php index 35b441d..0f75b6a 100644 --- a/test/Repository/Pdo/RefreshTokenRepositoryFactoryTest.php +++ b/test/Repository/Pdo/RefreshTokenRepositoryFactoryTest.php @@ -31,7 +31,8 @@ public function setUp() public function testFactory() { - $this->container->get(PdoService::class) + $this->container + ->get(PdoService::class) ->willReturn($this->pdo->reveal()); $factory = (new RefreshTokenRepositoryFactory)($this->container->reveal()); diff --git a/test/Repository/Pdo/ScopeRepositoryFactoryTest.php b/test/Repository/Pdo/ScopeRepositoryFactoryTest.php index 30c99e2..2a46fdf 100644 --- a/test/Repository/Pdo/ScopeRepositoryFactoryTest.php +++ b/test/Repository/Pdo/ScopeRepositoryFactoryTest.php @@ -31,7 +31,8 @@ public function setUp() public function testFactory() { - $this->container->get(PdoService::class) + $this->container + ->get(PdoService::class) ->willReturn($this->pdo->reveal()); $factory = (new ScopeRepositoryFactory)($this->container->reveal()); diff --git a/test/RepositoryTraitTest.php b/test/RepositoryTraitTest.php index cad42ce..90c69a4 100644 --- a/test/RepositoryTraitTest.php +++ b/test/RepositoryTraitTest.php @@ -40,16 +40,19 @@ public function proxy(string $name, ContainerInterface $container) */ public function testGetUserRepositoryWithoutService() { - $this->container->has(UserRepositoryInterface::class) + $this->container + ->has(UserRepositoryInterface::class) ->willReturn(false); $this->trait->proxy('getUserRepository', $this->container->reveal()); } public function testGetUserRepository() { - $this->container->has(UserRepositoryInterface::class) + $this->container + ->has(UserRepositoryInterface::class) ->willReturn(true); - $this->container->get(UserRepositoryInterface::class) + $this->container + ->get(UserRepositoryInterface::class) ->willReturn($this->prophesize(UserRepositoryInterface::class)->reveal()); $result = $this->trait->proxy('getUserRepository', $this->container->reveal()); @@ -61,16 +64,19 @@ public function testGetUserRepository() */ public function testGetScopeRepositoryWithoutService() { - $this->container->has(ScopeRepositoryInterface::class) + $this->container + ->has(ScopeRepositoryInterface::class) ->willReturn(false); $this->trait->proxy('getScopeRepository', $this->container->reveal()); } public function testGetScopeRepository() { - $this->container->has(ScopeRepositoryInterface::class) + $this->container + ->has(ScopeRepositoryInterface::class) ->willReturn(true); - $this->container->get(ScopeRepositoryInterface::class) + $this->container + ->get(ScopeRepositoryInterface::class) ->willReturn($this->prophesize(ScopeRepositoryInterface::class)->reveal()); $result = $this->trait->proxy('getScopeRepository', $this->container->reveal()); @@ -82,16 +88,19 @@ public function testGetScopeRepository() */ public function testGetAccessTokenRepositoryWithoutService() { - $this->container->has(AccessTokenRepositoryInterface::class) + $this->container + ->has(AccessTokenRepositoryInterface::class) ->willReturn(false); $this->trait->proxy('getAccessTokenRepository', $this->container->reveal()); } public function testGetAccessTokenRepository() { - $this->container->has(AccessTokenRepositoryInterface::class) + $this->container + ->has(AccessTokenRepositoryInterface::class) ->willReturn(true); - $this->container->get(AccessTokenRepositoryInterface::class) + $this->container + ->get(AccessTokenRepositoryInterface::class) ->willReturn($this->prophesize(AccessTokenRepositoryInterface::class)->reveal()); $result = $this->trait->proxy('getAccessTokenRepository', $this->container->reveal()); @@ -103,16 +112,19 @@ public function testGetAccessTokenRepository() */ public function testGetClientRepositoryWithoutService() { - $this->container->has(ClientRepositoryInterface::class) + $this->container + ->has(ClientRepositoryInterface::class) ->willReturn(false); $this->trait->proxy('getClientRepository', $this->container->reveal()); } public function testGetClientRepository() { - $this->container->has(ClientRepositoryInterface::class) + $this->container + ->has(ClientRepositoryInterface::class) ->willReturn(true); - $this->container->get(ClientRepositoryInterface::class) + $this->container + ->get(ClientRepositoryInterface::class) ->willReturn($this->prophesize(ClientRepositoryInterface::class)->reveal()); $result = $this->trait->proxy('getClientRepository', $this->container->reveal()); @@ -124,16 +136,19 @@ public function testGetClientRepository() */ public function testGetRefreshTokenRepositoryWithoutService() { - $this->container->has(RefreshTokenRepositoryInterface::class) + $this->container + ->has(RefreshTokenRepositoryInterface::class) ->willReturn(false); $this->trait->proxy('getRefreshTokenRepository', $this->container->reveal()); } public function testGetRefreshTokenRepository() { - $this->container->has(RefreshTokenRepositoryInterface::class) + $this->container + ->has(RefreshTokenRepositoryInterface::class) ->willReturn(true); - $this->container->get(RefreshTokenRepositoryInterface::class) + $this->container + ->get(RefreshTokenRepositoryInterface::class) ->willReturn($this->prophesize(RefreshTokenRepositoryInterface::class)->reveal()); $result = $this->trait->proxy('getRefreshTokenRepository', $this->container->reveal()); @@ -145,16 +160,19 @@ public function testGetRefreshTokenRepository() */ public function testGetAuthCodeRepositoryWithoutService() { - $this->container->has(AuthCodeRepositoryInterface::class) + $this->container + ->has(AuthCodeRepositoryInterface::class) ->willReturn(false); $this->trait->proxy('getAuthCodeRepository', $this->container->reveal()); } public function testGetAuthCodeRepository() { - $this->container->has(AuthCodeRepositoryInterface::class) + $this->container + ->has(AuthCodeRepositoryInterface::class) ->willReturn(true); - $this->container->get(AuthCodeRepositoryInterface::class) + $this->container + ->get(AuthCodeRepositoryInterface::class) ->willReturn($this->prophesize(AuthCodeRepositoryInterface::class)->reveal()); $result = $this->trait->proxy('getAuthCodeRepository', $this->container->reveal()); From cc0a998507662c29a8f5cf81cc01e5ea100b582e Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Wed, 26 Sep 2018 11:41:07 -0500 Subject: [PATCH 33/99] Updates copyright dates on all files touched by this patch - New files: 2018 - Existing files: range adds "-2018" --- src/ConfigProvider.php | 2 +- src/ConfigTrait.php | 2 +- src/Entity/TimestampableTrait.php | 2 +- test/Entity/AccessTokenEntityTest.php | 2 +- test/Entity/AuthCodeEntityTest.php | 2 +- test/Entity/ClientEntityTest.php | 2 +- test/Entity/RefreshTokenEntityTest.php | 2 +- test/Entity/RevokableTraitTest.php | 2 +- test/Entity/ScopeEntityTest.php | 2 +- test/Entity/TimestampableTraitTest.php | 2 +- test/Entity/UserEntityTest.php | 2 +- test/Repository/Pdo/AbstractRepositoryTest.php | 2 +- test/Repository/Pdo/AccessTokenRepositoryFactoryTest.php | 2 +- test/Repository/Pdo/AccessTokenRepositoryTest.php | 2 +- test/Repository/Pdo/AuthCodeRepositoryFactoryTest.php | 2 +- test/Repository/Pdo/AuthCodeRepositoryTest.php | 2 +- test/Repository/Pdo/ClientRepositoryFactoryTest.php | 2 +- test/Repository/Pdo/RefreshTokenRepositoryFactoryTest.php | 2 +- test/Repository/Pdo/RefreshTokenRepositoryTest.php | 2 +- test/Repository/Pdo/ScopeRepositoryFactoryTest.php | 2 +- test/Repository/Pdo/ScopeRepositoryTest.php | 2 +- test/Repository/Pdo/UserRepositoryTest.php | 2 +- test/RepositoryTraitTest.php | 2 +- 23 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/ConfigProvider.php b/src/ConfigProvider.php index 14190f7..d8950e3 100644 --- a/src/ConfigProvider.php +++ b/src/ConfigProvider.php @@ -1,7 +1,7 @@ Date: Wed, 26 Sep 2018 11:45:11 -0500 Subject: [PATCH 34/99] Adds php-nightly build to travis So we can test against PHP 7.3. --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 05e0d40..0dee3e5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,6 +33,9 @@ matrix: - php: 7.2 env: - DEPS=latest + - php: nightly + env: + - DEPS=latest before_install: - if [[ $TEST_COVERAGE != 'true' ]]; then phpenv config-rm xdebug.ini || return 0 ; fi From 10c77671f94afbd7e4d9a9b5c6703efc6935c00c Mon Sep 17 00:00:00 2001 From: Enrico Zimuel Date: Mon, 1 Oct 2018 18:10:56 +0200 Subject: [PATCH 35/99] Added oauth2 data to user --- CHANGELOG.md | 32 +- composer.json | 2 +- composer.lock | 370 +++++++++--------- docs/book/v1/authenticated-user.md | 56 +++ docs/book/{ => v1}/authorization-server.md | 46 +-- docs/book/{ => v1}/grant/auth_code.md | 0 docs/book/{ => v1}/grant/auth_code.png | Bin .../book/{ => v1}/grant/client_credentials.md | 0 docs/book/{ => v1}/grant/implicit.md | 0 docs/book/{ => v1}/grant/password.md | 0 docs/book/{ => v1}/grant/refresh_token.md | 0 docs/book/{ => v1}/intro.md | 28 +- docs/book/{ => v1}/usage.md | 0 mkdocs.yml | 17 +- src/OAuth2Adapter.php | 33 +- src/OAuth2AdapterFactory.php | 4 +- test/OAuth2AdapterFactoryTest.php | 21 + test/OAuth2AdapterTest.php | 60 ++- 18 files changed, 405 insertions(+), 264 deletions(-) create mode 100644 docs/book/v1/authenticated-user.md rename docs/book/{ => v1}/authorization-server.md (84%) rename docs/book/{ => v1}/grant/auth_code.md (100%) rename docs/book/{ => v1}/grant/auth_code.png (100%) rename docs/book/{ => v1}/grant/client_credentials.md (100%) rename docs/book/{ => v1}/grant/implicit.md (100%) rename docs/book/{ => v1}/grant/password.md (100%) rename docs/book/{ => v1}/grant/refresh_token.md (100%) rename docs/book/{ => v1}/intro.md (91%) rename docs/book/{ => v1}/usage.md (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 82c399d..31cbf53 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,17 +2,20 @@ All notable changes to this project will be documented in this file, in reverse chronological order by release. -## 0.4.3 - 2018-05-09 +## 1.0.0 - TBD ### Added +- [#41](https://github.com/zendframework/zend-expressive-authentication-oauth2/pull/41) Allows + existing PDO service to be used. This will allow us to reuse existing pdo + services instead of opening up a second connection for oauth. - [#42](https://github.com/zendframework/zend-expressive-authentication-oauth2/pull/42) Adds `TokenEndpointHandler`, `AuthorizationMiddleware` and `AuthorizationHandler` in the `Zend\Expressive\Authentication\OAuth2` namespace to [implement an authorization server](docs/book/authorization-server.md). ### Changed -- [#42](https://github.com/zendframework/zend-expressive-authentication-oauth2/pull/42) Splits +- [#42](https://github.com/zendframework/zend-expressive-authentication-oauth2/pull/42) Splits `Zend\Expressive\Authentication\OAuth2\OAuth2Middleware` into individual implementations that allow [OAuth RFC-6749](https://tools.ietf.org/html/rfc6749) compliant authorization server implementations. @@ -27,6 +30,31 @@ All notable changes to this project will be documented in this file, in reverse ### Fixed +- [#44](https://github.com/zendframework/zend-expressive-authentication-oauth2/pull/44/) Fixes + revocation of access token for PDO repository +- [#45](https://github.com/zendframework/zend-expressive-authentication-oauth2/pull/45) Fixes + issue with empty scope being passed throwing exception. + +## 0.4.3 - 2018-05-09 + +### Added + +- Nothing. + +### Changed + +- Nothing. + +### Deprecated + +- Nothing. + +### Removed + +- Nothing. + +### Fixed + - Removes auto-requiring of the encryption key via the configuration unless the default file actually exists and is readable. As the configuration is processed in every request, this is necessary to prevent issues when the file does not exist (e.g., if the user has specified an alternate location). diff --git a/composer.json b/composer.json index cca3743..8bd66a7 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,7 @@ "psr/container": "^1.0", "psr/http-message": "^1.0.1", "psr/http-server-middleware": "^1.0", - "zendframework/zend-expressive-authentication": "^0.4.0" + "zendframework/zend-expressive-authentication": "^1.0" }, "require-dev": { "phpunit/phpunit": "^7.0.1", diff --git a/composer.lock b/composer.lock index a4d4585..e04b4b8 100644 --- a/composer.lock +++ b/composer.lock @@ -1,32 +1,32 @@ { "_readme": [ "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "714de628f77f24ce564890f1614c06a3", + "content-hash": "d8f6be31fe18e6a9ab7a576fb39fd9f2", "packages": [ { "name": "defuse/php-encryption", - "version": "v2.1.0", + "version": "v2.2.1", "source": { "type": "git", "url": "https://github.com/defuse/php-encryption.git", - "reference": "5176f5abb38d3ea8a6e3ac6cd3bbb54d8185a689" + "reference": "0f407c43b953d571421e0020ba92082ed5fb7620" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/defuse/php-encryption/zipball/5176f5abb38d3ea8a6e3ac6cd3bbb54d8185a689", - "reference": "5176f5abb38d3ea8a6e3ac6cd3bbb54d8185a689", + "url": "https://api.github.com/repos/defuse/php-encryption/zipball/0f407c43b953d571421e0020ba92082ed5fb7620", + "reference": "0f407c43b953d571421e0020ba92082ed5fb7620", "shasum": "" }, "require": { "ext-openssl": "*", - "paragonie/random_compat": "~2.0", + "paragonie/random_compat": ">= 2", "php": ">=5.4.0" }, "require-dev": { - "nikic/php-parser": "^2.0|^3.0", + "nikic/php-parser": "^2.0|^3.0|^4.0", "phpunit/phpunit": "^4|^5" }, "bin": [ @@ -67,20 +67,20 @@ "security", "symmetric key cryptography" ], - "time": "2017-05-18T21:28:48+00:00" + "time": "2018-07-24T23:27:56+00:00" }, { "name": "lcobucci/jwt", - "version": "3.2.2", + "version": "3.2.4", "source": { "type": "git", "url": "https://github.com/lcobucci/jwt.git", - "reference": "0b5930be73582369e10c4d4bb7a12bac927a203c" + "reference": "c9704b751315d21735dc98d78d4f37bd73596da7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/lcobucci/jwt/zipball/0b5930be73582369e10c4d4bb7a12bac927a203c", - "reference": "0b5930be73582369e10c4d4bb7a12bac927a203c", + "url": "https://api.github.com/repos/lcobucci/jwt/zipball/c9704b751315d21735dc98d78d4f37bd73596da7", + "reference": "c9704b751315d21735dc98d78d4f37bd73596da7", "shasum": "" }, "require": { @@ -125,7 +125,7 @@ "JWS", "jwt" ], - "time": "2017-09-01T08:23:26+00:00" + "time": "2018-08-03T11:23:50+00:00" }, { "name": "league/event", @@ -247,16 +247,16 @@ }, { "name": "paragonie/random_compat", - "version": "v2.0.11", + "version": "v2.0.17", "source": { "type": "git", "url": "https://github.com/paragonie/random_compat.git", - "reference": "5da4d3c796c275c55f057af5a643ae297d96b4d8" + "reference": "29af24f25bab834fcbb38ad2a69fa93b867e070d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paragonie/random_compat/zipball/5da4d3c796c275c55f057af5a643ae297d96b4d8", - "reference": "5da4d3c796c275c55f057af5a643ae297d96b4d8", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/29af24f25bab834fcbb38ad2a69fa93b867e070d", + "reference": "29af24f25bab834fcbb38ad2a69fa93b867e070d", "shasum": "" }, "require": { @@ -288,10 +288,11 @@ "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", "keywords": [ "csprng", + "polyfill", "pseudorandom", "random" ], - "time": "2017-09-27T21:40:39+00:00" + "time": "2018-07-04T16:31:37+00:00" }, { "name": "psr/container", @@ -500,16 +501,16 @@ }, { "name": "zendframework/zend-expressive-authentication", - "version": "0.4.0", + "version": "1.0.0", "source": { "type": "git", "url": "https://github.com/zendframework/zend-expressive-authentication.git", - "reference": "2fea5529d78cddc26921e46e87ea886ccb8cc7d1" + "reference": "52594067ffc149cd7defb87388e2c33707b5203f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-expressive-authentication/zipball/2fea5529d78cddc26921e46e87ea886ccb8cc7d1", - "reference": "2fea5529d78cddc26921e46e87ea886ccb8cc7d1", + "url": "https://api.github.com/repos/zendframework/zend-expressive-authentication/zipball/52594067ffc149cd7defb87388e2c33707b5203f", + "reference": "52594067ffc149cd7defb87388e2c33707b5203f", "shasum": "" }, "require": { @@ -561,7 +562,7 @@ "zend-expressive", "zf" ], - "time": "2018-03-15T17:19:40+00:00" + "time": "2018-08-27T15:09:06+00:00" } ], "packages-dev": [ @@ -621,25 +622,28 @@ }, { "name": "myclabs/deep-copy", - "version": "1.7.0", + "version": "1.8.1", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e" + "reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", - "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8", + "reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8", "shasum": "" }, "require": { - "php": "^5.6 || ^7.0" + "php": "^7.1" + }, + "replace": { + "myclabs/deep-copy": "self.version" }, "require-dev": { "doctrine/collections": "^1.0", "doctrine/common": "^2.6", - "phpunit/phpunit": "^4.1" + "phpunit/phpunit": "^7.1" }, "type": "library", "autoload": { @@ -662,26 +666,26 @@ "object", "object graph" ], - "time": "2017-10-19T19:58:43+00:00" + "time": "2018-06-11T23:09:50+00:00" }, { "name": "phar-io/manifest", - "version": "1.0.1", + "version": "1.0.3", "source": { "type": "git", "url": "https://github.com/phar-io/manifest.git", - "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0" + "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/2df402786ab5368a0169091f61a7c1e0eb6852d0", - "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", + "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", "shasum": "" }, "require": { "ext-dom": "*", "ext-phar": "*", - "phar-io/version": "^1.0.1", + "phar-io/version": "^2.0", "php": "^5.6 || ^7.0" }, "type": "library", @@ -717,20 +721,20 @@ } ], "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", - "time": "2017-03-05T18:14:27+00:00" + "time": "2018-07-08T19:23:20+00:00" }, { "name": "phar-io/version", - "version": "1.0.1", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/phar-io/version.git", - "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df" + "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/a70c0ced4be299a63d32fa96d9281d03e94041df", - "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df", + "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6", + "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6", "shasum": "" }, "require": { @@ -764,7 +768,7 @@ } ], "description": "Library for handling version information and constraints", - "time": "2017-03-05T17:38:23+00:00" + "time": "2018-07-08T19:19:57+00:00" }, { "name": "phpdocumentor/reflection-common", @@ -920,33 +924,33 @@ }, { "name": "phpspec/prophecy", - "version": "1.7.5", + "version": "1.8.0", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "dfd6be44111a7c41c2e884a336cc4f461b3b2401" + "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/dfd6be44111a7c41c2e884a336cc4f461b3b2401", - "reference": "dfd6be44111a7c41c2e884a336cc4f461b3b2401", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/4ba436b55987b4bf311cb7c6ba82aa528aac0a06", + "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06", "shasum": "" }, "require": { "doctrine/instantiator": "^1.0.2", "php": "^5.3|^7.0", "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", - "sebastian/comparator": "^1.1|^2.0", + "sebastian/comparator": "^1.1|^2.0|^3.0", "sebastian/recursion-context": "^1.0|^2.0|^3.0" }, "require-dev": { "phpspec/phpspec": "^2.5|^3.2", - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5" + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.7.x-dev" + "dev-master": "1.8.x-dev" } }, "autoload": { @@ -979,31 +983,31 @@ "spy", "stub" ], - "time": "2018-02-19T10:16:54+00:00" + "time": "2018-08-05T17:53:17+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "6.0.1", + "version": "6.0.7", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "f8ca4b604baf23dab89d87773c28cc07405189ba" + "reference": "865662550c384bc1db7e51d29aeda1c2c161d69a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f8ca4b604baf23dab89d87773c28cc07405189ba", - "reference": "f8ca4b604baf23dab89d87773c28cc07405189ba", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/865662550c384bc1db7e51d29aeda1c2c161d69a", + "reference": "865662550c384bc1db7e51d29aeda1c2c161d69a", "shasum": "" }, "require": { "ext-dom": "*", "ext-xmlwriter": "*", "php": "^7.1", - "phpunit/php-file-iterator": "^1.4.2", + "phpunit/php-file-iterator": "^2.0", "phpunit/php-text-template": "^1.2.1", "phpunit/php-token-stream": "^3.0", "sebastian/code-unit-reverse-lookup": "^1.0.1", - "sebastian/environment": "^3.0", + "sebastian/environment": "^3.1", "sebastian/version": "^2.0.1", "theseer/tokenizer": "^1.1" }, @@ -1042,29 +1046,32 @@ "testing", "xunit" ], - "time": "2018-02-02T07:01:41+00:00" + "time": "2018-06-01T07:51:50+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "1.4.5", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4" + "reference": "050bedf145a257b1ff02746c31894800e5122946" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4", - "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/050bedf145a257b1ff02746c31894800e5122946", + "reference": "050bedf145a257b1ff02746c31894800e5122946", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": "^7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { @@ -1079,7 +1086,7 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", + "email": "sebastian@phpunit.de", "role": "lead" } ], @@ -1089,7 +1096,7 @@ "filesystem", "iterator" ], - "time": "2017-11-27T13:52:08+00:00" + "time": "2018-09-13T20:33:42+00:00" }, { "name": "phpunit/php-text-template", @@ -1232,35 +1239,35 @@ }, { "name": "phpunit/phpunit", - "version": "7.0.2", + "version": "7.3.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "e2f8aa21bc54b6ba218bdd4f9e0dac1e9bc3b4e9" + "reference": "7b331efabbb628c518c408fdfcaf571156775de2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/e2f8aa21bc54b6ba218bdd4f9e0dac1e9bc3b4e9", - "reference": "e2f8aa21bc54b6ba218bdd4f9e0dac1e9bc3b4e9", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/7b331efabbb628c518c408fdfcaf571156775de2", + "reference": "7b331efabbb628c518c408fdfcaf571156775de2", "shasum": "" }, "require": { + "doctrine/instantiator": "^1.1", "ext-dom": "*", "ext-json": "*", "ext-libxml": "*", "ext-mbstring": "*", "ext-xml": "*", - "myclabs/deep-copy": "^1.6.1", - "phar-io/manifest": "^1.0.1", - "phar-io/version": "^1.0", + "myclabs/deep-copy": "^1.7", + "phar-io/manifest": "^1.0.2", + "phar-io/version": "^2.0", "php": "^7.1", "phpspec/prophecy": "^1.7", - "phpunit/php-code-coverage": "^6.0", - "phpunit/php-file-iterator": "^1.4.3", + "phpunit/php-code-coverage": "^6.0.7", + "phpunit/php-file-iterator": "^2.0.1", "phpunit/php-text-template": "^1.2.1", "phpunit/php-timer": "^2.0", - "phpunit/phpunit-mock-objects": "^6.0", - "sebastian/comparator": "^2.1", + "sebastian/comparator": "^3.0", "sebastian/diff": "^3.0", "sebastian/environment": "^3.1", "sebastian/exporter": "^3.1", @@ -1269,10 +1276,14 @@ "sebastian/resource-operations": "^1.0", "sebastian/version": "^2.0.1" }, + "conflict": { + "phpunit/phpunit-mock-objects": "*" + }, "require-dev": { "ext-pdo": "*" }, "suggest": { + "ext-soap": "*", "ext-xdebug": "*", "phpunit/php-invoker": "^2.0" }, @@ -1282,7 +1293,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "7.0-dev" + "dev-master": "7.3-dev" } }, "autoload": { @@ -1308,95 +1319,31 @@ "testing", "xunit" ], - "time": "2018-02-26T07:03:12+00:00" - }, - { - "name": "phpunit/phpunit-mock-objects", - "version": "6.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "e3249dedc2d99259ccae6affbc2684eac37c2e53" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/e3249dedc2d99259ccae6affbc2684eac37c2e53", - "reference": "e3249dedc2d99259ccae6affbc2684eac37c2e53", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.0.5", - "php": "^7.1", - "phpunit/php-text-template": "^1.2.1", - "sebastian/exporter": "^3.1" - }, - "require-dev": { - "phpunit/phpunit": "^7.0" - }, - "suggest": { - "ext-soap": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "6.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Mock Object library for PHPUnit", - "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", - "keywords": [ - "mock", - "xunit" - ], - "time": "2018-02-15T05:27:38+00:00" + "time": "2018-09-08T15:14:29+00:00" }, { "name": "roave/security-advisories", "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "664836e89c7ecad3dbaabc1572ea752c0d532d80" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/664836e89c7ecad3dbaabc1572ea752c0d532d80", - "reference": "664836e89c7ecad3dbaabc1572ea752c0d532d80", - "shasum": "" - }, "conflict": { "3f/pygmentize": "<1.2", - "adodb/adodb-php": "<5.20.6", + "adodb/adodb-php": "<5.20.12", "amphp/artax": "<1.0.6|>=2,<2.0.6", + "amphp/http": "<1.0.1", "asymmetricrypt/asymmetricrypt": ">=0,<9.9.99", "aws/aws-sdk-php": ">=3,<3.2.1", + "brightlocal/phpwhois": "<=4.2.5", "bugsnag/bugsnag-laravel": ">=2,<2.0.2", - "cakephp/cakephp": ">=1.3,<1.3.18|>=2,<2.4.99|>=2.5,<2.5.99|>=2.6,<2.6.12|>=2.7,<2.7.6|>=3,<3.0.15|>=3.1,<3.1.4", + "cakephp/cakephp": ">=1.3,<1.3.18|>=2,<2.4.99|>=2.5,<2.5.99|>=2.6,<2.6.12|>=2.7,<2.7.6|>=3,<3.0.15|>=3.1,<3.1.4|>=3.4,<3.4.14|>=3.5,<3.5.17|>=3.6,<3.6.4", "cart2quote/module-quotation": ">=4.1.6,<=4.4.5|>=5,<5.4.4", "cartalyst/sentry": "<=2.1.6", "codeigniter/framework": "<=3.0.6", "composer/composer": "<=1.0.0-alpha11", "contao-components/mediaelement": ">=2.14.2,<2.21.1", - "contao/core": ">=2,<3.5.32", - "contao/core-bundle": ">=4,<4.4.8", + "contao/core": ">=2,<3.5.35", + "contao/core-bundle": ">=4,<4.4.18|>=4.5,<4.5.8", "contao/listing-bundle": ">=4,<4.4.8", "contao/newsletter-bundle": ">=4,<4.1", + "david-garcia/phpwhois": "<=4.3.1", "doctrine/annotations": ">=1,<1.2.7", "doctrine/cache": ">=1,<1.3.2|>=1.4,<1.4.2", "doctrine/common": ">=2,<2.4.3|>=2.5,<2.5.1", @@ -1407,89 +1354,116 @@ "doctrine/mongodb-odm-bundle": ">=2,<3.0.1", "doctrine/orm": ">=2,<2.4.8|>=2.5,<2.5.1", "dompdf/dompdf": ">=0.6,<0.6.2", - "drupal/core": ">=8,<8.4.5", - "drupal/drupal": ">=8,<8.4.5", + "drupal/core": ">=7,<7.59|>=8,<8.4.8|>=8.5,<8.5.3", + "drupal/drupal": ">=7,<7.59|>=8,<8.4.8|>=8.5,<8.5.3", "erusev/parsedown": "<1.7", "ezsystems/ezpublish-legacy": ">=5.3,<5.3.12.3|>=5.4,<5.4.11.3|>=2017.8,<2017.8.1.1|>=2017.12,<2017.12.2.1", + "ezyang/htmlpurifier": "<4.1.1", "firebase/php-jwt": "<2", "friendsofsymfony/rest-bundle": ">=1.2,<1.2.2", "friendsofsymfony/user-bundle": ">=1.2,<1.3.5", + "fuel/core": "<1.8.1", "gree/jose": "<=2.2", "gregwar/rst": "<1.0.3", "guzzlehttp/guzzle": ">=6,<6.2.1|>=4.0.0-rc2,<4.2.4|>=5,<5.3.1", - "illuminate/auth": ">=4,<4.0.99|>=4.1,<4.1.26", + "illuminate/auth": ">=4,<4.0.99|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.10", + "illuminate/cookie": ">=4,<=4.0.11|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.42|>=5.6,<5.6.30", "illuminate/database": ">=4,<4.0.99|>=4.1,<4.1.29", + "illuminate/encryption": ">=4,<=4.0.11|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.40|>=5.6,<5.6.15", + "ivankristianto/phpwhois": "<=4.3", + "james-heinrich/getid3": "<1.9.9", "joomla/session": "<1.3.1", - "laravel/framework": ">=4,<4.0.99|>=4.1,<4.1.29", + "jsmitty12/phpwhois": "<5.1", + "kazist/phpwhois": "<=4.2.6", + "kreait/firebase-php": ">=3.2,<3.8.1", + "laravel/framework": ">=4,<4.0.99|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.42|>=5.6,<5.6.30", "laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10", - "magento/magento1ce": ">=1.5.0.1,<1.9.3.2", + "magento/magento1ce": "<1.9.3.9", "magento/magento1ee": ">=1.9,<1.14.3.2", - "magento/magento2ce": ">=2,<2.2", + "magento/product-community-edition": ">=2,<2.2.5", "monolog/monolog": ">=1.8,<1.12", "namshi/jose": "<2.2", "onelogin/php-saml": "<2.10.4", + "openid/php-openid": "<2.3", "oro/crm": ">=1.7,<1.7.4", "oro/platform": ">=1.7,<1.7.4", "padraic/humbug_get_contents": "<1.1.2", "pagarme/pagarme-php": ">=0,<3", "paragonie/random_compat": "<2", + "paypal/merchant-sdk-php": "<3.12", "phpmailer/phpmailer": ">=5,<5.2.24", "phpunit/phpunit": ">=4.8.19,<4.8.28|>=5.0.10,<5.6.3", + "phpwhois/phpwhois": "<=4.2.5", "phpxmlrpc/extras": "<0.6.1", "propel/propel": ">=2.0.0-alpha1,<=2.0.0-alpha7", "propel/propel1": ">=1,<=1.7.1", "pusher/pusher-php-server": "<2.2.1", "sabre/dav": ">=1.6,<1.6.99|>=1.7,<1.7.11|>=1.8,<1.8.9", + "sensiolabs/connect": "<4.2.3", + "serluck/phpwhois": "<=4.2.6", "shopware/shopware": "<5.3.7", "silverstripe/cms": ">=3,<=3.0.11|>=3.1,<3.1.11", "silverstripe/forum": "<=0.6.1|>=0.7,<=0.7.3", "silverstripe/framework": ">=3,<3.3", "silverstripe/userforms": "<3", + "simple-updates/phpwhois": "<=1", "simplesamlphp/saml2": "<1.10.6|>=2,<2.3.8|>=3,<3.1.4", "simplesamlphp/simplesamlphp": "<1.15.2", "simplesamlphp/simplesamlphp-module-infocard": "<1.0.1", + "slim/slim": "<2.6", + "smarty/smarty": "<3.1.33", "socalnick/scn-social-auth": "<1.15.2", - "squizlabs/php_codesniffer": ">=1,<2.8.1", + "squizlabs/php_codesniffer": ">=1,<2.8.1|>=3,<3.0.1", "stormpath/sdk": ">=0,<9.9.99", "swiftmailer/swiftmailer": ">=4,<5.4.5", + "sylius/admin-bundle": ">=1,<1.0.17|>=1.1,<1.1.9|>=1.2,<1.2.2", + "sylius/sylius": ">=1,<1.0.17|>=1.1,<1.1.9|>=1.2,<1.2.2", "symfony/dependency-injection": ">=2,<2.0.17", "symfony/form": ">=2.3,<2.3.35|>=2.4,<2.6.12|>=2.7,<2.7.38|>=2.8,<2.8.31|>=3,<3.2.14|>=3.3,<3.3.13", "symfony/framework-bundle": ">=2,<2.3.18|>=2.4,<2.4.8|>=2.5,<2.5.2", - "symfony/http-foundation": ">=2,<2.3.27|>=2.4,<2.5.11|>=2.6,<2.6.6", + "symfony/http-foundation": ">=2,<2.7.49|>=2.8,<2.8.44|>=3,<3.3.18|>=3.4,<3.4.14|>=4,<4.0.14|>=4.1,<4.1.3", "symfony/http-kernel": ">=2,<2.3.29|>=2.4,<2.5.12|>=2.6,<2.6.8", "symfony/intl": ">=2.7,<2.7.38|>=2.8,<2.8.31|>=3,<3.2.14|>=3.3,<3.3.13", "symfony/routing": ">=2,<2.0.19", - "symfony/security": ">=2,<2.0.25|>=2.1,<2.1.13|>=2.2,<2.2.9|>=2.3,<2.3.37|>=2.4,<2.6.13|>=2.7,<2.7.9|>=2.7.30,<2.7.32|>=2.8.23,<2.8.25|>=3.2.10,<3.2.12|>=3.3.3,<3.3.5", - "symfony/security-core": ">=2.4,<2.6.13|>=2.7,<2.7.9|>=2.7.30,<2.7.32|>=2.8,<2.8.6|>=2.8.23,<2.8.25|>=3,<3.0.6|>=3.2.10,<3.2.12|>=3.3.3,<3.3.5", - "symfony/security-csrf": ">=2.7,<2.7.38|>=2.8,<2.8.31|>=3,<3.2.14|>=3.3,<3.3.13", - "symfony/security-http": ">=2.3,<2.3.41|>=2.4,<2.7.38|>=2.8,<2.8.31|>=3,<3.2.14|>=3.3,<3.3.13", + "symfony/security": ">=2,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", + "symfony/security-bundle": ">=2,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", + "symfony/security-core": ">=2.4,<2.6.13|>=2.7,<2.7.9|>=2.7.30,<2.7.32|>=2.8,<2.8.37|>=3,<3.3.17|>=3.4,<3.4.7|>=4,<4.0.7", + "symfony/security-csrf": ">=2.4,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", + "symfony/security-guard": ">=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", + "symfony/security-http": ">=2.3,<2.3.41|>=2.4,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", "symfony/serializer": ">=2,<2.0.11", - "symfony/symfony": ">=2,<2.3.41|>=2.4,<2.7.38|>=2.8,<2.8.31|>=3,<3.2.14|>=3.3,<3.3.13", + "symfony/symfony": ">=2,<2.7.49|>=2.8,<2.8.44|>=3,<3.3.18|>=3.4,<3.4.14|>=4,<4.0.14|>=4.1,<4.1.3", "symfony/translation": ">=2,<2.0.17", "symfony/validator": ">=2,<2.0.24|>=2.1,<2.1.12|>=2.2,<2.2.5|>=2.3,<2.3.3", "symfony/web-profiler-bundle": ">=2,<2.3.19|>=2.4,<2.4.9|>=2.5,<2.5.4", "symfony/yaml": ">=2,<2.0.22|>=2.1,<2.1.7", "thelia/backoffice-default-template": ">=2.1,<2.1.2", - "thelia/thelia": ">=2.1,<2.1.2|>=2.1.0-beta1,<2.1.3", + "thelia/thelia": ">=2.1.0-beta1,<2.1.3|>=2.1,<2.1.2", + "theonedemon/phpwhois": "<=4.2.5", "titon/framework": ">=0,<9.9.99", + "truckersmp/phpwhois": "<=4.3.1", "twig/twig": "<1.20", - "typo3/cms": ">=6.2,<6.2.30|>=7,<7.6.22|>=8,<8.7.5", + "typo3/cms": ">=6.2,<6.2.30|>=7,<7.6.30|>=8,<8.7.17|>=9,<9.3.2", + "typo3/cms-core": ">=8,<8.7.17|>=9,<9.3.2", "typo3/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.10|>=3.1,<3.1.7|>=3.2,<3.2.7|>=3.3,<3.3.5", "typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4", "willdurand/js-translation-bundle": "<2.1.1", "yiisoft/yii": ">=1.1.14,<1.1.15", - "yiisoft/yii2": "<2.0.14", + "yiisoft/yii2": "<2.0.15", "yiisoft/yii2-bootstrap": "<2.0.4", - "yiisoft/yii2-dev": "<2.0.14", + "yiisoft/yii2-dev": "<2.0.15", + "yiisoft/yii2-elasticsearch": "<2.0.5", "yiisoft/yii2-gii": "<2.0.4", "yiisoft/yii2-jui": "<2.0.4", + "yiisoft/yii2-redis": "<2.0.8", "zendframework/zend-cache": ">=2.4,<2.4.8|>=2.5,<2.5.3", "zendframework/zend-captcha": ">=2,<2.4.9|>=2.5,<2.5.2", "zendframework/zend-crypt": ">=2,<2.4.9|>=2.5,<2.5.2", "zendframework/zend-db": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.2,<2.2.10|>=2.3,<2.3.5", - "zendframework/zend-diactoros": ">=1,<1.0.4", + "zendframework/zend-diactoros": ">=1,<1.8.4", + "zendframework/zend-feed": ">=1,<2.10.3", "zendframework/zend-form": ">=2,<2.2.7|>=2.3,<2.3.1", - "zendframework/zend-http": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.3,<2.3.8|>=2.4,<2.4.1", + "zendframework/zend-http": ">=1,<2.8.1", "zendframework/zend-json": ">=2.1,<2.1.6|>=2.2,<2.2.6", "zendframework/zend-ldap": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.2,<2.2.8|>=2.3,<2.3.3", "zendframework/zend-mail": ">=2,<2.4.11|>=2.5,<2.7.2", @@ -1498,7 +1472,7 @@ "zendframework/zend-validator": ">=2.3,<2.3.6", "zendframework/zend-view": ">=2,<2.2.7|>=2.3,<2.3.1", "zendframework/zend-xmlrpc": ">=2.1,<2.1.6|>=2.2,<2.2.6", - "zendframework/zendframework": ">=2,<2.4.11|>=2.5,<2.5.1", + "zendframework/zendframework": "<2.5.1", "zendframework/zendframework1": "<1.12.20", "zendframework/zendopenid": ">=2,<2.0.2", "zendframework/zendxml": ">=1,<1.0.1", @@ -1520,7 +1494,7 @@ } ], "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it", - "time": "2018-03-07T15:45:44+00:00" + "time": "2018-09-17T20:20:31+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", @@ -1569,30 +1543,30 @@ }, { "name": "sebastian/comparator", - "version": "2.1.3", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9" + "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/34369daee48eafb2651bea869b4b15d75ccc35f9", - "reference": "34369daee48eafb2651bea869b4b15d75ccc35f9", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/5de4fc177adf9bce8df98d8d141a7559d7ccf6da", + "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da", "shasum": "" }, "require": { - "php": "^7.0", - "sebastian/diff": "^2.0 || ^3.0", + "php": "^7.1", + "sebastian/diff": "^3.0", "sebastian/exporter": "^3.1" }, "require-dev": { - "phpunit/phpunit": "^6.4" + "phpunit/phpunit": "^7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.1.x-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -1629,20 +1603,20 @@ "compare", "equality" ], - "time": "2018-02-01T13:46:46+00:00" + "time": "2018-07-12T15:12:46+00:00" }, { "name": "sebastian/diff", - "version": "3.0.0", + "version": "3.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "e09160918c66281713f1c324c1f4c4c3037ba1e8" + "reference": "366541b989927187c4ca70490a35615d3fef2dce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/e09160918c66281713f1c324c1f4c4c3037ba1e8", - "reference": "e09160918c66281713f1c324c1f4c4c3037ba1e8", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/366541b989927187c4ca70490a35615d3fef2dce", + "reference": "366541b989927187c4ca70490a35615d3fef2dce", "shasum": "" }, "require": { @@ -1685,7 +1659,7 @@ "unidiff", "unified diff" ], - "time": "2018-02-01T13:45:15+00:00" + "time": "2018-06-10T07:54:39+00:00" }, { "name": "sebastian/environment", @@ -2284,16 +2258,16 @@ }, { "name": "zendframework/zend-diactoros", - "version": "1.7.1", + "version": "1.8.6", "source": { "type": "git", "url": "https://github.com/zendframework/zend-diactoros.git", - "reference": "bf26aff803a11c5cc8eb7c4878a702c403ec67f1" + "reference": "20da13beba0dde8fb648be3cc19765732790f46e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-diactoros/zipball/bf26aff803a11c5cc8eb7c4878a702c403ec67f1", - "reference": "bf26aff803a11c5cc8eb7c4878a702c403ec67f1", + "url": "https://api.github.com/repos/zendframework/zend-diactoros/zipball/20da13beba0dde8fb648be3cc19765732790f46e", + "reference": "20da13beba0dde8fb648be3cc19765732790f46e", "shasum": "" }, "require": { @@ -2306,17 +2280,29 @@ "require-dev": { "ext-dom": "*", "ext-libxml": "*", - "phpunit/phpunit": "^5.7.16 || ^6.0.8", + "php-http/psr7-integration-tests": "dev-master", + "phpunit/phpunit": "^5.7.16 || ^6.0.8 || ^7.2.7", "zendframework/zend-coding-standard": "~1.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.7.x-dev", - "dev-develop": "1.8.x-dev" + "dev-master": "1.8.x-dev", + "dev-develop": "1.9.x-dev", + "dev-release-2.0": "2.0.x-dev" } }, "autoload": { + "files": [ + "src/functions/create_uploaded_file.php", + "src/functions/marshal_headers_from_sapi.php", + "src/functions/marshal_method_from_sapi.php", + "src/functions/marshal_protocol_version_from_sapi.php", + "src/functions/marshal_uri_from_sapi.php", + "src/functions/normalize_server.php", + "src/functions/normalize_uploaded_files.php", + "src/functions/parse_cookie_header.php" + ], "psr-4": { "Zend\\Diactoros\\": "src/" } @@ -2332,7 +2318,7 @@ "psr", "psr-7" ], - "time": "2018-02-26T15:44:50+00:00" + "time": "2018-09-05T19:29:37+00:00" } ], "aliases": [], diff --git a/docs/book/v1/authenticated-user.md b/docs/book/v1/authenticated-user.md new file mode 100644 index 0000000..b5b0906 --- /dev/null +++ b/docs/book/v1/authenticated-user.md @@ -0,0 +1,56 @@ +# Authenticated user + +Once the user is authenticated, `zend-expressive-authentication-oauth2` stores +the user's credential in a PSR-7 attribute under the name `Zend\Expressive\Authentication\UserInterface`. + +This attribute contains an object that implements the [UserInterface](https://github.com/zendframework/zend-expressive-authentication/blob/master/src/UserInterface.php). + +This object contains all the information generated by [thephpleage/oauth2-server](https://github.com/thephpleague/oauth2-server), +including the following data: + +```php +[ + 'oauth_user_id' => /* user's identifier (string) */, + 'oauth_client_id' => /* the client id (string) */, + 'oauth_access_token_id' => /* the access token id (string) */, + 'oauth_scopes' => /* the scopes (mixed, usually an array) */ +] +``` + +You can retrieve all these values using `getDetails()` or `getDetail($name)` +functions of `UserInterface`. Here is reported an examples: + +```php +$user->getDetails(); // returns all the values, as array + +$userId = $user->getDetail('oauth_user_id', false); +if (false !== $userId) { + printf("The user ID is %s", $userId); +} +``` + +If you want to retrieve the identity of the user (or the client) you can also +use the `getIdentity()` function. This function returns the user's ID if it is +not null, otherwise it returns the client's ID. + +The `getRoles()` function of the `UserInterface` object returns always an empty +array. + +## Customize the user's object + +You can customize the user's object as you need but you must implement the +`UserInterface`. To customize the user object you need to change the service +with name `Zend\Expressive\Authentication\UserInterface` pointing to your +implementation. For instance, you can point to a `CustomUserFactory` class +that returns a `CustomUser` object (that implements `UserInterface`) as follows: + +```php +// config/autoload/custom-user.local.php +return [ + 'dependencies' => [ + 'factories' => [ + UserInterface::class => CustomUserFactory::class, + ] + ] +]; +``` diff --git a/docs/book/authorization-server.md b/docs/book/v1/authorization-server.md similarity index 84% rename from docs/book/authorization-server.md rename to docs/book/v1/authorization-server.md index 3eb298c..243be71 100644 --- a/docs/book/authorization-server.md +++ b/docs/book/v1/authorization-server.md @@ -1,6 +1,6 @@ # Implement an authorization server -This library provides the basics to implement an authorization server +This library provides the basics to implement an authorization server for your application. Since there are authorization flows that require user interaction, @@ -8,8 +8,8 @@ your application is expected to provide the middleware to handle this. ## Add the token endpoint -This is the most simple part, since this library provides -`Zend\Expressive\Authentication\OAuth2\TokenHandler` to deal with it. +This is the most simple part, since this library provides +`Zend\Expressive\Authentication\OAuth2\TokenEndpointHandler` to deal with it. This endpoint must accept POST requests. @@ -18,7 +18,7 @@ For example: ```php use Zend\Expressive\Authentication\OAuth2; -$app->route('/oauth2/token', OAuth2\TokenHandler::class, ['POST']); +$app->post('/oauth2/token', OAuth2\TokenEndpointHandler::class); ``` ## Add the authorization endpoint @@ -29,11 +29,11 @@ to obtain an access token or authorization code. This endpoint must accept GET requests and should: - Validate the request (especially for a valid client id and redirect url) - - Make sure the User is authenticated (for example by showing a login + - Make sure the User is authenticated (for example by showing a login prompt if needed) - Optionally request the users consent to grant access to the client - Redirect to a specified url of the client with success or error information - + The first and the last part is provided by this library. For example, to add the authorization endpoint you can declare a middleware pipe @@ -43,18 +43,18 @@ to compose these parts: use Zend\Expressive\Authentication\OAuth2; $app->route('/oauth2/authorize', [ - OAuth2\AuthorizatonMiddleware, - + OAuth2\AuthorizationMiddleware::class, + // The followig middleware is provided by your application (see below) - Application\OAuthAuthorizationMiddleware::class, - - OAuth2\AuthorizationHandler + Application\OAuthAuthorizationMiddleware::class, + + OAuth2\AuthorizationHandler::class ], ['GET', 'POST']); ``` In your `Application\OAuthAuthorizationMiddleware`, you'll have access to the `League\OAuth2\Server\RequestTypes\AuthorizationRequest` via the -psr-7 request. Your middleware should populate the user entity with `setUser()` and the +PSR-7 request. Your middleware should populate the user entity with `setUser()` and the user's consent decision with `setAuthorizationApproved()` to this authorization request instance. @@ -68,46 +68,46 @@ use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; use Psr\Http\Message\ResponseInterface; use League\OAuth2\Server\RequestTypes\AuthorizationRequest; +use Zend\Expressive\Authentication\UserInterface; class OAuthAuthorizationMiddleware implements MiddlewareInterface { - public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface + public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface { // Assume a middleware handled the authentication check and // populates the user object which also implements the // OAuth2 UserEntityInterface - $user = $request->getAttribute('authenticated_user'); - + $user = $request->getAttribute(UserInterface::class); + // Assume some middleware handles and populates a session // container $session = $request->getAttribute('session'); - + // This is populated by the previous middleware /** @var AuthorizationRequest $authRequest */ $authRequest = $request->getAttribute(AuthorizationRequest::class); - + // the user is authenticated if ($user) { $authRequest->setUser($user); - + // Assume all clients are trusted, but you could // handle consent here or within the next middleware // as needed $authRequest->setAuthorizationApproved(true); - + return $handler->handle($request); } - + // The user is not authenticated, show login form ... - + // Store the auth request state // NOTE: Do not attempt to serialize or store the authorization // request object. Store the query parameters instead and redirect // with these to this endpoint again to replay the request. $session['oauth2_request_params'] = $request->getQueryParams(); - + return new RedirectResponse('/oauth2/login'); } } ``` - diff --git a/docs/book/grant/auth_code.md b/docs/book/v1/grant/auth_code.md similarity index 100% rename from docs/book/grant/auth_code.md rename to docs/book/v1/grant/auth_code.md diff --git a/docs/book/grant/auth_code.png b/docs/book/v1/grant/auth_code.png similarity index 100% rename from docs/book/grant/auth_code.png rename to docs/book/v1/grant/auth_code.png diff --git a/docs/book/grant/client_credentials.md b/docs/book/v1/grant/client_credentials.md similarity index 100% rename from docs/book/grant/client_credentials.md rename to docs/book/v1/grant/client_credentials.md diff --git a/docs/book/grant/implicit.md b/docs/book/v1/grant/implicit.md similarity index 100% rename from docs/book/grant/implicit.md rename to docs/book/v1/grant/implicit.md diff --git a/docs/book/grant/password.md b/docs/book/v1/grant/password.md similarity index 100% rename from docs/book/grant/password.md rename to docs/book/v1/grant/password.md diff --git a/docs/book/grant/refresh_token.md b/docs/book/v1/grant/refresh_token.md similarity index 100% rename from docs/book/grant/refresh_token.md rename to docs/book/v1/grant/refresh_token.md diff --git a/docs/book/intro.md b/docs/book/v1/intro.md similarity index 91% rename from docs/book/intro.md rename to docs/book/v1/intro.md index 2bc387b..c7aaa34 100644 --- a/docs/book/intro.md +++ b/docs/book/v1/intro.md @@ -63,7 +63,7 @@ return [ 'username' => '', 'password' => '' ], - + // Set value to null to disable a grant 'grants' => [ \League\OAuth2\Server\Grant\ClientCredentialsGrant::class @@ -111,9 +111,9 @@ return [ ``` The `grants` array is for enabling/disabling grants. By default all the supported -grants are configured to be available. If you would like to disable any of the +grants are configured to be available. If you would like to disable any of the supplied grants, simply change the value for the grant to NULL. Additionally, -you can extend this array to add your own custom grants. +you can extend this array to add your own custom grants. You need to provide an OAuth2 database yourself, or generate a [SQLite](https://www.sqlite.org) @@ -142,22 +142,10 @@ For security reason, the client `secret` and the user `password` are stored using the `bcrypt` algorithm provided by [password_hash](http://php.net/manual/en/function.password-hash.php) function of PHP. -## Configure the OAuth2 route - -As last step, in order to use the OAuth2 server you need to configure a route -to point to `Zend\Expressive\Authentication\OAuth2\OAuth2Middleware` with -GET and POST HTTP verbs. - -For instance, you can add the following route to your Expressive application: +## Configure OAuth2 routes -```php -$app->route( - '/oauth', - Zend\Expressive\Authentication\OAuth2\OAuth2Middleware::class, - ['GET', 'POST'], - 'oauth' -); -``` +As last step, in order to use the OAuth2 server you need to configure the routes +for the **token endpoint** and **authorization**. -With this configuration, you can interact with the OAuth2 server using `/oauth` -URL. +You can read how add the **token endpoint** and the **authorization** routes in +the [Implement an authorization server](authorization-server) section. diff --git a/docs/book/usage.md b/docs/book/v1/usage.md similarity index 100% rename from docs/book/usage.md rename to docs/book/v1/usage.md diff --git a/mkdocs.yml b/mkdocs.yml index bb56eee..1989b01 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -2,15 +2,16 @@ docs_dir: docs/book site_dir: docs/html pages: - index.md - - Introduction: intro.md - - Usage: usage.md - - "Authorization server": authorization-server.md + - Introduction: v1/intro.md + - Usage: v1/usage.md + - "Authorization server": v1/authorization-server.md + - "Authenticated user": v1/authenticated-user.md - Grant: - - "Client credentials": grant/client_credentials.md - - "Password": grant/password.md - - "Authorization code": grant/auth_code.md - - "Implicit": grant/implicit.md - - "Refresh token": grant/refresh_token.md + - "Client credentials": v1/grant/client_credentials.md + - "Password": v1/grant/password.md + - "Authorization code": v1/grant/auth_code.md + - "Implicit": v1/grant/implicit.md + - "Refresh token": v1/grant/refresh_token.md site_name: OAuth2 middleware site_description: 'OAuth2 (server) for Expressive and PSR-7 applications.' repo_url: 'https://github.com/zendframework/zend-expressive-authentication-oauth2' diff --git a/src/OAuth2Adapter.php b/src/OAuth2Adapter.php index f1278f1..379025b 100644 --- a/src/OAuth2Adapter.php +++ b/src/OAuth2Adapter.php @@ -16,12 +16,9 @@ use Psr\Http\Message\ServerRequestInterface; use Zend\Expressive\Authentication\AuthenticationInterface; use Zend\Expressive\Authentication\UserInterface; -use Zend\Expressive\Authentication\UserRepository\UserTrait; class OAuth2Adapter implements AuthenticationInterface { - use UserTrait; - /** * @var ResourceServer */ @@ -32,12 +29,22 @@ class OAuth2Adapter implements AuthenticationInterface */ protected $responseFactory; - public function __construct(ResourceServer $resourceServer, callable $responseFactory) - { + public function __construct( + ResourceServer $resourceServer, + callable $responseFactory, + callable $userFactory + ) { $this->resourceServer = $resourceServer; $this->responseFactory = function () use ($responseFactory) : ResponseInterface { return $responseFactory(); }; + $this->userFactory = function ( + string $identity, + array $roles = [], + array $details = [] + ) use ($userFactory) : UserInterface { + return $userFactory($identity, $roles, $details); + }; } /** @@ -47,9 +54,19 @@ public function authenticate(ServerRequestInterface $request) : ?UserInterface { try { $result = $this->resourceServer->validateAuthenticatedRequest($request); - $userId = $result->getAttribute('oauth_user_id', false); - if (false !== $userId) { - return $this->generateUser($userId, []); + $userId = $result->getAttribute('oauth_user_id', null); + $clientId = $result->getAttribute('oauth_client_id', null); + if (isset($userId) || isset($clientId)) { + return ($this->userFactory)( + $userId ?? $clientId ?? '', + [], + [ + 'oauth_user_id' => $userId, + 'oauth_client_id' => $clientId, + 'oauth_access_token_id' => $result->getAttribute('oauth_access_token_id', null), + 'oauth_scopes' => $result->getAttribute('oauth_scopes', null) + ] + ); } } catch (OAuthServerException $exception) { return null; diff --git a/src/OAuth2AdapterFactory.php b/src/OAuth2AdapterFactory.php index d35e52e..f8b6f91 100644 --- a/src/OAuth2AdapterFactory.php +++ b/src/OAuth2AdapterFactory.php @@ -13,6 +13,7 @@ use League\OAuth2\Server\ResourceServer; use Psr\Container\ContainerInterface; use Psr\Http\Message\ResponseInterface; +use Zend\Expressive\Authentication\UserInterface; class OAuth2AdapterFactory { @@ -30,7 +31,8 @@ public function __invoke(ContainerInterface $container) : OAuth2Adapter return new OAuth2Adapter( $resourceServer, - $container->get(ResponseInterface::class) + $container->get(ResponseInterface::class), + $container->get(UserInterface::class) ); } } diff --git a/test/OAuth2AdapterFactoryTest.php b/test/OAuth2AdapterFactoryTest.php index aa08059..c9c6a7e 100644 --- a/test/OAuth2AdapterFactoryTest.php +++ b/test/OAuth2AdapterFactoryTest.php @@ -20,6 +20,7 @@ use Zend\Expressive\Authentication\AuthenticationInterface; use Zend\Expressive\Authentication\OAuth2\OAuth2Adapter; use Zend\Expressive\Authentication\OAuth2\OAuth2AdapterFactory; +use Zend\Expressive\Authentication\UserInterface; class OAuth2AdapterFactoryTest extends TestCase { @@ -43,6 +44,14 @@ public function setUp() $this->responseFactory = function () { return $this->response->reveal(); }; + $this->user = $this->prophesize(UserInterface::class); + $this->userFactory = function ( + string $identity, + array $roles = [], + array $details = [] + ) { + return $this->user->reveal($identity, $roles, $details); + }; } public function testConstructor() @@ -73,6 +82,10 @@ public function testFactoryRaisesTypeErrorForNonCallableResponseFactory() ->get(ResponseInterface::class) ->willReturn(new stdClass()); + $this->container + ->get(UserInterface::class) + ->willReturn($this->userFactory); + $factory = new OAuth2AdapterFactory(); $this->expectException(TypeError::class); @@ -92,6 +105,10 @@ public function testFactoryRaisesTypeErrorWhenResponseServiceProvidesResponseIns ->get(ResponseInterface::class) ->will([$this->response, 'reveal']); + $this->container + ->get(UserInterface::class) + ->willReturn($this->userFactory); + $factory = new OAuth2AdapterFactory(); $this->expectException(TypeError::class); @@ -114,6 +131,10 @@ public function testFactoryReturnsInstanceWhenAppropriateDependenciesArePresentI ->get(ResponseInterface::class) ->willReturn($this->responseFactory); + $this->container + ->get(UserInterface::class) + ->willReturn($this->userFactory); + $factory = new OAuth2AdapterFactory(); $adapter = $factory($this->container->reveal()); diff --git a/test/OAuth2AdapterTest.php b/test/OAuth2AdapterTest.php index bed3ce8..51dd4a3 100644 --- a/test/OAuth2AdapterTest.php +++ b/test/OAuth2AdapterTest.php @@ -17,6 +17,7 @@ use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Zend\Expressive\Authentication\AuthenticationInterface; +use Zend\Expressive\Authentication\DefaultUser; use Zend\Expressive\Authentication\OAuth2\OAuth2Adapter; use Zend\Expressive\Authentication\UserInterface; @@ -38,13 +39,21 @@ public function setUp() $this->responseFactory = function () { return $this->response->reveal(); }; + $this->userFactory = function ( + string $identity, + array $roles = [], + array $details = [] + ) { + return new DefaultUser($identity, $roles, $details); + }; } public function testConstructor() { $adapter = new OAuth2Adapter( $this->resourceServer->reveal(), - $this->responseFactory + $this->responseFactory, + $this->userFactory ); $this->assertInstanceOf(OAuth2Adapter::class, $adapter); $this->assertInstanceOf(AuthenticationInterface::class, $adapter); @@ -62,16 +71,18 @@ public function testOAuthServerExceptionRaisedDuringAuthenticateResultsInInvalid $adapter = new OAuth2Adapter( $this->resourceServer->reveal(), - $this->responseFactory + $this->responseFactory, + $this->userFactory ); $this->assertNull($adapter->authenticate($request->reveal())); } - public function testAuthenticateReturnsNullIfResourceServerDoesNotProduceAUserId() + public function testAuthenticateReturnsNullIfResourceServerDoesNotProduceAUserIdOrClientId() { $request = $this->prophesize(ServerRequestInterface::class); - $request->getAttribute('oauth_user_id', false)->willReturn(false); + $request->getAttribute('oauth_user_id', null)->willReturn(null); + $request->getAttribute('oauth_client_id', null)->willReturn(null); $this->resourceServer ->validateAuthenticatedRequest(Argument::that([$request, 'reveal'])) @@ -79,7 +90,8 @@ public function testAuthenticateReturnsNullIfResourceServerDoesNotProduceAUserId $adapter = new OAuth2Adapter( $this->resourceServer->reveal(), - $this->responseFactory + $this->responseFactory, + $this->userFactory ); $this->assertNull($adapter->authenticate($request->reveal())); @@ -88,7 +100,35 @@ public function testAuthenticateReturnsNullIfResourceServerDoesNotProduceAUserId public function testAuthenticateReturnsAUserIfTheResourceServerProducesAUserId() { $request = $this->prophesize(ServerRequestInterface::class); - $request->getAttribute('oauth_user_id', false)->willReturn('some-identifier'); + $request->getAttribute('oauth_user_id', null)->willReturn('some-identifier'); + $request->getAttribute('oauth_client_id', null)->willReturn(null); + $request->getAttribute('oauth_access_token_id', null)->willReturn(null); + $request->getAttribute('oauth_scopes', null)->willReturn(null); + + $this->resourceServer + ->validateAuthenticatedRequest(Argument::that([$request, 'reveal'])) + ->will([$request, 'reveal']); + + $adapter = new OAuth2Adapter( + $this->resourceServer->reveal(), + $this->responseFactory, + $this->userFactory + ); + + $user = $adapter->authenticate($request->reveal()); + + $this->assertInstanceOf(UserInterface::class, $user); + $this->assertSame('some-identifier', $user->getIdentity()); + $this->assertSame([], $user->getRoles()); + } + + public function testAuthenticateReturnsAClientIfTheResourceServerProducesAClientId() + { + $request = $this->prophesize(ServerRequestInterface::class); + $request->getAttribute('oauth_user_id', null)->willReturn(null); + $request->getAttribute('oauth_client_id', null)->willReturn('some-identifier'); + $request->getAttribute('oauth_access_token_id', null)->willReturn(null); + $request->getAttribute('oauth_scopes', null)->willReturn(null); $this->resourceServer ->validateAuthenticatedRequest(Argument::that([$request, 'reveal'])) @@ -96,14 +136,15 @@ public function testAuthenticateReturnsAUserIfTheResourceServerProducesAUserId() $adapter = new OAuth2Adapter( $this->resourceServer->reveal(), - $this->responseFactory + $this->responseFactory, + $this->userFactory ); $user = $adapter->authenticate($request->reveal()); $this->assertInstanceOf(UserInterface::class, $user); $this->assertSame('some-identifier', $user->getIdentity()); - $this->assertSame([], $user->getUserRoles()); + $this->assertSame([], $user->getRoles()); } public function testUnauthorizedResponseProducesAResponseWithAWwwAuthenticateHeader() @@ -119,7 +160,8 @@ public function testUnauthorizedResponseProducesAResponseWithAWwwAuthenticateHea $adapter = new OAuth2Adapter( $this->resourceServer->reveal(), - $this->responseFactory + $this->responseFactory, + $this->userFactory ); $this->assertSame( From 9728d43984de103d73783f0cdb933e8409bada50 Mon Sep 17 00:00:00 2001 From: Enrico Zimuel Date: Tue, 2 Oct 2018 18:12:40 +0200 Subject: [PATCH 36/99] Updated with feedback from #50 --- CHANGELOG.md | 2 +- docs/book/authorization-server.md | 6 ++++ docs/book/grant/auth_code.md | 6 ++++ docs/book/grant/client_credentials.md | 6 ++++ docs/book/grant/implicit.md | 6 ++++ docs/book/grant/password.md | 6 ++++ docs/book/grant/refresh_token.md | 6 ++++ docs/book/intro.md | 6 ++++ docs/book/usage.md | 6 ++++ docs/book/v1/authenticated-user.md | 51 ++++++++++++++++++++++----- docs/book/v1/authorization-server.md | 4 +-- mkdocs.yml | 9 +++++ src/OAuth2Adapter.php | 2 +- 13 files changed, 104 insertions(+), 12 deletions(-) create mode 100644 docs/book/authorization-server.md create mode 100644 docs/book/grant/auth_code.md create mode 100644 docs/book/grant/client_credentials.md create mode 100644 docs/book/grant/implicit.md create mode 100644 docs/book/grant/password.md create mode 100644 docs/book/grant/refresh_token.md create mode 100644 docs/book/intro.md create mode 100644 docs/book/usage.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 31cbf53..bf3268c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ All notable changes to this project will be documented in this file, in reverse services instead of opening up a second connection for oauth. - [#42](https://github.com/zendframework/zend-expressive-authentication-oauth2/pull/42) Adds `TokenEndpointHandler`, `AuthorizationMiddleware` and `AuthorizationHandler` in the `Zend\Expressive\Authentication\OAuth2` namespace - to [implement an authorization server](docs/book/authorization-server.md). + to [implement an authorization server](https://docs.zendframework.com/zend-expressive-authentication-oauth2/v1/authorization-server/). ### Changed diff --git a/docs/book/authorization-server.md b/docs/book/authorization-server.md new file mode 100644 index 0000000..5203650 --- /dev/null +++ b/docs/book/authorization-server.md @@ -0,0 +1,6 @@ + + diff --git a/docs/book/grant/auth_code.md b/docs/book/grant/auth_code.md new file mode 100644 index 0000000..fe37c6b --- /dev/null +++ b/docs/book/grant/auth_code.md @@ -0,0 +1,6 @@ + + diff --git a/docs/book/grant/client_credentials.md b/docs/book/grant/client_credentials.md new file mode 100644 index 0000000..f63f96a --- /dev/null +++ b/docs/book/grant/client_credentials.md @@ -0,0 +1,6 @@ + + diff --git a/docs/book/grant/implicit.md b/docs/book/grant/implicit.md new file mode 100644 index 0000000..06419ca --- /dev/null +++ b/docs/book/grant/implicit.md @@ -0,0 +1,6 @@ + + diff --git a/docs/book/grant/password.md b/docs/book/grant/password.md new file mode 100644 index 0000000..938dc84 --- /dev/null +++ b/docs/book/grant/password.md @@ -0,0 +1,6 @@ + + diff --git a/docs/book/grant/refresh_token.md b/docs/book/grant/refresh_token.md new file mode 100644 index 0000000..24a8ddc --- /dev/null +++ b/docs/book/grant/refresh_token.md @@ -0,0 +1,6 @@ + + diff --git a/docs/book/intro.md b/docs/book/intro.md new file mode 100644 index 0000000..8edcf57 --- /dev/null +++ b/docs/book/intro.md @@ -0,0 +1,6 @@ + + diff --git a/docs/book/usage.md b/docs/book/usage.md new file mode 100644 index 0000000..fe265d8 --- /dev/null +++ b/docs/book/usage.md @@ -0,0 +1,6 @@ + + diff --git a/docs/book/v1/authenticated-user.md b/docs/book/v1/authenticated-user.md index b5b0906..166027b 100644 --- a/docs/book/v1/authenticated-user.md +++ b/docs/book/v1/authenticated-user.md @@ -1,7 +1,7 @@ # Authenticated user Once the user is authenticated, `zend-expressive-authentication-oauth2` stores -the user's credential in a PSR-7 attribute under the name `Zend\Expressive\Authentication\UserInterface`. +the user's authorization details in a PSR-7 attribute under the name `Zend\Expressive\Authentication\UserInterface`. This attribute contains an object that implements the [UserInterface](https://github.com/zendframework/zend-expressive-authentication/blob/master/src/UserInterface.php). @@ -17,8 +17,8 @@ including the following data: ] ``` -You can retrieve all these values using `getDetails()` or `getDetail($name)` -functions of `UserInterface`. Here is reported an examples: +You may retrieve these values using the `getDetails()` method or individually +using the `getDetail($name)` method of the user instance. As an example: ```php $user->getDetails(); // returns all the values, as array @@ -38,11 +38,46 @@ array. ## Customize the user's object -You can customize the user's object as you need but you must implement the -`UserInterface`. To customize the user object you need to change the service -with name `Zend\Expressive\Authentication\UserInterface` pointing to your -implementation. For instance, you can point to a `CustomUserFactory` class -that returns a `CustomUser` object (that implements `UserInterface`) as follows: +If you wish to provide a custom `Zend\Expressive\Authentication\UserInterface` +implementation, you will need to provide: + +- a custom implementation of the the interface +- a factory capable of generating instances of that interface +- a DI factory for generating the previous factory +- configuration wiring the `UserInterface` service to your factory. + +The factory noted in the second step should be a callable with the following +signature: + +```php +function ( + string $identity, + array $roles = [], + array $details = [] +) : Zend\Expressive\Authentication\UserInterface +``` + +As an example of the factory in the third point, you will create a standard DI +factory to return it. It could, for instance, compose a database adapter o pull +information and create your custom user implementation: + +```php +class CustomUserFactory +{ + public function __invoke(Psr\Container\ContainerInterface $container) : callable + { + $db = $container->get(Zend\Db\Adapter\AdapterInterface::class); + return function (string $identity, array $roles = [], array $details = []) use ($db) : Zend\Expressive\Authentication\UserInterface { + // get some data from $db + // return a new instance + return new MyCustomUserType(/* ... */); + }); + } +} +``` + +You will then need to wire this factory to the `UserInterface` service, +per the following example: ```php // config/autoload/custom-user.local.php diff --git a/docs/book/v1/authorization-server.md b/docs/book/v1/authorization-server.md index 243be71..41f7c61 100644 --- a/docs/book/v1/authorization-server.md +++ b/docs/book/v1/authorization-server.md @@ -8,8 +8,8 @@ your application is expected to provide the middleware to handle this. ## Add the token endpoint -This is the most simple part, since this library provides -`Zend\Expressive\Authentication\OAuth2\TokenEndpointHandler` to deal with it. +Adding the token endpoint involves routing to the provided +`Zend\Expressive\Authentication\OAuth2\TokenEndpointHandler`. This endpoint must accept POST requests. diff --git a/mkdocs.yml b/mkdocs.yml index 1989b01..bc2d4e0 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -12,6 +12,15 @@ pages: - "Authorization code": v1/grant/auth_code.md - "Implicit": v1/grant/implicit.md - "Refresh token": v1/grant/refresh_token.md + - "_hidden-legacy-page-links": + - "_introduction": intro.md + - "_usage": usage.md + - "_authorizationserver": authorization-server.md + - "_grant_clientcredentials": grant/client_credentials.md + - "_grant_password": grant/password.md + - "_grant_authcode": grant/auth_code.md + - "_grant_implicit": grant/implicit.md + - "_grant_refreshtoken": grant/refresh_token.md site_name: OAuth2 middleware site_description: 'OAuth2 (server) for Expressive and PSR-7 applications.' repo_url: 'https://github.com/zendframework/zend-expressive-authentication-oauth2' diff --git a/src/OAuth2Adapter.php b/src/OAuth2Adapter.php index 379025b..455fcc2 100644 --- a/src/OAuth2Adapter.php +++ b/src/OAuth2Adapter.php @@ -58,7 +58,7 @@ public function authenticate(ServerRequestInterface $request) : ?UserInterface $clientId = $result->getAttribute('oauth_client_id', null); if (isset($userId) || isset($clientId)) { return ($this->userFactory)( - $userId ?? $clientId ?? '', + $userId ?? $clientId, [], [ 'oauth_user_id' => $userId, From a37aa8f5a7da8386d739c0e128376f0a68d51152 Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Tue, 2 Oct 2018 17:03:33 -0500 Subject: [PATCH 37/99] Provides final edits for documentation --- docs/book/v1/authenticated-user.md | 58 +++++++++++--------- docs/book/v1/authorization-server.md | 68 +++++++++++++----------- docs/book/v1/grant/auth_code.md | 8 +-- docs/book/v1/grant/client_credentials.md | 7 +-- docs/book/v1/grant/implicit.md | 2 +- docs/book/v1/grant/password.md | 33 ++++++------ docs/book/v1/intro.md | 52 +++++++++--------- docs/book/v1/usage.md | 20 +++---- 8 files changed, 129 insertions(+), 119 deletions(-) diff --git a/docs/book/v1/authenticated-user.md b/docs/book/v1/authenticated-user.md index 166027b..c717749 100644 --- a/docs/book/v1/authenticated-user.md +++ b/docs/book/v1/authenticated-user.md @@ -1,49 +1,51 @@ # Authenticated user -Once the user is authenticated, `zend-expressive-authentication-oauth2` stores -the user's authorization details in a PSR-7 attribute under the name `Zend\Expressive\Authentication\UserInterface`. +Once the user is authenticated, zend-expressive-authentication-oauth2 stores the +user's authorization details in a PSR-7 attribute under the name +`Zend\Expressive\Authentication\UserInterface`, using an object implementing the +[interface of the same name](https://github.com/zendframework/zend-expressive-authentication/blob/master/src/UserInterface.php). -This attribute contains an object that implements the [UserInterface](https://github.com/zendframework/zend-expressive-authentication/blob/master/src/UserInterface.php). - -This object contains all the information generated by [thephpleage/oauth2-server](https://github.com/thephpleague/oauth2-server), -including the following data: +This object contains all information discovered and/or generated by +[thephpleage/oauth2-server](https://oauth2.thephpleague.com), including the +following data: ```php [ - 'oauth_user_id' => /* user's identifier (string) */, - 'oauth_client_id' => /* the client id (string) */, + 'oauth_user_id' => /* user's identifier (string) */, + 'oauth_client_id' => /* the client id (string) */, 'oauth_access_token_id' => /* the access token id (string) */, - 'oauth_scopes' => /* the scopes (mixed, usually an array) */ + 'oauth_scopes' => /* the scopes (mixed, usually an array) */ ] ``` -You may retrieve these values using the `getDetails()` method or individually -using the `getDetail($name)` method of the user instance. As an example: +You may retrieve all of these values using the `getDetails()` method, or +individually using the `getDetail($name)` method, of the user instance. As an +example: ```php $user->getDetails(); // returns all the values, as array +// Retrieves only the oauth_user_id value, using a default of boolean false: $userId = $user->getDetail('oauth_user_id', false); if (false !== $userId) { printf("The user ID is %s", $userId); } ``` -If you want to retrieve the identity of the user (or the client) you can also -use the `getIdentity()` function. This function returns the user's ID if it is -not null, otherwise it returns the client's ID. +If you want to retrieve the identity of the user (or the client), you can also +use the `getIdentity()` method. This method returns the user's ID if it is +not null; otherwise it returns the client's ID. -The `getRoles()` function of the `UserInterface` object returns always an empty -array. +**The `getRoles()` method of the user instance always returns an empty array.** -## Customize the user's object +## Customize the user instance If you wish to provide a custom `Zend\Expressive\Authentication\UserInterface` implementation, you will need to provide: -- a custom implementation of the the interface -- a factory capable of generating instances of that interface -- a DI factory for generating the previous factory +- a custom implementation of the the interface. +- a factory capable of generating instances of that implementation. +- a DI factory for generating the previous factory. - configuration wiring the `UserInterface` service to your factory. The factory noted in the second step should be a callable with the following @@ -58,16 +60,20 @@ function ( ``` As an example of the factory in the third point, you will create a standard DI -factory to return it. It could, for instance, compose a database adapter o pull +factory to return it. It could, for instance, compose a database adapter to pull information and create your custom user implementation: ```php +use Psr\Container\ContainerInterface; +use Zend\Db\Adapter\AdapterInterface as DbAdapter; +use Zend\Expressive\Authentication\UserInterface; + class CustomUserFactory { - public function __invoke(Psr\Container\ContainerInterface $container) : callable + public function __invoke(ContainerInterface $container) : callable { - $db = $container->get(Zend\Db\Adapter\AdapterInterface::class); - return function (string $identity, array $roles = [], array $details = []) use ($db) : Zend\Expressive\Authentication\UserInterface { + $db = $container->get(DbAdapter::class); + return function (string $identity, array $roles = [], array $details = []) use ($db) : UserInterface { // get some data from $db // return a new instance return new MyCustomUserType(/* ... */); @@ -85,7 +91,7 @@ return [ 'dependencies' => [ 'factories' => [ UserInterface::class => CustomUserFactory::class, - ] - ] + ], + ], ]; ``` diff --git a/docs/book/v1/authorization-server.md b/docs/book/v1/authorization-server.md index 41f7c61..ab998fc 100644 --- a/docs/book/v1/authorization-server.md +++ b/docs/book/v1/authorization-server.md @@ -1,17 +1,17 @@ # Implement an authorization server -This library provides the basics to implement an authorization server +This library provides the basics for implementing an authorization server for your application. Since there are authorization flows that require user interaction, -your application is expected to provide the middleware to handle this. +**your application is expected to provide the middleware to handle this**. ## Add the token endpoint Adding the token endpoint involves routing to the provided `Zend\Expressive\Authentication\OAuth2\TokenEndpointHandler`. -This endpoint must accept POST requests. +This endpoint **MUST** accept `POST` requests. For example: @@ -23,45 +23,51 @@ $app->post('/oauth2/token', OAuth2\TokenEndpointHandler::class); ## Add the authorization endpoint -The authorization endpoint is an url of to which the client redirects +The authorization endpoint is the URL to which the client redirects to obtain an access token or authorization code. -This endpoint must accept GET requests and should: +This endpoint **MUST** accept `GET` requests and should: - - Validate the request (especially for a valid client id and redirect url) - - Make sure the User is authenticated (for example by showing a login - prompt if needed) - - Optionally request the users consent to grant access to the client - - Redirect to a specified url of the client with success or error information +- Validate the request (especially for a valid client id and redirect url). + +- Make sure the user is authenticated (for example, by showing a login + prompt if needed). -The first and the last part is provided by this library. +- Optionally, request the user's consent to grant access to the client. -For example, to add the authorization endpoint you can declare a middleware pipe -to compose these parts: +- Redirect to a specified url of the client with success or error information. + +The first and the last items are provided by this library. + +For example, to add the authorization endpoint, you can declare a middleware +pipeline for the route as follows: ```php use Zend\Expressive\Authentication\OAuth2; +use Zend\Expressive\Session\SessionMiddleware; $app->route('/oauth2/authorize', [ + SessionMiddleware::class, + OAuth2\AuthorizationMiddleware::class, - // The followig middleware is provided by your application (see below) - Application\OAuthAuthorizationMiddleware::class, + // The following middleware is provided by your application (see below): + App\OAuthAuthorizationMiddleware::class, OAuth2\AuthorizationHandler::class ], ['GET', 'POST']); ``` -In your `Application\OAuthAuthorizationMiddleware`, you'll have access -to the `League\OAuth2\Server\RequestTypes\AuthorizationRequest` via the -PSR-7 request. Your middleware should populate the user entity with `setUser()` and the -user's consent decision with `setAuthorizationApproved()` to this authorization -request instance. +In your `App\OAuthAuthorizationMiddleware`, you'll have access to the +`League\OAuth2\Server\RequestTypes\AuthorizationRequest` via the PSR-7 request. +Your middleware should populate the `AuthorizationRequest`'s user entity via its +`setUser()` method, and the user's consent decision via the +`setAuthorizationApproved()`method. -```php -getAttribute(UserInterface::class); - // Assume some middleware handles and populates a session + // Assume the SessionMiddleware handles and populates a session // container $session = $request->getAttribute('session'); - // This is populated by the previous middleware + // This is populated by the previous middleware: /** @var AuthorizationRequest $authRequest */ $authRequest = $request->getAttribute(AuthorizationRequest::class); - // the user is authenticated + // The user is authenticated: if ($user) { $authRequest->setUser($user); - // Assume all clients are trusted, but you could - // handle consent here or within the next middleware - // as needed + // This assumes all clients are trusted, but you could + // handle consent here, or within the next middleware + // as needed. $authRequest->setAuthorizationApproved(true); return $handler->handle($request); diff --git a/docs/book/v1/grant/auth_code.md b/docs/book/v1/grant/auth_code.md index d716567..33733bc 100644 --- a/docs/book/v1/grant/auth_code.md +++ b/docs/book/v1/grant/auth_code.md @@ -8,14 +8,14 @@ third-party server with a 4-step flow as illustrated in this diagram: ![Authorization code diagram](auth_code.png) The web application sends a request (including the `client_id` and the -`redirect_uri`) to the authorization server asking for an Authorization code (1). -The authorization server shows an Allow/Deny page to the end-user requesting +`redirect_uri`) to the authorization server asking for an authorization code (1). +The authorization server shows an allow/deny page to the end-user requesting authorization for access. If the user clicks on "Allow", the server sends the authorization code to the web application using the `redirect_uri` (2). The web application can now perform a token request, passing the `client_id`, the `redirect_uri`, the `client_secret`, and the authentication code to prove that it is authorized to perform the request (3). The authorization server sends -the access token in response if the request is valid (4). +the access token in the response if the request is valid (4). ## Request the authorization code @@ -29,7 +29,7 @@ authorization server: the user will be redirected to a default location on completion. - `scope` with a space-delimited list of requested scope permissions. - `state` with a Cross-Site Request Forgery (CSRF) token. This parameter is - optional, but highly recommended. You can store the value of the CSRF token in + optional, but highly recommended. You can store the value of the CSRF token in the user’s session to be validated in the next step. The user will then be asked to login to the authorization server and approve the diff --git a/docs/book/v1/grant/client_credentials.md b/docs/book/v1/grant/client_credentials.md index d7e9969..20e1ac5 100644 --- a/docs/book/v1/grant/client_credentials.md +++ b/docs/book/v1/grant/client_credentials.md @@ -1,9 +1,10 @@ # Client credentials -The client credentials grant is used in machine-to-machine scenarios: for -example, a client making API requests that do not require a user's permission. +The client credentials grant is used in machine-to-machine scenarios. For +example, you would use it with a client making API requests that do not require +a user's permission. -The client sends a `POST` request with following body parameters to the +The client sends a `POST` request with the following body parameters to the authorization server: - `grant_type` = client_credentials. diff --git a/docs/book/v1/grant/implicit.md b/docs/book/v1/grant/implicit.md index 5ca2d4c..b8c162c 100644 --- a/docs/book/v1/grant/implicit.md +++ b/docs/book/v1/grant/implicit.md @@ -20,7 +20,7 @@ authorization server: user’s session to be validated in the next step. The user will then be asked to login to the authorization server and approve the -client request. If the user approves the request they will be redirected to the +client request. If the user approves the request, they will be redirected to the redirect URI with the following parameters in the query string arguments: - `token_type` = Bearer. diff --git a/docs/book/v1/grant/password.md b/docs/book/v1/grant/password.md index 30f7f69..a2101f5 100644 --- a/docs/book/v1/grant/password.md +++ b/docs/book/v1/grant/password.md @@ -1,18 +1,19 @@ # Password -This use case can be used to authenticate an API with user's password grant. -The typical scenario includes a Login web page with username and password that -is used to authenticate against a first-party API. Password grant is only -appropriate for **trusted clients**. If you build your own website as a client -of your API, then this is a great way to handle logging in. +This use case allows authentication to an API using the user's credentials +(generally a username and password). The typical scenario includes a "Login" +web page that captures a username and password combination that is used to +authenticate against a first-party API. Password grant is only appropriate for +**trusted clients**. If you build your own website as a client of your API, then +this is a great way to handle logging in. The client sends a POST request with following parameters: -- `grant_type` = password; -- `client_id` with the client’s ID; -- `client_secret` with the client’s secret; -- `scope` with a space-delimited list of requested scope permissions; -- `username` with the user’s username; +- `grant_type` = password. +- `client_id` with the client’s ID. +- `client_secret` with the client’s secret. +- `scope` with a space-delimited list of requested scope permissions. +- `username` with the user’s username. - `password` with the user’s password. The authorization server responds with a JSON as follows: @@ -26,9 +27,9 @@ The authorization server responds with a JSON as follows: } ``` -The `token_type` is the type of generated token (Bearer). The `expires_in` is -an integer representing the TTL (in seconds) of the access token. -The `refresh_token` a token that can be used to refresh the `access_token` when -expired. -The `access_token` contains a `JWT` signed with the authorization server’s -private key. This token must be used in the `Authorization` request HTTP header. +The `token_type` is the type of generated token (Bearer). The `expires_in` is an +integer representing the TTL (in seconds) of the access token. The +`refresh_token` a token that can be used to refresh the `access_token` when +expired. The `access_token` contains a `JWT` signed with the authorization +server’s private key. This token must be used in the `Authorization` request +HTTP header. diff --git a/docs/book/v1/intro.md b/docs/book/v1/intro.md index c7aaa34..8df0477 100644 --- a/docs/book/v1/intro.md +++ b/docs/book/v1/intro.md @@ -2,9 +2,9 @@ This component provides [OAuth2](https://oauth.net/2/) (server) authentication for [Expressive](https://docs.zendframework.com/zend-expressive/) and -[PSR-7](https://www.php-fig.org/psr/psr-7/) applications. It implements -`Zend\Expressive\Authentication\AuthenticationInterface`, and it be used as -an adapter for [zend-expressive-authentication](https://github.com/zendframework/zend-expressive-authentication). +[PSR-7](https://www.php-fig.org/psr/psr-7/)/[PSR-15](https://www.php-fig.org/psr/psr-15/) +applications. It implements `Zend\Expressive\Authentication\AuthenticationInterface`, +and it can be used as an adapter for [zend-expressive-authentication](https://github.com/zendframework/zend-expressive-authentication). This library uses the [league/oauth2-server](https://oauth2.thephpleague.com/) package for implementing the OAuth2 server. @@ -14,7 +14,7 @@ If you need an introduction to OAuth2, you can read the following references: - [OAuth2 documentation](https://apigility.org/documentation/auth/authentication-oauth2) from the Apigility project. - [An Introduction to OAuth 2](https://www.digitalocean.com/community/tutorials/an-introduction-to-oauth-2) - by Digital Ocean. + by DigitalOcean. - The [OAuth2 specification](https://oauth.net/2/) itself, via its official website. @@ -22,15 +22,15 @@ If you need an introduction to OAuth2, you can read the following references: In order to implement the OAuth2 server, we first need to configure it. The first step is to generate new cryptographic keys. We need to execute the script -`bin/generate-oauth2-keys` in order to generate these keys. +`./vendor/bin/generate-oauth2-keys` in order to generate these keys. ```bash $ ./vendor/bin/generate-oauth2-keys ``` -This script will store the keys in the parent application `data` folder if found: +This script will store the keys in the application's `data` folder if found: -``` +```text Private key stored in: ./data/oauth/private.key Public key stored in: @@ -51,6 +51,8 @@ PSR-11 container (e.g. [zend-servicemanager](https://github.com/zendframework/ze The default values are: ```php +use League\OAuth2\Server\Grant; + return [ 'private_key' => __DIR__ . '/../data/oauth/private.key', 'public_key' => __DIR__ . '/../data/oauth/public.key', @@ -66,16 +68,11 @@ return [ // Set value to null to disable a grant 'grants' => [ - \League\OAuth2\Server\Grant\ClientCredentialsGrant::class - => \League\OAuth2\Server\Grant\ClientCredentialsGrant::class, - \League\OAuth2\Server\Grant\PasswordGrant::class - => \League\OAuth2\Server\Grant\PasswordGrant::class, - \League\OAuth2\Server\Grant\AuthCodeGrant::class - => \League\OAuth2\Server\Grant\AuthCodeGrant::class, - \League\OAuth2\Server\Grant\ImplicitGrant::class - => \League\OAuth2\Server\Grant\ImplicitGrant::class, - \League\OAuth2\Server\Grant\RefreshTokenGrant::class - => \League\OAuth2\Server\Grant\RefreshTokenGrant::class + Grant\ClientCredentialsGrant::class => Grant\ClientCredentialsGrant::class, + Grant\PasswordGrant::class => Grant\PasswordGrant::class, + Grant\AuthCodeGrant::class => Grant\AuthCodeGrant::class, + Grant\ImplicitGrant::class => Grant\ImplicitGrant::class, + Grant\RefreshTokenGrant::class => Grant\RefreshTokenGrant::class ], ]; ``` @@ -101,7 +98,7 @@ the `username`, and the `password`, if required. The SQL structure of this database is stored in the [data/oauth2.sql](https://github.com/zendframework/zend-expressive-authentication-oauth2/blob/master/data/oauth2.sql) file. -If you already have a PDO service configured, you can simply pass in the service +If you already have a PDO service configured, you can instead pass the service name to the `pdo` key as follows: ```php @@ -110,23 +107,22 @@ return [ ]; ``` -The `grants` array is for enabling/disabling grants. By default all the supported -grants are configured to be available. If you would like to disable any of the -supplied grants, simply change the value for the grant to NULL. Additionally, +The `grants` array is for enabling/disabling grants. By default, all the supported +grants are configured to be available. If you would like to disable any of the +supplied grants, change the value for the grant to `null`. Additionally, you can extend this array to add your own custom grants. - You need to provide an OAuth2 database yourself, or generate a [SQLite](https://www.sqlite.org) database with the following command (using `sqlite3` for GNU/Linux): ```bash -$ sqlite3 data/oauth2.sqlite < data/oauth2.sql +$ sqlite3 data/oauth2.sqlite < vendor/zendframework/zend-expressive-authentication-oauth2/data/oauth2.sql ``` You can also create some testing values using the `data/oauth2_test.sql` file: ```bash -$ sqlite3 data/oauth2.sqlite < data/oauth2_test.sql +$ sqlite3 data/oauth2.sqlite < vendor/zendframework/zend-expressive-authentication-oauth2/data/oauth2_test.sql ``` These commands will insert the following testing values: @@ -139,13 +135,13 @@ These commands will insert the following testing values: - a `test` scope. For security reason, the client `secret` and the user `password` are stored -using the `bcrypt` algorithm provided by [password_hash](http://php.net/manual/en/function.password-hash.php) -function of PHP. +using the `bcrypt` algorithm as used by the [password_hash](http://php.net/manual/en/function.password-hash.php) +function. ## Configure OAuth2 routes -As last step, in order to use the OAuth2 server you need to configure the routes +As the final step, in order to use the OAuth2 server you need to configure the routes for the **token endpoint** and **authorization**. You can read how add the **token endpoint** and the **authorization** routes in -the [Implement an authorization server](authorization-server) section. +the [Implement an authorization server](authorization-server.md) section. diff --git a/docs/book/v1/usage.md b/docs/book/v1/usage.md index 2d47cd1..faed762 100644 --- a/docs/book/v1/usage.md +++ b/docs/book/v1/usage.md @@ -2,7 +2,7 @@ If you successfully configured the OAuth2 server as detailed in the [installation](intro.md) section, you can request an access token using the -OAuth2 server route defined [before](intro.md#configure-the-oauth2-route) +OAuth2 server route you [defined](intro.md#configure-the-oauth2-route) (e.g. `/oauth`). You can require an access token using one of the following scenarios: @@ -18,11 +18,10 @@ You can require an access token using one of the following scenarios: This library uses the authentication abstraction of the `Zend\Expressive\Authentication\AuthenticationMiddleware` class provided by [zend-expressive-authentication](https://github.com/zendframework/zend-expressive-authentication). -In order to use OAuth2 we need to configure the service -`Zend\Expressive\Authentication\AuthenticationInterface` to resolve in -`Zend\Expressive\Authentication\OAuth2\OAuth2Adapter`. Using the -[zend-servicemanager](https://github.com/zendframework/zend-servicemanager) this -can be achieved using `aliases` with the following configuration: +In order to use OAuth2, we need to configure the service +`Zend\Expressive\Authentication\AuthenticationInterface` to resolve to +`Zend\Expressive\Authentication\OAuth2\OAuth2Adapter`. This can be achieved +using the following configuration: ```php use Zend\Expressive\Authentication; @@ -37,9 +36,10 @@ return [ ``` The previous configuration will instruct `zend-expressive-authentication` to use -the OAuth2 adapter. This adapter does not require a `Zend\Expressive\Authentication\UserRepositoryInterface`. -The OAuth2 database with user and client credentials is managed by the component -itself. +the OAuth2 adapter provided in this package. (Unlike other adapters, this +adapter does not require a `Zend\Expressive\Authentication\UserRepositoryInterface`; +the OAuth2 database with user and client credentials is managed by the component +itself.) When the service alias is configured, you can immediately begin authenticating your application/API by adding the `AuthenticationMiddleware` to either your @@ -57,4 +57,4 @@ $app->post('/api/users', [ # Providing an authorization server See the chapter [Authorization server](authorization-server.md) for details on how -to implement this. \ No newline at end of file +to implement this. From 8ec4b2525ff70c8e80604ec8330120c5bd56cdc6 Mon Sep 17 00:00:00 2001 From: Enrico Zimuel Date: Thu, 4 Oct 2018 10:05:46 +0200 Subject: [PATCH 38/99] Updated CHANGELOG for 1.0.0 --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bf3268c..c8d469d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to this project will be documented in this file, in reverse chronological order by release. -## 1.0.0 - TBD +## 1.0.0 - 2018-10-04 ### Added @@ -12,6 +12,10 @@ All notable changes to this project will be documented in this file, in reverse - [#42](https://github.com/zendframework/zend-expressive-authentication-oauth2/pull/42) Adds `TokenEndpointHandler`, `AuthorizationMiddleware` and `AuthorizationHandler` in the `Zend\Expressive\Authentication\OAuth2` namespace to [implement an authorization server](https://docs.zendframework.com/zend-expressive-authentication-oauth2/v1/authorization-server/). +- [#50](https://github.com/zendframework/zend-expressive-authentication-oauth2/pull/50) Adds + all the OAuth2 identity data generated by [thephpleague/oauth2-server](https://github.com/thephpleague/oauth2-server) + to `UserInterface` PSR-7 attribute. These values are `oauth_user_id`, + `oauth_client_id`, `oauth_access_token_id`, `oauth_scopes`. ### Changed From 78a90c8ad939171f913e64dfc70865fa3d5a9db9 Mon Sep 17 00:00:00 2001 From: Enrico Zimuel Date: Thu, 4 Oct 2018 10:09:38 +0200 Subject: [PATCH 39/99] Updated README --- README.md | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/README.md b/README.md index 6c358a6..e793ffd 100644 --- a/README.md +++ b/README.md @@ -17,16 +17,6 @@ types: - implicit; - refresh token; -## WORK IN PROGRESS - -This repository contains a **work in progress** project for building an -authentication module for Expressive and PSR-7 applications. -It also provides an OAuth2 adapter for [zend-expressive-authentication](https://github.com/zendframework/zend-expressive-authentication) -library. - - -**Please, don't use this code in a production environment!** - ## Installation You can install the *zend-expressive-authentication-oauth2* library with From 98fe5eb43023da720537457a83d236e28ba52b23 Mon Sep 17 00:00:00 2001 From: Enrico Zimuel Date: Thu, 4 Oct 2018 10:14:05 +0200 Subject: [PATCH 40/99] Updated CHANGELOG --- CHANGELOG.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c8d469d..8685e79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,28 @@ All notable changes to this project will be documented in this file, in reverse chronological order by release. +## 1.0.1 - TBD + +### Added + +- Nothing. + +### Changed + +- Nothing. + +### Deprecated + +- Nothing. + +### Removed + +- Nothing. + +### Fixed + +- Nothing. + ## 1.0.0 - 2018-10-04 ### Added From e5ccc66539829901dd08c4f0c8c74c7a799faac3 Mon Sep 17 00:00:00 2001 From: Marc Bennewitz Date: Tue, 30 Oct 2018 14:45:50 +0100 Subject: [PATCH 41/99] fixed #52: AuthorizationHandler mapped to wrong factory --- CHANGELOG.md | 3 +- composer.json | 3 +- composer.lock | 154 ++++++++++++++++++++++- src/ConfigProvider.php | 2 +- test/AuthorizationHandlerFactoryTest.php | 17 +++ 5 files changed, 174 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8685e79..badd0e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,7 +22,8 @@ All notable changes to this project will be documented in this file, in reverse ### Fixed -- Nothing. +- [#52](https://github.com/zendframework/zend-expressive-authentication-oauth2/issues/52) + Wrong factory mapped to AuthorizationHandler ## 1.0.0 - 2018-10-04 diff --git a/composer.json b/composer.json index 8bd66a7..acbaac4 100644 --- a/composer.json +++ b/composer.json @@ -32,7 +32,8 @@ "phpunit/phpunit": "^7.0.1", "roave/security-advisories": "dev-master", "zendframework/zend-coding-standard": "~1.0.0", - "zendframework/zend-diactoros": "^1.4.0" + "zendframework/zend-diactoros": "^1.4.0", + "zendframework/zend-servicemanager": "^3.0.0" }, "conflict": { "container-interop/container-interop": "<1.2.0" diff --git a/composer.lock b/composer.lock index e04b4b8..ca715de 100644 --- a/composer.lock +++ b/composer.lock @@ -1,10 +1,10 @@ { "_readme": [ "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "d8f6be31fe18e6a9ab7a576fb39fd9f2", + "content-hash": "8a696ccb3ecfce33801c7767868837e6", "packages": [ { "name": "defuse/php-encryption", @@ -566,6 +566,37 @@ } ], "packages-dev": [ + { + "name": "container-interop/container-interop", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/container-interop/container-interop.git", + "reference": "79cbf1341c22ec75643d841642dd5d6acd83bdb8" + }, + "dist": { + "type": "zip", + "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": { + "Interop\\Container\\": "src/Interop/Container/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Promoting the interoperability of container objects (DIC, SL, etc.)", + "homepage": "https://github.com/container-interop/container-interop", + "time": "2017-02-14T19:40:03+00:00" + }, { "name": "doctrine/instantiator", "version": "1.1.0", @@ -1324,6 +1355,11 @@ { "name": "roave/security-advisories", "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/Roave/SecurityAdvisories.git", + "reference": "0d96c6cd7cee8572be836fca71f9f01c8b1c0cb2" + }, "conflict": { "3f/pygmentize": "<1.2", "adodb/adodb-php": "<5.20.12", @@ -2319,6 +2355,120 @@ "psr-7" ], "time": "2018-09-05T19:29:37+00:00" + }, + { + "name": "zendframework/zend-servicemanager", + "version": "3.3.2", + "source": { + "type": "git", + "url": "https://github.com/zendframework/zend-servicemanager.git", + "reference": "9f35a104b8d4d3b32da5f4a3b6efc0dd62e5af42" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zendframework/zend-servicemanager/zipball/9f35a104b8d4d3b32da5f4a3b6efc0dd62e5af42", + "reference": "9f35a104b8d4d3b32da5f4a3b6efc0dd62e5af42", + "shasum": "" + }, + "require": { + "container-interop/container-interop": "^1.2", + "php": "^5.6 || ^7.0", + "psr/container": "^1.0", + "zendframework/zend-stdlib": "^3.1" + }, + "provide": { + "container-interop/container-interop-implementation": "^1.2", + "psr/container-implementation": "^1.0" + }, + "require-dev": { + "mikey179/vfsstream": "^1.6.5", + "ocramius/proxy-manager": "^1.0 || ^2.0", + "phpbench/phpbench": "^0.13.0", + "phpunit/phpunit": "^5.7.25 || ^6.4.4", + "zendframework/zend-coding-standard": "~1.0.0" + }, + "suggest": { + "ocramius/proxy-manager": "ProxyManager 1.* to handle lazy initialization of services", + "zendframework/zend-stdlib": "zend-stdlib ^2.5 if you wish to use the MergeReplaceKey or MergeRemoveKey features in Config instances" + }, + "bin": [ + "bin/generate-deps-for-config-factory", + "bin/generate-factory-for-class" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.3-dev", + "dev-develop": "4.0-dev" + } + }, + "autoload": { + "psr-4": { + "Zend\\ServiceManager\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Factory-Driven Dependency Injection Container", + "keywords": [ + "PSR-11", + "ZendFramework", + "dependency-injection", + "di", + "dic", + "service-manager", + "servicemanager", + "zf" + ], + "time": "2018-01-29T16:48:37+00:00" + }, + { + "name": "zendframework/zend-stdlib", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/zendframework/zend-stdlib.git", + "reference": "66536006722aff9e62d1b331025089b7ec71c065" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zendframework/zend-stdlib/zipball/66536006722aff9e62d1b331025089b7ec71c065", + "reference": "66536006722aff9e62d1b331025089b7ec71c065", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "phpbench/phpbench": "^0.13", + "phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1.2", + "zendframework/zend-coding-standard": "~1.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2.x-dev", + "dev-develop": "3.3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Zend\\Stdlib\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "SPL extensions, array utilities, error handlers, and more", + "keywords": [ + "ZendFramework", + "stdlib", + "zf" + ], + "time": "2018-08-28T21:34:05+00:00" } ], "aliases": [], diff --git a/src/ConfigProvider.php b/src/ConfigProvider.php index d8950e3..80b0410 100644 --- a/src/ConfigProvider.php +++ b/src/ConfigProvider.php @@ -66,7 +66,7 @@ public function getDependencies() : array ], 'factories' => [ AuthorizationMiddleware::class => AuthorizationMiddlewareFactory::class, - AuthorizationHandler::class => AuthorizationServerFactory::class, + AuthorizationHandler::class => AuthorizationHandlerFactory::class, TokenEndpointHandler::class => TokenEndpointHandlerFactory::class, OAuth2Adapter::class => OAuth2AdapterFactory::class, AuthorizationServer::class => AuthorizationServerFactory::class, diff --git a/test/AuthorizationHandlerFactoryTest.php b/test/AuthorizationHandlerFactoryTest.php index 47c6ecb..1fbec51 100644 --- a/test/AuthorizationHandlerFactoryTest.php +++ b/test/AuthorizationHandlerFactoryTest.php @@ -17,8 +17,10 @@ use Psr\Http\Message\ResponseInterface; use stdClass; use TypeError; +use Zend\Expressive\Authentication\OAuth2\ConfigProvider; use Zend\Expressive\Authentication\OAuth2\AuthorizationHandler; use Zend\Expressive\Authentication\OAuth2\AuthorizationHandlerFactory; +use Zend\ServiceManager\ServiceManager; /** * @covers \Zend\Expressive\Authentication\OAuth2\AuthorizationHandlerFactory @@ -108,4 +110,19 @@ public function testFactoryReturnsInstanceWhenAppropriateDependenciesArePresentI $middleware = $factory($this->container->reveal()); $this->assertInstanceOf(AuthorizationHandler::class, $middleware); } + + public function testConfigProvider() + { + $authServer = $this->prophesize(AuthorizationServer::class)->reveal(); + $responseFactory = function () { + return $this->prophesize(ResponseInterface::class)->reveal(); + }; + + $container = new ServiceManager((new ConfigProvider())->getDependencies()); + $container->setService(AuthorizationServer::class, $authServer); + $container->setService(ResponseInterface::class, $responseFactory); + + $authHandler = $container->get(AuthorizationHandler::class); + $this->assertInstanceOf(AuthorizationHandler::class, $authHandler); + } } From 05eee805f686d91ec4b29d47bd275743b029171d Mon Sep 17 00:00:00 2001 From: Marc Bennewitz Date: Tue, 30 Oct 2018 16:05:04 +0100 Subject: [PATCH 42/99] fixed "WWW-Authenticate" header value format --- src/OAuth2Adapter.php | 2 +- test/OAuth2AdapterTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/OAuth2Adapter.php b/src/OAuth2Adapter.php index 455fcc2..999bcd6 100644 --- a/src/OAuth2Adapter.php +++ b/src/OAuth2Adapter.php @@ -82,7 +82,7 @@ public function unauthorizedResponse(ServerRequestInterface $request) : Response return ($this->responseFactory)() ->withHeader( 'WWW-Authenticate', - 'Bearer token-example' + 'Bearer realm="OAuth2 token"' ) ->withStatus(401); } diff --git a/test/OAuth2AdapterTest.php b/test/OAuth2AdapterTest.php index 51dd4a3..e1bdb3a 100644 --- a/test/OAuth2AdapterTest.php +++ b/test/OAuth2AdapterTest.php @@ -152,7 +152,7 @@ public function testUnauthorizedResponseProducesAResponseWithAWwwAuthenticateHea $request = $this->prophesize(ServerRequestInterface::class)->reveal(); $this->response - ->withHeader('WWW-Authenticate', 'Bearer token-example') + ->withHeader('WWW-Authenticate', 'Bearer realm="OAuth2 token"') ->will([$this->response, 'reveal']); $this->response ->withStatus(401) From b24155f96267c08155832535fee0380f0713e82d Mon Sep 17 00:00:00 2001 From: Enrico Zimuel Date: Wed, 31 Oct 2018 12:32:36 +0100 Subject: [PATCH 43/99] Updated for CHANGELOG for 1.0.1 --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index badd0e6..a84700e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to this project will be documented in this file, in reverse chronological order by release. -## 1.0.1 - TBD +## 1.0.1 - 2018-10-31 ### Added @@ -24,6 +24,8 @@ All notable changes to this project will be documented in this file, in reverse - [#52](https://github.com/zendframework/zend-expressive-authentication-oauth2/issues/52) Wrong factory mapped to AuthorizationHandler +- [#54](https://github.com/zendframework/zend-expressive-authentication-oauth2/pull/54) + Fixed "WWW-Authenticate" header value format ## 1.0.0 - 2018-10-04 From 367be7d19a2c87194f06fa7ac16dd14b68c9755c Mon Sep 17 00:00:00 2001 From: Enrico Zimuel Date: Wed, 31 Oct 2018 12:35:21 +0100 Subject: [PATCH 44/99] Updated CHANGELOG --- CHANGELOG.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a84700e..2c84e74 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,28 @@ All notable changes to this project will be documented in this file, in reverse chronological order by release. +## 1.0.2 - TBD + +### Added + +- Nothing. + +### Changed + +- Nothing. + +### Deprecated + +- Nothing. + +### Removed + +- Nothing. + +### Fixed + +- Nothing. + ## 1.0.1 - 2018-10-31 ### Added From 1739723f5c3480db0f0f0dd0856f48ba901a9fd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frank=20Bru=CC=88ckner?= Date: Mon, 12 Nov 2018 09:16:33 +0100 Subject: [PATCH 45/99] Fixes site name in MkDocs configuration --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index bc2d4e0..f3696c0 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -21,7 +21,7 @@ pages: - "_grant_authcode": grant/auth_code.md - "_grant_implicit": grant/implicit.md - "_grant_refreshtoken": grant/refresh_token.md -site_name: OAuth2 middleware +site_name: zend-expressive-authentication-oauth2 site_description: 'OAuth2 (server) for Expressive and PSR-7 applications.' repo_url: 'https://github.com/zendframework/zend-expressive-authentication-oauth2' copyright: 'Copyright (c) 2015-2018 Zend Technologies USA Inc.' From e4487546715f9f86237d71142bf1bfac267b087d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frank=20Bru=CC=88ckner?= Date: Mon, 12 Nov 2018 09:45:25 +0100 Subject: [PATCH 46/99] Adds page name for home in MkDocs configuration (prevents duplicate entries in breadcrumbs and sub-navigation) --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index f3696c0..adb0c9c 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,7 +1,7 @@ docs_dir: docs/book site_dir: docs/html pages: - - index.md + - Home: index.md - Introduction: v1/intro.md - Usage: v1/usage.md - "Authorization server": v1/authorization-server.md From 400953b2572ef0ff600cd1c63040ff638c41cf43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frank=20Bru=CC=88ckner?= Date: Mon, 12 Nov 2018 09:58:02 +0100 Subject: [PATCH 47/99] Updates documentation section in readme file --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index e793ffd..4fd5d06 100644 --- a/README.md +++ b/README.md @@ -28,10 +28,10 @@ $ composer require zendframework/zend-expressive-authentication-oauth2 ## Documentation -Documentation is [in the doc tree](doc/book/), and can be compiled using [mkdocs](http://www.mkdocs.org): +Browse the documentation online at https://docs.zendframework.com/zend-expressive-authentication-oauth2/ -```bash -$ mkdocs build -``` +## Support -You may also [browse the documentation online](https://docs.zendframework.com/zend-expressive-authentication-oauth2/). +* [Issues](https://github.com/zendframework/zend-expressive-authentication-oauth2/issues/) +* [Chat](https://zendframework-slack.herokuapp.com/) +* [Forum](https://discourse.zendframework.com/) From c3444f1d23797f28c53d72e86fdf0bdf87e53e36 Mon Sep 17 00:00:00 2001 From: Krishnaprasad MG Date: Mon, 19 Nov 2018 14:10:24 +0100 Subject: [PATCH 48/99] Upgrade league/oauth2-server to 7.x --- composer.json | 2 +- composer.lock | 178 +++++++++++++----------- src/Repository/Pdo/ClientRepository.php | 10 +- 3 files changed, 102 insertions(+), 88 deletions(-) diff --git a/composer.json b/composer.json index acbaac4..7ce67f0 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ }, "require": { "php": "^7.1", - "league/oauth2-server": "^6.0.2", + "league/oauth2-server": "^7.0", "psr/container": "^1.0", "psr/http-message": "^1.0.1", "psr/http-server-middleware": "^1.0", diff --git a/composer.lock b/composer.lock index ca715de..4153990 100644 --- a/composer.lock +++ b/composer.lock @@ -1,10 +1,10 @@ { "_readme": [ "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "8a696ccb3ecfce33801c7767868837e6", + "content-hash": "f1eeb97ae0b809d71d12348e65d012c8", "packages": [ { "name": "defuse/php-encryption", @@ -71,16 +71,16 @@ }, { "name": "lcobucci/jwt", - "version": "3.2.4", + "version": "3.2.5", "source": { "type": "git", "url": "https://github.com/lcobucci/jwt.git", - "reference": "c9704b751315d21735dc98d78d4f37bd73596da7" + "reference": "82be04b4753f8b7693b62852b7eab30f97524f9b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/lcobucci/jwt/zipball/c9704b751315d21735dc98d78d4f37bd73596da7", - "reference": "c9704b751315d21735dc98d78d4f37bd73596da7", + "url": "https://api.github.com/repos/lcobucci/jwt/zipball/82be04b4753f8b7693b62852b7eab30f97524f9b", + "reference": "82be04b4753f8b7693b62852b7eab30f97524f9b", "shasum": "" }, "require": { @@ -125,7 +125,7 @@ "JWS", "jwt" ], - "time": "2018-08-03T11:23:50+00:00" + "time": "2018-11-11T12:22:26+00:00" }, { "name": "league/event", @@ -179,34 +179,37 @@ }, { "name": "league/oauth2-server", - "version": "6.1.1", + "version": "7.3.1", "source": { "type": "git", "url": "https://github.com/thephpleague/oauth2-server.git", - "reference": "a0cabb573c7cd5ee01803daec992d6ee3677c4ae" + "reference": "f2cd3646ffe92a5ce83942cb487702e34b0cf504" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/oauth2-server/zipball/a0cabb573c7cd5ee01803daec992d6ee3677c4ae", - "reference": "a0cabb573c7cd5ee01803daec992d6ee3677c4ae", + "url": "https://api.github.com/repos/thephpleague/oauth2-server/zipball/f2cd3646ffe92a5ce83942cb487702e34b0cf504", + "reference": "f2cd3646ffe92a5ce83942cb487702e34b0cf504", "shasum": "" }, "require": { "defuse/php-encryption": "^2.1", "ext-openssl": "*", - "lcobucci/jwt": "^3.1", + "lcobucci/jwt": "^3.2.2", "league/event": "^2.1", - "paragonie/random_compat": "^2.0", - "php": ">=5.6.0", - "psr/http-message": "^1.0" + "php": ">=7.0.0", + "psr/http-message": "^1.0.1" }, "replace": { "league/oauth2server": "*", "lncd/oauth2": "*" }, "require-dev": { - "phpunit/phpunit": "^4.8.38 || ^5.7.21", - "zendframework/zend-diactoros": "^1.0" + "phpstan/phpstan": "^0.9.2", + "phpstan/phpstan-phpunit": "^0.9.4", + "phpstan/phpstan-strict-rules": "^0.9.0", + "phpunit/phpunit": "^6.3 || ^7.0", + "roave/security-advisories": "dev-master", + "zendframework/zend-diactoros": "^1.3.2" }, "type": "library", "autoload": { @@ -224,6 +227,12 @@ "email": "hello@alexbilbie.com", "homepage": "http://www.alexbilbie.com", "role": "Developer" + }, + { + "name": "Andy Millington", + "email": "andrew@noexceptions.io", + "homepage": "https://www.noexceptions.io", + "role": "Developer" } ], "description": "A lightweight and powerful OAuth 2.0 authorization and resource server library with support for all the core specification grants. This library will allow you to secure your API with OAuth and allow your applications users to approve apps that want to access their data from your API.", @@ -243,37 +252,33 @@ "secure", "server" ], - "time": "2017-12-23T23:33:42+00:00" + "time": "2018-11-15T22:37:18+00:00" }, { "name": "paragonie/random_compat", - "version": "v2.0.17", + "version": "v9.99.99", "source": { "type": "git", "url": "https://github.com/paragonie/random_compat.git", - "reference": "29af24f25bab834fcbb38ad2a69fa93b867e070d" + "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paragonie/random_compat/zipball/29af24f25bab834fcbb38ad2a69fa93b867e070d", - "reference": "29af24f25bab834fcbb38ad2a69fa93b867e070d", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95", + "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95", "shasum": "" }, "require": { - "php": ">=5.2.0" + "php": "^7" }, "require-dev": { - "phpunit/phpunit": "4.*|5.*" + "phpunit/phpunit": "4.*|5.*", + "vimeo/psalm": "^1" }, "suggest": { "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." }, "type": "library", - "autoload": { - "files": [ - "lib/random.php" - ] - }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" @@ -292,7 +297,7 @@ "pseudorandom", "random" ], - "time": "2018-07-04T16:31:37+00:00" + "time": "2018-07-02T15:55:56+00:00" }, { "name": "psr/container", @@ -395,16 +400,16 @@ }, { "name": "psr/http-server-handler", - "version": "1.0.0", + "version": "1.0.1", "source": { "type": "git", "url": "https://github.com/php-fig/http-server-handler.git", - "reference": "439d92054dc06097f2406ec074a2627839955a02" + "reference": "aff2f80e33b7f026ec96bb42f63242dc50ffcae7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-server-handler/zipball/439d92054dc06097f2406ec074a2627839955a02", - "reference": "439d92054dc06097f2406ec074a2627839955a02", + "url": "https://api.github.com/repos/php-fig/http-server-handler/zipball/aff2f80e33b7f026ec96bb42f63242dc50ffcae7", + "reference": "aff2f80e33b7f026ec96bb42f63242dc50ffcae7", "shasum": "" }, "require": { @@ -444,7 +449,7 @@ "response", "server" ], - "time": "2018-01-22T17:04:15+00:00" + "time": "2018-10-30T16:46:14+00:00" }, { "name": "psr/http-server-middleware", @@ -501,16 +506,16 @@ }, { "name": "zendframework/zend-expressive-authentication", - "version": "1.0.0", + "version": "1.0.1", "source": { "type": "git", "url": "https://github.com/zendframework/zend-expressive-authentication.git", - "reference": "52594067ffc149cd7defb87388e2c33707b5203f" + "reference": "c85f7602dc607dbcb1950dd8809c0defc92040e6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-expressive-authentication/zipball/52594067ffc149cd7defb87388e2c33707b5203f", - "reference": "52594067ffc149cd7defb87388e2c33707b5203f", + "url": "https://api.github.com/repos/zendframework/zend-expressive-authentication/zipball/c85f7602dc607dbcb1950dd8809c0defc92040e6", + "reference": "c85f7602dc607dbcb1950dd8809c0defc92040e6", "shasum": "" }, "require": { @@ -562,7 +567,7 @@ "zend-expressive", "zf" ], - "time": "2018-08-27T15:09:06+00:00" + "time": "2018-09-28T08:25:39+00:00" } ], "packages-dev": [ @@ -1018,16 +1023,16 @@ }, { "name": "phpunit/php-code-coverage", - "version": "6.0.7", + "version": "6.1.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "865662550c384bc1db7e51d29aeda1c2c161d69a" + "reference": "807e6013b00af69b6c5d9ceb4282d0393dbb9d8d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/865662550c384bc1db7e51d29aeda1c2c161d69a", - "reference": "865662550c384bc1db7e51d29aeda1c2c161d69a", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/807e6013b00af69b6c5d9ceb4282d0393dbb9d8d", + "reference": "807e6013b00af69b6c5d9ceb4282d0393dbb9d8d", "shasum": "" }, "require": { @@ -1038,7 +1043,7 @@ "phpunit/php-text-template": "^1.2.1", "phpunit/php-token-stream": "^3.0", "sebastian/code-unit-reverse-lookup": "^1.0.1", - "sebastian/environment": "^3.1", + "sebastian/environment": "^3.1 || ^4.0", "sebastian/version": "^2.0.1", "theseer/tokenizer": "^1.1" }, @@ -1051,7 +1056,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "6.0-dev" + "dev-master": "6.1-dev" } }, "autoload": { @@ -1077,7 +1082,7 @@ "testing", "xunit" ], - "time": "2018-06-01T07:51:50+00:00" + "time": "2018-10-31T16:06:48+00:00" }, { "name": "phpunit/php-file-iterator", @@ -1221,16 +1226,16 @@ }, { "name": "phpunit/php-token-stream", - "version": "3.0.0", + "version": "3.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "21ad88bbba7c3d93530d93994e0a33cd45f02ace" + "reference": "c99e3be9d3e85f60646f152f9002d46ed7770d18" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/21ad88bbba7c3d93530d93994e0a33cd45f02ace", - "reference": "21ad88bbba7c3d93530d93994e0a33cd45f02ace", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/c99e3be9d3e85f60646f152f9002d46ed7770d18", + "reference": "c99e3be9d3e85f60646f152f9002d46ed7770d18", "shasum": "" }, "require": { @@ -1266,20 +1271,20 @@ "keywords": [ "tokenizer" ], - "time": "2018-02-01T13:16:43+00:00" + "time": "2018-10-30T05:52:18+00:00" }, { "name": "phpunit/phpunit", - "version": "7.3.5", + "version": "7.4.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "7b331efabbb628c518c408fdfcaf571156775de2" + "reference": "b1be2c8530c4c29c3519a052c9fb6cee55053bbd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/7b331efabbb628c518c408fdfcaf571156775de2", - "reference": "7b331efabbb628c518c408fdfcaf571156775de2", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b1be2c8530c4c29c3519a052c9fb6cee55053bbd", + "reference": "b1be2c8530c4c29c3519a052c9fb6cee55053bbd", "shasum": "" }, "require": { @@ -1300,11 +1305,11 @@ "phpunit/php-timer": "^2.0", "sebastian/comparator": "^3.0", "sebastian/diff": "^3.0", - "sebastian/environment": "^3.1", + "sebastian/environment": "^3.1 || ^4.0", "sebastian/exporter": "^3.1", "sebastian/global-state": "^2.0", "sebastian/object-enumerator": "^3.0.3", - "sebastian/resource-operations": "^1.0", + "sebastian/resource-operations": "^2.0", "sebastian/version": "^2.0.1" }, "conflict": { @@ -1324,7 +1329,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "7.3-dev" + "dev-master": "7.4-dev" } }, "autoload": { @@ -1350,19 +1355,15 @@ "testing", "xunit" ], - "time": "2018-09-08T15:14:29+00:00" + "time": "2018-11-14T16:52:02+00:00" }, { "name": "roave/security-advisories", "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "0d96c6cd7cee8572be836fca71f9f01c8b1c0cb2" - }, "conflict": { "3f/pygmentize": "<1.2", "adodb/adodb-php": "<5.20.12", + "alterphp/easyadmin-extension-bundle": ">=1.2,<1.2.11|>=1.3,<1.3.1", "amphp/artax": "<1.0.6|>=2,<2.0.6", "amphp/http": "<1.0.1", "asymmetricrypt/asymmetricrypt": ">=0,<9.9.99", @@ -1390,12 +1391,14 @@ "doctrine/mongodb-odm-bundle": ">=2,<3.0.1", "doctrine/orm": ">=2,<2.4.8|>=2.5,<2.5.1", "dompdf/dompdf": ">=0.6,<0.6.2", - "drupal/core": ">=7,<7.59|>=8,<8.4.8|>=8.5,<8.5.3", - "drupal/drupal": ">=7,<7.59|>=8,<8.4.8|>=8.5,<8.5.3", + "drupal/core": ">=7,<7.60|>=8,<8.5.8|>=8.6,<8.6.2", + "drupal/drupal": ">=7,<7.60|>=8,<8.5.8|>=8.6,<8.6.2", "erusev/parsedown": "<1.7", - "ezsystems/ezpublish-legacy": ">=5.3,<5.3.12.3|>=5.4,<5.4.11.3|>=2017.8,<2017.8.1.1|>=2017.12,<2017.12.2.1", + "ezsystems/ezpublish-legacy": ">=5.3,<5.3.12.5|>=5.4,<5.4.12.2|>=2017.8,<2017.8.1.1|>=2017.12,<2017.12.4.2|>=2018.6,<2018.6.1.3|>=2018.9,<2018.9.1.2", "ezyang/htmlpurifier": "<4.1.1", "firebase/php-jwt": "<2", + "fooman/tcpdf": "<6.2.22", + "fossar/tcpdf-parser": "<6.2.22", "friendsofsymfony/rest-bundle": ">=1.2,<1.2.2", "friendsofsymfony/user-bundle": ">=1.2,<1.3.5", "fuel/core": "<1.8.1", @@ -1412,11 +1415,12 @@ "jsmitty12/phpwhois": "<5.1", "kazist/phpwhois": "<=4.2.6", "kreait/firebase-php": ">=3.2,<3.8.1", + "la-haute-societe/tcpdf": "<6.2.22", "laravel/framework": ">=4,<4.0.99|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.42|>=5.6,<5.6.30", "laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10", "magento/magento1ce": "<1.9.3.9", "magento/magento1ee": ">=1.9,<1.14.3.2", - "magento/product-community-edition": ">=2,<2.2.5", + "magento/product-community-edition": ">=2,<2.2.6", "monolog/monolog": ">=1.8,<1.12", "namshi/jose": "<2.2", "onelogin/php-saml": "<2.10.4", @@ -1427,13 +1431,14 @@ "pagarme/pagarme-php": ">=0,<3", "paragonie/random_compat": "<2", "paypal/merchant-sdk-php": "<3.12", - "phpmailer/phpmailer": ">=5,<5.2.24", + "phpmailer/phpmailer": ">=5,<5.2.27|>=6,<6.0.6", "phpunit/phpunit": ">=4.8.19,<4.8.28|>=5.0.10,<5.6.3", "phpwhois/phpwhois": "<=4.2.5", "phpxmlrpc/extras": "<0.6.1", "propel/propel": ">=2.0.0-alpha1,<=2.0.0-alpha7", "propel/propel1": ">=1,<=1.7.1", "pusher/pusher-php-server": "<2.2.1", + "robrichards/xmlseclibs": ">=1,<3.0.2", "sabre/dav": ">=1.6,<1.6.99|>=1.7,<1.7.11|>=1.8,<1.8.9", "sensiolabs/connect": "<4.2.3", "serluck/phpwhois": "<=4.2.6", @@ -1449,6 +1454,7 @@ "slim/slim": "<2.6", "smarty/smarty": "<3.1.33", "socalnick/scn-social-auth": "<1.15.2", + "spoonity/tcpdf": "<6.2.22", "squizlabs/php_codesniffer": ">=1,<2.8.1|>=3,<3.0.1", "stormpath/sdk": ">=0,<9.9.99", "swiftmailer/swiftmailer": ">=4,<5.4.5", @@ -1460,6 +1466,8 @@ "symfony/http-foundation": ">=2,<2.7.49|>=2.8,<2.8.44|>=3,<3.3.18|>=3.4,<3.4.14|>=4,<4.0.14|>=4.1,<4.1.3", "symfony/http-kernel": ">=2,<2.3.29|>=2.4,<2.5.12|>=2.6,<2.6.8", "symfony/intl": ">=2.7,<2.7.38|>=2.8,<2.8.31|>=3,<3.2.14|>=3.3,<3.3.13", + "symfony/polyfill": ">=1,<1.10", + "symfony/polyfill-php55": ">=1,<1.10", "symfony/routing": ">=2,<2.0.19", "symfony/security": ">=2,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", "symfony/security-bundle": ">=2,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", @@ -1473,8 +1481,9 @@ "symfony/validator": ">=2,<2.0.24|>=2.1,<2.1.12|>=2.2,<2.2.5|>=2.3,<2.3.3", "symfony/web-profiler-bundle": ">=2,<2.3.19|>=2.4,<2.4.9|>=2.5,<2.5.4", "symfony/yaml": ">=2,<2.0.22|>=2.1,<2.1.7", + "tecnickcom/tcpdf": "<6.2.22", "thelia/backoffice-default-template": ">=2.1,<2.1.2", - "thelia/thelia": ">=2.1.0-beta1,<2.1.3|>=2.1,<2.1.2", + "thelia/thelia": ">=2.1,<2.1.2|>=2.1.0-beta1,<2.1.3", "theonedemon/phpwhois": "<=4.2.5", "titon/framework": ">=0,<9.9.99", "truckersmp/phpwhois": "<=4.3.1", @@ -1483,6 +1492,7 @@ "typo3/cms-core": ">=8,<8.7.17|>=9,<9.3.2", "typo3/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.10|>=3.1,<3.1.7|>=3.2,<3.2.7|>=3.3,<3.3.5", "typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4", + "wallabag/tcpdf": "<6.2.22", "willdurand/js-translation-bundle": "<2.1.1", "yiisoft/yii": ">=1.1.14,<1.1.15", "yiisoft/yii2": "<2.0.15", @@ -1530,7 +1540,7 @@ } ], "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it", - "time": "2018-09-17T20:20:31+00:00" + "time": "2018-11-16T03:31:38+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", @@ -2012,25 +2022,25 @@ }, { "name": "sebastian/resource-operations", - "version": "1.0.0", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" + "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", - "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/4d7a795d35b889bf80a0cc04e08d77cedfa917a9", + "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9", "shasum": "" }, "require": { - "php": ">=5.6.0" + "php": "^7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -2050,7 +2060,7 @@ ], "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "time": "2015-07-28T20:34:47+00:00" + "time": "2018-10-04T04:07:39+00:00" }, { "name": "sebastian/version", @@ -2097,16 +2107,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "2.9.1", + "version": "2.9.2", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "dcbed1074f8244661eecddfc2a675430d8d33f62" + "reference": "2acf168de78487db620ab4bc524135a13cfe6745" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/dcbed1074f8244661eecddfc2a675430d8d33f62", - "reference": "dcbed1074f8244661eecddfc2a675430d8d33f62", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/2acf168de78487db620ab4bc524135a13cfe6745", + "reference": "2acf168de78487db620ab4bc524135a13cfe6745", "shasum": "" }, "require": { @@ -2171,7 +2181,7 @@ "phpcs", "standards" ], - "time": "2017-05-22T02:43:20+00:00" + "time": "2018-11-07T22:31:41+00:00" }, { "name": "theseer/tokenizer", diff --git a/src/Repository/Pdo/ClientRepository.php b/src/Repository/Pdo/ClientRepository.php index f6613af..a2f2107 100644 --- a/src/Repository/Pdo/ClientRepository.php +++ b/src/Repository/Pdo/ClientRepository.php @@ -20,8 +20,12 @@ class ClientRepository extends AbstractRepository implements ClientRepositoryInt /** * {@inheritDoc} */ - public function getClientEntity($clientIdentifier, $grantType, $clientSecret = null, $mustValidateSecret = true) - { + public function getClientEntity( + $clientIdentifier, + $grantType = null, + $clientSecret = null, + $mustValidateSecret = true + ) { $sth = $this->pdo->prepare( 'SELECT * FROM oauth_clients WHERE name = :clientIdentifier' ); @@ -51,7 +55,7 @@ public function getClientEntity($clientIdentifier, $grantType, $clientSecret = n * @param string $grantType * @return bool */ - protected function isGranted(array $row, string $grantType) : bool + protected function isGranted(array $row, string $grantType = null) : bool { switch ($grantType) { case 'authorization_code': From 702545aae17d3ed7394369814ea2e48e1bd759d5 Mon Sep 17 00:00:00 2001 From: Enrico Zimuel Date: Mon, 19 Nov 2018 15:43:19 +0100 Subject: [PATCH 49/99] Changed league/oauth2-server ^ 7.3.0 --- CHANGELOG.md | 27 ++++++++++++++++++++++++++- composer.json | 2 +- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c84e74..fc91169 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to this project will be documented in this file, in reverse chronological order by release. -## 1.0.2 - TBD +## 1.1.1 - TBD ### Added @@ -24,6 +24,31 @@ All notable changes to this project will be documented in this file, in reverse - Nothing. +## 1.1.0 - 2018-11-19 + +### Added + +- Nothing. + +### Changed + +- [#58](https://github.com/zendframework/zend-expressive-authentication-oauth2/pull/58) + Upgrades the `league/oauth2-server` library to 7.3.0 in order to use it with + [Swoole](https://www.swoole.co.uk/). This is provided by `league/oauth2-server` + thanks to [#960 AuthorizationServer stateless](https://github.com/thephpleague/oauth2-server/pull/960) + +### Deprecated + +- Nothing. + +### Removed + +- Nothing. + +### Fixed + +- Nothing. + ## 1.0.1 - 2018-10-31 ### Added diff --git a/composer.json b/composer.json index 7ce67f0..24e888e 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ }, "require": { "php": "^7.1", - "league/oauth2-server": "^7.0", + "league/oauth2-server": "^7.3.0", "psr/container": "^1.0", "psr/http-message": "^1.0.1", "psr/http-server-middleware": "^1.0", From f660fe7b15bf12ca4de83c08338865397382394c Mon Sep 17 00:00:00 2001 From: webimpress Date: Sun, 1 Sep 2019 19:02:55 +0100 Subject: [PATCH 50/99] Hotfix - updated configuration to register ConfigProvider --- composer.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/composer.json b/composer.json index 24e888e..f845825 100644 --- a/composer.json +++ b/composer.json @@ -54,6 +54,9 @@ "extra": { "branch-alias": { "dev-master": "0.4.x-dev" + }, + "zf": { + "config-provider": "Zend\\Expressive\\Authentication\\OAuth2\\ConfigProvider" } }, "bin": [ From b078e413e494d2a7ac2160fdf4826d44cfe48c5a Mon Sep 17 00:00:00 2001 From: webimpress Date: Sun, 1 Sep 2019 19:19:38 +0100 Subject: [PATCH 51/99] Updated composer.lock --- composer.lock | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/composer.lock b/composer.lock index 4153990..39ee4f8 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "f1eeb97ae0b809d71d12348e65d012c8", + "content-hash": "f726e6c4d82d41d3d3c58506afd8fd93", "packages": [ { "name": "defuse/php-encryption", @@ -116,8 +116,8 @@ "authors": [ { "name": "Luís Otávio Cobucci Oblonczyk", - "email": "lcobucci@gmail.com", - "role": "Developer" + "role": "Developer", + "email": "lcobucci@gmail.com" } ], "description": "A simple library to work with JSON Web Token and JSON Web Signature", @@ -742,18 +742,18 @@ "authors": [ { "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" + "role": "Developer", + "email": "arne@blankerts.de" }, { "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" + "role": "Developer", + "email": "sebastian@phpeople.de" }, { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" + "role": "Developer", + "email": "sebastian@phpunit.de" } ], "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", @@ -1122,8 +1122,8 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "role": "lead", + "email": "sebastian@phpunit.de" } ], "description": "FilterIterator implementation that filters files based on a list of suffixes.", @@ -1344,8 +1344,8 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "role": "lead", + "email": "sebastian@phpunit.de" } ], "description": "The PHP Unit Testing framework.", @@ -1540,7 +1540,7 @@ } ], "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it", - "time": "2018-11-16T03:31:38+00:00" + "time": "2018-03-07T15:45:44+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", From ff69fd0058aed62bcb2b0add6437e9f034d5904f Mon Sep 17 00:00:00 2001 From: webimpress Date: Sun, 1 Sep 2019 19:20:46 +0100 Subject: [PATCH 52/99] Adds CHANGELOG for #63 --- CHANGELOG.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fc91169..de1cc15 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,11 +2,13 @@ All notable changes to this project will be documented in this file, in reverse chronological order by release. -## 1.1.1 - TBD +## 1.2.0 - TBD ### Added -- Nothing. +- [#63](https://github.com/zendframework/zend-expressive-authentication-oauth2/issues/63) + registers the `ConfigProvider` with the package. If you are using zend-component-installer + it will be added to your configuration during the installation. ### Changed From ff4d1bd9c2d5dd942c60183ff4dd877717c4b52b Mon Sep 17 00:00:00 2001 From: webimpress Date: Sun, 1 Sep 2019 19:23:29 +0100 Subject: [PATCH 53/99] PHP 7.3 support - updated Travis CI configuration --- .travis.yml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0dee3e5..632cf7a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,3 @@ -sudo: false - language: php cache: @@ -33,7 +31,13 @@ matrix: - php: 7.2 env: - DEPS=latest - - php: nightly + - php: 7.3 + env: + - DEPS=lowest + - php: 7.3 + env: + - DEPS=locked + - php: 7.3 env: - DEPS=latest @@ -56,4 +60,3 @@ after_script: notifications: email: false - From 4253f6f4b5ac2819fe7913269328ccc92cd09038 Mon Sep 17 00:00:00 2001 From: webimpress Date: Sun, 1 Sep 2019 19:25:34 +0100 Subject: [PATCH 54/99] Adds CHANGELOG for #64 --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index de1cc15..b20f246 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,10 +6,13 @@ All notable changes to this project will be documented in this file, in reverse ### Added -- [#63](https://github.com/zendframework/zend-expressive-authentication-oauth2/issues/63) +- [#63](https://github.com/zendframework/zend-expressive-authentication-oauth2/pull/63) registers the `ConfigProvider` with the package. If you are using zend-component-installer it will be added to your configuration during the installation. +- [#64](https://github.com/zendframework/zend-expressive-authentication-oauth2/pull/64) + adds support for PHP 7.3. + ### Changed - Nothing. From e1dc684eed6496c4b8b71816ddcb1836cd7d1a9c Mon Sep 17 00:00:00 2001 From: webimpress Date: Sun, 1 Sep 2019 19:34:21 +0100 Subject: [PATCH 55/99] s/slack/chat --- composer.json | 2 +- docs/CONTRIBUTING.md | 2 +- docs/ISSUE_TEMPLATE.md | 2 +- docs/SUPPORT.md | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/composer.json b/composer.json index f845825..b5de81f 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ "issues": "https://github.com/zendframework/zend-expressive-authentication-oauth2/issues", "source": "https://github.com/zendframework/zend-expressive-authentication-oauth2", "rss": "https://github.com/zendframework/zend-expressive-authentication-oauth2/releases.atom", - "slack": "https://zendframework-slack.herokuapp.com", + "chat": "https://zendframework-slack.herokuapp.com", "forum": "https://discourse.zendframework.com/c/questions/expressive" }, "require": { diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index ec1829f..36c9f2a 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -7,7 +7,7 @@ read/subscribe to the following resources: - [Coding Standards](https://github.com/zendframework/zend-coding-standard) - [Forums](https://discourse.zendframework.com/c/contributors) - - [Slack](https://zendframework-slack.herokuapp.com) + - [Chat](https://zendframework-slack.herokuapp.com) - [Code of Conduct](CODE_OF_CONDUCT.md) If you are working on new features or refactoring diff --git a/docs/ISSUE_TEMPLATE.md b/docs/ISSUE_TEMPLATE.md index eaaad0f..1826652 100644 --- a/docs/ISSUE_TEMPLATE.md +++ b/docs/ISSUE_TEMPLATE.md @@ -1,5 +1,5 @@ - [ ] I was not able to find an [open](https://github.com/zendframework/zend-expressive-authentication-oauth2/issues?q=is%3Aopen) or [closed](https://github.com/zendframework/zend-expressive-authentication-oauth2/issues?q=is%3Aclosed) issue matching what I'm seeing. - - [ ] This is not a question. (Questions should be asked on [slack](https://zendframework.slack.com/) ([Signup for Slack here](https://zendframework-slack.herokuapp.com/)) or our [forums](https://discourse.zendframework.com/).) + - [ ] This is not a question. (Questions should be asked on [chat](https://zendframework.slack.com/) ([Signup here](https://zendframework-slack.herokuapp.com/)) or our [forums](https://discourse.zendframework.com/).) Provide a narrative description of what you are trying to accomplish. diff --git a/docs/SUPPORT.md b/docs/SUPPORT.md index daa20e7..ae71cc0 100644 --- a/docs/SUPPORT.md +++ b/docs/SUPPORT.md @@ -3,13 +3,13 @@ Zend Framework offers three support channels: - For real-time questions, use our - [Slack](https://zendframework-slack.herokuapp.com) + [chat](https://zendframework-slack.herokuapp.com) - For detailed questions (e.g., those requiring examples) use our [forums](https://discourse.zendframework.com/c/questions/expressive) - To report issues, use this repository's [issue tracker](https://github.com/zendframework/zend-expressive-authentication-oauth2/issues/new) -**DO NOT** use the issue tracker to ask questions; use Slack or the forums for +**DO NOT** use the issue tracker to ask questions; use chat or the forums for that. Questions posed to the issue tracker will be closed. When reporting an issue, please include the following details: From 7943dc31c1b4804c889ef5606356af938602e4f1 Mon Sep 17 00:00:00 2001 From: webimpress Date: Sun, 1 Sep 2019 19:34:36 +0100 Subject: [PATCH 56/99] Remove copyright in mkdocs.yml configuration file --- mkdocs.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index adb0c9c..4b5b479 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -24,4 +24,3 @@ pages: site_name: zend-expressive-authentication-oauth2 site_description: 'OAuth2 (server) for Expressive and PSR-7 applications.' repo_url: 'https://github.com/zendframework/zend-expressive-authentication-oauth2' -copyright: 'Copyright (c) 2015-2018 Zend Technologies USA Inc.' From 6e0a49e026f0d582d7245bbeb240241b716fd5ba Mon Sep 17 00:00:00 2001 From: webimpress Date: Sun, 1 Sep 2019 19:34:53 +0100 Subject: [PATCH 57/99] Remove unused docs/book/index.html --- docs/book/index.html | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 docs/book/index.html diff --git a/docs/book/index.html b/docs/book/index.html deleted file mode 100644 index 6ec4e7c..0000000 --- a/docs/book/index.html +++ /dev/null @@ -1,9 +0,0 @@ -
-
-

zendframework/zend-expressive-authentication-oauth2

- -

OAuth2 (server) for Expressive and PSR-7 applications.

- -
$ composer require zendframework/zend-expressive-authentication-oauth2
-
-
From b2b56665177d6551d0c9bdf45f6a55cb919f70fd Mon Sep 17 00:00:00 2001 From: webimpress Date: Sun, 1 Sep 2019 19:35:14 +0100 Subject: [PATCH 58/99] Remove IDE specific directory from .gitignore --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 8d7f3f7..245087a 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,3 @@ /vendor/ /zf-mkdoc-theme.tgz /zf-mkdoc-theme/ -.idea From 763b1039f05b6e44eb871f1022fdf22cb81bd8fe Mon Sep 17 00:00:00 2001 From: webimpress Date: Sun, 1 Sep 2019 19:35:24 +0100 Subject: [PATCH 59/99] Update copyright year in LICENSE.md --- LICENSE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE.md b/LICENSE.md index 4d6af70..ed2bafe 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,4 +1,4 @@ -Copyright (c) 2017-2018, Zend Technologies USA, Inc. +Copyright (c) 2017-2019, Zend Technologies USA, Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, From 84be89a1e5ae74dfeb79954e75469fd197eb5fdf Mon Sep 17 00:00:00 2001 From: webimpress Date: Sun, 1 Sep 2019 19:35:36 +0100 Subject: [PATCH 60/99] Fix end of line in docs file --- docs/book/v1/authorization-server.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/book/v1/authorization-server.md b/docs/book/v1/authorization-server.md index ab998fc..1981f87 100644 --- a/docs/book/v1/authorization-server.md +++ b/docs/book/v1/authorization-server.md @@ -29,7 +29,7 @@ to obtain an access token or authorization code. This endpoint **MUST** accept `GET` requests and should: - Validate the request (especially for a valid client id and redirect url). - + - Make sure the user is authenticated (for example, by showing a login prompt if needed). From 11340f296ea6431aa8565f3b060533d04417369e Mon Sep 17 00:00:00 2001 From: webimpress Date: Sun, 1 Sep 2019 20:44:03 +0100 Subject: [PATCH 61/99] Update to support PHPUnit 8 - added void RTH to setUp - changed annotation `@expectedException` to function calls - updated Travis CI configuration - updated composer - added .phpunit.result.cache to .gitignore --- .gitignore | 1 + .travis.yml | 6 +- composer.json | 4 +- composer.lock | 543 +++++++++++------- test/AuthorizationHandlerFactoryTest.php | 2 +- test/AuthorizationMiddlewareFactoryTest.php | 2 +- test/AuthorizationMiddlewareTest.php | 2 +- test/ConfigTraitTest.php | 37 +- test/Entity/ClientEntityTest.php | 2 +- test/Entity/RevokableTraitTest.php | 2 +- test/Entity/ScopeEntityTest.php | 2 +- test/Entity/TimestampableTraitTest.php | 2 +- test/Entity/UserEntityTest.php | 10 +- test/OAuth2AdapterFactoryTest.php | 10 +- test/OAuth2AdapterTest.php | 2 +- test/Pdo/OAuth2PdoMiddlewareTest.php | 14 +- .../Repository/Pdo/AbstractRepositoryTest.php | 2 +- .../Pdo/AccessTokenRepositoryFactoryTest.php | 2 +- .../Pdo/AccessTokenRepositoryTest.php | 2 +- .../Pdo/AuthCodeRepositoryFactoryTest.php | 2 +- .../Repository/Pdo/AuthCodeRepositoryTest.php | 2 +- .../Pdo/ClientRepositoryFactoryTest.php | 2 +- test/Repository/Pdo/ClientRepositoryTest.php | 2 +- test/Repository/Pdo/PdoServiceFactoryTest.php | 2 +- .../Pdo/RefreshTokenRepositoryFactoryTest.php | 2 +- .../Pdo/RefreshTokenRepositoryTest.php | 2 +- .../Pdo/ScopeRepositoryFactoryTest.php | 2 +- test/Repository/Pdo/ScopeRepositoryTest.php | 2 +- test/Repository/Pdo/UserRepositoryTest.php | 2 +- test/RepositoryTraitTest.php | 35 +- test/ResourceServerFactoryTest.php | 7 +- test/TokenEndpointHandlerFactoryTest.php | 2 +- 32 files changed, 420 insertions(+), 291 deletions(-) diff --git a/.gitignore b/.gitignore index 245087a..1bcb3fc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +/.phpunit.result.cache /clover.xml /coveralls-upload.json /docs/html/ diff --git a/.travis.yml b/.travis.yml index 632cf7a..9eb9fcf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,6 +17,7 @@ matrix: - php: 7.1 env: - DEPS=locked + - LEGACY_DEPS="phpunit/phpunit" - CS_CHECK=true - TEST_COVERAGE=true - php: 7.1 @@ -45,9 +46,10 @@ before_install: - if [[ $TEST_COVERAGE != 'true' ]]; then phpenv config-rm xdebug.ini || return 0 ; fi install: - - travis_retry composer install $COMPOSER_ARGS + - travis_retry composer install $COMPOSER_ARGS --ignore-platform-reqs + - if [[ $LEGACY_DEPS != '' ]]; then travis_retry composer update $COMPOSER_ARGS --with-dependencies $LEGACY_DEPS ; fi - if [[ $DEPS == 'latest' ]]; then travis_retry composer update $COMPOSER_ARGS ; fi - - if [[ $DEPS == 'lowest' ]]; then travis_retry composer update --prefer-lowest --prefer-stable $COMPOSER_ARGS ; fi + - if [[ $DEPS == 'lowest' ]]; then travis_retry composer update $COMPOSER_ARGS --prefer-lowest --prefer-stable ; fi - if [[ $TEST_COVERAGE == 'true' ]]; then travis_retry composer require --dev $COMPOSER_ARGS $COVERAGE_DEPS ; fi - stty cols 120 && composer show diff --git a/composer.json b/composer.json index b5de81f..bf3aaa8 100644 --- a/composer.json +++ b/composer.json @@ -29,7 +29,7 @@ "zendframework/zend-expressive-authentication": "^1.0" }, "require-dev": { - "phpunit/phpunit": "^7.0.1", + "phpunit/phpunit": "^7.5.15 || ^8.3.4", "roave/security-advisories": "dev-master", "zendframework/zend-coding-standard": "~1.0.0", "zendframework/zend-diactoros": "^1.4.0", @@ -53,7 +53,7 @@ }, "extra": { "branch-alias": { - "dev-master": "0.4.x-dev" + "dev-master": "1.1.x-dev" }, "zf": { "config-provider": "Zend\\Expressive\\Authentication\\OAuth2\\ConfigProvider" diff --git a/composer.lock b/composer.lock index 39ee4f8..83b3e46 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "f726e6c4d82d41d3d3c58506afd8fd93", + "content-hash": "14f6297d20e21bf6cefd49cddbbf4555", "packages": [ { "name": "defuse/php-encryption", @@ -71,33 +71,30 @@ }, { "name": "lcobucci/jwt", - "version": "3.2.5", + "version": "3.3.1", "source": { "type": "git", "url": "https://github.com/lcobucci/jwt.git", - "reference": "82be04b4753f8b7693b62852b7eab30f97524f9b" + "reference": "a11ec5f4b4d75d1fcd04e133dede4c317aac9e18" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/lcobucci/jwt/zipball/82be04b4753f8b7693b62852b7eab30f97524f9b", - "reference": "82be04b4753f8b7693b62852b7eab30f97524f9b", + "url": "https://api.github.com/repos/lcobucci/jwt/zipball/a11ec5f4b4d75d1fcd04e133dede4c317aac9e18", + "reference": "a11ec5f4b4d75d1fcd04e133dede4c317aac9e18", "shasum": "" }, "require": { + "ext-mbstring": "*", "ext-openssl": "*", - "php": ">=5.5" + "php": "^5.6 || ^7.0" }, "require-dev": { - "mdanter/ecc": "~0.3.1", "mikey179/vfsstream": "~1.5", "phpmd/phpmd": "~2.2", "phpunit/php-invoker": "~1.1", - "phpunit/phpunit": "~4.5", + "phpunit/phpunit": "^5.7 || ^7.3", "squizlabs/php_codesniffer": "~2.3" }, - "suggest": { - "mdanter/ecc": "Required to use Elliptic Curves based algorithms." - }, "type": "library", "extra": { "branch-alias": { @@ -125,20 +122,20 @@ "JWS", "jwt" ], - "time": "2018-11-11T12:22:26+00:00" + "time": "2019-05-24T18:30:49+00:00" }, { "name": "league/event", - "version": "2.1.2", + "version": "2.2.0", "source": { "type": "git", "url": "https://github.com/thephpleague/event.git", - "reference": "e4bfc88dbcb60c8d8a2939a71f9813e141bbe4cd" + "reference": "d2cc124cf9a3fab2bb4ff963307f60361ce4d119" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/event/zipball/e4bfc88dbcb60c8d8a2939a71f9813e141bbe4cd", - "reference": "e4bfc88dbcb60c8d8a2939a71f9813e141bbe4cd", + "url": "https://api.github.com/repos/thephpleague/event/zipball/d2cc124cf9a3fab2bb4ff963307f60361ce4d119", + "reference": "d2cc124cf9a3fab2bb4ff963307f60361ce4d119", "shasum": "" }, "require": { @@ -146,7 +143,7 @@ }, "require-dev": { "henrikbjorn/phpspec-code-coverage": "~1.0.1", - "phpspec/phpspec": "~2.0.0" + "phpspec/phpspec": "^2.2" }, "type": "library", "extra": { @@ -175,20 +172,20 @@ "event", "listener" ], - "time": "2015-05-21T12:24:47+00:00" + "time": "2018-11-26T11:52:41+00:00" }, { "name": "league/oauth2-server", - "version": "7.3.1", + "version": "7.4.0", "source": { "type": "git", "url": "https://github.com/thephpleague/oauth2-server.git", - "reference": "f2cd3646ffe92a5ce83942cb487702e34b0cf504" + "reference": "2eb1cf79e59d807d89c256e7ac5e2bf8bdbd4acf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/oauth2-server/zipball/f2cd3646ffe92a5ce83942cb487702e34b0cf504", - "reference": "f2cd3646ffe92a5ce83942cb487702e34b0cf504", + "url": "https://api.github.com/repos/thephpleague/oauth2-server/zipball/2eb1cf79e59d807d89c256e7ac5e2bf8bdbd4acf", + "reference": "2eb1cf79e59d807d89c256e7ac5e2bf8bdbd4acf", "shasum": "" }, "require": { @@ -252,7 +249,7 @@ "secure", "server" ], - "time": "2018-11-15T22:37:18+00:00" + "time": "2019-05-05T09:22:01+00:00" }, { "name": "paragonie/random_compat", @@ -453,16 +450,16 @@ }, { "name": "psr/http-server-middleware", - "version": "1.0.0", + "version": "1.0.1", "source": { "type": "git", "url": "https://github.com/php-fig/http-server-middleware.git", - "reference": "ea17eb1fb2c8df6db919cc578451a8013c6a0ae5" + "reference": "2296f45510945530b9dceb8bcedb5cb84d40c5f5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-server-middleware/zipball/ea17eb1fb2c8df6db919cc578451a8013c6a0ae5", - "reference": "ea17eb1fb2c8df6db919cc578451a8013c6a0ae5", + "url": "https://api.github.com/repos/php-fig/http-server-middleware/zipball/2296f45510945530b9dceb8bcedb5cb84d40c5f5", + "reference": "2296f45510945530b9dceb8bcedb5cb84d40c5f5", "shasum": "" }, "require": { @@ -502,20 +499,20 @@ "request", "response" ], - "time": "2018-01-22T17:08:31+00:00" + "time": "2018-10-30T17:12:04+00:00" }, { "name": "zendframework/zend-expressive-authentication", - "version": "1.0.1", + "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/zendframework/zend-expressive-authentication.git", - "reference": "c85f7602dc607dbcb1950dd8809c0defc92040e6" + "reference": "d602ab47649cd550ffc9c745cb6de862d6c8a862" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-expressive-authentication/zipball/c85f7602dc607dbcb1950dd8809c0defc92040e6", - "reference": "c85f7602dc607dbcb1950dd8809c0defc92040e6", + "url": "https://api.github.com/repos/zendframework/zend-expressive-authentication/zipball/d602ab47649cd550ffc9c745cb6de862d6c8a862", + "reference": "d602ab47649cd550ffc9c745cb6de862d6c8a862", "shasum": "" }, "require": { @@ -541,7 +538,8 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "0.4.x-dev" + "dev-master": "1.1.x-dev", + "dev-develop": "1.2.x-dev" }, "zf": { "config-provider": "Zend\\Expressive\\Authentication\\ConfigProvider" @@ -567,7 +565,7 @@ "zend-expressive", "zf" ], - "time": "2018-09-28T08:25:39+00:00" + "time": "2019-03-05T17:50:29+00:00" } ], "packages-dev": [ @@ -604,27 +602,29 @@ }, { "name": "doctrine/instantiator", - "version": "1.1.0", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda" + "reference": "a2c590166b2133a4633738648b6b064edae0814a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", - "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/a2c590166b2133a4633738648b6b064edae0814a", + "reference": "a2c590166b2133a4633738648b6b064edae0814a", "shasum": "" }, "require": { "php": "^7.1" }, "require-dev": { - "athletic/athletic": "~0.1.8", + "doctrine/coding-standard": "^6.0", "ext-pdo": "*", "ext-phar": "*", - "phpunit/phpunit": "^6.2.3", - "squizlabs/php_codesniffer": "^3.0.2" + "phpbench/phpbench": "^0.13", + "phpstan/phpstan-phpunit": "^0.11", + "phpstan/phpstan-shim": "^0.11", + "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { @@ -649,25 +649,25 @@ } ], "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://github.com/doctrine/instantiator", + "homepage": "https://www.doctrine-project.org/projects/instantiator.html", "keywords": [ "constructor", "instantiate" ], - "time": "2017-07-22T11:58:36+00:00" + "time": "2019-03-17T17:37:11+00:00" }, { "name": "myclabs/deep-copy", - "version": "1.8.1", + "version": "1.9.3", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8" + "reference": "007c053ae6f31bba39dfa19a7726f56e9763bbea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8", - "reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/007c053ae6f31bba39dfa19a7726f56e9763bbea", + "reference": "007c053ae6f31bba39dfa19a7726f56e9763bbea", "shasum": "" }, "require": { @@ -702,7 +702,7 @@ "object", "object graph" ], - "time": "2018-06-11T23:09:50+00:00" + "time": "2019-08-09T12:45:53+00:00" }, { "name": "phar-io/manifest", @@ -862,16 +862,16 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "4.3.0", + "version": "4.3.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "94fd0001232e47129dd3504189fa1c7225010d08" + "reference": "bdd9f737ebc2a01c06ea7ff4308ec6697db9b53c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94fd0001232e47129dd3504189fa1c7225010d08", - "reference": "94fd0001232e47129dd3504189fa1c7225010d08", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/bdd9f737ebc2a01c06ea7ff4308ec6697db9b53c", + "reference": "bdd9f737ebc2a01c06ea7ff4308ec6697db9b53c", "shasum": "" }, "require": { @@ -909,7 +909,7 @@ } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2017-11-30T07:14:17+00:00" + "time": "2019-04-30T17:48:53+00:00" }, { "name": "phpdocumentor/type-resolver", @@ -960,16 +960,16 @@ }, { "name": "phpspec/prophecy", - "version": "1.8.0", + "version": "1.8.1", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06" + "reference": "1927e75f4ed19131ec9bcc3b002e07fb1173ee76" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/4ba436b55987b4bf311cb7c6ba82aa528aac0a06", - "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/1927e75f4ed19131ec9bcc3b002e07fb1173ee76", + "reference": "1927e75f4ed19131ec9bcc3b002e07fb1173ee76", "shasum": "" }, "require": { @@ -990,8 +990,8 @@ } }, "autoload": { - "psr-0": { - "Prophecy\\": "src/" + "psr-4": { + "Prophecy\\": "src/Prophecy" } }, "notification-url": "https://packagist.org/downloads/", @@ -1019,44 +1019,44 @@ "spy", "stub" ], - "time": "2018-08-05T17:53:17+00:00" + "time": "2019-06-13T12:50:23+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "6.1.4", + "version": "7.0.7", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "807e6013b00af69b6c5d9ceb4282d0393dbb9d8d" + "reference": "7743bbcfff2a907e9ee4a25be13d0f8ec5e73800" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/807e6013b00af69b6c5d9ceb4282d0393dbb9d8d", - "reference": "807e6013b00af69b6c5d9ceb4282d0393dbb9d8d", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/7743bbcfff2a907e9ee4a25be13d0f8ec5e73800", + "reference": "7743bbcfff2a907e9ee4a25be13d0f8ec5e73800", "shasum": "" }, "require": { "ext-dom": "*", "ext-xmlwriter": "*", - "php": "^7.1", - "phpunit/php-file-iterator": "^2.0", + "php": "^7.2", + "phpunit/php-file-iterator": "^2.0.2", "phpunit/php-text-template": "^1.2.1", - "phpunit/php-token-stream": "^3.0", + "phpunit/php-token-stream": "^3.1.0", "sebastian/code-unit-reverse-lookup": "^1.0.1", - "sebastian/environment": "^3.1 || ^4.0", + "sebastian/environment": "^4.2.2", "sebastian/version": "^2.0.1", - "theseer/tokenizer": "^1.1" + "theseer/tokenizer": "^1.1.3" }, "require-dev": { - "phpunit/phpunit": "^7.0" + "phpunit/phpunit": "^8.2.2" }, "suggest": { - "ext-xdebug": "^2.6.0" + "ext-xdebug": "^2.7.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "6.1-dev" + "dev-master": "7.0-dev" } }, "autoload": { @@ -1082,7 +1082,7 @@ "testing", "xunit" ], - "time": "2018-10-31T16:06:48+00:00" + "time": "2019-07-25T05:31:54+00:00" }, { "name": "phpunit/php-file-iterator", @@ -1177,16 +1177,16 @@ }, { "name": "phpunit/php-timer", - "version": "2.0.0", + "version": "2.1.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "8b8454ea6958c3dee38453d3bd571e023108c91f" + "reference": "1038454804406b0b5f5f520358e78c1c2f71501e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/8b8454ea6958c3dee38453d3bd571e023108c91f", - "reference": "8b8454ea6958c3dee38453d3bd571e023108c91f", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/1038454804406b0b5f5f520358e78c1c2f71501e", + "reference": "1038454804406b0b5f5f520358e78c1c2f71501e", "shasum": "" }, "require": { @@ -1198,7 +1198,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "2.1-dev" } }, "autoload": { @@ -1213,8 +1213,8 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "role": "lead", + "email": "sebastian@phpunit.de" } ], "description": "Utility class for timing", @@ -1222,20 +1222,20 @@ "keywords": [ "timer" ], - "time": "2018-02-01T13:07:23+00:00" + "time": "2019-06-07T04:22:29+00:00" }, { "name": "phpunit/php-token-stream", - "version": "3.0.1", + "version": "3.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "c99e3be9d3e85f60646f152f9002d46ed7770d18" + "reference": "e899757bb3df5ff6e95089132f32cd59aac2220a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/c99e3be9d3e85f60646f152f9002d46ed7770d18", - "reference": "c99e3be9d3e85f60646f152f9002d46ed7770d18", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/e899757bb3df5ff6e95089132f32cd59aac2220a", + "reference": "e899757bb3df5ff6e95089132f32cd59aac2220a", "shasum": "" }, "require": { @@ -1248,7 +1248,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "3.1-dev" } }, "autoload": { @@ -1271,57 +1271,56 @@ "keywords": [ "tokenizer" ], - "time": "2018-10-30T05:52:18+00:00" + "time": "2019-07-25T05:29:42+00:00" }, { "name": "phpunit/phpunit", - "version": "7.4.4", + "version": "8.3.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "b1be2c8530c4c29c3519a052c9fb6cee55053bbd" + "reference": "e31cce0cf4499c0ccdbbb211a3280d36ab341e36" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b1be2c8530c4c29c3519a052c9fb6cee55053bbd", - "reference": "b1be2c8530c4c29c3519a052c9fb6cee55053bbd", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/e31cce0cf4499c0ccdbbb211a3280d36ab341e36", + "reference": "e31cce0cf4499c0ccdbbb211a3280d36ab341e36", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.1", + "doctrine/instantiator": "^1.2.0", "ext-dom": "*", "ext-json": "*", "ext-libxml": "*", "ext-mbstring": "*", "ext-xml": "*", - "myclabs/deep-copy": "^1.7", - "phar-io/manifest": "^1.0.2", - "phar-io/version": "^2.0", - "php": "^7.1", - "phpspec/prophecy": "^1.7", - "phpunit/php-code-coverage": "^6.0.7", - "phpunit/php-file-iterator": "^2.0.1", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.9.1", + "phar-io/manifest": "^1.0.3", + "phar-io/version": "^2.0.1", + "php": "^7.2", + "phpspec/prophecy": "^1.8.1", + "phpunit/php-code-coverage": "^7.0.7", + "phpunit/php-file-iterator": "^2.0.2", "phpunit/php-text-template": "^1.2.1", - "phpunit/php-timer": "^2.0", - "sebastian/comparator": "^3.0", - "sebastian/diff": "^3.0", - "sebastian/environment": "^3.1 || ^4.0", - "sebastian/exporter": "^3.1", - "sebastian/global-state": "^2.0", + "phpunit/php-timer": "^2.1.2", + "sebastian/comparator": "^3.0.2", + "sebastian/diff": "^3.0.2", + "sebastian/environment": "^4.2.2", + "sebastian/exporter": "^3.1.0", + "sebastian/global-state": "^3.0.0", "sebastian/object-enumerator": "^3.0.3", - "sebastian/resource-operations": "^2.0", + "sebastian/resource-operations": "^2.0.1", + "sebastian/type": "^1.1.3", "sebastian/version": "^2.0.1" }, - "conflict": { - "phpunit/phpunit-mock-objects": "*" - }, "require-dev": { "ext-pdo": "*" }, "suggest": { "ext-soap": "*", "ext-xdebug": "*", - "phpunit/php-invoker": "^2.0" + "phpunit/php-invoker": "^2.0.0" }, "bin": [ "phpunit" @@ -1329,7 +1328,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "7.4-dev" + "dev-master": "8.3-dev" } }, "autoload": { @@ -1355,29 +1354,41 @@ "testing", "xunit" ], - "time": "2018-11-14T16:52:02+00:00" + "time": "2019-08-11T06:56:55+00:00" }, { "name": "roave/security-advisories", "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/Roave/SecurityAdvisories.git", + "reference": "ea693fa060702164985511acc3ceb5389c9ac761" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/ea693fa060702164985511acc3ceb5389c9ac761", + "reference": "ea693fa060702164985511acc3ceb5389c9ac761", + "shasum": "" + }, "conflict": { "3f/pygmentize": "<1.2", "adodb/adodb-php": "<5.20.12", "alterphp/easyadmin-extension-bundle": ">=1.2,<1.2.11|>=1.3,<1.3.1", "amphp/artax": "<1.0.6|>=2,<2.0.6", "amphp/http": "<1.0.1", + "api-platform/core": ">=2.2,<2.2.10|>=2.3,<2.3.6", "asymmetricrypt/asymmetricrypt": ">=0,<9.9.99", "aws/aws-sdk-php": ">=3,<3.2.1", "brightlocal/phpwhois": "<=4.2.5", "bugsnag/bugsnag-laravel": ">=2,<2.0.2", - "cakephp/cakephp": ">=1.3,<1.3.18|>=2,<2.4.99|>=2.5,<2.5.99|>=2.6,<2.6.12|>=2.7,<2.7.6|>=3,<3.0.15|>=3.1,<3.1.4|>=3.4,<3.4.14|>=3.5,<3.5.17|>=3.6,<3.6.4", + "cakephp/cakephp": ">=1.3,<1.3.18|>=2,<2.4.99|>=2.5,<2.5.99|>=2.6,<2.6.12|>=2.7,<2.7.6|>=3,<3.5.18|>=3.6,<3.6.15|>=3.7,<3.7.7", "cart2quote/module-quotation": ">=4.1.6,<=4.4.5|>=5,<5.4.4", "cartalyst/sentry": "<=2.1.6", "codeigniter/framework": "<=3.0.6", - "composer/composer": "<=1.0.0-alpha11", + "composer/composer": "<=1-alpha.11", "contao-components/mediaelement": ">=2.14.2,<2.21.1", - "contao/core": ">=2,<3.5.35", - "contao/core-bundle": ">=4,<4.4.18|>=4.5,<4.5.8", + "contao/core": ">=2,<3.5.39", + "contao/core-bundle": ">=4,<4.4.39|>=4.5,<4.7.5", "contao/listing-bundle": ">=4,<4.4.8", "contao/newsletter-bundle": ">=4,<4.1", "david-garcia/phpwhois": "<=4.3.1", @@ -1391,10 +1402,13 @@ "doctrine/mongodb-odm-bundle": ">=2,<3.0.1", "doctrine/orm": ">=2,<2.4.8|>=2.5,<2.5.1", "dompdf/dompdf": ">=0.6,<0.6.2", - "drupal/core": ">=7,<7.60|>=8,<8.5.8|>=8.6,<8.6.2", - "drupal/drupal": ">=7,<7.60|>=8,<8.5.8|>=8.6,<8.6.2", - "erusev/parsedown": "<1.7", - "ezsystems/ezpublish-legacy": ">=5.3,<5.3.12.5|>=5.4,<5.4.12.2|>=2017.8,<2017.8.1.1|>=2017.12,<2017.12.4.2|>=2018.6,<2018.6.1.3|>=2018.9,<2018.9.1.2", + "drupal/core": ">=7,<7.67|>=8,<8.6.16|>=8.7,<8.7.1|>8.7.3,<8.7.5", + "drupal/drupal": ">=7,<7.67|>=8,<8.6.16|>=8.7,<8.7.1|>8.7.3,<8.7.5", + "erusev/parsedown": "<1.7.2", + "ezsystems/ezplatform-admin-ui": ">=1.3,<1.3.5|>=1.4,<1.4.4", + "ezsystems/ezpublish-kernel": ">=5.3,<5.3.12.1|>=5.4,<5.4.13.1|>=6,<6.7.9.1|>=6.8,<6.13.5.1|>=7,<7.2.4.1|>=7.3,<7.3.2.1", + "ezsystems/ezpublish-legacy": ">=5.3,<5.3.12.6|>=5.4,<5.4.12.3|>=2011,<2017.12.4.3|>=2018.6,<2018.6.1.4|>=2018.9,<2018.9.1.3", + "ezsystems/repository-forms": ">=2.3,<2.3.2.1", "ezyang/htmlpurifier": "<4.1.1", "firebase/php-jwt": "<2", "fooman/tcpdf": "<6.2.22", @@ -1404,7 +1418,7 @@ "fuel/core": "<1.8.1", "gree/jose": "<=2.2", "gregwar/rst": "<1.0.3", - "guzzlehttp/guzzle": ">=6,<6.2.1|>=4.0.0-rc2,<4.2.4|>=5,<5.3.1", + "guzzlehttp/guzzle": ">=4-rc.2,<4.2.4|>=5,<5.3.1|>=6,<6.2.1", "illuminate/auth": ">=4,<4.0.99|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.10", "illuminate/cookie": ">=4,<=4.0.11|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.42|>=5.6,<5.6.30", "illuminate/database": ">=4,<4.0.99|>=4.1,<4.1.29", @@ -1418,9 +1432,10 @@ "la-haute-societe/tcpdf": "<6.2.22", "laravel/framework": ">=4,<4.0.99|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.42|>=5.6,<5.6.30", "laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10", - "magento/magento1ce": "<1.9.3.9", - "magento/magento1ee": ">=1.9,<1.14.3.2", - "magento/product-community-edition": ">=2,<2.2.6", + "league/commonmark": "<0.18.3", + "magento/magento1ce": "<1.9.4.1", + "magento/magento1ee": ">=1.9,<1.14.4.1", + "magento/product-community-edition": ">=2,<2.2.8|>=2.3,<2.3.1", "monolog/monolog": ">=1.8,<1.12", "namshi/jose": "<2.2", "onelogin/php-saml": "<2.10.4", @@ -1431,11 +1446,14 @@ "pagarme/pagarme-php": ">=0,<3", "paragonie/random_compat": "<2", "paypal/merchant-sdk-php": "<3.12", + "pear/archive_tar": "<1.4.4", "phpmailer/phpmailer": ">=5,<5.2.27|>=6,<6.0.6", + "phpoffice/phpexcel": "<=1.8.1", + "phpoffice/phpspreadsheet": "<=1.5", "phpunit/phpunit": ">=4.8.19,<4.8.28|>=5.0.10,<5.6.3", "phpwhois/phpwhois": "<=4.2.5", "phpxmlrpc/extras": "<0.6.1", - "propel/propel": ">=2.0.0-alpha1,<=2.0.0-alpha7", + "propel/propel": ">=2-alpha.1,<=2-alpha.7", "propel/propel1": ">=1,<=1.7.1", "pusher/pusher-php-server": "<2.2.1", "robrichards/xmlseclibs": ">=1,<3.0.2", @@ -1445,11 +1463,14 @@ "shopware/shopware": "<5.3.7", "silverstripe/cms": ">=3,<=3.0.11|>=3.1,<3.1.11", "silverstripe/forum": "<=0.6.1|>=0.7,<=0.7.3", - "silverstripe/framework": ">=3,<3.3", + "silverstripe/framework": ">=3,<3.6.7|>=3.7,<3.7.3|>=4,<4.4", + "silverstripe/graphql": ">=2,<2.0.5|>=3,<3.1.2", + "silverstripe/registry": ">=2.1,<2.1.2|>=2.2,<2.2.1", + "silverstripe/restfulserver": ">=1,<1.0.9|>=2,<2.0.4", "silverstripe/userforms": "<3", "simple-updates/phpwhois": "<=1", "simplesamlphp/saml2": "<1.10.6|>=2,<2.3.8|>=3,<3.1.4", - "simplesamlphp/simplesamlphp": "<1.15.2", + "simplesamlphp/simplesamlphp": "<1.17.3", "simplesamlphp/simplesamlphp-module-infocard": "<1.0.1", "slim/slim": "<2.6", "smarty/smarty": "<3.1.33", @@ -1459,39 +1480,46 @@ "stormpath/sdk": ">=0,<9.9.99", "swiftmailer/swiftmailer": ">=4,<5.4.5", "sylius/admin-bundle": ">=1,<1.0.17|>=1.1,<1.1.9|>=1.2,<1.2.2", - "sylius/sylius": ">=1,<1.0.17|>=1.1,<1.1.9|>=1.2,<1.2.2", - "symfony/dependency-injection": ">=2,<2.0.17", - "symfony/form": ">=2.3,<2.3.35|>=2.4,<2.6.12|>=2.7,<2.7.38|>=2.8,<2.8.31|>=3,<3.2.14|>=3.3,<3.3.13", - "symfony/framework-bundle": ">=2,<2.3.18|>=2.4,<2.4.8|>=2.5,<2.5.2", - "symfony/http-foundation": ">=2,<2.7.49|>=2.8,<2.8.44|>=3,<3.3.18|>=3.4,<3.4.14|>=4,<4.0.14|>=4.1,<4.1.3", + "sylius/grid": ">=1,<1.1.19|>=1.2,<1.2.18|>=1.3,<1.3.13|>=1.4,<1.4.5|>=1.5,<1.5.1", + "sylius/grid-bundle": ">=1,<1.1.19|>=1.2,<1.2.18|>=1.3,<1.3.13|>=1.4,<1.4.5|>=1.5,<1.5.1", + "sylius/sylius": ">=1,<1.1.18|>=1.2,<1.2.17|>=1.3,<1.3.12|>=1.4,<1.4.4", + "symfony/cache": ">=3.1,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", + "symfony/dependency-injection": ">=2,<2.0.17|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", + "symfony/form": ">=2.3,<2.3.35|>=2.4,<2.6.12|>=2.7,<2.7.50|>=2.8,<2.8.49|>=3,<3.4.20|>=4,<4.0.15|>=4.1,<4.1.9|>=4.2,<4.2.1", + "symfony/framework-bundle": ">=2,<2.3.18|>=2.4,<2.4.8|>=2.5,<2.5.2|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", + "symfony/http-foundation": ">=2,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", "symfony/http-kernel": ">=2,<2.3.29|>=2.4,<2.5.12|>=2.6,<2.6.8", "symfony/intl": ">=2.7,<2.7.38|>=2.8,<2.8.31|>=3,<3.2.14|>=3.3,<3.3.13", + "symfony/phpunit-bridge": ">=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", "symfony/polyfill": ">=1,<1.10", "symfony/polyfill-php55": ">=1,<1.10", + "symfony/proxy-manager-bridge": ">=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", "symfony/routing": ">=2,<2.0.19", - "symfony/security": ">=2,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", + "symfony/security": ">=2,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", "symfony/security-bundle": ">=2,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", "symfony/security-core": ">=2.4,<2.6.13|>=2.7,<2.7.9|>=2.7.30,<2.7.32|>=2.8,<2.8.37|>=3,<3.3.17|>=3.4,<3.4.7|>=4,<4.0.7", "symfony/security-csrf": ">=2.4,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", "symfony/security-guard": ">=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", - "symfony/security-http": ">=2.3,<2.3.41|>=2.4,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", + "symfony/security-http": ">=2.3,<2.3.41|>=2.4,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", "symfony/serializer": ">=2,<2.0.11", - "symfony/symfony": ">=2,<2.7.49|>=2.8,<2.8.44|>=3,<3.3.18|>=3.4,<3.4.14|>=4,<4.0.14|>=4.1,<4.1.3", + "symfony/symfony": ">=2,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", "symfony/translation": ">=2,<2.0.17", "symfony/validator": ">=2,<2.0.24|>=2.1,<2.1.12|>=2.2,<2.2.5|>=2.3,<2.3.3", "symfony/web-profiler-bundle": ">=2,<2.3.19|>=2.4,<2.4.9|>=2.5,<2.5.4", "symfony/yaml": ">=2,<2.0.22|>=2.1,<2.1.7", "tecnickcom/tcpdf": "<6.2.22", "thelia/backoffice-default-template": ">=2.1,<2.1.2", - "thelia/thelia": ">=2.1,<2.1.2|>=2.1.0-beta1,<2.1.3", + "thelia/thelia": ">=2.1-beta.1,<2.1.3", "theonedemon/phpwhois": "<=4.2.5", "titon/framework": ">=0,<9.9.99", "truckersmp/phpwhois": "<=4.3.1", - "twig/twig": "<1.20", - "typo3/cms": ">=6.2,<6.2.30|>=7,<7.6.30|>=8,<8.7.17|>=9,<9.3.2", - "typo3/cms-core": ">=8,<8.7.17|>=9,<9.3.2", + "twig/twig": "<1.38|>=2,<2.7", + "typo3/cms": ">=6.2,<6.2.30|>=7,<7.6.32|>=8,<8.7.27|>=9,<9.5.8", + "typo3/cms-core": ">=8,<8.7.27|>=9,<9.5.8", "typo3/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.10|>=3.1,<3.1.7|>=3.2,<3.2.7|>=3.3,<3.3.5", "typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4", + "typo3/phar-stream-wrapper": ">=1,<2.1.1|>=3,<3.1.1", + "ua-parser/uap-php": "<3.8", "wallabag/tcpdf": "<6.2.22", "willdurand/js-translation-bundle": "<2.1.1", "yiisoft/yii": ">=1.1.14,<1.1.15", @@ -1506,6 +1534,7 @@ "zendframework/zend-captcha": ">=2,<2.4.9|>=2.5,<2.5.2", "zendframework/zend-crypt": ">=2,<2.4.9|>=2.5,<2.5.2", "zendframework/zend-db": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.2,<2.2.10|>=2.3,<2.3.5", + "zendframework/zend-developer-tools": ">=1.2.2,<1.2.3", "zendframework/zend-diactoros": ">=1,<1.8.4", "zendframework/zend-feed": ">=1,<2.10.3", "zendframework/zend-form": ">=2,<2.2.7|>=2.3,<2.3.1", @@ -1653,23 +1682,23 @@ }, { "name": "sebastian/diff", - "version": "3.0.1", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "366541b989927187c4ca70490a35615d3fef2dce" + "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/366541b989927187c4ca70490a35615d3fef2dce", - "reference": "366541b989927187c4ca70490a35615d3fef2dce", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/720fcc7e9b5cf384ea68d9d930d480907a0c1a29", + "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29", "shasum": "" }, "require": { "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^7.0", + "phpunit/phpunit": "^7.5 || ^8.0", "symfony/process": "^2 || ^3.3 || ^4" }, "type": "library", @@ -1705,32 +1734,35 @@ "unidiff", "unified diff" ], - "time": "2018-06-10T07:54:39+00:00" + "time": "2019-02-04T06:01:07+00:00" }, { "name": "sebastian/environment", - "version": "3.1.0", + "version": "4.2.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5" + "reference": "f2a2c8e1c97c11ace607a7a667d73d47c19fe404" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/cd0871b3975fb7fc44d11314fd1ee20925fce4f5", - "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/f2a2c8e1c97c11ace607a7a667d73d47c19fe404", + "reference": "f2a2c8e1c97c11ace607a7a667d73d47c19fe404", "shasum": "" }, "require": { - "php": "^7.0" + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^6.1" + "phpunit/phpunit": "^7.5" + }, + "suggest": { + "ext-posix": "*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1.x-dev" + "dev-master": "4.2-dev" } }, "autoload": { @@ -1755,20 +1787,20 @@ "environment", "hhvm" ], - "time": "2017-07-01T08:51:00+00:00" + "time": "2019-05-05T09:05:15+00:00" }, { "name": "sebastian/exporter", - "version": "3.1.0", + "version": "3.1.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "234199f4528de6d12aaa58b612e98f7d36adb937" + "reference": "06a9a5947f47b3029d76118eb5c22802e5869687" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/234199f4528de6d12aaa58b612e98f7d36adb937", - "reference": "234199f4528de6d12aaa58b612e98f7d36adb937", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/06a9a5947f47b3029d76118eb5c22802e5869687", + "reference": "06a9a5947f47b3029d76118eb5c22802e5869687", "shasum": "" }, "require": { @@ -1795,6 +1827,10 @@ "BSD-3-Clause" ], "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, { "name": "Jeff Welch", "email": "whatthejeff@gmail.com" @@ -1803,17 +1839,13 @@ "name": "Volker Dusch", "email": "github@wallbash.com" }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, { "name": "Adam Harvey", "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" } ], "description": "Provides the functionality to export PHP variables for visualization", @@ -1822,27 +1854,30 @@ "export", "exporter" ], - "time": "2017-04-03T13:19:02+00:00" + "time": "2019-08-11T12:43:14+00:00" }, { "name": "sebastian/global-state", - "version": "2.0.0", + "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4" + "reference": "edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", - "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4", + "reference": "edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4", "shasum": "" }, "require": { - "php": "^7.0" + "php": "^7.2", + "sebastian/object-reflector": "^1.1.1", + "sebastian/recursion-context": "^3.0" }, "require-dev": { - "phpunit/phpunit": "^6.0" + "ext-dom": "*", + "phpunit/phpunit": "^8.0" }, "suggest": { "ext-uopz": "*" @@ -1850,7 +1885,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -1873,7 +1908,7 @@ "keywords": [ "global state" ], - "time": "2017-04-27T15:39:26+00:00" + "time": "2019-02-01T05:30:01+00:00" }, { "name": "sebastian/object-enumerator", @@ -2062,6 +2097,52 @@ "homepage": "https://www.github.com/sebastianbergmann/resource-operations", "time": "2018-10-04T04:07:39+00:00" }, + { + "name": "sebastian/type", + "version": "1.1.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "3aaaa15fa71d27650d62a948be022fe3b48541a3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/3aaaa15fa71d27650d62a948be022fe3b48541a3", + "reference": "3aaaa15fa71d27650d62a948be022fe3b48541a3", + "shasum": "" + }, + "require": { + "php": "^7.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "role": "lead", + "email": "sebastian@phpunit.de" + } + ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "time": "2019-07-02T08:10:15+00:00" + }, { "name": "sebastian/version", "version": "2.0.1", @@ -2183,18 +2264,76 @@ ], "time": "2018-11-07T22:31:41+00:00" }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.12.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "550ebaac289296ce228a706d0867afc34687e3f4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/550ebaac289296ce228a706d0867afc34687e3f4", + "reference": "550ebaac289296ce228a706d0867afc34687e3f4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.12-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "time": "2019-08-06T08:03:45+00:00" + }, { "name": "theseer/tokenizer", - "version": "1.1.0", + "version": "1.1.3", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b" + "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/cb2f008f3f05af2893a87208fe6a6c4985483f8b", - "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/11336f6f84e16a720dae9d8e6ed5019efa85a0f9", + "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9", "shasum": "" }, "require": { @@ -2216,33 +2355,33 @@ "authors": [ { "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" + "role": "Developer", + "email": "arne@blankerts.de" } ], "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", - "time": "2017-04-07T12:08:54+00:00" + "time": "2019-06-13T22:48:21+00:00" }, { "name": "webmozart/assert", - "version": "1.3.0", + "version": "1.5.0", "source": { "type": "git", "url": "https://github.com/webmozart/assert.git", - "reference": "0df1908962e7a3071564e857d86874dad1ef204a" + "reference": "88e6d84706d09a236046d686bbea96f07b3a34f4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/0df1908962e7a3071564e857d86874dad1ef204a", - "reference": "0df1908962e7a3071564e857d86874dad1ef204a", + "url": "https://api.github.com/repos/webmozart/assert/zipball/88e6d84706d09a236046d686bbea96f07b3a34f4", + "reference": "88e6d84706d09a236046d686bbea96f07b3a34f4", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0" + "php": "^5.3.3 || ^7.0", + "symfony/polyfill-ctype": "^1.8" }, "require-dev": { - "phpunit/phpunit": "^4.6", - "sebastian/version": "^1.0.1" + "phpunit/phpunit": "^4.8.36 || ^7.5.13" }, "type": "library", "extra": { @@ -2271,7 +2410,7 @@ "check", "validate" ], - "time": "2018-01-29T19:49:41+00:00" + "time": "2019-08-24T08:43:50+00:00" }, { "name": "zendframework/zend-coding-standard", @@ -2304,16 +2443,16 @@ }, { "name": "zendframework/zend-diactoros", - "version": "1.8.6", + "version": "1.8.7", "source": { "type": "git", "url": "https://github.com/zendframework/zend-diactoros.git", - "reference": "20da13beba0dde8fb648be3cc19765732790f46e" + "reference": "a85e67b86e9b8520d07e6415fcbcb8391b44a75b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-diactoros/zipball/20da13beba0dde8fb648be3cc19765732790f46e", - "reference": "20da13beba0dde8fb648be3cc19765732790f46e", + "url": "https://api.github.com/repos/zendframework/zend-diactoros/zipball/a85e67b86e9b8520d07e6415fcbcb8391b44a75b", + "reference": "a85e67b86e9b8520d07e6415fcbcb8391b44a75b", "shasum": "" }, "require": { @@ -2333,9 +2472,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.8.x-dev", - "dev-develop": "1.9.x-dev", - "dev-release-2.0": "2.0.x-dev" + "dev-release-1.8": "1.8.x-dev" } }, "autoload": { @@ -2364,27 +2501,27 @@ "psr", "psr-7" ], - "time": "2018-09-05T19:29:37+00:00" + "time": "2019-08-06T17:53:53+00:00" }, { "name": "zendframework/zend-servicemanager", - "version": "3.3.2", + "version": "3.4.0", "source": { "type": "git", "url": "https://github.com/zendframework/zend-servicemanager.git", - "reference": "9f35a104b8d4d3b32da5f4a3b6efc0dd62e5af42" + "reference": "a1ed6140d0d3ee803fec96582593ed024950067b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-servicemanager/zipball/9f35a104b8d4d3b32da5f4a3b6efc0dd62e5af42", - "reference": "9f35a104b8d4d3b32da5f4a3b6efc0dd62e5af42", + "url": "https://api.github.com/repos/zendframework/zend-servicemanager/zipball/a1ed6140d0d3ee803fec96582593ed024950067b", + "reference": "a1ed6140d0d3ee803fec96582593ed024950067b", "shasum": "" }, "require": { "container-interop/container-interop": "^1.2", "php": "^5.6 || ^7.0", "psr/container": "^1.0", - "zendframework/zend-stdlib": "^3.1" + "zendframework/zend-stdlib": "^3.2.1" }, "provide": { "container-interop/container-interop-implementation": "^1.2", @@ -2432,7 +2569,7 @@ "servicemanager", "zf" ], - "time": "2018-01-29T16:48:37+00:00" + "time": "2018-12-22T06:05:09+00:00" }, { "name": "zendframework/zend-stdlib", diff --git a/test/AuthorizationHandlerFactoryTest.php b/test/AuthorizationHandlerFactoryTest.php index 1fbec51..50c5581 100644 --- a/test/AuthorizationHandlerFactoryTest.php +++ b/test/AuthorizationHandlerFactoryTest.php @@ -36,7 +36,7 @@ class AuthorizationHandlerFactoryTest extends TestCase /** @var ResponseInterface|ObjectProphecy */ private $response; - public function setUp() + protected function setUp() : void { $this->container = $this->prophesize(ContainerInterface::class); $this->authServer = $this->prophesize(AuthorizationServer::class); diff --git a/test/AuthorizationMiddlewareFactoryTest.php b/test/AuthorizationMiddlewareFactoryTest.php index 32c536e..cc7e92b 100644 --- a/test/AuthorizationMiddlewareFactoryTest.php +++ b/test/AuthorizationMiddlewareFactoryTest.php @@ -34,7 +34,7 @@ class AuthorizationMiddlewareFactoryTest extends TestCase /** @var ResponseInterface|ObjectProphecy */ private $response; - public function setUp() + protected function setUp() : void { $this->container = $this->prophesize(ContainerInterface::class); $this->authServer = $this->prophesize(AuthorizationServer::class); diff --git a/test/AuthorizationMiddlewareTest.php b/test/AuthorizationMiddlewareTest.php index d5d0eb7..4b292a4 100644 --- a/test/AuthorizationMiddlewareTest.php +++ b/test/AuthorizationMiddlewareTest.php @@ -44,7 +44,7 @@ class AuthorizationMiddlewareTest extends TestCase /** @var ServerRequestInterface|ObjectProphecy */ private $serverRequest; - public function setUp() + protected function setUp() : void { $this->authServer = $this->prophesize(AuthorizationServer::class); $this->response = $this->prophesize(ResponseInterface::class); diff --git a/test/ConfigTraitTest.php b/test/ConfigTraitTest.php index f1e9659..52c71aa 100644 --- a/test/ConfigTraitTest.php +++ b/test/ConfigTraitTest.php @@ -13,10 +13,11 @@ use PHPUnit\Framework\TestCase; use Psr\Container\ContainerInterface; use Zend\Expressive\Authentication\OAuth2\ConfigTrait; +use Zend\Expressive\Authentication\OAuth2\Exception; class ConfigTraitTest extends TestCase { - public function setUp() + protected function setUp() : void { $this->trait = $trait = new class { use ConfigTrait; @@ -42,14 +43,13 @@ public function proxy(string $name, ContainerInterface $container) ->willReturn($this->config); } - /** - * @expectedException Zend\Expressive\Authentication\OAuth2\Exception\InvalidConfigException - */ public function testGetPrivateKeyWhenNoConfigPresentWillResultInAnException() { $this->container ->get('config') ->willReturn([]); + + $this->expectException(Exception\InvalidConfigException::class); $this->trait->proxy('getPrivateKey', $this->container->reveal()); } @@ -59,14 +59,13 @@ public function testGetPrivateKey() $this->assertEquals($this->config['authentication']['private_key'], $result); } - /** - * @expectedException Zend\Expressive\Authentication\OAuth2\Exception\InvalidConfigException - */ public function testGetEncryptionKeyNoConfig() { $this->container ->get('config') ->willReturn([]); + + $this->expectException(Exception\InvalidConfigException::class); $this->trait->proxy('getEncryptionKey', $this->container->reveal()); } @@ -76,14 +75,13 @@ public function testGetEncryptionKey() $this->assertEquals($this->config['authentication']['encryption_key'], $result); } - /** - * @expectedException Zend\Expressive\Authentication\OAuth2\Exception\InvalidConfigException - */ public function testGetAccessTokenExpireNoConfig() { $this->container ->get('config') ->willReturn([]); + + $this->expectException(Exception\InvalidConfigException::class); $this->trait->proxy('getAccessTokenExpire', $this->container->reveal()); } @@ -93,14 +91,13 @@ public function testGetAccessTokenExpire() $this->assertEquals($this->config['authentication']['access_token_expire'], $result); } - /** - * @expectedException Zend\Expressive\Authentication\OAuth2\Exception\InvalidConfigException - */ public function testGetRefreshTokenExpireNoConfig() { $this->container ->get('config') ->willReturn([]); + + $this->expectException(Exception\InvalidConfigException::class); $this->trait->proxy('getRefreshTokenExpire', $this->container->reveal()); } @@ -110,14 +107,13 @@ public function testGetRefreshTokenExpire() $this->assertEquals($this->config['authentication']['refresh_token_expire'], $result); } - /** - * @expectedException Zend\Expressive\Authentication\OAuth2\Exception\InvalidConfigException - */ public function testGetAuthCodeExpireNoConfig() { $this->container ->get('config') ->willReturn([]); + + $this->expectException(Exception\InvalidConfigException::class); $this->trait->proxy('getAuthCodeExpire', $this->container->reveal()); } @@ -127,20 +123,16 @@ public function testGetAuthCodeExpire() $this->assertEquals($this->config['authentication']['auth_code_expire'], $result); } - /** - * @expectedException Zend\Expressive\Authentication\OAuth2\Exception\InvalidConfigException - */ public function testGetGrantsConfigNoConfig() { $this->container ->get('config') ->willReturn([]); + + $this->expectException(Exception\InvalidConfigException::class); $this->trait->proxy('getGrantsConfig', $this->container->reveal()); } - /** - * @expectedException Zend\Expressive\Authentication\OAuth2\Exception\InvalidConfigException - */ public function testGetGrantsConfigNoArrayValue() { $this->container @@ -151,6 +143,7 @@ public function testGetGrantsConfigNoArrayValue() ], ]); + $this->expectException(Exception\InvalidConfigException::class); $this->trait->proxy('getGrantsConfig', $this->container->reveal()); } diff --git a/test/Entity/ClientEntityTest.php b/test/Entity/ClientEntityTest.php index 7283c30..210707c 100644 --- a/test/Entity/ClientEntityTest.php +++ b/test/Entity/ClientEntityTest.php @@ -16,7 +16,7 @@ class ClientEntityTest extends TestCase { - public function setUp() + protected function setUp() : void { $this->entity = new ClientEntity('foo', 'bar', 'http://localhost'); } diff --git a/test/Entity/RevokableTraitTest.php b/test/Entity/RevokableTraitTest.php index bc043f2..b2964b1 100644 --- a/test/Entity/RevokableTraitTest.php +++ b/test/Entity/RevokableTraitTest.php @@ -15,7 +15,7 @@ class RevokableTraitTest extends TestCase { - public function setUp() + protected function setUp() : void { $this->trait = $this->getMockForTrait(RevokableTrait::class); } diff --git a/test/Entity/ScopeEntityTest.php b/test/Entity/ScopeEntityTest.php index 6088db8..2a70dfb 100644 --- a/test/Entity/ScopeEntityTest.php +++ b/test/Entity/ScopeEntityTest.php @@ -16,7 +16,7 @@ class ScopeEntityTest extends TestCase { - public function setUp() + protected function setUp() : void { $this->entity = new ScopeEntity(); } diff --git a/test/Entity/TimestampableTraitTest.php b/test/Entity/TimestampableTraitTest.php index 56cd7fe..3c1c9f7 100644 --- a/test/Entity/TimestampableTraitTest.php +++ b/test/Entity/TimestampableTraitTest.php @@ -16,7 +16,7 @@ class TimestampableTraitTest extends TestCase { - public function setUp() + protected function setUp() : void { $this->trait = $this->getMockForTrait(TimestampableTrait::class); } diff --git a/test/Entity/UserEntityTest.php b/test/Entity/UserEntityTest.php index 3420496..c46186a 100644 --- a/test/Entity/UserEntityTest.php +++ b/test/Entity/UserEntityTest.php @@ -10,22 +10,24 @@ namespace ZendTest\Expressive\Authentication\OAuth2\Entity; +use ArgumentCountError; use League\OAuth2\Server\Entities\UserEntityInterface; use PHPUnit\Framework\TestCase; use Zend\Expressive\Authentication\OAuth2\Entity\UserEntity; class UserEntityTest extends TestCase { - public function setUp() + /** @var UserEntity */ + private $entity; + + protected function setUp() : void { $this->entity = new UserEntity('foo'); } - /** - * @expectedException ArgumentCountError - */ public function testConstructorWithoutParamWillResultInAnException() { + $this->expectException(ArgumentCountError::class); $entity = new UserEntity(); } diff --git a/test/OAuth2AdapterFactoryTest.php b/test/OAuth2AdapterFactoryTest.php index c9c6a7e..50acbd9 100644 --- a/test/OAuth2AdapterFactoryTest.php +++ b/test/OAuth2AdapterFactoryTest.php @@ -18,6 +18,7 @@ use stdClass; use TypeError; use Zend\Expressive\Authentication\AuthenticationInterface; +use Zend\Expressive\Authentication\OAuth2\Exception; use Zend\Expressive\Authentication\OAuth2\OAuth2Adapter; use Zend\Expressive\Authentication\OAuth2\OAuth2AdapterFactory; use Zend\Expressive\Authentication\UserInterface; @@ -36,7 +37,7 @@ class OAuth2AdapterFactoryTest extends TestCase /** @var callable */ private $responseFactory; - public function setUp() + protected function setUp() : void { $this->container = $this->prophesize(ContainerInterface::class); $this->resourceServer = $this->prophesize(ResourceServer::class); @@ -60,13 +61,12 @@ public function testConstructor() $this->assertInstanceOf(OAuth2AdapterFactory::class, $factory); } - /** - * @expectedException \Zend\Expressive\Authentication\OAuth2\Exception\InvalidConfigException - */ public function testInvokeWithEmptyContainer() { $factory = new OAuth2AdapterFactory(); - $oauth2Adapter = $factory($this->container->reveal()); + + $this->expectException(Exception\InvalidConfigException::class); + $factory($this->container->reveal()); } public function testFactoryRaisesTypeErrorForNonCallableResponseFactory() diff --git a/test/OAuth2AdapterTest.php b/test/OAuth2AdapterTest.php index e1bdb3a..611e92d 100644 --- a/test/OAuth2AdapterTest.php +++ b/test/OAuth2AdapterTest.php @@ -32,7 +32,7 @@ class OAuth2AdapterTest extends TestCase /** @var callable */ private $responseFactory; - public function setUp() + protected function setUp() : void { $this->resourceServer = $this->prophesize(ResourceServer::class); $this->response = $this->prophesize(ResponseInterface::class); diff --git a/test/Pdo/OAuth2PdoMiddlewareTest.php b/test/Pdo/OAuth2PdoMiddlewareTest.php index e1858f4..5bfed5a 100644 --- a/test/Pdo/OAuth2PdoMiddlewareTest.php +++ b/test/Pdo/OAuth2PdoMiddlewareTest.php @@ -97,7 +97,7 @@ class OAuth2PdoMiddlewareTest extends TestCase /** @var UserRepository */ private $userRepository; - public static function setUpBeforeClass() + public static function setUpBeforeClass() : void { self::tearDownAfterClass(); @@ -118,14 +118,14 @@ public static function setUpBeforeClass() } } - public static function tearDownAfterClass() + public static function tearDownAfterClass() : void { if (file_exists(self::DB_FILE)) { unlink(self::DB_FILE); } } - public function setUp() + protected function setUp() : void { $this->response = new Response(); $this->pdoService = new PdoService('sqlite:' . self::DB_FILE); @@ -188,7 +188,7 @@ public function testProcessClientCredentialGrant() $this->assertEquals(200, $response->getStatusCode()); $content = json_decode((string) $response->getBody()); $this->assertEquals('Bearer', $content->token_type); - $this->assertInternalType("int", $content->expires_in); + $this->assertIsInt($content->expires_in); $this->assertNotEmpty($content->access_token); } @@ -236,7 +236,7 @@ public function testProcessPasswordGrant() $this->assertEquals(200, $response->getStatusCode()); $content = json_decode((string) $response->getBody()); $this->assertEquals('Bearer', $content->token_type); - $this->assertInternalType("int", $content->expires_in); + $this->assertIsInt($content->expires_in); $this->assertNotEmpty($content->access_token); $this->assertNotEmpty($content->refresh_token); } @@ -344,7 +344,7 @@ public function testProcessFromAuthorizationCode(string $code) $this->assertEquals(200, $response->getStatusCode()); $content = json_decode((string) $response->getBody()); $this->assertEquals('Bearer', $content->token_type); - $this->assertInternalType("int", $content->expires_in); + $this->assertIsInt($content->expires_in); $this->assertNotEmpty($content->access_token); $this->assertNotEmpty($content->refresh_token); @@ -443,7 +443,7 @@ public function testProcessRefreshTokenGrant(string $refreshToken) $this->assertEquals(200, $response->getStatusCode()); $content = json_decode((string) $response->getBody()); $this->assertEquals('Bearer', $content->token_type); - $this->assertInternalType("int", $content->expires_in); + $this->assertIsInt($content->expires_in); $this->assertNotEmpty($content->access_token); $this->assertNotEmpty($content->refresh_token); } diff --git a/test/Repository/Pdo/AbstractRepositoryTest.php b/test/Repository/Pdo/AbstractRepositoryTest.php index 455be99..de275d1 100644 --- a/test/Repository/Pdo/AbstractRepositoryTest.php +++ b/test/Repository/Pdo/AbstractRepositoryTest.php @@ -16,7 +16,7 @@ class AbstractRepositoryTest extends TestCase { - public function setUp() + protected function setUp() : void { $this->pdo = $this->prophesize(PdoService::class); } diff --git a/test/Repository/Pdo/AccessTokenRepositoryFactoryTest.php b/test/Repository/Pdo/AccessTokenRepositoryFactoryTest.php index fad93cf..27807b0 100644 --- a/test/Repository/Pdo/AccessTokenRepositoryFactoryTest.php +++ b/test/Repository/Pdo/AccessTokenRepositoryFactoryTest.php @@ -23,7 +23,7 @@ class AccessTokenRepositoryFactoryTest extends TestCase */ private $container; - public function setUp() + protected function setUp() : void { $this->container = $this->prophesize(ContainerInterface::class); $this->pdo = $this->prophesize(PdoService::class); diff --git a/test/Repository/Pdo/AccessTokenRepositoryTest.php b/test/Repository/Pdo/AccessTokenRepositoryTest.php index b4fa4b9..4bb48cc 100644 --- a/test/Repository/Pdo/AccessTokenRepositoryTest.php +++ b/test/Repository/Pdo/AccessTokenRepositoryTest.php @@ -32,7 +32,7 @@ class AccessTokenRepositoryTest extends TestCase */ private $repo; - public function setUp() + protected function setUp() : void { $this->pdo = $this->prophesize(PdoService::class); $this->repo = new AccessTokenRepository($this->pdo->reveal()); diff --git a/test/Repository/Pdo/AuthCodeRepositoryFactoryTest.php b/test/Repository/Pdo/AuthCodeRepositoryFactoryTest.php index 9dd51f9..2897242 100644 --- a/test/Repository/Pdo/AuthCodeRepositoryFactoryTest.php +++ b/test/Repository/Pdo/AuthCodeRepositoryFactoryTest.php @@ -23,7 +23,7 @@ class AuthCodeRepositoryFactoryTest extends TestCase */ private $container; - public function setUp() + protected function setUp() : void { $this->container = $this->prophesize(ContainerInterface::class); $this->pdo = $this->prophesize(PdoService::class); diff --git a/test/Repository/Pdo/AuthCodeRepositoryTest.php b/test/Repository/Pdo/AuthCodeRepositoryTest.php index 6a78144..64e297a 100644 --- a/test/Repository/Pdo/AuthCodeRepositoryTest.php +++ b/test/Repository/Pdo/AuthCodeRepositoryTest.php @@ -25,7 +25,7 @@ class AuthCodeRepositoryTest extends TestCase { - public function setUp() + protected function setUp() : void { $this->pdo = $this->prophesize(PdoService::class); $this->repo = new AuthCodeRepository($this->pdo->reveal()); diff --git a/test/Repository/Pdo/ClientRepositoryFactoryTest.php b/test/Repository/Pdo/ClientRepositoryFactoryTest.php index 60874c4..e1a3072 100644 --- a/test/Repository/Pdo/ClientRepositoryFactoryTest.php +++ b/test/Repository/Pdo/ClientRepositoryFactoryTest.php @@ -23,7 +23,7 @@ class ClientRepositoryFactoryTest extends TestCase */ private $container; - public function setUp() + protected function setUp() : void { $this->container = $this->prophesize(ContainerInterface::class); $this->pdo = $this->prophesize(PdoService::class); diff --git a/test/Repository/Pdo/ClientRepositoryTest.php b/test/Repository/Pdo/ClientRepositoryTest.php index 312601e..df7e137 100644 --- a/test/Repository/Pdo/ClientRepositoryTest.php +++ b/test/Repository/Pdo/ClientRepositoryTest.php @@ -19,7 +19,7 @@ class ClientRepositoryTest extends TestCase { - public function setUp() + protected function setUp() : void { $this->pdo = $this->prophesize(PdoService::class); $this->repo = new ClientRepository($this->pdo->reveal()); diff --git a/test/Repository/Pdo/PdoServiceFactoryTest.php b/test/Repository/Pdo/PdoServiceFactoryTest.php index 5e60c7c..cc7c9fe 100644 --- a/test/Repository/Pdo/PdoServiceFactoryTest.php +++ b/test/Repository/Pdo/PdoServiceFactoryTest.php @@ -18,7 +18,7 @@ class PdoServiceFactoryTest extends TestCase { - public function setUp() + protected function setUp() : void { $this->container = $this->prophesize(ContainerInterface::class); $this->factory = new PdoServiceFactory(); diff --git a/test/Repository/Pdo/RefreshTokenRepositoryFactoryTest.php b/test/Repository/Pdo/RefreshTokenRepositoryFactoryTest.php index 30ab113..7fd6a0b 100644 --- a/test/Repository/Pdo/RefreshTokenRepositoryFactoryTest.php +++ b/test/Repository/Pdo/RefreshTokenRepositoryFactoryTest.php @@ -23,7 +23,7 @@ class RefreshTokenRepositoryFactoryTest extends TestCase */ private $container; - public function setUp() + protected function setUp() : void { $this->container = $this->prophesize(ContainerInterface::class); $this->pdo = $this->prophesize(PdoService::class); diff --git a/test/Repository/Pdo/RefreshTokenRepositoryTest.php b/test/Repository/Pdo/RefreshTokenRepositoryTest.php index a92f179..c726839 100644 --- a/test/Repository/Pdo/RefreshTokenRepositoryTest.php +++ b/test/Repository/Pdo/RefreshTokenRepositoryTest.php @@ -25,7 +25,7 @@ class RefreshTokenRepositoryTest extends TestCase { - public function setUp() + protected function setUp() : void { $this->pdo = $this->prophesize(PdoService::class); $this->repo = new RefreshTokenRepository($this->pdo->reveal()); diff --git a/test/Repository/Pdo/ScopeRepositoryFactoryTest.php b/test/Repository/Pdo/ScopeRepositoryFactoryTest.php index 3fa5c2f..55c0da3 100644 --- a/test/Repository/Pdo/ScopeRepositoryFactoryTest.php +++ b/test/Repository/Pdo/ScopeRepositoryFactoryTest.php @@ -23,7 +23,7 @@ class ScopeRepositoryFactoryTest extends TestCase */ private $container; - public function setUp() + protected function setUp() : void { $this->container = $this->prophesize(ContainerInterface::class); $this->pdo = $this->prophesize(PdoService::class); diff --git a/test/Repository/Pdo/ScopeRepositoryTest.php b/test/Repository/Pdo/ScopeRepositoryTest.php index a218416..e30f88b 100644 --- a/test/Repository/Pdo/ScopeRepositoryTest.php +++ b/test/Repository/Pdo/ScopeRepositoryTest.php @@ -20,7 +20,7 @@ class ScopeRepositoryTest extends TestCase { - public function setUp() + protected function setUp() : void { $this->pdo = $this->prophesize(PdoService::class); $this->repo = new ScopeRepository($this->pdo->reveal()); diff --git a/test/Repository/Pdo/UserRepositoryTest.php b/test/Repository/Pdo/UserRepositoryTest.php index 4c25a47..7eac734 100644 --- a/test/Repository/Pdo/UserRepositoryTest.php +++ b/test/Repository/Pdo/UserRepositoryTest.php @@ -20,7 +20,7 @@ class UserRepositoryTest extends TestCase { - public function setUp() + protected function setUp() : void { $this->pdo = $this->prophesize(PdoService::class); $this->repo = new UserRepository($this->pdo->reveal()); diff --git a/test/RepositoryTraitTest.php b/test/RepositoryTraitTest.php index 5470cb8..5facc85 100644 --- a/test/RepositoryTraitTest.php +++ b/test/RepositoryTraitTest.php @@ -18,13 +18,14 @@ use League\OAuth2\Server\Repositories\UserRepositoryInterface; use PHPUnit\Framework\TestCase; use Psr\Container\ContainerInterface; +use Zend\Expressive\Authentication\OAuth2\Exception; use Zend\Expressive\Authentication\OAuth2\RepositoryTrait; class RepositoryTraitTest extends TestCase { - public function setUp() + protected function setUp() : void { - $this->trait = $trait = new class { + $this->trait = new class { use RepositoryTrait; public function proxy(string $name, ContainerInterface $container) @@ -35,14 +36,13 @@ public function proxy(string $name, ContainerInterface $container) $this->container = $this->prophesize(ContainerInterface::class); } - /** - * @expectedException Zend\Expressive\Authentication\OAuth2\Exception\InvalidConfigException - */ public function testGetUserRepositoryWithoutService() { $this->container ->has(UserRepositoryInterface::class) ->willReturn(false); + + $this->expectException(Exception\InvalidConfigException::class); $this->trait->proxy('getUserRepository', $this->container->reveal()); } @@ -59,14 +59,13 @@ public function testGetUserRepository() $this->assertInstanceOf(UserRepositoryInterface::class, $result); } - /** - * @expectedException Zend\Expressive\Authentication\OAuth2\Exception\InvalidConfigException - */ public function testGetScopeRepositoryWithoutService() { $this->container ->has(ScopeRepositoryInterface::class) ->willReturn(false); + + $this->expectException(Exception\InvalidConfigException::class); $this->trait->proxy('getScopeRepository', $this->container->reveal()); } @@ -83,14 +82,13 @@ public function testGetScopeRepository() $this->assertInstanceOf(ScopeRepositoryInterface::class, $result); } - /** - * @expectedException Zend\Expressive\Authentication\OAuth2\Exception\InvalidConfigException - */ public function testGetAccessTokenRepositoryWithoutService() { $this->container ->has(AccessTokenRepositoryInterface::class) ->willReturn(false); + + $this->expectException(Exception\InvalidConfigException::class); $this->trait->proxy('getAccessTokenRepository', $this->container->reveal()); } @@ -107,14 +105,13 @@ public function testGetAccessTokenRepository() $this->assertInstanceOf(AccessTokenRepositoryInterface::class, $result); } - /** - * @expectedException Zend\Expressive\Authentication\OAuth2\Exception\InvalidConfigException - */ public function testGetClientRepositoryWithoutService() { $this->container ->has(ClientRepositoryInterface::class) ->willReturn(false); + + $this->expectException(Exception\InvalidConfigException::class); $this->trait->proxy('getClientRepository', $this->container->reveal()); } @@ -131,14 +128,13 @@ public function testGetClientRepository() $this->assertInstanceOf(ClientRepositoryInterface::class, $result); } - /** - * @expectedException Zend\Expressive\Authentication\OAuth2\Exception\InvalidConfigException - */ public function testGetRefreshTokenRepositoryWithoutService() { $this->container ->has(RefreshTokenRepositoryInterface::class) ->willReturn(false); + + $this->expectException(Exception\InvalidConfigException::class); $this->trait->proxy('getRefreshTokenRepository', $this->container->reveal()); } @@ -155,14 +151,13 @@ public function testGetRefreshTokenRepository() $this->assertInstanceOf(RefreshTokenRepositoryInterface::class, $result); } - /** - * @expectedException Zend\Expressive\Authentication\OAuth2\Exception\InvalidConfigException - */ public function testGetAuthCodeRepositoryWithoutService() { $this->container ->has(AuthCodeRepositoryInterface::class) ->willReturn(false); + + $this->expectException(Exception\InvalidConfigException::class); $this->trait->proxy('getAuthCodeRepository', $this->container->reveal()); } diff --git a/test/ResourceServerFactoryTest.php b/test/ResourceServerFactoryTest.php index ad3be93..085c4a0 100644 --- a/test/ResourceServerFactoryTest.php +++ b/test/ResourceServerFactoryTest.php @@ -27,7 +27,7 @@ class ResourceServerFactoryTest extends TestCase 'key_permissions_check' => false, ]; - public function setUp() + protected function setUp() : void { $this->container = $this->prophesize(ContainerInterface::class); } @@ -48,9 +48,6 @@ public function testInvokeWithEmptyConfig() $factory($this->container->reveal()); } - /** - * @expectedException Zend\Expressive\Authentication\OAuth2\Exception\InvalidConfigException - */ public function testInvokeWithConfigWithoutRepository() { $this->container->has('config')->willReturn(true); @@ -64,6 +61,8 @@ public function testInvokeWithConfigWithoutRepository() ->willReturn(false); $factory = new ResourceServerFactory(); + + $this->expectException(Exception\InvalidConfigException::class); $factory($this->container->reveal()); } diff --git a/test/TokenEndpointHandlerFactoryTest.php b/test/TokenEndpointHandlerFactoryTest.php index f706b21..3f05a0a 100644 --- a/test/TokenEndpointHandlerFactoryTest.php +++ b/test/TokenEndpointHandlerFactoryTest.php @@ -30,7 +30,7 @@ class TokenEndpointHandlerFactoryTest extends TestCase */ private $subject; - protected function setUp()/* The :void return type declaration that should be here would cause a BC issue */ + protected function setUp() : void { $this->subject = new TokenEndpointHandlerFactory(); parent::setUp(); From 9bc15adce0ede41bf89c1b4fc3e6605f08f39a93 Mon Sep 17 00:00:00 2001 From: webimpress Date: Sun, 1 Sep 2019 20:58:23 +0100 Subject: [PATCH 62/99] Adds support for zend-diactoros v2 Updated composer.json to allow zend-diactoros v2 --- composer.json | 2 +- composer.lock | 78 +++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 68 insertions(+), 12 deletions(-) diff --git a/composer.json b/composer.json index bf3aaa8..63081f7 100644 --- a/composer.json +++ b/composer.json @@ -32,7 +32,7 @@ "phpunit/phpunit": "^7.5.15 || ^8.3.4", "roave/security-advisories": "dev-master", "zendframework/zend-coding-standard": "~1.0.0", - "zendframework/zend-diactoros": "^1.4.0", + "zendframework/zend-diactoros": "^1.4.0 || ^2.0", "zendframework/zend-servicemanager": "^3.0.0" }, "conflict": { diff --git a/composer.lock b/composer.lock index 83b3e46..38cb4b5 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "14f6297d20e21bf6cefd49cddbbf4555", + "content-hash": "adf1f147909e00e29fd3784d926597e7", "packages": [ { "name": "defuse/php-encryption", @@ -1356,6 +1356,58 @@ ], "time": "2019-08-11T06:56:55+00:00" }, + { + "name": "psr/http-factory", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be", + "shasum": "" + }, + "require": { + "php": ">=7.0.0", + "psr/http-message": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "time": "2019-04-30T12:38:16+00:00" + }, { "name": "roave/security-advisories", "version": "dev-master", @@ -2443,35 +2495,40 @@ }, { "name": "zendframework/zend-diactoros", - "version": "1.8.7", + "version": "2.1.3", "source": { "type": "git", "url": "https://github.com/zendframework/zend-diactoros.git", - "reference": "a85e67b86e9b8520d07e6415fcbcb8391b44a75b" + "reference": "279723778c40164bcf984a2df12ff2c6ec5e61c1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-diactoros/zipball/a85e67b86e9b8520d07e6415fcbcb8391b44a75b", - "reference": "a85e67b86e9b8520d07e6415fcbcb8391b44a75b", + "url": "https://api.github.com/repos/zendframework/zend-diactoros/zipball/279723778c40164bcf984a2df12ff2c6ec5e61c1", + "reference": "279723778c40164bcf984a2df12ff2c6ec5e61c1", "shasum": "" }, "require": { - "php": "^5.6 || ^7.0", + "php": "^7.1", + "psr/http-factory": "^1.0", "psr/http-message": "^1.0" }, "provide": { + "psr/http-factory-implementation": "1.0", "psr/http-message-implementation": "1.0" }, "require-dev": { "ext-dom": "*", "ext-libxml": "*", + "http-interop/http-factory-tests": "^0.5.0", "php-http/psr7-integration-tests": "dev-master", - "phpunit/phpunit": "^5.7.16 || ^6.0.8 || ^7.2.7", - "zendframework/zend-coding-standard": "~1.0" + "phpunit/phpunit": "^7.0.2", + "zendframework/zend-coding-standard": "~1.0.0" }, "type": "library", "extra": { "branch-alias": { + "dev-master": "2.1.x-dev", + "dev-develop": "2.2.x-dev", "dev-release-1.8": "1.8.x-dev" } }, @@ -2492,16 +2549,15 @@ }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-2-Clause" + "BSD-3-Clause" ], "description": "PSR HTTP Message implementations", - "homepage": "https://github.com/zendframework/zend-diactoros", "keywords": [ "http", "psr", "psr-7" ], - "time": "2019-08-06T17:53:53+00:00" + "time": "2019-07-10T16:13:25+00:00" }, { "name": "zendframework/zend-servicemanager", From a67145ec2545edf4081d9e76929f068e38c14118 Mon Sep 17 00:00:00 2001 From: webimpress Date: Sun, 1 Sep 2019 21:22:57 +0100 Subject: [PATCH 63/99] Update branch-alias in composer - dev-master - 1.2.x - dev-develop - 1.3.x --- composer.json | 3 ++- composer.lock | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 63081f7..c421e58 100644 --- a/composer.json +++ b/composer.json @@ -53,7 +53,8 @@ }, "extra": { "branch-alias": { - "dev-master": "1.1.x-dev" + "dev-master": "1.2.x-dev", + "dev-develop": "1.3.x-dev" }, "zf": { "config-provider": "Zend\\Expressive\\Authentication\\OAuth2\\ConfigProvider" diff --git a/composer.lock b/composer.lock index 38cb4b5..2de372e 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "adf1f147909e00e29fd3784d926597e7", + "content-hash": "bda1e7feca55a8efac26338aa133c188", "packages": [ { "name": "defuse/php-encryption", From c0d149e9d3a424652d79f9c46894553971e87529 Mon Sep 17 00:00:00 2001 From: webimpress Date: Sun, 1 Sep 2019 21:23:16 +0100 Subject: [PATCH 64/99] release: 1.2.0 readiness --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b20f246..561b775 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to this project will be documented in this file, in reverse chronological order by release. -## 1.2.0 - TBD +## 1.2.0 - 2019-09-01 ### Added From 967e2450fae2d80e4557a8d075f67d3f1086e7e0 Mon Sep 17 00:00:00 2001 From: webimpress Date: Sun, 1 Sep 2019 21:25:23 +0100 Subject: [PATCH 65/99] Bumped to next dev version (1.2.1) --- CHANGELOG.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 561b775..4dfef9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,28 @@ All notable changes to this project will be documented in this file, in reverse chronological order by release. +## 1.2.1 - TBD + +### Added + +- Nothing. + +### Changed + +- Nothing. + +### Deprecated + +- Nothing. + +### Removed + +- Nothing. + +### Fixed + +- Nothing. + ## 1.2.0 - 2019-09-01 ### Added From ff44b98bfa2524f977628812e6b9b97f80a08353 Mon Sep 17 00:00:00 2001 From: webimpress Date: Sun, 1 Sep 2019 21:27:04 +0100 Subject: [PATCH 66/99] Bumped to next dev version (1.3.0) --- CHANGELOG.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4dfef9b..f86d47b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,28 @@ All notable changes to this project will be documented in this file, in reverse chronological order by release. +## 1.3.0 - TBD + +### Added + +- Nothing. + +### Changed + +- Nothing. + +### Deprecated + +- Nothing. + +### Removed + +- Nothing. + +### Fixed + +- Nothing. + ## 1.2.1 - TBD ### Added From b10e7399eff57d8517838a34a1961e07ea4055fe Mon Sep 17 00:00:00 2001 From: Michael Deutscher Date: Sun, 8 Sep 2019 14:07:29 +0200 Subject: [PATCH 67/99] Update docs with option to disable permission check for keys --- docs/book/v1/intro.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/book/v1/intro.md b/docs/book/v1/intro.md index 8df0477..3f544e5 100644 --- a/docs/book/v1/intro.md +++ b/docs/book/v1/intro.md @@ -81,6 +81,19 @@ The `private_key` and `public_key` values contains the paths to the previous generated pair of keys. The `encryption_key` contains the encryption key value as a string, as stored in the `data/oauth/encryption.key` file. +By default both key files are checked for correct permissions (chmod 600 or 660 +is expected). In case the environment/operating system (e.g. Windows) does not +support such a permissions, the check can be disabled: + +```php + // ... + 'private_key' => [ + 'key_or_path' => __DIR__ . '/../data/oauth/private.key', + 'key_permissions_check' => false, + ], + // ... +``` + The `access_token_expire` value is the time-to-live (TTL) value of the access token. The time period is represented using the [DateInterval](http://php.net/manual/en/class.dateinterval.php) format in PHP. The default value is `P1D` (1 day). From 483fb118c5168631c3bc5a589a8a98f783caae1d Mon Sep 17 00:00:00 2001 From: webimpress Date: Sun, 8 Sep 2019 22:01:34 +0200 Subject: [PATCH 68/99] Updated permission check - expected and recommended --- docs/book/v1/intro.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/book/v1/intro.md b/docs/book/v1/intro.md index 3f544e5..9759f54 100644 --- a/docs/book/v1/intro.md +++ b/docs/book/v1/intro.md @@ -81,9 +81,10 @@ The `private_key` and `public_key` values contains the paths to the previous generated pair of keys. The `encryption_key` contains the encryption key value as a string, as stored in the `data/oauth/encryption.key` file. -By default both key files are checked for correct permissions (chmod 600 or 660 -is expected). In case the environment/operating system (e.g. Windows) does not -support such a permissions, the check can be disabled: +By default both key files are checked for correct permissions (chmod 400, 440, +600, 640 or 660 is expected, and 600 or 660 is recommended). In case the +environment/operating system (e.g. Windows) does not support such a permissions, +the check can be disabled: ```php // ... From 64f220c47a3db6fff135f3439b1a1c879037705c Mon Sep 17 00:00:00 2001 From: Anderson Luciano Date: Tue, 26 Nov 2019 11:55:31 -0300 Subject: [PATCH 69/99] Implemented the check of fetched row, if isn't a array, throw exception --- src/Repository/Pdo/AccessTokenRepository.php | 4 ++++ .../Repository/Pdo/AccessTokenRepositoryTest.php | 16 ++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/Repository/Pdo/AccessTokenRepository.php b/src/Repository/Pdo/AccessTokenRepository.php index cac3249..630839e 100644 --- a/src/Repository/Pdo/AccessTokenRepository.php +++ b/src/Repository/Pdo/AccessTokenRepository.php @@ -12,6 +12,7 @@ use League\OAuth2\Server\Entities\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\ClientEntityInterface; +use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use Zend\Expressive\Authentication\OAuth2\Entity\AccessTokenEntity; @@ -114,6 +115,9 @@ public function isAccessTokenRevoked($tokenId) return false; } $row = $sth->fetch(); + if (!is_array($row)) { + throw OAuthServerException::invalidRefreshToken(); + } return array_key_exists('revoked', $row) ? (bool) $row['revoked'] : false; } diff --git a/test/Repository/Pdo/AccessTokenRepositoryTest.php b/test/Repository/Pdo/AccessTokenRepositoryTest.php index 4bb48cc..85b61b9 100644 --- a/test/Repository/Pdo/AccessTokenRepositoryTest.php +++ b/test/Repository/Pdo/AccessTokenRepositoryTest.php @@ -15,6 +15,7 @@ use League\OAuth2\Server\Entities\ClientEntityInterface; use League\OAuth2\Server\Entities\ScopeEntityInterface; use League\OAuth2\Server\Entities\Traits\AccessTokenTrait; +use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException; use PDOStatement; use PHPUnit\Framework\TestCase; @@ -133,6 +134,21 @@ public function testIsAccessTokenRevokedReturnsTrueWhenRowRevokedFlagIsTrue() $this->assertTrue($this->repo->isAccessTokenRevoked('token_id')); } + public function testIsAcessTokenRevokedRaisesExceptionWhenTokenIdDontExists() + { + $statement = $this->prophesize(PDOStatement::class); + $statement->bindParam(':tokenId', 'token_id')->shouldBeCalled(); + $statement->execute()->willReturn(true)->shouldBeCalled(); + $statement->fetch()->willReturn(false)->shouldBeCalled(); + + $this->pdo + ->prepare(Argument::containingString('SELECT revoked FROM oauth_access_tokens')) + ->will([$statement, 'reveal']); + + $this->expectException(OAuthServerException::class); + $this->repo->isAccessTokenRevoked('token_id'); + } + public function testRevokeAccessToken() { $statement = $this->prophesize(PDOStatement::class); From 9af0b0063f887f896bd61d2adc84ae649ee7a03a Mon Sep 17 00:00:00 2001 From: Anderson Luciano Date: Tue, 26 Nov 2019 12:17:01 -0300 Subject: [PATCH 70/99] Fix cs-check issue --- src/Repository/Pdo/AccessTokenRepository.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Repository/Pdo/AccessTokenRepository.php b/src/Repository/Pdo/AccessTokenRepository.php index 630839e..03aa739 100644 --- a/src/Repository/Pdo/AccessTokenRepository.php +++ b/src/Repository/Pdo/AccessTokenRepository.php @@ -115,7 +115,7 @@ public function isAccessTokenRevoked($tokenId) return false; } $row = $sth->fetch(); - if (!is_array($row)) { + if (! is_array($row)) { throw OAuthServerException::invalidRefreshToken(); } From 425e5e80d30f25a8e46ebc7da68d61d907ca1e68 Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Sat, 28 Dec 2019 13:28:24 -0600 Subject: [PATCH 71/99] docs: adds CHANGELOG entry for #71 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4dfef9b..30c4a31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,7 +22,7 @@ All notable changes to this project will be documented in this file, in reverse ### Fixed -- Nothing. +- [#71](https://github.com/zendframework/zend-expressive-authentication-oauth2/pull/71) adds a check to `AccessTokenRepository` to verify that a row was returned before checking if a token was revoked, raising an exception if not. ## 1.2.0 - 2019-09-01 From 73da89822c082409d1c761798ff4465172a7eeb8 Mon Sep 17 00:00:00 2001 From: Marc Bennewitz Date: Fri, 2 Nov 2018 10:04:17 +0100 Subject: [PATCH 72/99] An OAuth2 client is not a user --- src/OAuth2Adapter.php | 9 +++++++-- test/OAuth2AdapterTest.php | 11 ++++++----- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/OAuth2Adapter.php b/src/OAuth2Adapter.php index 999bcd6..c24659c 100644 --- a/src/OAuth2Adapter.php +++ b/src/OAuth2Adapter.php @@ -29,6 +29,11 @@ class OAuth2Adapter implements AuthenticationInterface */ protected $responseFactory; + /** + * @var callable + */ + protected $userFactory; + public function __construct( ResourceServer $resourceServer, callable $responseFactory, @@ -56,9 +61,9 @@ public function authenticate(ServerRequestInterface $request) : ?UserInterface $result = $this->resourceServer->validateAuthenticatedRequest($request); $userId = $result->getAttribute('oauth_user_id', null); $clientId = $result->getAttribute('oauth_client_id', null); - if (isset($userId) || isset($clientId)) { + if (isset($userId)) { return ($this->userFactory)( - $userId ?? $clientId, + $userId, [], [ 'oauth_user_id' => $userId, diff --git a/test/OAuth2AdapterTest.php b/test/OAuth2AdapterTest.php index 611e92d..5bced61 100644 --- a/test/OAuth2AdapterTest.php +++ b/test/OAuth2AdapterTest.php @@ -14,6 +14,7 @@ use League\OAuth2\Server\ResourceServer; use PHPUnit\Framework\TestCase; use Prophecy\Argument; +use Prophecy\Prophecy\ObjectProphecy; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Zend\Expressive\Authentication\AuthenticationInterface; @@ -32,6 +33,9 @@ class OAuth2AdapterTest extends TestCase /** @var callable */ private $responseFactory; + /** @var callable */ + private $userFactory; + protected function setUp() : void { $this->resourceServer = $this->prophesize(ResourceServer::class); @@ -122,7 +126,7 @@ public function testAuthenticateReturnsAUserIfTheResourceServerProducesAUserId() $this->assertSame([], $user->getRoles()); } - public function testAuthenticateReturnsAClientIfTheResourceServerProducesAClientId() + public function testAuthenticateReturnsNullIfTheResourceServerProducesAClientIdOnly() { $request = $this->prophesize(ServerRequestInterface::class); $request->getAttribute('oauth_user_id', null)->willReturn(null); @@ -141,10 +145,7 @@ public function testAuthenticateReturnsAClientIfTheResourceServerProducesAClient ); $user = $adapter->authenticate($request->reveal()); - - $this->assertInstanceOf(UserInterface::class, $user); - $this->assertSame('some-identifier', $user->getIdentity()); - $this->assertSame([], $user->getRoles()); + $this->assertNull($user); } public function testUnauthorizedResponseProducesAResponseWithAWwwAuthenticateHeader() From d6806e33dbc328fefdfd057487839b93a4e60a65 Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Sat, 28 Dec 2019 13:45:06 -0600 Subject: [PATCH 73/99] docs: adds CHANGELOG for #55 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 30c4a31..60c6c81 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ All notable changes to this project will be documented in this file, in reverse ### Changed -- Nothing. +- [#55](https://github.com/zendframework/zend-expressive-authentication-oauth2/pull/55) changes how the `OAuth2Adapter` validates when a client ID is present. Previously, if a client ID was present, but not a user ID, it would attempt to pull a user from the user factory using the client ID, which was incorrect. With this release, it no longer does that. ### Deprecated From f18115596239514d9fa04c1da1dfb9b4d39539ac Mon Sep 17 00:00:00 2001 From: Sam Sheridan Date: Tue, 10 Dec 2019 10:39:23 +0000 Subject: [PATCH 74/99] Fixed issues with incorrect mysql schema in provided example The example mysql example has missing columns and incorrect column types. --- data/oauth2.sql | 145 ++++++++++++++++++++++++++++-------------------- 1 file changed, 85 insertions(+), 60 deletions(-) diff --git a/data/oauth2.sql b/data/oauth2.sql index 508e667..984c600 100644 --- a/data/oauth2.sql +++ b/data/oauth2.sql @@ -1,66 +1,91 @@ -CREATE TABLE oauth_auth_codes ( - id VARCHAR(100), - user_id INTEGER, - client_id INTEGER, - scopes TEXT NULL, - revoked BOOLEAN, - expires_at TIMESTAMP NULL, - PRIMARY KEY(id) -); +-- +-- Table structure for table `oauth_access_tokens` +-- -CREATE TABLE oauth_access_tokens ( - id VARCHAR(100), - user_id VARCHAR(40) NULL, - client_id VARCHAR(40), - name VARCHAR(255) NULL, - scopes TEXT NULL, - revoked BOOLEAN, - created_at TIMESTAMP NULL, - updated_at TIMESTAMP NULL, - expires_at TIMESTAMP NULL, - PRIMARY KEY(id) -); -CREATE INDEX idx1_oauth_access_tokens ON oauth_access_tokens(user_id); +CREATE TABLE `oauth_access_tokens` ( + `id` varchar(100) NOT NULL, + `user_id` int(10) unsigned DEFAULT NULL, + `client_id` int(10) unsigned NOT NULL, + `name` varchar(255) DEFAULT NULL, + `scopes` text, + `revoked` tinyint(1) NOT NULL DEFAULT '0', + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` datetime DEFAULT NULL, + `expires_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `IDX_CA42527CA76ED39519EB6921BDA26CCD` (`user_id`,`client_id`), + KEY `IDX_CA42527CA76ED395` (`user_id`), + KEY `IDX_CA42527C19EB6921` (`client_id`) +) ENGINE=InnoDB; -CREATE TABLE oauth_refresh_tokens ( - id VARCHAR(100), - access_token_id VARCHAR(100), - revoked BOOLEAN, - expires_at TIMESTAMP NULL, - PRIMARY KEY(id) -); -CREATE INDEX idx1_oauth_refresh_tokens ON oauth_refresh_tokens(access_token_id); +-- +-- Table structure for table `oauth_auth_codes` +-- -CREATE TABLE oauth_clients ( - name VARCHAR(40) NOT NULL, - user_id INTEGER NULL, - secret VARCHAR(100) NULL, - redirect VARCHAR(255), - personal_access_client BOOLEAN, - password_client BOOLEAN, - revoked BOOLEAN, - created_at TIMESTAMP NULL, - updated_at TIMESTAMP NULL, - PRIMARY KEY (name) -); -CREATE INDEX idx1_oauth_clients ON oauth_clients(user_id); +CREATE TABLE `oauth_auth_codes` ( + `id` varchar(100) NOT NULL, + `user_id` int(10) unsigned DEFAULT NULL, + `client_id` int(10) unsigned NOT NULL, + `scopes` text, + `revoked` tinyint(1) NOT NULL DEFAULT '0', + `expires_at` datetime DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `IDX_BB493F83A76ED395` (`user_id`), + KEY `IDX_BB493F8319EB6921` (`client_id`) +) ENGINE=InnoDB; -CREATE TABLE oauth_personal_access_clients ( - client_id INTEGER, - created_at TIMESTAMP NULL, - updated_at TIMESTAMP NULL -); -CREATE INDEX idx1_oauth_personal_access_clients ON oauth_personal_access_clients(client_id); +-- +-- Table structure for table `oauth_clients` +-- -CREATE TABLE oauth_users ( - username VARCHAR(40) NOT NULL, - password VARCHAR(100) NOT NULL, - first_name VARCHAR(80), - last_name VARCHAR(80), - PRIMARY KEY (username) -); +CREATE TABLE `oauth_clients` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `user_id` int(10) unsigned DEFAULT NULL, + `name` varchar(100) NOT NULL, + `secret` varchar(100) DEFAULT NULL, + `redirect` varchar(255) DEFAULT NULL, + `personal_access_client` tinyint(1) DEFAULT NULL, + `password_client` tinyint(1) DEFAULT NULL, + `revoked` tinyint(1) DEFAULT NULL, + `created_at` datetime DEFAULT CURRENT_TIMESTAMP, + `updated_at` datetime DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `IDX_13CE81015E237E06A76ED395BDA26CCD` (`name`,`user_id`), + KEY `IDX_13CE8101A76ED395` (`user_id`) +) ENGINE=InnoDB; -CREATE TABLE oauth_scopes ( - id VARCHAR(30) NOT NULL, - PRIMARY KEY (id) -); +-- +-- Table structure for table `oauth_refresh_tokens` +-- + +CREATE TABLE `oauth_refresh_tokens` ( + `id` varchar(100) NOT NULL, + `access_token_id` varchar(100) NOT NULL, + `revoked` tinyint(1) NOT NULL DEFAULT '0', + `expires_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `IDX_5AB6872CCB2688BDA26CCD` (`access_token_id`) +) ENGINE=InnoDB; + +-- +-- Table structure for table `oauth_scopes` +-- + +CREATE TABLE `oauth_scopes` ( + `id` varchar(100) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB; + +-- +-- Table structure for table `oauth_users` +-- + +CREATE TABLE `oauth_users` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `username` varchar(320) NOT NULL, + `password` varchar(100) NOT NULL, + `first_name` varchar(80) DEFAULT NULL, + `last_name` varchar(80) DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `UNIQ_93804FF8F85E0677` (`username`) +) ENGINE=InnoDB; From 64f9d4cb903041ed2505829b6d79f9ac52c95c89 Mon Sep 17 00:00:00 2001 From: Sam Sheridan Date: Tue, 10 Dec 2019 10:39:45 +0000 Subject: [PATCH 75/99] docs: adds CHANGELOG entry for #72 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 60c6c81..639cb7b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,8 @@ All notable changes to this project will be documented in this file, in reverse - [#71](https://github.com/zendframework/zend-expressive-authentication-oauth2/pull/71) adds a check to `AccessTokenRepository` to verify that a row was returned before checking if a token was revoked, raising an exception if not. +- [#72](https://github.com/zendframework/zend-expressive-authentication-oauth2/pull/72) updates the database schema in provided examples to reflect actual requirements. + ## 1.2.0 - 2019-09-01 ### Added From e53f2bc38e29cd7c1f5570ecb468c5806cc7dd29 Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Sat, 28 Dec 2019 13:56:45 -0600 Subject: [PATCH 76/99] 1.2.1 readiness --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 639cb7b..8d3f141 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to this project will be documented in this file, in reverse chronological order by release. -## 1.2.1 - TBD +## 1.2.1 - 2019-12-28 ### Added From 242406ed07038222504d54e94842df43921e6c77 Mon Sep 17 00:00:00 2001 From: Marc Guyer Date: Tue, 30 Jul 2019 16:54:57 -0400 Subject: [PATCH 77/99] Enable event listeners via config. Tests. Docs. --- config/oauth2.php | 19 +++++++++ docs/book/v1/intro.md | 16 +++++++ src/AuthorizationServerFactory.php | 49 +++++++++++++++++++--- src/ConfigTrait.php | 21 ++++++++++ test/AuthorizationServerFactoryTest.php | 55 +++++++++++++++++++++++++ test/ConfigTraitTest.php | 39 ++++++++++++++++++ 6 files changed, 193 insertions(+), 6 deletions(-) diff --git a/config/oauth2.php b/config/oauth2.php index 9abb090..70ef994 100644 --- a/config/oauth2.php +++ b/config/oauth2.php @@ -35,6 +35,25 @@ \League\OAuth2\Server\Grant\RefreshTokenGrant::class => \League\OAuth2\Server\Grant\RefreshTokenGrant::class ], + + // optionally add listener config + // 'listeners' => [ + // [ + // // event name + // \League\OAuth2\Server\RequestEvent::CLIENT_AUTHENTICATION_FAILED, + // // listener defined as a service key + // \My\League\Event\Listener\For\Auth\Failure::class, + // ], [ + // \League\OAuth2\Server\RequestEvent::CLIENT_AUTHENTICATION_FAILED, + // // listener defined as an anonymous function + // function (\League\OAuth2\Server\RequestEvent $event) { + // // do something + // }, + // // priority NORMAL (0) is the default but you may set an + // // int val of your choosing + // // League\Event\ListenerAcceptorInterface::P_HIGH, + // ], + // ], ]; // Conditionally include the encryption_key config setting, based on presence of file. diff --git a/docs/book/v1/intro.md b/docs/book/v1/intro.md index 9759f54..27e23d2 100644 --- a/docs/book/v1/intro.md +++ b/docs/book/v1/intro.md @@ -74,6 +74,20 @@ return [ Grant\ImplicitGrant::class => Grant\ImplicitGrant::class, Grant\RefreshTokenGrant::class => Grant\RefreshTokenGrant::class ], + + // optionally configure event listeners + // 'listeners' => [ + // [ + // \League\OAuth2\Server\RequestEvent::CLIENT_AUTHENTICATION_FAILED, + // \My\Event\Listener\Service::class, + // ], + // [ + // \League\OAuth2\Server\RequestEvent::ACCESS_TOKEN_ISSUED, + // function (\League\OAuth2\Server\RequestEvent $event) { + // // do something + // }, + // ], + // ], ]; ``` @@ -126,6 +140,8 @@ grants are configured to be available. If you would like to disable any of the supplied grants, change the value for the grant to `null`. Additionally, you can extend this array to add your own custom grants. +The `listeners` array is for enabling event listeners. Listeners are not required. This is an array of arrays. Each array in the list must contain at least 2 elements. The first element must be a string that corresponds to the name of the event to listen for. The second element must be either a string or an anonymous function. If it's a string it's assumed to be a container service key that points to your listener. There may be a third element of the array -- it must be an integer. The third element is the `$priority` argument when registering the listener. See the [Authorization Server Domain Events documentation](https://oauth2.thephpleague.com/authorization-server/events/). + You need to provide an OAuth2 database yourself, or generate a [SQLite](https://www.sqlite.org) database with the following command (using `sqlite3` for GNU/Linux): diff --git a/src/AuthorizationServerFactory.php b/src/AuthorizationServerFactory.php index 1ecbc76..9d4ded8 100644 --- a/src/AuthorizationServerFactory.php +++ b/src/AuthorizationServerFactory.php @@ -12,19 +12,27 @@ use DateInterval; use League\OAuth2\Server\AuthorizationServer; -use League\OAuth2\Server\Grant; -use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface; -use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface; -use League\OAuth2\Server\Repositories\UserRepositoryInterface; use Psr\Container\ContainerInterface; -use Zend\Expressive\Authentication\OAuth2\Exception\InvalidConfigException; +/** + * Factory for OAuth AuthorizationServer + * + * Initializes a new AuthorizationServer with required params from config. + * Then configured grant types are enabled with configured access token + * expiry. Then any optionally configured event listeners are attached to the + * AuthorizationServer. + */ class AuthorizationServerFactory { use ConfigTrait; use CryptKeyTrait; use RepositoryTrait; + /** + * @param ContainerInterface $container + * + * @return AuthorizationServer + */ public function __invoke(ContainerInterface $container) : AuthorizationServer { $clientRepository = $this->getClientRepository($container); @@ -46,7 +54,7 @@ public function __invoke(ContainerInterface $container) : AuthorizationServer $accessTokenInterval = new DateInterval($this->getAccessTokenExpire($container)); foreach ($grants as $grant) { - // Config may set this grant to null. Continue on if grant has been disabled + // Config may set this grant to null. Continue on if grant has been disabled if (empty($grant)) { continue; } @@ -57,6 +65,35 @@ public function __invoke(ContainerInterface $container) : AuthorizationServer ); } + // add listeners if configured + $this->addListeners($authServer, $container); + return $authServer; } + + /** + * Optionally add event listeners + * + * @param AuthorizationServer $authServer + * @param ContainerInterface $container + */ + private function addListeners( + AuthorizationServer $authServer, + ContainerInterface $container + ): void { + $listeners = $this->getListenersConfig($container); + if (null === $listeners) { + return; + } + foreach ($listeners as $listenerConfig) { + $event = $listenerConfig[0]; + $listener = $listenerConfig[1]; + $priority = $listenerConfig[2] ?? null; + if (is_string($listener)) { + $listener = $container->get($listener); + } + $authServer->getEmitter() + ->addListener($event, $listener, $priority); + } + } } diff --git a/src/ConfigTrait.php b/src/ConfigTrait.php index 163e9bf..7822406 100644 --- a/src/ConfigTrait.php +++ b/src/ConfigTrait.php @@ -103,4 +103,25 @@ protected function getGrantsConfig(ContainerInterface $container) : array return $config['grants']; } + + /** + * @param ContainerInterface $container + * + * @return array|null + */ + protected function getListenersConfig(ContainerInterface $container) : ?array + { + $config = $container->get('config')['authentication'] ?? []; + + if (empty($config['listeners'])) { + return null; + } + if (! is_array($config['listeners'])) { + throw new InvalidConfigException( + 'The listeners must be an array value' + ); + } + + return $config['listeners']; + } } diff --git a/test/AuthorizationServerFactoryTest.php b/test/AuthorizationServerFactoryTest.php index ef1df13..ae3a9bd 100644 --- a/test/AuthorizationServerFactoryTest.php +++ b/test/AuthorizationServerFactoryTest.php @@ -19,6 +19,8 @@ use PHPUnit\Framework\TestCase; use Psr\Container\ContainerInterface; use Zend\Expressive\Authentication\OAuth2\AuthorizationServerFactory; +use League\OAuth2\Server\RequestEvent; +use League\Event\ListenerInterface; use function array_merge; use function array_slice; @@ -66,4 +68,57 @@ public function testInvoke() $this->assertInstanceOf(AuthorizationServer::class, $result); } + + public function testInvokeWithListenerConfig() + { + $mockContainer = $this->prophesize(ContainerInterface::class); + $mockClientRepo = $this->prophesize(ClientRepositoryInterface::class); + $mockAccessTokenRepo = $this->prophesize(AccessTokenRepositoryInterface::class); + $mockScopeRepo = $this->prophesize(ScopeRepositoryInterface::class); + $mockClientGrant = $this->prophesize(GrantTypeInterface::class); + $mockPasswordGrant = $this->prophesize(GrantTypeInterface::class); + + $mockListener = $this->prophesize(ListenerInterface::class); + $mockContainer->get(ListenerInterface::class) + ->will([$mockListener, 'reveal']); + + $config = [ + 'authentication' => [ + 'private_key' => __DIR__ . '/TestAsset/private.key', + 'encryption_key' => 'iALlwJ1sH77dmFCJFo+pMdM6Af4bF/hCca1EDDx7MwE=', + 'access_token_expire' => 'P1D', + 'grants' => [ + ClientCredentialsGrant::class + => ClientCredentialsGrant::class, + ], + 'listeners' => [ + [ + RequestEvent::CLIENT_AUTHENTICATION_FAILED, + function (RequestEvent $event) { + // do something + } + ], [ + RequestEvent::CLIENT_AUTHENTICATION_FAILED, + ListenerInterface::class + ] + ] + ] + ]; + + $mockContainer->has(ClientRepositoryInterface::class)->willReturn(true); + $mockContainer->has(AccessTokenRepositoryInterface::class)->willReturn(true); + $mockContainer->has(ScopeRepositoryInterface::class)->willReturn(true); + + $mockContainer->get(ClientRepositoryInterface::class)->willReturn($mockClientRepo->reveal()); + $mockContainer->get(AccessTokenRepositoryInterface::class)->willReturn($mockAccessTokenRepo->reveal()); + $mockContainer->get(ScopeRepositoryInterface::class)->willReturn($mockScopeRepo->reveal()); + $mockContainer->get(ClientCredentialsGrant::class)->willReturn($mockClientGrant->reveal()); + $mockContainer->get('config')->willReturn($config); + + $factory = new AuthorizationServerFactory(); + + $result = $factory($mockContainer->reveal()); + + $this->assertInstanceOf(AuthorizationServer::class, $result); + } } diff --git a/test/ConfigTraitTest.php b/test/ConfigTraitTest.php index 52c71aa..4460349 100644 --- a/test/ConfigTraitTest.php +++ b/test/ConfigTraitTest.php @@ -152,4 +152,43 @@ public function testGetGrantsConfig() $result = $this->trait->proxy('getGrantsConfig', $this->container->reveal()); $this->assertEquals($this->config['authentication']['grants'], $result); } + + public function testGetListenersConfigNoConfig() + { + $this->container + ->get('config') + ->willReturn([]); + $result = $this->trait + ->proxy('getListenersConfig', $this->container->reveal()); + $this->assertNull($result); + } + + /** + * @expectedException Zend\Expressive\Authentication\OAuth2\Exception\InvalidConfigException + */ + public function testGetListenersConfigNoArrayValue() + { + $this->container + ->get('config') + ->willReturn([ + 'authentication' => [ + 'listeners' => 'xxx', + ], + ]); + + $this->trait->proxy('getListenersConfig', $this->container->reveal()); + } + + public function testGetListenersConfig() + { + $this->container->get('config') + ->willReturn([ + 'authentication' => [ + 'listeners' => $expected = [['xxx']], + ], + ]); + $result = $this->trait + ->proxy('getListenersConfig', $this->container->reveal()); + $this->assertEquals($expected, $result); + } } From 49a0cf739bca89ad355f64cf2a0960b64f1afac6 Mon Sep 17 00:00:00 2001 From: Marc Guyer Date: Sun, 11 Aug 2019 22:09:47 -0400 Subject: [PATCH 78/99] Add support for listener providers config * Remove commented out example listeners config * Rewrite docs with subheadings and better example configs * Empty config returns empty array instead of null * Add some basic error handling for missing container services * Tests --- docs/book/v1/intro.md | 58 ++++++--- src/AuthorizationServerFactory.php | 51 +++++++- src/ConfigTrait.php | 35 ++++- test/AuthorizationServerFactoryTest.php | 164 ++++++++++++++++++++++-- test/ConfigTraitTest.php | 45 ++++++- 5 files changed, 311 insertions(+), 42 deletions(-) diff --git a/docs/book/v1/intro.md b/docs/book/v1/intro.md index 27e23d2..eda3fb1 100644 --- a/docs/book/v1/intro.md +++ b/docs/book/v1/intro.md @@ -74,20 +74,6 @@ return [ Grant\ImplicitGrant::class => Grant\ImplicitGrant::class, Grant\RefreshTokenGrant::class => Grant\RefreshTokenGrant::class ], - - // optionally configure event listeners - // 'listeners' => [ - // [ - // \League\OAuth2\Server\RequestEvent::CLIENT_AUTHENTICATION_FAILED, - // \My\Event\Listener\Service::class, - // ], - // [ - // \League\OAuth2\Server\RequestEvent::ACCESS_TOKEN_ISSUED, - // function (\League\OAuth2\Server\RequestEvent $event) { - // // do something - // }, - // ], - // ], ]; ``` @@ -140,7 +126,47 @@ grants are configured to be available. If you would like to disable any of the supplied grants, change the value for the grant to `null`. Additionally, you can extend this array to add your own custom grants. -The `listeners` array is for enabling event listeners. Listeners are not required. This is an array of arrays. Each array in the list must contain at least 2 elements. The first element must be a string that corresponds to the name of the event to listen for. The second element must be either a string or an anonymous function. If it's a string it's assumed to be a container service key that points to your listener. There may be a third element of the array -- it must be an integer. The third element is the `$priority` argument when registering the listener. See the [Authorization Server Domain Events documentation](https://oauth2.thephpleague.com/authorization-server/events/). +### Configure Event Listeners + +_Optional_ The `event-listeners` and `event-listener-providers` arrays may be used to enable event listeners for events published by `league\oauth2-server`. See the [Authorization Server Domain Events documentation](https://oauth2.thephpleague.com/authorization-server/events/). The possible event names can be found [in `League\OAuth2\Server\RequestEvent`](https://github.com/thephpleague/oauth2-server/blob/0b0b43d43342c0909b3b32fb7a09d502c368d2ec/src/RequestEvent.php#L17-L22). + +#### Event Listeners + +The `event-listeners` key must contain an array of arrays. Each array element must contain at least 2 elements and may include a 3rd element. These roughly correspond to the arguments passed to [`League\Event\ListenerAcceptorInterface::addListener()`](https://github.com/thephpleague/event/blob/d2cc124cf9a3fab2bb4ff963307f60361ce4d119/src/ListenerAcceptorInterface.php#L43). The first element must be a string -- either the [wildcard (`*`)](https://event.thephpleague.com/2.0/listeners/wildcard/) or a [single event name](https://event.thephpleague.com/2.0/events/named/). The second element must be either a callable, a concrete instance of `League\Event\ListenerInterface`, or a string pointing to your listener service instance in the container. The third element is optional, and must be an integer if provided. + +See the [documentation for callable listeners](https://event.thephpleague.com/2.0/listeners/callables/). + +#### Event Listener Providers + +The `event-listener-providers` key must contain an array. Each array element must contain either a concrete instance of `League\Event\ListenerProviderInterface` or a string pointing to your container service instance of a listener provider. + +See the [documentation for listener providers](https://event.thephpleague.com/2.0/listeners/providers/). + +Example config: + +```php +return [ + 'event-listeners' => [ + // using a container service + [ + \League\OAuth2\Server\RequestEvent::CLIENT_AUTHENTICATION_FAILED, + \My\Event\Listener\Service::class, + ], + // using a callable + [ + \League\OAuth2\Server\RequestEvent::ACCESS_TOKEN_ISSUED, + function (\League\OAuth2\Server\RequestEvent $event) { + // do something + }, + ], + ], + 'event-listener-providers' => [ + \My\Event\ListenerProvider\Service::class, + ], +]; +``` + +## OAuth2 Database You need to provide an OAuth2 database yourself, or generate a [SQLite](https://www.sqlite.org) database with the following command (using `sqlite3` for GNU/Linux): @@ -168,7 +194,7 @@ For security reason, the client `secret` and the user `password` are stored using the `bcrypt` algorithm as used by the [password_hash](http://php.net/manual/en/function.password-hash.php) function. -## Configure OAuth2 routes +## Configure OAuth2 Routes As the final step, in order to use the OAuth2 server you need to configure the routes for the **token endpoint** and **authorization**. diff --git a/src/AuthorizationServerFactory.php b/src/AuthorizationServerFactory.php index 9d4ded8..6eb1106 100644 --- a/src/AuthorizationServerFactory.php +++ b/src/AuthorizationServerFactory.php @@ -11,6 +11,8 @@ namespace Zend\Expressive\Authentication\OAuth2; use DateInterval; +use League\Event\ListenerProviderInterface; + use League\OAuth2\Server\AuthorizationServer; use Psr\Container\ContainerInterface; @@ -68,6 +70,9 @@ public function __invoke(ContainerInterface $container) : AuthorizationServer // add listeners if configured $this->addListeners($authServer, $container); + // add listener providers if configured + $this->addListenerProviders($authServer, $container); + return $authServer; } @@ -82,18 +87,56 @@ private function addListeners( ContainerInterface $container ): void { $listeners = $this->getListenersConfig($container); - if (null === $listeners) { - return; - } - foreach ($listeners as $listenerConfig) { + + foreach ($listeners as $idx => $listenerConfig) { $event = $listenerConfig[0]; $listener = $listenerConfig[1]; $priority = $listenerConfig[2] ?? null; if (is_string($listener)) { + if (!$container->has($listener)) { + throw new Exception\InvalidConfigException(sprintf( + 'The second element of event-listeners config at ' . + 'index "%s" is a string and therefore expected to ' . + 'be available as a service key in the container. ' . + 'A service named "%s" was not found.', + $idx, + $listener + )); + } $listener = $container->get($listener); } $authServer->getEmitter() ->addListener($event, $listener, $priority); } } + + /** + * Optionally add event listener providers + * + * @param AuthorizationServer $authServer + * @param ContainerInterface $container + */ + private function addListenerProviders( + AuthorizationServer $authServer, + ContainerInterface $container + ): void { + $providers = $this->getListenerProvidersConfig($container); + + foreach ($providers as $idx => $provider) { + if (is_string($provider)) { + if (!$container->has($provider)) { + throw new Exception\InvalidConfigException(sprintf( + 'The event-listener-providers config at ' . + 'index "%s" is a string and therefore expected to ' . + 'be available as a service key in the container. ' . + 'A service named "%s" was not found.', + $idx, + $provider + )); + } + $provider = $container->get($provider); + } + $authServer->getEmitter()->useListenerProvider($provider); + } + } } diff --git a/src/ConfigTrait.php b/src/ConfigTrait.php index 7822406..b424412 100644 --- a/src/ConfigTrait.php +++ b/src/ConfigTrait.php @@ -107,21 +107,42 @@ protected function getGrantsConfig(ContainerInterface $container) : array /** * @param ContainerInterface $container * - * @return array|null + * @return array */ - protected function getListenersConfig(ContainerInterface $container) : ?array + protected function getListenersConfig(ContainerInterface $container) : array { $config = $container->get('config')['authentication'] ?? []; - if (empty($config['listeners'])) { - return null; + if (empty($config['event-listeners'])) { + return []; } - if (! is_array($config['listeners'])) { + if (! is_array($config['event-listeners'])) { throw new InvalidConfigException( - 'The listeners must be an array value' + 'The event-listeners config must be an array value' ); } - return $config['listeners']; + return $config['event-listeners']; + } + + /** + * @param ContainerInterface $container + * + * @return array + */ + protected function getListenerProvidersConfig(ContainerInterface $container) : array + { + $config = $container->get('config')['authentication'] ?? []; + + if (empty($config['event-listener-providers'])) { + return []; + } + if (! is_array($config['event-listener-providers'])) { + throw new InvalidConfigException( + 'The event-listener-providers config must be an array value' + ); + } + + return $config['event-listener-providers']; } } diff --git a/test/AuthorizationServerFactoryTest.php b/test/AuthorizationServerFactoryTest.php index ae3a9bd..94c5990 100644 --- a/test/AuthorizationServerFactoryTest.php +++ b/test/AuthorizationServerFactoryTest.php @@ -10,13 +10,18 @@ namespace ZendTest\Expressive\Authentication\OAuth2; +use League\Event\ListenerProviderInterface; + use League\OAuth2\Server\AuthorizationServer; +use League\OAuth2\Server\Grant\PasswordGrant; use League\OAuth2\Server\Grant\ClientCredentialsGrant; use League\OAuth2\Server\Grant\GrantTypeInterface; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use League\OAuth2\Server\Repositories\ScopeRepositoryInterface; use PHPUnit\Framework\TestCase; +use Prophecy\Prophecy\ObjectProphecy; + use Psr\Container\ContainerInterface; use Zend\Expressive\Authentication\OAuth2\AuthorizationServerFactory; use League\OAuth2\Server\RequestEvent; @@ -26,8 +31,11 @@ use function array_slice; use function in_array; +use Zend\Expressive\Authentication\OAuth2\Exception\InvalidConfigException; + class AuthorizationServerFactoryTest extends TestCase { + public function testInvoke() { $mockContainer = $this->prophesize(ContainerInterface::class); @@ -69,8 +77,10 @@ public function testInvoke() $this->assertInstanceOf(AuthorizationServer::class, $result); } - public function testInvokeWithListenerConfig() - { + /** + * @return ObjectProphecy + */ + private function getContainerMock(): ObjectProphecy { $mockContainer = $this->prophesize(ContainerInterface::class); $mockClientRepo = $this->prophesize(ClientRepositoryInterface::class); $mockAccessTokenRepo = $this->prophesize(AccessTokenRepositoryInterface::class); @@ -78,9 +88,52 @@ public function testInvokeWithListenerConfig() $mockClientGrant = $this->prophesize(GrantTypeInterface::class); $mockPasswordGrant = $this->prophesize(GrantTypeInterface::class); + $mockContainer->has(ClientRepositoryInterface::class)->willReturn(true); + $mockContainer->has(AccessTokenRepositoryInterface::class)->willReturn(true); + $mockContainer->has(ScopeRepositoryInterface::class)->willReturn(true); + + $mockContainer->get(ClientRepositoryInterface::class)->willReturn($mockClientRepo->reveal()); + $mockContainer->get(AccessTokenRepositoryInterface::class)->willReturn($mockAccessTokenRepo->reveal()); + $mockContainer->get(ScopeRepositoryInterface::class)->willReturn($mockScopeRepo->reveal()); + $mockContainer->get(ClientCredentialsGrant::class)->willReturn($mockClientGrant->reveal()); + $mockContainer->get(PasswordGrant::class)->willReturn($mockPasswordGrant->reveal()); + + return $mockContainer; + } + + public function testInvokeWithNullGrant() + { + $mockContainer = $this->getContainerMock(); + + $config = [ + 'authentication' => [ + 'private_key' => __DIR__ . '/TestAsset/private.key', + 'encryption_key' => 'iALlwJ1sH77dmFCJFo+pMdM6Af4bF/hCca1EDDx7MwE=', + 'access_token_expire' => 'P1D', + 'grants' => [ + ClientCredentialsGrant::class + => null, + PasswordGrant::class + => PasswordGrant::class, + ], + ] + ]; + + $mockContainer->get('config')->willReturn($config); + + $factory = new AuthorizationServerFactory(); + + $result = $factory($mockContainer->reveal()); + + $this->assertInstanceOf(AuthorizationServer::class, $result); + } + + public function testInvokeWithListenerConfig() + { + $mockContainer = $this->getContainerMock(); $mockListener = $this->prophesize(ListenerInterface::class); - $mockContainer->get(ListenerInterface::class) - ->will([$mockListener, 'reveal']); + $mockContainer->has(ListenerInterface::class)->willReturn(true); + $mockContainer->get(ListenerInterface::class)->willReturn($mockListener->reveal()); $config = [ 'authentication' => [ @@ -91,7 +144,7 @@ public function testInvokeWithListenerConfig() ClientCredentialsGrant::class => ClientCredentialsGrant::class, ], - 'listeners' => [ + 'event-listeners' => [ [ RequestEvent::CLIENT_AUTHENTICATION_FAILED, function (RequestEvent $event) { @@ -105,14 +158,70 @@ function (RequestEvent $event) { ] ]; - $mockContainer->has(ClientRepositoryInterface::class)->willReturn(true); - $mockContainer->has(AccessTokenRepositoryInterface::class)->willReturn(true); - $mockContainer->has(ScopeRepositoryInterface::class)->willReturn(true); + $mockContainer->get('config')->willReturn($config); + + $factory = new AuthorizationServerFactory(); + + $result = $factory($mockContainer->reveal()); + + $this->assertInstanceOf(AuthorizationServer::class, $result); + } + + public function testInvokeWithListenerConfigMissingServiceThrowsException() + { + $mockContainer = $this->getContainerMock(); + $mockListener = $this->prophesize(ListenerInterface::class); + $mockContainer->has(ListenerInterface::class)->willReturn(false); + + $config = [ + 'authentication' => [ + 'private_key' => __DIR__ . '/TestAsset/private.key', + 'encryption_key' => 'iALlwJ1sH77dmFCJFo+pMdM6Af4bF/hCca1EDDx7MwE=', + 'access_token_expire' => 'P1D', + 'grants' => [ + ClientCredentialsGrant::class + => ClientCredentialsGrant::class, + ], + 'event-listeners' => [ + [ + RequestEvent::CLIENT_AUTHENTICATION_FAILED, + ListenerInterface::class + ] + ] + ] + ]; + + $mockContainer->get('config')->willReturn($config); + + $factory = new AuthorizationServerFactory(); + + $this->expectException(InvalidConfigException::class); + + $result = $factory($mockContainer->reveal()); + } + + public function testInvokeWithListenerProviderConfig() + { + $mockContainer = $this->getContainerMock(); + $mockProvider = $this->prophesize(ListenerProviderInterface::class); + $mockContainer->has(ListenerProviderInterface::class)->willReturn(true); + $mockContainer->get(ListenerProviderInterface::class)->willReturn($mockProvider->reveal()); + + $config = [ + 'authentication' => [ + 'private_key' => __DIR__ . '/TestAsset/private.key', + 'encryption_key' => 'iALlwJ1sH77dmFCJFo+pMdM6Af4bF/hCca1EDDx7MwE=', + 'access_token_expire' => 'P1D', + 'grants' => [ + ClientCredentialsGrant::class + => ClientCredentialsGrant::class, + ], + 'event-listener-providers' => [ + ListenerProviderInterface::class + ] + ] + ]; - $mockContainer->get(ClientRepositoryInterface::class)->willReturn($mockClientRepo->reveal()); - $mockContainer->get(AccessTokenRepositoryInterface::class)->willReturn($mockAccessTokenRepo->reveal()); - $mockContainer->get(ScopeRepositoryInterface::class)->willReturn($mockScopeRepo->reveal()); - $mockContainer->get(ClientCredentialsGrant::class)->willReturn($mockClientGrant->reveal()); $mockContainer->get('config')->willReturn($config); $factory = new AuthorizationServerFactory(); @@ -121,4 +230,35 @@ function (RequestEvent $event) { $this->assertInstanceOf(AuthorizationServer::class, $result); } + + public function testInvokeWithListenerProviderConfigMissingServiceThrowsException() + { + $mockContainer = $this->getContainerMock(); + $mockProvider = $this->prophesize(ListenerProviderInterface::class); + $mockContainer->has(ListenerProviderInterface::class)->willReturn(false); + + $config = [ + 'authentication' => [ + 'private_key' => __DIR__ . '/TestAsset/private.key', + 'encryption_key' => 'iALlwJ1sH77dmFCJFo+pMdM6Af4bF/hCca1EDDx7MwE=', + 'access_token_expire' => 'P1D', + 'grants' => [ + ClientCredentialsGrant::class + => ClientCredentialsGrant::class, + ], + 'event-listener-providers' => [ + ListenerProviderInterface::class + ] + ] + ]; + + $mockContainer->get('config')->willReturn($config); + + $factory = new AuthorizationServerFactory(); + + $this->expectException(InvalidConfigException::class); + + $result = $factory($mockContainer->reveal()); + + } } diff --git a/test/ConfigTraitTest.php b/test/ConfigTraitTest.php index 4460349..6e615f0 100644 --- a/test/ConfigTraitTest.php +++ b/test/ConfigTraitTest.php @@ -160,7 +160,7 @@ public function testGetListenersConfigNoConfig() ->willReturn([]); $result = $this->trait ->proxy('getListenersConfig', $this->container->reveal()); - $this->assertNull($result); + $this->assertInternalType('array', $result); } /** @@ -172,7 +172,7 @@ public function testGetListenersConfigNoArrayValue() ->get('config') ->willReturn([ 'authentication' => [ - 'listeners' => 'xxx', + 'event-listeners' => 'xxx', ], ]); @@ -184,11 +184,50 @@ public function testGetListenersConfig() $this->container->get('config') ->willReturn([ 'authentication' => [ - 'listeners' => $expected = [['xxx']], + 'event-listeners' => $expected = [['xxx']], ], ]); $result = $this->trait ->proxy('getListenersConfig', $this->container->reveal()); $this->assertEquals($expected, $result); } + + public function testGetListenerProvidersConfigNoConfig() + { + $this->container + ->get('config') + ->willReturn([]); + $result = $this->trait + ->proxy('getListenerProvidersConfig', $this->container->reveal()); + $this->assertInternalType('array', $result); + } + + /** + * @expectedException Zend\Expressive\Authentication\OAuth2\Exception\InvalidConfigException + */ + public function testGetListenerProvidersConfigNoArrayValue() + { + $this->container + ->get('config') + ->willReturn([ + 'authentication' => [ + 'event-listener-providers' => 'xxx', + ], + ]); + + $this->trait->proxy('getListenerProvidersConfig', $this->container->reveal()); + } + + public function testGetListenerProvidersConfig() + { + $this->container->get('config') + ->willReturn([ + 'authentication' => [ + 'event-listener-providers' => $expected = ['xxx'], + ], + ]); + $result = $this->trait + ->proxy('getListenerProvidersConfig', $this->container->reveal()); + $this->assertEquals($expected, $result); + } } From 9361dd22857ebc35c06aed2b99aa3109955d84e9 Mon Sep 17 00:00:00 2001 From: Marc Guyer Date: Sun, 11 Aug 2019 22:16:39 -0400 Subject: [PATCH 79/99] Fix cs errors --- src/AuthorizationServerFactory.php | 4 ++-- test/AuthorizationServerFactoryTest.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/AuthorizationServerFactory.php b/src/AuthorizationServerFactory.php index 6eb1106..e41d399 100644 --- a/src/AuthorizationServerFactory.php +++ b/src/AuthorizationServerFactory.php @@ -93,7 +93,7 @@ private function addListeners( $listener = $listenerConfig[1]; $priority = $listenerConfig[2] ?? null; if (is_string($listener)) { - if (!$container->has($listener)) { + if (! $container->has($listener)) { throw new Exception\InvalidConfigException(sprintf( 'The second element of event-listeners config at ' . 'index "%s" is a string and therefore expected to ' . @@ -124,7 +124,7 @@ private function addListenerProviders( foreach ($providers as $idx => $provider) { if (is_string($provider)) { - if (!$container->has($provider)) { + if (! $container->has($provider)) { throw new Exception\InvalidConfigException(sprintf( 'The event-listener-providers config at ' . 'index "%s" is a string and therefore expected to ' . diff --git a/test/AuthorizationServerFactoryTest.php b/test/AuthorizationServerFactoryTest.php index 94c5990..9edfb49 100644 --- a/test/AuthorizationServerFactoryTest.php +++ b/test/AuthorizationServerFactoryTest.php @@ -80,7 +80,8 @@ public function testInvoke() /** * @return ObjectProphecy */ - private function getContainerMock(): ObjectProphecy { + private function getContainerMock(): ObjectProphecy + { $mockContainer = $this->prophesize(ContainerInterface::class); $mockClientRepo = $this->prophesize(ClientRepositoryInterface::class); $mockAccessTokenRepo = $this->prophesize(AccessTokenRepositoryInterface::class); @@ -259,6 +260,5 @@ public function testInvokeWithListenerProviderConfigMissingServiceThrowsExceptio $this->expectException(InvalidConfigException::class); $result = $factory($mockContainer->reveal()); - } } From 43311f018b42233de05f5091ea57a3efc6096910 Mon Sep 17 00:00:00 2001 From: Marc Guyer Date: Wed, 14 Aug 2019 13:47:24 -0400 Subject: [PATCH 80/99] Remove commented-out listener config example --- config/oauth2.php | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/config/oauth2.php b/config/oauth2.php index 70ef994..9abb090 100644 --- a/config/oauth2.php +++ b/config/oauth2.php @@ -35,25 +35,6 @@ \League\OAuth2\Server\Grant\RefreshTokenGrant::class => \League\OAuth2\Server\Grant\RefreshTokenGrant::class ], - - // optionally add listener config - // 'listeners' => [ - // [ - // // event name - // \League\OAuth2\Server\RequestEvent::CLIENT_AUTHENTICATION_FAILED, - // // listener defined as a service key - // \My\League\Event\Listener\For\Auth\Failure::class, - // ], [ - // \League\OAuth2\Server\RequestEvent::CLIENT_AUTHENTICATION_FAILED, - // // listener defined as an anonymous function - // function (\League\OAuth2\Server\RequestEvent $event) { - // // do something - // }, - // // priority NORMAL (0) is the default but you may set an - // // int val of your choosing - // // League\Event\ListenerAcceptorInterface::P_HIGH, - // ], - // ], ]; // Conditionally include the encryption_key config setting, based on presence of file. From 68c8c2c174b1ffc9607a1a1881fe073d963015bf Mon Sep 17 00:00:00 2001 From: Marc Guyer Date: Wed, 14 Aug 2019 14:48:04 -0400 Subject: [PATCH 81/99] Use underscores for config keys --- docs/book/v1/intro.md | 10 +++++----- src/AuthorizationServerFactory.php | 4 ++-- src/ConfigTrait.php | 16 ++++++++-------- test/AuthorizationServerFactoryTest.php | 8 ++++---- test/ConfigTraitTest.php | 8 ++++---- 5 files changed, 23 insertions(+), 23 deletions(-) diff --git a/docs/book/v1/intro.md b/docs/book/v1/intro.md index eda3fb1..86e43e2 100644 --- a/docs/book/v1/intro.md +++ b/docs/book/v1/intro.md @@ -128,17 +128,17 @@ you can extend this array to add your own custom grants. ### Configure Event Listeners -_Optional_ The `event-listeners` and `event-listener-providers` arrays may be used to enable event listeners for events published by `league\oauth2-server`. See the [Authorization Server Domain Events documentation](https://oauth2.thephpleague.com/authorization-server/events/). The possible event names can be found [in `League\OAuth2\Server\RequestEvent`](https://github.com/thephpleague/oauth2-server/blob/0b0b43d43342c0909b3b32fb7a09d502c368d2ec/src/RequestEvent.php#L17-L22). +_Optional_ The `event_listeners` and `event_listener_providers` arrays may be used to enable event listeners for events published by `league\oauth2-server`. See the [Authorization Server Domain Events documentation](https://oauth2.thephpleague.com/authorization-server/events/). The possible event names can be found [in `League\OAuth2\Server\RequestEvent`](https://github.com/thephpleague/oauth2-server/blob/0b0b43d43342c0909b3b32fb7a09d502c368d2ec/src/RequestEvent.php#L17-L22). #### Event Listeners -The `event-listeners` key must contain an array of arrays. Each array element must contain at least 2 elements and may include a 3rd element. These roughly correspond to the arguments passed to [`League\Event\ListenerAcceptorInterface::addListener()`](https://github.com/thephpleague/event/blob/d2cc124cf9a3fab2bb4ff963307f60361ce4d119/src/ListenerAcceptorInterface.php#L43). The first element must be a string -- either the [wildcard (`*`)](https://event.thephpleague.com/2.0/listeners/wildcard/) or a [single event name](https://event.thephpleague.com/2.0/events/named/). The second element must be either a callable, a concrete instance of `League\Event\ListenerInterface`, or a string pointing to your listener service instance in the container. The third element is optional, and must be an integer if provided. +The `event_listeners` key must contain an array of arrays. Each array element must contain at least 2 elements and may include a 3rd element. These roughly correspond to the arguments passed to [`League\Event\ListenerAcceptorInterface::addListener()`](https://github.com/thephpleague/event/blob/d2cc124cf9a3fab2bb4ff963307f60361ce4d119/src/ListenerAcceptorInterface.php#L43). The first element must be a string -- either the [wildcard (`*`)](https://event.thephpleague.com/2.0/listeners/wildcard/) or a [single event name](https://event.thephpleague.com/2.0/events/named/). The second element must be either a callable, a concrete instance of `League\Event\ListenerInterface`, or a string pointing to your listener service instance in the container. The third element is optional, and must be an integer if provided. See the [documentation for callable listeners](https://event.thephpleague.com/2.0/listeners/callables/). #### Event Listener Providers -The `event-listener-providers` key must contain an array. Each array element must contain either a concrete instance of `League\Event\ListenerProviderInterface` or a string pointing to your container service instance of a listener provider. +The `event_listener_providers` key must contain an array. Each array element must contain either a concrete instance of `League\Event\ListenerProviderInterface` or a string pointing to your container service instance of a listener provider. See the [documentation for listener providers](https://event.thephpleague.com/2.0/listeners/providers/). @@ -146,7 +146,7 @@ Example config: ```php return [ - 'event-listeners' => [ + 'event_listeners' => [ // using a container service [ \League\OAuth2\Server\RequestEvent::CLIENT_AUTHENTICATION_FAILED, @@ -160,7 +160,7 @@ return [ }, ], ], - 'event-listener-providers' => [ + 'event_listener_providers' => [ \My\Event\ListenerProvider\Service::class, ], ]; diff --git a/src/AuthorizationServerFactory.php b/src/AuthorizationServerFactory.php index e41d399..b4ad06f 100644 --- a/src/AuthorizationServerFactory.php +++ b/src/AuthorizationServerFactory.php @@ -95,7 +95,7 @@ private function addListeners( if (is_string($listener)) { if (! $container->has($listener)) { throw new Exception\InvalidConfigException(sprintf( - 'The second element of event-listeners config at ' . + 'The second element of event_listeners config at ' . 'index "%s" is a string and therefore expected to ' . 'be available as a service key in the container. ' . 'A service named "%s" was not found.', @@ -126,7 +126,7 @@ private function addListenerProviders( if (is_string($provider)) { if (! $container->has($provider)) { throw new Exception\InvalidConfigException(sprintf( - 'The event-listener-providers config at ' . + 'The event_listener_providers config at ' . 'index "%s" is a string and therefore expected to ' . 'be available as a service key in the container. ' . 'A service named "%s" was not found.', diff --git a/src/ConfigTrait.php b/src/ConfigTrait.php index b424412..1b75670 100644 --- a/src/ConfigTrait.php +++ b/src/ConfigTrait.php @@ -113,16 +113,16 @@ protected function getListenersConfig(ContainerInterface $container) : array { $config = $container->get('config')['authentication'] ?? []; - if (empty($config['event-listeners'])) { + if (empty($config['event_listeners'])) { return []; } - if (! is_array($config['event-listeners'])) { + if (! is_array($config['event_listeners'])) { throw new InvalidConfigException( - 'The event-listeners config must be an array value' + 'The event_listeners config must be an array value' ); } - return $config['event-listeners']; + return $config['event_listeners']; } /** @@ -134,15 +134,15 @@ protected function getListenerProvidersConfig(ContainerInterface $container) : a { $config = $container->get('config')['authentication'] ?? []; - if (empty($config['event-listener-providers'])) { + if (empty($config['event_listener_providers'])) { return []; } - if (! is_array($config['event-listener-providers'])) { + if (! is_array($config['event_listener_providers'])) { throw new InvalidConfigException( - 'The event-listener-providers config must be an array value' + 'The event_listener_providers config must be an array value' ); } - return $config['event-listener-providers']; + return $config['event_listener_providers']; } } diff --git a/test/AuthorizationServerFactoryTest.php b/test/AuthorizationServerFactoryTest.php index 9edfb49..e84df8e 100644 --- a/test/AuthorizationServerFactoryTest.php +++ b/test/AuthorizationServerFactoryTest.php @@ -145,7 +145,7 @@ public function testInvokeWithListenerConfig() ClientCredentialsGrant::class => ClientCredentialsGrant::class, ], - 'event-listeners' => [ + 'event_listeners' => [ [ RequestEvent::CLIENT_AUTHENTICATION_FAILED, function (RequestEvent $event) { @@ -183,7 +183,7 @@ public function testInvokeWithListenerConfigMissingServiceThrowsException() ClientCredentialsGrant::class => ClientCredentialsGrant::class, ], - 'event-listeners' => [ + 'event_listeners' => [ [ RequestEvent::CLIENT_AUTHENTICATION_FAILED, ListenerInterface::class @@ -217,7 +217,7 @@ public function testInvokeWithListenerProviderConfig() ClientCredentialsGrant::class => ClientCredentialsGrant::class, ], - 'event-listener-providers' => [ + 'event_listener_providers' => [ ListenerProviderInterface::class ] ] @@ -247,7 +247,7 @@ public function testInvokeWithListenerProviderConfigMissingServiceThrowsExceptio ClientCredentialsGrant::class => ClientCredentialsGrant::class, ], - 'event-listener-providers' => [ + 'event_listener_providers' => [ ListenerProviderInterface::class ] ] diff --git a/test/ConfigTraitTest.php b/test/ConfigTraitTest.php index 6e615f0..2808660 100644 --- a/test/ConfigTraitTest.php +++ b/test/ConfigTraitTest.php @@ -172,7 +172,7 @@ public function testGetListenersConfigNoArrayValue() ->get('config') ->willReturn([ 'authentication' => [ - 'event-listeners' => 'xxx', + 'event_listeners' => 'xxx', ], ]); @@ -184,7 +184,7 @@ public function testGetListenersConfig() $this->container->get('config') ->willReturn([ 'authentication' => [ - 'event-listeners' => $expected = [['xxx']], + 'event_listeners' => $expected = [['xxx']], ], ]); $result = $this->trait @@ -211,7 +211,7 @@ public function testGetListenerProvidersConfigNoArrayValue() ->get('config') ->willReturn([ 'authentication' => [ - 'event-listener-providers' => 'xxx', + 'event_listener_providers' => 'xxx', ], ]); @@ -223,7 +223,7 @@ public function testGetListenerProvidersConfig() $this->container->get('config') ->willReturn([ 'authentication' => [ - 'event-listener-providers' => $expected = ['xxx'], + 'event_listener_providers' => $expected = ['xxx'], ], ]); $result = $this->trait From db8cc1ba8e9f5e5e89784aef6ed54c981a71c801 Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Sat, 28 Dec 2019 14:01:54 -0600 Subject: [PATCH 82/99] docs: note that configurable event listeners are from 1.3.0 forward --- docs/book/v1/intro.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/book/v1/intro.md b/docs/book/v1/intro.md index 86e43e2..16dbf3b 100644 --- a/docs/book/v1/intro.md +++ b/docs/book/v1/intro.md @@ -128,6 +128,8 @@ you can extend this array to add your own custom grants. ### Configure Event Listeners +- **Since 1.3.0** + _Optional_ The `event_listeners` and `event_listener_providers` arrays may be used to enable event listeners for events published by `league\oauth2-server`. See the [Authorization Server Domain Events documentation](https://oauth2.thephpleague.com/authorization-server/events/). The possible event names can be found [in `League\OAuth2\Server\RequestEvent`](https://github.com/thephpleague/oauth2-server/blob/0b0b43d43342c0909b3b32fb7a09d502c368d2ec/src/RequestEvent.php#L17-L22). #### Event Listeners From 08e5e5f29e42ff210b9408aa1ff81820f6c61fdb Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Sat, 28 Dec 2019 14:05:25 -0600 Subject: [PATCH 83/99] qa: CS fixes for AuthorizationServerFactoryTest - trailing commas in array entries - consistent whitespace --- test/AuthorizationServerFactoryTest.php | 60 +++++++++++-------------- 1 file changed, 26 insertions(+), 34 deletions(-) diff --git a/test/AuthorizationServerFactoryTest.php b/test/AuthorizationServerFactoryTest.php index e84df8e..05d9898 100644 --- a/test/AuthorizationServerFactoryTest.php +++ b/test/AuthorizationServerFactoryTest.php @@ -51,10 +51,8 @@ public function testInvoke() 'encryption_key' => 'iALlwJ1sH77dmFCJFo+pMdM6Af4bF/hCca1EDDx7MwE=', 'access_token_expire' => 'P1D', 'grants' => [ - ClientCredentialsGrant::class - => ClientCredentialsGrant::class, - PasswordGrant::class - => PasswordGrant::class, + ClientCredentialsGrant::class => ClientCredentialsGrant::class, + PasswordGrant::class => PasswordGrant::class, ], ] ]; @@ -112,12 +110,10 @@ public function testInvokeWithNullGrant() 'encryption_key' => 'iALlwJ1sH77dmFCJFo+pMdM6Af4bF/hCca1EDDx7MwE=', 'access_token_expire' => 'P1D', 'grants' => [ - ClientCredentialsGrant::class - => null, - PasswordGrant::class - => PasswordGrant::class, + ClientCredentialsGrant::class => null, + PasswordGrant::class => PasswordGrant::class, ], - ] + ], ]; $mockContainer->get('config')->willReturn($config); @@ -142,21 +138,21 @@ public function testInvokeWithListenerConfig() 'encryption_key' => 'iALlwJ1sH77dmFCJFo+pMdM6Af4bF/hCca1EDDx7MwE=', 'access_token_expire' => 'P1D', 'grants' => [ - ClientCredentialsGrant::class - => ClientCredentialsGrant::class, + ClientCredentialsGrant::class => ClientCredentialsGrant::class, ], 'event_listeners' => [ [ RequestEvent::CLIENT_AUTHENTICATION_FAILED, function (RequestEvent $event) { // do something - } - ], [ + }, + ], + [ RequestEvent::CLIENT_AUTHENTICATION_FAILED, - ListenerInterface::class - ] - ] - ] + ListenerInterface::class, + ], + ], + ], ]; $mockContainer->get('config')->willReturn($config); @@ -180,16 +176,15 @@ public function testInvokeWithListenerConfigMissingServiceThrowsException() 'encryption_key' => 'iALlwJ1sH77dmFCJFo+pMdM6Af4bF/hCca1EDDx7MwE=', 'access_token_expire' => 'P1D', 'grants' => [ - ClientCredentialsGrant::class - => ClientCredentialsGrant::class, + ClientCredentialsGrant::class => ClientCredentialsGrant::class, ], 'event_listeners' => [ [ RequestEvent::CLIENT_AUTHENTICATION_FAILED, - ListenerInterface::class - ] - ] - ] + ListenerInterface::class, + ], + ], + ], ]; $mockContainer->get('config')->willReturn($config); @@ -214,13 +209,12 @@ public function testInvokeWithListenerProviderConfig() 'encryption_key' => 'iALlwJ1sH77dmFCJFo+pMdM6Af4bF/hCca1EDDx7MwE=', 'access_token_expire' => 'P1D', 'grants' => [ - ClientCredentialsGrant::class - => ClientCredentialsGrant::class, + ClientCredentialsGrant::class => ClientCredentialsGrant::class, ], 'event_listener_providers' => [ ListenerProviderInterface::class - ] - ] + ], + ], ]; $mockContainer->get('config')->willReturn($config); @@ -244,13 +238,12 @@ public function testInvokeWithListenerProviderConfigMissingServiceThrowsExceptio 'encryption_key' => 'iALlwJ1sH77dmFCJFo+pMdM6Af4bF/hCca1EDDx7MwE=', 'access_token_expire' => 'P1D', 'grants' => [ - ClientCredentialsGrant::class - => ClientCredentialsGrant::class, + ClientCredentialsGrant::class => ClientCredentialsGrant::class, ], 'event_listener_providers' => [ - ListenerProviderInterface::class - ] - ] + ListenerProviderInterface::class, + ], + ], ]; $mockContainer->get('config')->willReturn($config); @@ -258,7 +251,6 @@ public function testInvokeWithListenerProviderConfigMissingServiceThrowsExceptio $factory = new AuthorizationServerFactory(); $this->expectException(InvalidConfigException::class); - - $result = $factory($mockContainer->reveal()); + $factory($mockContainer->reveal()); } } From 93ddf21e717d2563952cdaee9f5c8b2b22645cb5 Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Sat, 28 Dec 2019 14:08:14 -0600 Subject: [PATCH 84/99] docs: adds CHANGELOG entry for #62 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a5760a6..bb34f4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ All notable changes to this project will be documented in this file, in reverse ### Added -- Nothing. +- [#62](https://github.com/zendframework/zend-expressive-authentication-oauth2/pull/62) adds the ability to configure and add event listeners for the underlying league/oauth2 implementation. See the [event listeners configuration documentation](https://docs.zendframework.com/zend-expressive-authentication-oauth2/intro/#configure-event-listeners) for more information. ### Changed From 0b9ed00cd1f367955459ccb732ec90cc1d8b4d82 Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Sat, 28 Dec 2019 14:39:37 -0600 Subject: [PATCH 85/99] fix: ensure `data/oauth2.sql` works for sqlite3 The database is used in unit tests, which use sqlite. The latest changes to the database made it unusable for anything but MySQL. The changes in this patch should work across any database that understands ANSI SQL, with the potential exception of how autoincrement is defined. --- data/oauth2.sql | 75 ++++++++++++++++++++++++------------------------- 1 file changed, 37 insertions(+), 38 deletions(-) diff --git a/data/oauth2.sql b/data/oauth2.sql index 984c600..f971783 100644 --- a/data/oauth2.sql +++ b/data/oauth2.sql @@ -3,44 +3,44 @@ -- CREATE TABLE `oauth_access_tokens` ( - `id` varchar(100) NOT NULL, - `user_id` int(10) unsigned DEFAULT NULL, - `client_id` int(10) unsigned NOT NULL, + `id` varchar(100) PRIMARY KEY NOT NULL, + `user_id` int(10) DEFAULT NULL, + `client_id` int(10) NOT NULL, `name` varchar(255) DEFAULT NULL, `scopes` text, `revoked` tinyint(1) NOT NULL DEFAULT '0', `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` datetime DEFAULT NULL, - `expires_at` datetime NOT NULL, - PRIMARY KEY (`id`), - KEY `IDX_CA42527CA76ED39519EB6921BDA26CCD` (`user_id`,`client_id`), - KEY `IDX_CA42527CA76ED395` (`user_id`), - KEY `IDX_CA42527C19EB6921` (`client_id`) -) ENGINE=InnoDB; + `expires_at` datetime NOT NULL +); + +CREATE INDEX `IDX_CA42527CA76ED39519EB6921BDA26CCD` ON oauth_access_tokens (`user_id`,`client_id`); +CREATE INDEX `IDX_CA42527CA76ED395` ON oauth_access_tokens (`user_id`); +CREATE INDEX `IDX_CA42527C19EB6921` ON oauth_access_tokens (`client_id`); -- -- Table structure for table `oauth_auth_codes` -- CREATE TABLE `oauth_auth_codes` ( - `id` varchar(100) NOT NULL, - `user_id` int(10) unsigned DEFAULT NULL, - `client_id` int(10) unsigned NOT NULL, + `id` varchar(100) PRIMARY KEY NOT NULL, + `user_id` int(10) DEFAULT NULL, + `client_id` int(10) NOT NULL, `scopes` text, `revoked` tinyint(1) NOT NULL DEFAULT '0', - `expires_at` datetime DEFAULT NULL, - PRIMARY KEY (`id`), - KEY `IDX_BB493F83A76ED395` (`user_id`), - KEY `IDX_BB493F8319EB6921` (`client_id`) -) ENGINE=InnoDB; + `expires_at` datetime DEFAULT NULL +); + +CREATE INDEX `IDX_BB493F83A76ED395` ON oauth_auth_codes (`user_id`); +CREATE INDEX `IDX_BB493F8319EB6921` ON oauth_auth_codes (`client_id`); -- -- Table structure for table `oauth_clients` -- CREATE TABLE `oauth_clients` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `user_id` int(10) unsigned DEFAULT NULL, + `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, + `user_id` int(10) DEFAULT NULL, `name` varchar(100) NOT NULL, `secret` varchar(100) DEFAULT NULL, `redirect` varchar(255) DEFAULT NULL, @@ -48,44 +48,43 @@ CREATE TABLE `oauth_clients` ( `password_client` tinyint(1) DEFAULT NULL, `revoked` tinyint(1) DEFAULT NULL, `created_at` datetime DEFAULT CURRENT_TIMESTAMP, - `updated_at` datetime DEFAULT NULL, - PRIMARY KEY (`id`), - KEY `IDX_13CE81015E237E06A76ED395BDA26CCD` (`name`,`user_id`), - KEY `IDX_13CE8101A76ED395` (`user_id`) -) ENGINE=InnoDB; + `updated_at` datetime DEFAULT NULL +); + +CREATE INDEX `IDX_13CE81015E237E06A76ED395BDA26CCD` ON oauth_clients (`name`,`user_id`); +CREATE INDEX `IDX_13CE8101A76ED395` ON oauth_clients (`user_id`); -- -- Table structure for table `oauth_refresh_tokens` -- CREATE TABLE `oauth_refresh_tokens` ( - `id` varchar(100) NOT NULL, + `id` varchar(100) PRIMARY KEY NOT NULL, `access_token_id` varchar(100) NOT NULL, `revoked` tinyint(1) NOT NULL DEFAULT '0', - `expires_at` datetime NOT NULL, - PRIMARY KEY (`id`), - KEY `IDX_5AB6872CCB2688BDA26CCD` (`access_token_id`) -) ENGINE=InnoDB; + `expires_at` datetime NOT NULL +); + +CREATE INDEX `IDX_5AB6872CCB2688BDA26CCD` ON oauth_refresh_tokens (`access_token_id`); -- -- Table structure for table `oauth_scopes` -- CREATE TABLE `oauth_scopes` ( - `id` varchar(100) NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB; + `id` varchar(100) PRIMARY KEY NOT NULL +); -- -- Table structure for table `oauth_users` -- CREATE TABLE `oauth_users` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `username` varchar(320) NOT NULL, + `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, + `username` varchar(320) UNIQUE NOT NULL, `password` varchar(100) NOT NULL, `first_name` varchar(80) DEFAULT NULL, - `last_name` varchar(80) DEFAULT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `UNIQ_93804FF8F85E0677` (`username`) -) ENGINE=InnoDB; + `last_name` varchar(80) DEFAULT NULL +); + +CREATE INDEX `UNIQ_93804FF8F85E0677` ON oauth_users (`username`); From 29690bddaada7f11ef43d170cb831ca3bf6d8595 Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Sat, 28 Dec 2019 14:42:06 -0600 Subject: [PATCH 86/99] 1.3.0 readiness - Updates branch aliases: - dev-master => 1.3.x-dev - dev-develop => 2.0.x-dev - Updates CHANGELOG - adds date for 1.3.0 release --- CHANGELOG.md | 2 +- composer.json | 4 ++-- composer.lock | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bb34f4a..3223d73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to this project will be documented in this file, in reverse chronological order by release. -## 1.3.0 - TBD +## 1.3.0 - 2019-12-28 ### Added diff --git a/composer.json b/composer.json index c421e58..12eb713 100644 --- a/composer.json +++ b/composer.json @@ -53,8 +53,8 @@ }, "extra": { "branch-alias": { - "dev-master": "1.2.x-dev", - "dev-develop": "1.3.x-dev" + "dev-master": "1.3.x-dev", + "dev-develop": "2.0.x-dev" }, "zf": { "config-provider": "Zend\\Expressive\\Authentication\\OAuth2\\ConfigProvider" diff --git a/composer.lock b/composer.lock index 2de372e..63cb195 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "bda1e7feca55a8efac26338aa133c188", + "content-hash": "3d1f67477142c8e8d333311a44340240", "packages": [ { "name": "defuse/php-encryption", From a508ed027c5056ccf2fb35065079214bff46fefb Mon Sep 17 00:00:00 2001 From: Tsvetomir Lazarov Date: Mon, 7 Oct 2019 17:33:34 +0300 Subject: [PATCH 87/99] Update league/oauth2-server to ^8.0.0 --- composer.json | 2 +- composer.lock | 309 +++++++++++++++++++++++++------------------------- 2 files changed, 157 insertions(+), 154 deletions(-) diff --git a/composer.json b/composer.json index 12eb713..733c754 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ }, "require": { "php": "^7.1", - "league/oauth2-server": "^7.3.0", + "league/oauth2-server": "^8.0.0", "psr/container": "^1.0", "psr/http-message": "^1.0.1", "psr/http-server-middleware": "^1.0", diff --git a/composer.lock b/composer.lock index 63cb195..f7a6268 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "3d1f67477142c8e8d333311a44340240", + "content-hash": "49e1aaaedd3215a18326b2b91a354874", "packages": [ { "name": "defuse/php-encryption", @@ -113,8 +113,8 @@ "authors": [ { "name": "Luís Otávio Cobucci Oblonczyk", - "role": "Developer", - "email": "lcobucci@gmail.com" + "email": "lcobucci@gmail.com", + "role": "Developer" } ], "description": "A simple library to work with JSON Web Token and JSON Web Signature", @@ -176,24 +176,25 @@ }, { "name": "league/oauth2-server", - "version": "7.4.0", + "version": "8.0.0", "source": { "type": "git", "url": "https://github.com/thephpleague/oauth2-server.git", - "reference": "2eb1cf79e59d807d89c256e7ac5e2bf8bdbd4acf" + "reference": "e1dc4d708c56fcfa205be4bb1862b6d525b4baac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/oauth2-server/zipball/2eb1cf79e59d807d89c256e7ac5e2bf8bdbd4acf", - "reference": "2eb1cf79e59d807d89c256e7ac5e2bf8bdbd4acf", + "url": "https://api.github.com/repos/thephpleague/oauth2-server/zipball/e1dc4d708c56fcfa205be4bb1862b6d525b4baac", + "reference": "e1dc4d708c56fcfa205be4bb1862b6d525b4baac", "shasum": "" }, "require": { - "defuse/php-encryption": "^2.1", + "defuse/php-encryption": "^2.2.1", + "ext-json": "*", "ext-openssl": "*", - "lcobucci/jwt": "^3.2.2", - "league/event": "^2.1", - "php": ">=7.0.0", + "lcobucci/jwt": "^3.3.1", + "league/event": "^2.2", + "php": ">=7.1.0", "psr/http-message": "^1.0.1" }, "replace": { @@ -201,12 +202,11 @@ "lncd/oauth2": "*" }, "require-dev": { - "phpstan/phpstan": "^0.9.2", - "phpstan/phpstan-phpunit": "^0.9.4", - "phpstan/phpstan-strict-rules": "^0.9.0", - "phpunit/phpunit": "^6.3 || ^7.0", + "phpstan/phpstan": "^0.11.8", + "phpstan/phpstan-phpunit": "^0.11.2", + "phpunit/phpunit": "^7.5.13 || ^8.2.3", "roave/security-advisories": "dev-master", - "zendframework/zend-diactoros": "^1.3.2" + "zendframework/zend-diactoros": "^2.1.2" }, "type": "library", "autoload": { @@ -249,7 +249,7 @@ "secure", "server" ], - "time": "2019-05-05T09:22:01+00:00" + "time": "2019-07-13T18:58:26+00:00" }, { "name": "paragonie/random_compat", @@ -598,20 +598,21 @@ ], "description": "Promoting the interoperability of container objects (DIC, SL, etc.)", "homepage": "https://github.com/container-interop/container-interop", + "abandoned": "psr/container", "time": "2017-02-14T19:40:03+00:00" }, { "name": "doctrine/instantiator", - "version": "1.2.0", + "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "a2c590166b2133a4633738648b6b064edae0814a" + "reference": "ae466f726242e637cebdd526a7d991b9433bacf1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/a2c590166b2133a4633738648b6b064edae0814a", - "reference": "a2c590166b2133a4633738648b6b064edae0814a", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/ae466f726242e637cebdd526a7d991b9433bacf1", + "reference": "ae466f726242e637cebdd526a7d991b9433bacf1", "shasum": "" }, "require": { @@ -654,20 +655,20 @@ "constructor", "instantiate" ], - "time": "2019-03-17T17:37:11+00:00" + "time": "2019-10-21T16:45:58+00:00" }, { "name": "myclabs/deep-copy", - "version": "1.9.3", + "version": "1.9.4", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "007c053ae6f31bba39dfa19a7726f56e9763bbea" + "reference": "579bb7356d91f9456ccd505f24ca8b667966a0a7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/007c053ae6f31bba39dfa19a7726f56e9763bbea", - "reference": "007c053ae6f31bba39dfa19a7726f56e9763bbea", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/579bb7356d91f9456ccd505f24ca8b667966a0a7", + "reference": "579bb7356d91f9456ccd505f24ca8b667966a0a7", "shasum": "" }, "require": { @@ -702,7 +703,7 @@ "object", "object graph" ], - "time": "2019-08-09T12:45:53+00:00" + "time": "2019-12-15T19:12:40+00:00" }, { "name": "phar-io/manifest", @@ -742,18 +743,18 @@ "authors": [ { "name": "Arne Blankerts", - "role": "Developer", - "email": "arne@blankerts.de" + "email": "arne@blankerts.de", + "role": "Developer" }, { "name": "Sebastian Heuer", - "role": "Developer", - "email": "sebastian@phpeople.de" + "email": "sebastian@phpeople.de", + "role": "Developer" }, { "name": "Sebastian Bergmann", - "role": "Developer", - "email": "sebastian@phpunit.de" + "email": "sebastian@phpunit.de", + "role": "Developer" } ], "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", @@ -808,35 +809,33 @@ }, { "name": "phpdocumentor/reflection-common", - "version": "1.0.1", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6" + "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", - "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/63a995caa1ca9e5590304cd845c15ad6d482a62a", + "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a", "shasum": "" }, "require": { - "php": ">=5.5" + "php": ">=7.1" }, "require-dev": { - "phpunit/phpunit": "^4.6" + "phpunit/phpunit": "~6" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "2.x-dev" } }, "autoload": { "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src" - ] + "phpDocumentor\\Reflection\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -858,31 +857,32 @@ "reflection", "static analysis" ], - "time": "2017-09-11T18:02:19+00:00" + "time": "2018-08-07T13:53:10+00:00" }, { "name": "phpdocumentor/reflection-docblock", - "version": "4.3.1", + "version": "4.3.4", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "bdd9f737ebc2a01c06ea7ff4308ec6697db9b53c" + "reference": "da3fd972d6bafd628114f7e7e036f45944b62e9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/bdd9f737ebc2a01c06ea7ff4308ec6697db9b53c", - "reference": "bdd9f737ebc2a01c06ea7ff4308ec6697db9b53c", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/da3fd972d6bafd628114f7e7e036f45944b62e9c", + "reference": "da3fd972d6bafd628114f7e7e036f45944b62e9c", "shasum": "" }, "require": { "php": "^7.0", - "phpdocumentor/reflection-common": "^1.0.0", - "phpdocumentor/type-resolver": "^0.4.0", + "phpdocumentor/reflection-common": "^1.0.0 || ^2.0.0", + "phpdocumentor/type-resolver": "~0.4 || ^1.0.0", "webmozart/assert": "^1.0" }, "require-dev": { - "doctrine/instantiator": "~1.0.5", + "doctrine/instantiator": "^1.0.5", "mockery/mockery": "^1.0", + "phpdocumentor/type-resolver": "0.4.*", "phpunit/phpunit": "^6.4" }, "type": "library", @@ -909,41 +909,40 @@ } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2019-04-30T17:48:53+00:00" + "time": "2019-12-28T18:55:12+00:00" }, { "name": "phpdocumentor/type-resolver", - "version": "0.4.0", + "version": "1.0.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7" + "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7", - "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", + "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", "shasum": "" }, "require": { - "php": "^5.5 || ^7.0", - "phpdocumentor/reflection-common": "^1.0" + "php": "^7.1", + "phpdocumentor/reflection-common": "^2.0" }, "require-dev": { - "mockery/mockery": "^0.9.4", - "phpunit/phpunit": "^5.2||^4.8.24" + "ext-tokenizer": "^7.1", + "mockery/mockery": "~1", + "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.x-dev" } }, "autoload": { "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src/" - ] + "phpDocumentor\\Reflection\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -956,37 +955,38 @@ "email": "me@mikevanriel.com" } ], - "time": "2017-07-14T14:27:02+00:00" + "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", + "time": "2019-08-22T18:11:29+00:00" }, { "name": "phpspec/prophecy", - "version": "1.8.1", + "version": "1.10.1", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "1927e75f4ed19131ec9bcc3b002e07fb1173ee76" + "reference": "cbe1df668b3fe136bcc909126a0f529a78d4cbbc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/1927e75f4ed19131ec9bcc3b002e07fb1173ee76", - "reference": "1927e75f4ed19131ec9bcc3b002e07fb1173ee76", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/cbe1df668b3fe136bcc909126a0f529a78d4cbbc", + "reference": "cbe1df668b3fe136bcc909126a0f529a78d4cbbc", "shasum": "" }, "require": { "doctrine/instantiator": "^1.0.2", "php": "^5.3|^7.0", - "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", - "sebastian/comparator": "^1.1|^2.0|^3.0", + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0", + "sebastian/comparator": "^1.2.3|^2.0|^3.0", "sebastian/recursion-context": "^1.0|^2.0|^3.0" }, "require-dev": { - "phpspec/phpspec": "^2.5|^3.2", + "phpspec/phpspec": "^2.5 || ^3.2", "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.8.x-dev" + "dev-master": "1.10.x-dev" } }, "autoload": { @@ -1019,20 +1019,20 @@ "spy", "stub" ], - "time": "2019-06-13T12:50:23+00:00" + "time": "2019-12-22T21:05:45+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "7.0.7", + "version": "7.0.10", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "7743bbcfff2a907e9ee4a25be13d0f8ec5e73800" + "reference": "f1884187926fbb755a9aaf0b3836ad3165b478bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/7743bbcfff2a907e9ee4a25be13d0f8ec5e73800", - "reference": "7743bbcfff2a907e9ee4a25be13d0f8ec5e73800", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f1884187926fbb755a9aaf0b3836ad3165b478bf", + "reference": "f1884187926fbb755a9aaf0b3836ad3165b478bf", "shasum": "" }, "require": { @@ -1041,7 +1041,7 @@ "php": "^7.2", "phpunit/php-file-iterator": "^2.0.2", "phpunit/php-text-template": "^1.2.1", - "phpunit/php-token-stream": "^3.1.0", + "phpunit/php-token-stream": "^3.1.1", "sebastian/code-unit-reverse-lookup": "^1.0.1", "sebastian/environment": "^4.2.2", "sebastian/version": "^2.0.1", @@ -1082,7 +1082,7 @@ "testing", "xunit" ], - "time": "2019-07-25T05:31:54+00:00" + "time": "2019-11-20T13:55:58+00:00" }, { "name": "phpunit/php-file-iterator", @@ -1122,8 +1122,8 @@ "authors": [ { "name": "Sebastian Bergmann", - "role": "lead", - "email": "sebastian@phpunit.de" + "email": "sebastian@phpunit.de", + "role": "lead" } ], "description": "FilterIterator implementation that filters files based on a list of suffixes.", @@ -1213,8 +1213,8 @@ "authors": [ { "name": "Sebastian Bergmann", - "role": "lead", - "email": "sebastian@phpunit.de" + "email": "sebastian@phpunit.de", + "role": "lead" } ], "description": "Utility class for timing", @@ -1226,16 +1226,16 @@ }, { "name": "phpunit/php-token-stream", - "version": "3.1.0", + "version": "3.1.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "e899757bb3df5ff6e95089132f32cd59aac2220a" + "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/e899757bb3df5ff6e95089132f32cd59aac2220a", - "reference": "e899757bb3df5ff6e95089132f32cd59aac2220a", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/995192df77f63a59e47f025390d2d1fdf8f425ff", + "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff", "shasum": "" }, "require": { @@ -1271,20 +1271,20 @@ "keywords": [ "tokenizer" ], - "time": "2019-07-25T05:29:42+00:00" + "time": "2019-09-17T06:23:10+00:00" }, { "name": "phpunit/phpunit", - "version": "8.3.4", + "version": "8.5.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "e31cce0cf4499c0ccdbbb211a3280d36ab341e36" + "reference": "7870c78da3c5e4883eaef36ae47853ebb3cb86f2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/e31cce0cf4499c0ccdbbb211a3280d36ab341e36", - "reference": "e31cce0cf4499c0ccdbbb211a3280d36ab341e36", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/7870c78da3c5e4883eaef36ae47853ebb3cb86f2", + "reference": "7870c78da3c5e4883eaef36ae47853ebb3cb86f2", "shasum": "" }, "require": { @@ -1307,7 +1307,7 @@ "sebastian/comparator": "^3.0.2", "sebastian/diff": "^3.0.2", "sebastian/environment": "^4.2.2", - "sebastian/exporter": "^3.1.0", + "sebastian/exporter": "^3.1.1", "sebastian/global-state": "^3.0.0", "sebastian/object-enumerator": "^3.0.3", "sebastian/resource-operations": "^2.0.1", @@ -1328,7 +1328,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "8.3-dev" + "dev-master": "8.5-dev" } }, "autoload": { @@ -1343,8 +1343,8 @@ "authors": [ { "name": "Sebastian Bergmann", - "role": "lead", - "email": "sebastian@phpunit.de" + "email": "sebastian@phpunit.de", + "role": "lead" } ], "description": "The PHP Unit Testing framework.", @@ -1354,7 +1354,7 @@ "testing", "xunit" ], - "time": "2019-08-11T06:56:55+00:00" + "time": "2019-12-25T14:49:39+00:00" }, { "name": "psr/http-factory", @@ -1414,12 +1414,12 @@ "source": { "type": "git", "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "ea693fa060702164985511acc3ceb5389c9ac761" + "reference": "44a677c8e06241a66409ae6e4820dc166fc09ab2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/ea693fa060702164985511acc3ceb5389c9ac761", - "reference": "ea693fa060702164985511acc3ceb5389c9ac761", + "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/44a677c8e06241a66409ae6e4820dc166fc09ab2", + "reference": "44a677c8e06241a66409ae6e4820dc166fc09ab2", "shasum": "" }, "conflict": { @@ -1440,9 +1440,9 @@ "composer/composer": "<=1-alpha.11", "contao-components/mediaelement": ">=2.14.2,<2.21.1", "contao/core": ">=2,<3.5.39", - "contao/core-bundle": ">=4,<4.4.39|>=4.5,<4.7.5", + "contao/core-bundle": ">=4,<4.4.46|>=4.5,<4.8.6", "contao/listing-bundle": ">=4,<4.4.8", - "contao/newsletter-bundle": ">=4,<4.1", + "datadog/dd-trace": ">=0.30,<0.30.2", "david-garcia/phpwhois": "<=4.3.1", "doctrine/annotations": ">=1,<1.2.7", "doctrine/cache": ">=1,<1.3.2|>=1.4,<1.4.2", @@ -1454,8 +1454,8 @@ "doctrine/mongodb-odm-bundle": ">=2,<3.0.1", "doctrine/orm": ">=2,<2.4.8|>=2.5,<2.5.1", "dompdf/dompdf": ">=0.6,<0.6.2", - "drupal/core": ">=7,<7.67|>=8,<8.6.16|>=8.7,<8.7.1|>8.7.3,<8.7.5", - "drupal/drupal": ">=7,<7.67|>=8,<8.6.16|>=8.7,<8.7.1|>8.7.3,<8.7.5", + "drupal/core": ">=7,<8.7.11|>=8.8,<8.8.1", + "drupal/drupal": ">=7,<8.7.11|>=8.8,<8.8.1", "erusev/parsedown": "<1.7.2", "ezsystems/ezplatform-admin-ui": ">=1.3,<1.3.5|>=1.4,<1.4.4", "ezsystems/ezpublish-kernel": ">=5.3,<5.3.12.1|>=5.4,<5.4.13.1|>=6,<6.7.9.1|>=6.8,<6.13.5.1|>=7,<7.2.4.1|>=7.3,<7.3.2.1", @@ -1485,9 +1485,9 @@ "laravel/framework": ">=4,<4.0.99|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.42|>=5.6,<5.6.30", "laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10", "league/commonmark": "<0.18.3", - "magento/magento1ce": "<1.9.4.1", - "magento/magento1ee": ">=1.9,<1.14.4.1", - "magento/product-community-edition": ">=2,<2.2.8|>=2.3,<2.3.1", + "magento/magento1ce": "<1.9.4.3", + "magento/magento1ee": ">=1,<1.14.4.3", + "magento/product-community-edition": ">=2,<2.2.10|>=2.3,<2.3.2-p.2", "monolog/monolog": ">=1.8,<1.12", "namshi/jose": "<2.2", "onelogin/php-saml": "<2.10.4", @@ -1508,8 +1508,9 @@ "propel/propel": ">=2-alpha.1,<=2-alpha.7", "propel/propel1": ">=1,<=1.7.1", "pusher/pusher-php-server": "<2.2.1", - "robrichards/xmlseclibs": ">=1,<3.0.2", + "robrichards/xmlseclibs": ">=1,<3.0.4", "sabre/dav": ">=1.6,<1.6.99|>=1.7,<1.7.11|>=1.8,<1.8.9", + "scheb/two-factor-bundle": ">=0,<3.26|>=4,<4.11", "sensiolabs/connect": "<4.2.3", "serluck/phpwhois": "<=4.2.6", "shopware/shopware": "<5.3.7", @@ -1522,7 +1523,7 @@ "silverstripe/userforms": "<3", "simple-updates/phpwhois": "<=1", "simplesamlphp/saml2": "<1.10.6|>=2,<2.3.8|>=3,<3.1.4", - "simplesamlphp/simplesamlphp": "<1.17.3", + "simplesamlphp/simplesamlphp": "<1.17.8", "simplesamlphp/simplesamlphp-module-infocard": "<1.0.1", "slim/slim": "<2.6", "smarty/smarty": "<3.1.33", @@ -1530,18 +1531,20 @@ "spoonity/tcpdf": "<6.2.22", "squizlabs/php_codesniffer": ">=1,<2.8.1|>=3,<3.0.1", "stormpath/sdk": ">=0,<9.9.99", + "studio-42/elfinder": "<2.1.48", "swiftmailer/swiftmailer": ">=4,<5.4.5", "sylius/admin-bundle": ">=1,<1.0.17|>=1.1,<1.1.9|>=1.2,<1.2.2", "sylius/grid": ">=1,<1.1.19|>=1.2,<1.2.18|>=1.3,<1.3.13|>=1.4,<1.4.5|>=1.5,<1.5.1", "sylius/grid-bundle": ">=1,<1.1.19|>=1.2,<1.2.18|>=1.3,<1.3.13|>=1.4,<1.4.5|>=1.5,<1.5.1", "sylius/sylius": ">=1,<1.1.18|>=1.2,<1.2.17|>=1.3,<1.3.12|>=1.4,<1.4.4", - "symfony/cache": ">=3.1,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", + "symfony/cache": ">=3.1,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8", "symfony/dependency-injection": ">=2,<2.0.17|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", "symfony/form": ">=2.3,<2.3.35|>=2.4,<2.6.12|>=2.7,<2.7.50|>=2.8,<2.8.49|>=3,<3.4.20|>=4,<4.0.15|>=4.1,<4.1.9|>=4.2,<4.2.1", "symfony/framework-bundle": ">=2,<2.3.18|>=2.4,<2.4.8|>=2.5,<2.5.2|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", - "symfony/http-foundation": ">=2,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", - "symfony/http-kernel": ">=2,<2.3.29|>=2.4,<2.5.12|>=2.6,<2.6.8", + "symfony/http-foundation": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8", + "symfony/http-kernel": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8", "symfony/intl": ">=2.7,<2.7.38|>=2.8,<2.8.31|>=3,<3.2.14|>=3.3,<3.3.13", + "symfony/mime": ">=4.3,<4.3.8", "symfony/phpunit-bridge": ">=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", "symfony/polyfill": ">=1,<1.10", "symfony/polyfill-php55": ">=1,<1.10", @@ -1552,11 +1555,12 @@ "symfony/security-core": ">=2.4,<2.6.13|>=2.7,<2.7.9|>=2.7.30,<2.7.32|>=2.8,<2.8.37|>=3,<3.3.17|>=3.4,<3.4.7|>=4,<4.0.7", "symfony/security-csrf": ">=2.4,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", "symfony/security-guard": ">=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", - "symfony/security-http": ">=2.3,<2.3.41|>=2.4,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", + "symfony/security-http": ">=2.3,<2.3.41|>=2.4,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.2.12|>=4.3,<4.3.8", "symfony/serializer": ">=2,<2.0.11", - "symfony/symfony": ">=2,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", + "symfony/symfony": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8", "symfony/translation": ">=2,<2.0.17", "symfony/validator": ">=2,<2.0.24|>=2.1,<2.1.12|>=2.2,<2.2.5|>=2.3,<2.3.3", + "symfony/var-exporter": ">=4.2,<4.2.12|>=4.3,<4.3.8", "symfony/web-profiler-bundle": ">=2,<2.3.19|>=2.4,<2.4.9|>=2.5,<2.5.4", "symfony/yaml": ">=2,<2.0.22|>=2.1,<2.1.7", "tecnickcom/tcpdf": "<6.2.22", @@ -1566,8 +1570,8 @@ "titon/framework": ">=0,<9.9.99", "truckersmp/phpwhois": "<=4.3.1", "twig/twig": "<1.38|>=2,<2.7", - "typo3/cms": ">=6.2,<6.2.30|>=7,<7.6.32|>=8,<8.7.27|>=9,<9.5.8", - "typo3/cms-core": ">=8,<8.7.27|>=9,<9.5.8", + "typo3/cms": ">=6.2,<6.2.30|>=7,<7.6.32|>=8,<8.7.30|>=9,<9.5.12|>=10,<10.2.1", + "typo3/cms-core": ">=8,<8.7.30|>=9,<9.5.12|>=10,<10.2.1", "typo3/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.10|>=3.1,<3.1.7|>=3.2,<3.2.7|>=3.3,<3.3.5", "typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4", "typo3/phar-stream-wrapper": ">=1,<2.1.1|>=3,<3.1.1", @@ -1621,7 +1625,7 @@ } ], "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it", - "time": "2018-03-07T15:45:44+00:00" + "time": "2019-12-26T14:16:40+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", @@ -1790,16 +1794,16 @@ }, { "name": "sebastian/environment", - "version": "4.2.2", + "version": "4.2.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "f2a2c8e1c97c11ace607a7a667d73d47c19fe404" + "reference": "464c90d7bdf5ad4e8a6aea15c091fec0603d4368" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/f2a2c8e1c97c11ace607a7a667d73d47c19fe404", - "reference": "f2a2c8e1c97c11ace607a7a667d73d47c19fe404", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/464c90d7bdf5ad4e8a6aea15c091fec0603d4368", + "reference": "464c90d7bdf5ad4e8a6aea15c091fec0603d4368", "shasum": "" }, "require": { @@ -1839,20 +1843,20 @@ "environment", "hhvm" ], - "time": "2019-05-05T09:05:15+00:00" + "time": "2019-11-20T08:46:58+00:00" }, { "name": "sebastian/exporter", - "version": "3.1.1", + "version": "3.1.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "06a9a5947f47b3029d76118eb5c22802e5869687" + "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/06a9a5947f47b3029d76118eb5c22802e5869687", - "reference": "06a9a5947f47b3029d76118eb5c22802e5869687", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/68609e1261d215ea5b21b7987539cbfbe156ec3e", + "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e", "shasum": "" }, "require": { @@ -1906,7 +1910,7 @@ "export", "exporter" ], - "time": "2019-08-11T12:43:14+00:00" + "time": "2019-09-14T09:02:43+00:00" }, { "name": "sebastian/global-state", @@ -2187,8 +2191,8 @@ "authors": [ { "name": "Sebastian Bergmann", - "role": "lead", - "email": "sebastian@phpunit.de" + "email": "sebastian@phpunit.de", + "role": "lead" } ], "description": "Collection of value objects that represent the types of the PHP type system", @@ -2318,16 +2322,16 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.12.0", + "version": "v1.13.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "550ebaac289296ce228a706d0867afc34687e3f4" + "reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/550ebaac289296ce228a706d0867afc34687e3f4", - "reference": "550ebaac289296ce228a706d0867afc34687e3f4", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/f8f0b461be3385e56d6de3dbb5a0df24c0c275e3", + "reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3", "shasum": "" }, "require": { @@ -2339,7 +2343,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.12-dev" + "dev-master": "1.13-dev" } }, "autoload": { @@ -2372,7 +2376,7 @@ "polyfill", "portable" ], - "time": "2019-08-06T08:03:45+00:00" + "time": "2019-11-27T13:56:44+00:00" }, { "name": "theseer/tokenizer", @@ -2407,8 +2411,8 @@ "authors": [ { "name": "Arne Blankerts", - "role": "Developer", - "email": "arne@blankerts.de" + "email": "arne@blankerts.de", + "role": "Developer" } ], "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", @@ -2416,31 +2420,29 @@ }, { "name": "webmozart/assert", - "version": "1.5.0", + "version": "1.6.0", "source": { "type": "git", "url": "https://github.com/webmozart/assert.git", - "reference": "88e6d84706d09a236046d686bbea96f07b3a34f4" + "reference": "573381c0a64f155a0d9a23f4b0c797194805b925" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/88e6d84706d09a236046d686bbea96f07b3a34f4", - "reference": "88e6d84706d09a236046d686bbea96f07b3a34f4", + "url": "https://api.github.com/repos/webmozart/assert/zipball/573381c0a64f155a0d9a23f4b0c797194805b925", + "reference": "573381c0a64f155a0d9a23f4b0c797194805b925", "shasum": "" }, "require": { "php": "^5.3.3 || ^7.0", "symfony/polyfill-ctype": "^1.8" }, + "conflict": { + "vimeo/psalm": "<3.6.0" + }, "require-dev": { "phpunit/phpunit": "^4.8.36 || ^7.5.13" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3-dev" - } - }, "autoload": { "psr-4": { "Webmozart\\Assert\\": "src/" @@ -2462,7 +2464,7 @@ "check", "validate" ], - "time": "2019-08-24T08:43:50+00:00" + "time": "2019-11-24T13:36:37+00:00" }, { "name": "zendframework/zend-coding-standard", @@ -2495,16 +2497,16 @@ }, { "name": "zendframework/zend-diactoros", - "version": "2.1.3", + "version": "2.2.1", "source": { "type": "git", "url": "https://github.com/zendframework/zend-diactoros.git", - "reference": "279723778c40164bcf984a2df12ff2c6ec5e61c1" + "reference": "de5847b068362a88684a55b0dbb40d85986cfa52" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-diactoros/zipball/279723778c40164bcf984a2df12ff2c6ec5e61c1", - "reference": "279723778c40164bcf984a2df12ff2c6ec5e61c1", + "url": "https://api.github.com/repos/zendframework/zend-diactoros/zipball/de5847b068362a88684a55b0dbb40d85986cfa52", + "reference": "de5847b068362a88684a55b0dbb40d85986cfa52", "shasum": "" }, "require": { @@ -2517,6 +2519,7 @@ "psr/http-message-implementation": "1.0" }, "require-dev": { + "ext-curl": "*", "ext-dom": "*", "ext-libxml": "*", "http-interop/http-factory-tests": "^0.5.0", @@ -2557,7 +2560,7 @@ "psr", "psr-7" ], - "time": "2019-07-10T16:13:25+00:00" + "time": "2019-11-13T19:16:13+00:00" }, { "name": "zendframework/zend-servicemanager", From 376b4bc752c7f785d3cbc6355fa02b8d4767acee Mon Sep 17 00:00:00 2001 From: Tsvetomir Lazarov Date: Mon, 7 Oct 2019 17:33:52 +0300 Subject: [PATCH 88/99] Implement validateClient in the ClientRepository --- src/Repository/Pdo/ClientRepository.php | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/Repository/Pdo/ClientRepository.php b/src/Repository/Pdo/ClientRepository.php index a2f2107..dc73035 100644 --- a/src/Repository/Pdo/ClientRepository.php +++ b/src/Repository/Pdo/ClientRepository.php @@ -10,6 +10,7 @@ namespace Zend\Expressive\Authentication\OAuth2\Repository\Pdo; +use League\OAuth2\Server\Entities\ClientEntityInterface; use League\OAuth2\Server\Repositories\ClientRepositoryInterface; use Zend\Expressive\Authentication\OAuth2\Entity\ClientEntity; @@ -32,17 +33,17 @@ public function getClientEntity( $sth->bindParam(':clientIdentifier', $clientIdentifier); if (false === $sth->execute()) { - return; + return null; } $row = $sth->fetch(); if (empty($row) || ! $this->isGranted($row, $grantType)) { - return; + return null; } if ($mustValidateSecret && (empty($row['secret']) || ! password_verify((string) $clientSecret, $row['secret'])) ) { - return; + return null; } return new ClientEntity($clientIdentifier, $row['name'], $row['redirect']); @@ -68,4 +69,18 @@ protected function isGranted(array $row, string $grantType = null) : bool return true; } } + + /** + * {@inheritDoc} + */ + public function validateClient($clientIdentifier, $clientSecret, $grantType) : bool + { + $client = $this->getClientEntity( + $clientIdentifier, + $grantType, + $clientSecret + ); + + return $client instanceof ClientEntityInterface; + } } From 51dc33ef4bd358fd10db7a6b8382c03c22d60499 Mon Sep 17 00:00:00 2001 From: Tsvetomir Lazarov Date: Mon, 7 Oct 2019 23:25:50 +0300 Subject: [PATCH 89/99] Change the ClientRepository::getClientEntity() implementation and re-write tests --- src/Repository/Pdo/ClientRepository.php | 80 ++++++++++++-------- test/Pdo/OAuth2PdoMiddlewareTest.php | 18 ++++- test/Repository/Pdo/ClientRepositoryTest.php | 41 +++++----- 3 files changed, 82 insertions(+), 57 deletions(-) diff --git a/src/Repository/Pdo/ClientRepository.php b/src/Repository/Pdo/ClientRepository.php index dc73035..498b3ab 100644 --- a/src/Repository/Pdo/ClientRepository.php +++ b/src/Repository/Pdo/ClientRepository.php @@ -21,39 +21,69 @@ class ClientRepository extends AbstractRepository implements ClientRepositoryInt /** * {@inheritDoc} */ - public function getClientEntity( - $clientIdentifier, - $grantType = null, - $clientSecret = null, - $mustValidateSecret = true - ) { - $sth = $this->pdo->prepare( - 'SELECT * FROM oauth_clients WHERE name = :clientIdentifier' - ); - $sth->bindParam(':clientIdentifier', $clientIdentifier); + public function getClientEntity($clientIdentifier) : ?ClientEntityInterface + { + $clientData = $this->getClientData($clientIdentifier); - if (false === $sth->execute()) { + if (empty($clientData)) { return null; } - $row = $sth->fetch(); - if (empty($row) || ! $this->isGranted($row, $grantType)) { + + return new ClientEntity( + $clientIdentifier, + $clientData['name'] ?? '', + $clientData['redirect'] ?? '', + ); + } + + /** + * {@inheritDoc} + */ + public function validateClient($clientIdentifier, $clientSecret, $grantType) : bool + { + $clientData = $this->getClientData($clientIdentifier); + + if (empty($clientData)) { + return false; + } + + if (! $this->isGranted($clientData, $grantType)) { + return false; + } + + if (empty($clientData['secret']) || ! password_verify((string) $clientSecret, $clientData['secret'])) { + return false; + } + + return true; + } + + protected function getClientData(string $clientIdentifier) : ?array + { + $statement = $this->pdo->prepare( + 'SELECT * FROM oauth_clients WHERE name = :clientIdentifier' + ); + $statement->bindParam(':clientIdentifier', $clientIdentifier); + + if ($statement->execute() === false) { return null; } - if ($mustValidateSecret - && (empty($row['secret']) || ! password_verify((string) $clientSecret, $row['secret'])) - ) { + $row = $statement->fetch(); + + if (empty($row)) { return null; } - return new ClientEntity($clientIdentifier, $row['name'], $row['redirect']); + return $row; } /** * Check the grantType for the client value, stored in $row * - * @param array $row + * @param array $row * @param string $grantType + * * @return bool */ protected function isGranted(array $row, string $grantType = null) : bool @@ -69,18 +99,4 @@ protected function isGranted(array $row, string $grantType = null) : bool return true; } } - - /** - * {@inheritDoc} - */ - public function validateClient($clientIdentifier, $clientSecret, $grantType) : bool - { - $client = $this->getClientEntity( - $clientIdentifier, - $grantType, - $clientSecret - ); - - return $client instanceof ClientEntityInterface; - } } diff --git a/test/Pdo/OAuth2PdoMiddlewareTest.php b/test/Pdo/OAuth2PdoMiddlewareTest.php index 5bfed5a..26d8bc1 100644 --- a/test/Pdo/OAuth2PdoMiddlewareTest.php +++ b/test/Pdo/OAuth2PdoMiddlewareTest.php @@ -12,6 +12,7 @@ use DateInterval; use League\OAuth2\Server\AuthorizationServer; +use League\OAuth2\Server\CodeChallengeVerifiers\S256Verifier; use League\OAuth2\Server\Grant\AuthCodeGrant; use League\OAuth2\Server\Grant\ClientCredentialsGrant; use League\OAuth2\Server\Grant\ImplicitGrant; @@ -64,6 +65,8 @@ class OAuth2PdoMiddlewareTest extends TestCase const PRIVATE_KEY = __DIR__ .'/../TestAsset/private.key'; const ENCRYPTION_KEY = 'T2x2+1OGrEzfS+01OUmwhOcJiGmE58UD1fllNn6CGcQ='; + const CODE_VERIFIER = 'dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk'; + /** @var AccessTokenRepository */ private $accessTokenRepository; @@ -269,6 +272,17 @@ public function testProcessGetAuthorizationCode() 'scope' => 'test', 'state' => $state ]; + + $codeVerifier = new S256Verifier(); + + $params['code_challenge_method'] = $codeVerifier->getMethod(); + $params['code_verifier'] = self::CODE_VERIFIER; + $params['code_challenge'] = strtr( + rtrim(base64_encode(hash('sha256', self::CODE_VERIFIER, true)), '='), + '+/', + '-_' + ); + $request = $this->buildServerRequest( 'GET', '/auth_code?' . http_build_query($params), @@ -324,8 +338,10 @@ public function testProcessFromAuthorizationCode(string $code) 'client_id' => 'client_test2', 'client_secret' => 'test', 'redirect_uri' => '/redirect', - 'code' => $code + 'code' => $code, + 'code_verifier' => self::CODE_VERIFIER, ]; + $request = $this->buildServerRequest( 'POST', '/access_token', diff --git a/test/Repository/Pdo/ClientRepositoryTest.php b/test/Repository/Pdo/ClientRepositoryTest.php index df7e137..b4e771e 100644 --- a/test/Repository/Pdo/ClientRepositoryTest.php +++ b/test/Repository/Pdo/ClientRepositoryTest.php @@ -36,10 +36,7 @@ public function testGetClientEntityReturnsNullIfStatementExecutionReturnsFalse() ->will([$statement, 'reveal']); $this->assertNull( - $this->repo ->getClientEntity( - 'client_id', - 'grant_type' - ) + $this->repo ->getClientEntity('client_id') ); } @@ -59,10 +56,7 @@ public function testGetClientEntityReturnsNullIfNoRowReturned() $client = $this->prophesize(ClientEntityInterface::class); $this->assertNull( - $this->repo ->getClientEntity( - 'client_id', - 'grant_type' - ) + $this->repo ->getClientEntity('client_id') ); } @@ -85,7 +79,7 @@ public function invalidGrants() /** * @dataProvider invalidGrants */ - public function testGetClientEntityReturnsNullIfRowIndicatesNotGranted(string $grantType, array $rowReturned) + public function testValidateClientReturnsFalseIfRowIndicatesNotGranted(string $grantType, array $rowReturned) { $statement = $this->prophesize(PDOStatement::class); $statement->bindParam(':clientIdentifier', 'client_id')->shouldBeCalled(); @@ -100,22 +94,23 @@ public function testGetClientEntityReturnsNullIfRowIndicatesNotGranted(string $g $client = $this->prophesize(ClientEntityInterface::class); - $this->assertNull( - $this->repo ->getClientEntity( + $this->assertFalse( + $this->repo ->validateClient( 'client_id', + '', $grantType ) ); } - public function testGetClientReturnsNullForNonMatchingClientSecret() + public function testValidateClientReturnsFalseForNonMatchingClientSecret() { $statement = $this->prophesize(PDOStatement::class); $statement->bindParam(':clientIdentifier', 'client_id')->shouldBeCalled(); $statement->execute()->will(function () use ($statement) { $statement->fetch()->willReturn([ 'password_client' => true, - 'secret' => 'unknown password', + 'secret' => 'bar', ]); return null; }); @@ -126,17 +121,16 @@ public function testGetClientReturnsNullForNonMatchingClientSecret() $client = $this->prophesize(ClientEntityInterface::class); - $this->assertNull( - $this->repo ->getClientEntity( + $this->assertFalse( + $this->repo ->validateClient( 'client_id', - 'password_client', - 'password', - true + 'foo', + 'password' ) ); } - public function testGetClientReturnsNullForEmptyClientSecret() + public function testValidateClientReturnsFalseForEmptyClientSecret() { $statement = $this->prophesize(PDOStatement::class); $statement->bindParam(':clientIdentifier', 'client_id')->shouldBeCalled(); @@ -154,12 +148,11 @@ public function testGetClientReturnsNullForEmptyClientSecret() $client = $this->prophesize(ClientEntityInterface::class); - $this->assertNull( - $this->repo ->getClientEntity( + $this->assertFalse( + $this->repo ->validateClient( 'client_id', - 'password_client', - 'password', - true + 'foo', + 'password' ) ); } From 8597adc16fba0fe79c9d4a2b405ad3e5addaf862 Mon Sep 17 00:00:00 2001 From: Tsvetomir Lazarov Date: Mon, 7 Oct 2019 23:27:04 +0300 Subject: [PATCH 90/99] Change the copyright year to 2019 in the docblock of changed files --- src/Repository/Pdo/ClientRepository.php | 2 +- test/Pdo/OAuth2PdoMiddlewareTest.php | 2 +- test/Repository/Pdo/ClientRepositoryTest.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Repository/Pdo/ClientRepository.php b/src/Repository/Pdo/ClientRepository.php index 498b3ab..0c95f8a 100644 --- a/src/Repository/Pdo/ClientRepository.php +++ b/src/Repository/Pdo/ClientRepository.php @@ -1,7 +1,7 @@ Date: Mon, 7 Oct 2019 23:38:59 +0300 Subject: [PATCH 91/99] Remove trailing comma from constructor call, causing builds to fail on PHP < 7.3 --- src/Repository/Pdo/ClientRepository.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Repository/Pdo/ClientRepository.php b/src/Repository/Pdo/ClientRepository.php index 0c95f8a..285da6d 100644 --- a/src/Repository/Pdo/ClientRepository.php +++ b/src/Repository/Pdo/ClientRepository.php @@ -32,7 +32,7 @@ public function getClientEntity($clientIdentifier) : ?ClientEntityInterface return new ClientEntity( $clientIdentifier, $clientData['name'] ?? '', - $clientData['redirect'] ?? '', + $clientData['redirect'] ?? '' ); } From a5f631e52d479533f4b0e5e42eb3d2254fb997fd Mon Sep 17 00:00:00 2001 From: Tsvetomir Lazarov Date: Mon, 7 Oct 2019 23:49:57 +0300 Subject: [PATCH 92/99] Add tests for more complete code coverage for the ClientRepository --- test/Repository/Pdo/ClientRepositoryTest.php | 62 ++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/test/Repository/Pdo/ClientRepositoryTest.php b/test/Repository/Pdo/ClientRepositoryTest.php index 78a2659..6a12c4e 100644 --- a/test/Repository/Pdo/ClientRepositoryTest.php +++ b/test/Repository/Pdo/ClientRepositoryTest.php @@ -60,6 +60,44 @@ public function testGetClientEntityReturnsNullIfNoRowReturned() ); } + public function testGetClientEntityReturnsCorrectEntity() + { + $name = 'foo'; + $redirect = 'bar'; + + $statement = $this->prophesize(PDOStatement::class); + $statement->bindParam(':clientIdentifier', 'client_id')->shouldBeCalled(); + $statement->execute()->will(function () use ($statement, $name, $redirect) { + $statement->fetch()->willReturn([ + 'name' => $name, + 'redirect' => $redirect, + ]); + return null; + }); + + $this->pdo + ->prepare(Argument::containingString('SELECT * FROM oauth_clients')) + ->will([$statement, 'reveal']); + + $this->prophesize(ClientEntityInterface::class); + + /** @var ClientEntityInterface $client */ + $client = $this->repo->getClientEntity('client_id'); + + $this->assertInstanceOf( + ClientEntityInterface::class, + $client + ); + $this->assertEquals( + $name, + $client->getName() + ); + $this->assertEquals( + [$redirect], + $client->getRedirectUri() + ); + } + public function invalidGrants() { return [ @@ -76,6 +114,30 @@ public function invalidGrants() ]; } + public function testValidateClientReturnsFalseIfNoRowReturned() + { + $statement = $this->prophesize(PDOStatement::class); + $statement->bindParam(':clientIdentifier', 'client_id')->shouldBeCalled(); + $statement->execute()->will(function () use ($statement) { + $statement->fetch()->willReturn([]); + return null; + }); + + $this->pdo + ->prepare(Argument::containingString('SELECT * FROM oauth_clients')) + ->will([$statement, 'reveal']); + + $client = $this->prophesize(ClientEntityInterface::class); + + $this->assertFalse( + $this->repo->validateClient( + 'client_id', + '', + 'password' + ) + ); + } + /** * @dataProvider invalidGrants */ From e5abc57f863aea75f94f2d816ff3521cf6fcdb4f Mon Sep 17 00:00:00 2001 From: Tsvetomir Lazarov Date: Sun, 13 Oct 2019 02:37:55 +0300 Subject: [PATCH 93/99] Change ClientRepository::getClientData() method visibility to "private" --- src/Repository/Pdo/ClientRepository.php | 40 ++++++++++++------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/Repository/Pdo/ClientRepository.php b/src/Repository/Pdo/ClientRepository.php index 285da6d..1dcf596 100644 --- a/src/Repository/Pdo/ClientRepository.php +++ b/src/Repository/Pdo/ClientRepository.php @@ -58,26 +58,6 @@ public function validateClient($clientIdentifier, $clientSecret, $grantType) : b return true; } - protected function getClientData(string $clientIdentifier) : ?array - { - $statement = $this->pdo->prepare( - 'SELECT * FROM oauth_clients WHERE name = :clientIdentifier' - ); - $statement->bindParam(':clientIdentifier', $clientIdentifier); - - if ($statement->execute() === false) { - return null; - } - - $row = $statement->fetch(); - - if (empty($row)) { - return null; - } - - return $row; - } - /** * Check the grantType for the client value, stored in $row * @@ -99,4 +79,24 @@ protected function isGranted(array $row, string $grantType = null) : bool return true; } } + + private function getClientData(string $clientIdentifier) : ?array + { + $statement = $this->pdo->prepare( + 'SELECT * FROM oauth_clients WHERE name = :clientIdentifier' + ); + $statement->bindParam(':clientIdentifier', $clientIdentifier); + + if ($statement->execute() === false) { + return null; + } + + $row = $statement->fetch(); + + if (empty($row)) { + return null; + } + + return $row; + } } From 7b0fa293aa079a52f4dcfb340e56eba27e73cf14 Mon Sep 17 00:00:00 2001 From: Tsvetomir Lazarov Date: Sun, 13 Oct 2019 02:39:10 +0300 Subject: [PATCH 94/99] Change the copyright year to 2017-2019 in the docblock of changed files --- src/Repository/Pdo/ClientRepository.php | 2 +- test/Pdo/OAuth2PdoMiddlewareTest.php | 2 +- test/Repository/Pdo/ClientRepositoryTest.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Repository/Pdo/ClientRepository.php b/src/Repository/Pdo/ClientRepository.php index 1dcf596..83597a0 100644 --- a/src/Repository/Pdo/ClientRepository.php +++ b/src/Repository/Pdo/ClientRepository.php @@ -1,7 +1,7 @@ Date: Sat, 28 Dec 2019 14:51:52 -0600 Subject: [PATCH 95/99] docs: adds CHANGELOG entry for #69 --- CHANGELOG.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3223d73..1235dcb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,28 @@ All notable changes to this project will be documented in this file, in reverse chronological order by release. +## 2.0.0 - TBD + +### Added + +- Nothing. + +### Changed + +- [#69](https://github.com/zendframework/zend-expressive-authentication-oauth2/pull/69) updates the minimum supported version of league/oauth-server to ^8.0. + +### Deprecated + +- Nothing. + +### Removed + +- Nothing. + +### Fixed + +- Nothing. + ## 1.3.0 - 2019-12-28 ### Added From be022bd58f4817bdf4e075177c6506c25f949666 Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Sat, 28 Dec 2019 14:52:47 -0600 Subject: [PATCH 96/99] 2.0.0 readiness - Updates branch aliases: - dev-master => 2.0.x-dev - dev-develop => 2.1.x-dev - Updates CHANGELOG - Adds 2.0.0 section - Sets date for 2.0.0 release --- CHANGELOG.md | 2 +- composer.json | 4 ++-- composer.lock | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1235dcb..8af8100 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to this project will be documented in this file, in reverse chronological order by release. -## 2.0.0 - TBD +## 2.0.0 - 2019-12-28 ### Added diff --git a/composer.json b/composer.json index 733c754..180b8d4 100644 --- a/composer.json +++ b/composer.json @@ -53,8 +53,8 @@ }, "extra": { "branch-alias": { - "dev-master": "1.3.x-dev", - "dev-develop": "2.0.x-dev" + "dev-master": "2.0.x-dev", + "dev-develop": "2.1.x-dev" }, "zf": { "config-provider": "Zend\\Expressive\\Authentication\\OAuth2\\ConfigProvider" diff --git a/composer.lock b/composer.lock index f7a6268..1915661 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "49e1aaaedd3215a18326b2b91a354874", + "content-hash": "607e2fc1e526e325c6d9b176d6250da4", "packages": [ { "name": "defuse/php-encryption", From 2a8417a11b6c631974a3a5b99d8375c4ed164da3 Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Sat, 28 Dec 2019 14:54:41 -0600 Subject: [PATCH 97/99] Bumped version to 2.0.1 --- CHANGELOG.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8af8100..7d0ddb1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,28 @@ All notable changes to this project will be documented in this file, in reverse chronological order by release. +## 2.0.1 - TBD + +### Added + +- Nothing. + +### Changed + +- Nothing. + +### Deprecated + +- Nothing. + +### Removed + +- Nothing. + +### Fixed + +- Nothing. + ## 2.0.0 - 2019-12-28 ### Added From b087dd64dd4aaadd86b1c2faf4a57ad727a8bfae Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Tue, 31 Dec 2019 14:53:13 -0600 Subject: [PATCH 98/99] Marking package as abandoned --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4fd5d06..0f6f5fc 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ # OAuth2 server middleware for Expressive and PSR-7 applications +> ## Repository abandoned 2019-12-31 +> +> This repository has moved to mezzio/mezzio-authentication-oauth2. + [![Build Status](https://secure.travis-ci.org/zendframework/zend-expressive-authentication-oauth2.svg?branch=master)](https://secure.travis-ci.org/zendframework/zend-expressive-authentication-oauth2) [![Coverage Status](https://coveralls.io/repos/github/zendframework/zend-expressive-authentication-oauth2/badge.svg?branch=master)](https://coveralls.io/github/zendframework/zend-expressive-authentication-oauth2?branch=master) @@ -34,4 +38,4 @@ Browse the documentation online at https://docs.zendframework.com/zend-expressiv * [Issues](https://github.com/zendframework/zend-expressive-authentication-oauth2/issues/) * [Chat](https://zendframework-slack.herokuapp.com/) -* [Forum](https://discourse.zendframework.com/) +* [Forum](https://discourse.zendframework.com/) \ No newline at end of file From 125acf0b898fe890b4c4b55541a12059980f2d89 Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Mon, 20 Jan 2020 11:41:24 -0600 Subject: [PATCH 99/99] Link to new repository --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0f6f5fc..aaa8e09 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ > ## Repository abandoned 2019-12-31 > -> This repository has moved to mezzio/mezzio-authentication-oauth2. +> This repository has moved to [mezzio/mezzio-authentication-oauth2](https://github.com/mezzio/mezzio-authentication-oauth2). [![Build Status](https://secure.travis-ci.org/zendframework/zend-expressive-authentication-oauth2.svg?branch=master)](https://secure.travis-ci.org/zendframework/zend-expressive-authentication-oauth2) [![Coverage Status](https://coveralls.io/repos/github/zendframework/zend-expressive-authentication-oauth2/badge.svg?branch=master)](https://coveralls.io/github/zendframework/zend-expressive-authentication-oauth2?branch=master) @@ -38,4 +38,4 @@ Browse the documentation online at https://docs.zendframework.com/zend-expressiv * [Issues](https://github.com/zendframework/zend-expressive-authentication-oauth2/issues/) * [Chat](https://zendframework-slack.herokuapp.com/) -* [Forum](https://discourse.zendframework.com/) \ No newline at end of file +* [Forum](https://discourse.zendframework.com/)