From 1f5caae50903bd48ef19efec1e9debabd4b64a4d Mon Sep 17 00:00:00 2001 From: "Charles J. C. Elling" Date: Thu, 21 Mar 2019 19:31:35 -0600 Subject: [PATCH 1/4] Add event dispatch for easier customization --- README.md | 10 +- composer.json | 3 +- lib/Event/GenerateTokenEvent.php | 125 +++++++++++++++++ lib/Event/PostGrantAccessTokenEvent.php | 57 ++++++++ lib/Event/PostGrantAuthorizationEvent.php | 56 ++++++++ lib/Event/PreGrantAccessTokenEvent.php | 131 ++++++++++++++++++ lib/Event/PreGrantAuthorizationEvent.php | 88 ++++++++++++ .../GenerateRandomTokenListener.php | 40 ++++++ lib/OAuth2.php | 104 ++++++++++++-- lib/OAuth2Events.php | 87 ++++++++++++ tests/Fixtures/OAuth2EventSubscriberStub.php | 84 +++++++++++ tests/OAuth2EventTest.php | 64 +++++++++ 12 files changed, 838 insertions(+), 11 deletions(-) create mode 100644 lib/Event/GenerateTokenEvent.php create mode 100644 lib/Event/PostGrantAccessTokenEvent.php create mode 100644 lib/Event/PostGrantAuthorizationEvent.php create mode 100644 lib/Event/PreGrantAccessTokenEvent.php create mode 100644 lib/Event/PreGrantAuthorizationEvent.php create mode 100644 lib/EventListener/GenerateRandomTokenListener.php create mode 100644 lib/OAuth2Events.php create mode 100644 tests/Fixtures/OAuth2EventSubscriberStub.php create mode 100644 tests/OAuth2EventTest.php diff --git a/README.md b/README.md index 1a25f19..de5e805 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,15 @@ This version of oauth2-php is a fork of https://github.com/quizlet/oauth2-php wi - Uses [HttpFoundation](https://github.com/symfony/HttpFoundation) Request and Response for input/output - More testable design - Better test coverage - + - Event dispatch for easier customization + - Use the *oauth2.pre.grant.authorization* event to modify the autorization parameters + - Use the *oauth2.generate.auth_code* event to customize the access token generation + - Use the *oauth2.post.grant.authorization* event to modify the autorization response variables + - Use the *oauth2.pre.grant.access_token* event to modify the grant access token parameters + - Use the *oauth2.generate.access_token* event to customize the access token generation + - Use the *oauth2.generate.refresh_token* event to customize the refresh token generation + - Use the *oauth2.post.grant.access_token* event to modify the grant access token response variables + (pull request is pending) https://github.com/quizlet/oauth2-php is a fork of http://code.google.com/p/oauth2-php/ updated against OAuth2.0 draft diff --git a/composer.json b/composer.json index d2fa88b..d562114 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,8 @@ ], "require": { "php": "^5.5.9|>=7.0.8", - "symfony/http-foundation": "~3.0|~4.0" + "symfony/http-foundation": "~3.0|~4.0", + "symfony/event-dispatcher": "~3.0|~4.0" }, "require-dev": { "phpunit/phpunit": "~4.0" diff --git a/lib/Event/GenerateTokenEvent.php b/lib/Event/GenerateTokenEvent.php new file mode 100644 index 0000000..3bad260 --- /dev/null +++ b/lib/Event/GenerateTokenEvent.php @@ -0,0 +1,125 @@ + + * + */ +class GenerateTokenEvent extends Event +{ + /** + * Client requesting the token + * + * @var IOAuth2Client $client + */ + protected $client; + + /** + * + * + * @var mixed $data + */ + protected $data; + + /** + * Scope of the token + * + * @var string|null + */ + protected $scope = null; + + /** + * Token lifetime + * + * @var int|null + */ + protected $token_lifetime = null; + + /** + * Generated token + * + * @var string|null + */ + protected $token = null; + + /** + * + * @param IOAuth2Client $client + * @param mixed $data + * @param string|null $scope + * @param int|null $token_lifetime + */ + public function __construct(IOAuth2Client $client, $data, $scope = null, $token_lifetime = null) + { + $this->client = $client; + $this->data = $data; + $this->scope = $scope; + $this->token_lifetime = $token_lifetime; + } + + /** + * + * @return IOAuth2Client + */ + public function getClient() + { + return $this->client; + } + + /** + * + * @return mixed + */ + public function getData() + { + return $this->data; + } + + + /** + * + * @return string|null + */ + public function getScope() + { + return $this->scope; + } + + /** + * + * @return number|null + */ + public function getToken_Lifetime() + { + return $this->token_lifetime; + } + + /** + * + * @return string|null + */ + public function getToken() + { + return $this->token; + } + + /** + * + * @param string|null $token + * @return self + */ + public function setToken($token) + { + $this->token = $token; + return $this; + } + + + +} + diff --git a/lib/Event/PostGrantAccessTokenEvent.php b/lib/Event/PostGrantAccessTokenEvent.php new file mode 100644 index 0000000..684b89f --- /dev/null +++ b/lib/Event/PostGrantAccessTokenEvent.php @@ -0,0 +1,57 @@ + + * + */ +class PostGrantAccessTokenEvent extends PreGrantAccessTokenEvent +{ + /** + * Access token variables + * + * @var array + */ + protected $token; + + /** + * + * @param array $token + * @param Request $request + * @param array $data + * @param array $input + * @param OAuth2Client $client + */ + public function __construct(array $token, Request $request, array $data=[], $input=[], OAuth2Client $client = null) + { + parent::__construct($request,$data, $input, $client); + $this->token = $token; + } + + /** + * Get the access token variables + * + * @return array + */ + public function getToken() + { + return $this->token; + } + + /** + * Set the access token variables + * + * @param array $token + * @return self + */ + public function setToken(array $token) + { + $this->token = $token; + return $this; + } +} \ No newline at end of file diff --git a/lib/Event/PostGrantAuthorizationEvent.php b/lib/Event/PostGrantAuthorizationEvent.php new file mode 100644 index 0000000..94778f8 --- /dev/null +++ b/lib/Event/PostGrantAuthorizationEvent.php @@ -0,0 +1,56 @@ + + * + */ +class PostGrantAuthorizationEvent extends PreGrantAuthorizationEvent +{ + + /** + * Result parameters + * + * @var array + */ + protected $result; + + /** + * + * @param array $result + * @param Request $request + * @param array $params + * @param boolean $isAuthorized + */ + public function __construct(array $result, Request $request, array $params, $isAuthorized) + { + parent::__construct($request, $params, $isAuthorized); + $this->result = $result; + } + + /** + * Get the result parameters + * + * @return mixed + */ + public function getResult() + { + return $this->result; + } + + /** + * Set the result parameters + * + * @param array $result + * @return self + */ + public function setResult(array $result) + { + $this->result = $result; + return $this; + } +} \ No newline at end of file diff --git a/lib/Event/PreGrantAccessTokenEvent.php b/lib/Event/PreGrantAccessTokenEvent.php new file mode 100644 index 0000000..0bf8dc6 --- /dev/null +++ b/lib/Event/PreGrantAccessTokenEvent.php @@ -0,0 +1,131 @@ + + * + */ +class PreGrantAccessTokenEvent extends Event +{ + /** + * HTTP request data + * @var Request + */ + protected $request; + + /** + * OAuth 2 request filtered data + * @var array + */ + protected $input; + + /** + * Request unfiltered data + * @var array + */ + protected $data; + + /** + * Client requesting the access token + * + * @var OAuth2Client + */ + protected $client; + + + /** + * + * @param Request $request + * @param array $data + * @param array $input + * @param OAuth2Client $client + */ + public function __construct(Request $request, array $data=[], $input=[], OAuth2Client $client = null) + { + $this->request = $request; + $this->input = $input; + $this->data = $data; + $this->client = $client; + } + + /** + * Get the HTTP request data + * + * @return \Symfony\Component\HttpFoundation\Request + */ + public function getRequest() + { + return $this->request; + } + + /** + * Get the request filtered data + * @return array + */ + public function getInput() + { + return $this->input; + } + + /** + * Get the request unfiltered data + * + * @return array + */ + public function getData() + { + return $this->data; + } + + /** + * Get the client requesting the access token + * + * @return \OAuth2\Model\OAuth2Client + */ + public function getClient() + { + return $this->client; + } + + /** + * Set request filtered data + * + * @param array $input + * @return self + */ + public function setInput($input) + { + $this->input = $input; + return $this; + } + + /** + * Set request unfiltered data + * + * @param array $data + * @return self + */ + public function setData($data) + { + $this->data = $data; + return $this; + } + + /** + * Set the client requesting the access token + * + * @param \OAuth2\Model\OAuth2Client $client + * @return self + */ + public function setClient($client) + { + $this->client = $client; + return $this; + } +} \ No newline at end of file diff --git a/lib/Event/PreGrantAuthorizationEvent.php b/lib/Event/PreGrantAuthorizationEvent.php new file mode 100644 index 0000000..5fbbbbe --- /dev/null +++ b/lib/Event/PreGrantAuthorizationEvent.php @@ -0,0 +1,88 @@ + + */ +class PreGrantAuthorizationEvent extends Event +{ + /** + * HTTP request data + * + * @var Request + */ + protected $request; + + /** + * OAuth 2 authorization data + * + * @var array + */ + protected $params; + + /** + * Is the client authorized by the user + * + * @var boolean + */ + protected $isAuthorized; + + /** + * + * @param Request $request + * @param array $params + * @param boolean $isAuthorized + */ + public function __construct(Request $request, array $params, $isAuthorized) + { + $this->request = $request; + $this->params = $params; + $this->isAuthorized = $isAuthorized; + } + /** + * Get the HTTP request data + * + * @return \Symfony\Component\HttpFoundation\Request + */ + public function getRequest() + { + return $this->request; + } + + /** + * Get the authorization data + * + * @return array + */ + public function getParams() + { + return $this->params; + } + + /** + * Is the client authorized by the user + * + * @return boolean + */ + public function isIsAuthorized() + { + return $this->isAuthorized; + } + + /** + * Set the authorization data + * + * @param array $params + * @return self + */ + public function setParams($params) + { + $this->params = $params; + return $this; + } +} \ No newline at end of file diff --git a/lib/EventListener/GenerateRandomTokenListener.php b/lib/EventListener/GenerateRandomTokenListener.php new file mode 100644 index 0000000..af1adaa --- /dev/null +++ b/lib/EventListener/GenerateRandomTokenListener.php @@ -0,0 +1,40 @@ + + * + */ +class GenerateRandomTokenListener +{ + /** + * Generate random token + * + * @param GenerateTokenEvent $event + */ + public function generateRandomToken(GenerateTokenEvent $event) + { + if (@file_exists('/dev/urandom')) { // Get 100 bytes of random data + $randomData = file_get_contents('/dev/urandom', false, null, 0, 100); + } elseif (function_exists('openssl_random_pseudo_bytes')) { // Get 100 bytes of pseudo-random data + $bytes = openssl_random_pseudo_bytes(100, $strong); + if (true === $strong && false !== $bytes) { + $randomData = $bytes; + } + } + // Last resort: mt_rand + if (empty($randomData)) { // Get 108 bytes of (pseudo-random, insecure) data + $randomData = mt_rand() . mt_rand() . mt_rand() . uniqid(mt_rand(), true) . microtime(true) . uniqid( + mt_rand(), + true + ); + } + + $token = rtrim(strtr(base64_encode(hash('sha256', $randomData)), '+/', '-_'), '='); + $event->setToken($token); + } +} \ No newline at end of file diff --git a/lib/OAuth2.php b/lib/OAuth2.php index b28d4c5..e4b116c 100644 --- a/lib/OAuth2.php +++ b/lib/OAuth2.php @@ -7,6 +7,14 @@ use OAuth2\Model\IOAuth2Client; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\EventDispatcher\EventDispatcher; +use OAuth2\Event\GenerateTokenEvent; +use OAuth2\Event\PreGrantAccessTokenEvent; +use OAuth2\Event\PostGrantAccessTokenEvent; +use OAuth2\Event\PreGrantAuthorizationEvent; +use OAuth2\Event\PostGrantAuthorizationEvent; +use OAuth2\EventListener\GenerateRandomTokenListener; /** * @mainpage @@ -32,6 +40,7 @@ * @author Aaron Parecki * @author Edison Wong * @author David Rochwerger + * @author Charles J. C. Elling * * @see http://code.google.com/p/oauth2-php/ * @see https://github.com/quizlet/oauth2-php @@ -46,6 +55,7 @@ * @author Updated to draft v10 by Aaron Parecki . * @author Debug, coding style clean up and documented by Edison Wong . * @author Refactored (including separating from raw POST/GET) and updated to draft v20 by David Rochwerger . + * @author Add event dispatch for easier customization by Charles J. C. Elling . */ class OAuth2 { @@ -61,6 +71,13 @@ class OAuth2 */ protected $storage; + /** + * Event dispatcher system + * + * @var EventDispatcherInterface + */ + protected $eventDispatcher; + /** * Keep track of the old refresh token. So we can unset * the old refresh tokens when a new one is issued. @@ -395,10 +412,16 @@ class OAuth2 * * @param IOAuth2Storage $storage * @param array $config An associative array as below of config options. See CONFIG_* constants. + * @param EventDispatcherInterface $eventDispatcher Event dispatcher system */ - public function __construct(IOAuth2Storage $storage, $config = array()) + public function __construct(IOAuth2Storage $storage, $config = array(), EventDispatcherInterface $eventDispatcher = null) { $this->storage = $storage; + + if($eventDispatcher === null) { + $eventDispatcher = new EventDispatcher(); + } + $this->eventDispatcher = $eventDispatcher; // Configuration options $this->setDefaultOptions(); @@ -805,6 +828,13 @@ public function grantAccessToken(Request $request = null) if (!$this->storage->checkRestrictedGrantType($client, $input["grant_type"])) { throw new OAuth2ServerException(Response::HTTP_BAD_REQUEST, self::ERROR_UNAUTHORIZED_CLIENT, 'The grant type is unauthorized for this client_id'); } + + // Trigger PRE_GRANT_ACCESS_TOKEN event + $event = new PreGrantAccessTokenEvent($request, $inputData, $input, $client); + $this->eventDispatcher->dispatch(OAuth2Events::PRE_GRANT_ACCESS_TOKEN, $event); + $inputData = $event->getData(); + $input = $event->getInput(); + $client = $event->getClient(); // Do the granting switch ($input["grant_type"]) { @@ -859,6 +889,12 @@ public function grantAccessToken(Request $request = null) } $token = $this->createAccessToken($client, $stored['data'], $scope, $stored['access_token_lifetime'], $stored['issue_refresh_token'], $stored['refresh_token_lifetime']); + + // Trigger POST_GRANT_ACCESS_TOKEN event + $event = new PostGrantAccessTokenEvent($token, $request, $inputData, $input, $client); + $this->eventDispatcher->dispatch(OAuth2Events::POST_GRANT_ACCESS_TOKEN, $event); + $token = $event->getToken(); + return new Response(json_encode($token), 200, $this->getJsonHeaders()); } @@ -1235,6 +1271,12 @@ public function finishClientAuthorization($isAuthorized, $data = null, Request $ $params += array( 'state' => null, ); + + // Trigger PRE_GRANT_AUTHORIZATION event + $event = new PreGrantAuthorizationEvent($request, $params, $isAuthorized); + $this->eventDispatcher->dispatch(OAuth2Events::PRE_GRANT_AUTHORIZATION,$event); + $params = $event->getParams(); + $isAuthorized = $event->isIsAuthorized(); $result = array(); @@ -1255,7 +1297,14 @@ public function finishClientAuthorization($isAuthorized, $data = null, Request $ $result[self::TRANSPORT_FRAGMENT] += $this->createAccessToken($params["client"], $data, $scope, null, false); } } - + + + // Trigger POST_GRANT_AUTHORIZATION event + $event = new PostGrantAuthorizationEvent($result, $request, $params, $isAuthorized); + $this->eventDispatcher->dispatch(OAuth2Events::POST_GRANT_AUTHORIZATION,$event); + $params = $event->getParams(); + $result = $event->getResult(); + return $this->createRedirectUriCallbackResponse($params["redirect_uri"], $result); } @@ -1333,9 +1382,22 @@ private function buildUri($uri, $params) */ public function createAccessToken(IOAuth2Client $client, $data, $scope = null, $access_token_lifetime = null, $issue_refresh_token = true, $refresh_token_lifetime = null) { + if($access_token_lifetime === null) { + $access_token_lifetime = $this->getVariable(self::CONFIG_ACCESS_LIFETIME); + } + + // Trigger GENERATE_ACCESS_TOKEN event + $event = new GenerateTokenEvent($client, $data, $scope, $access_token_lifetime); + $this->eventDispatcher->dispatch(OAuth2Events::GENERATE_ACCESS_TOKEN, $event); + + $accessToken = $event->getToken(); + if(empty($accessToken)) { + $accessToken = $this->genAccessToken(); //rollback to default access token generation + } + $token = array( - "access_token" => $this->genAccessToken(), - "expires_in" => ($access_token_lifetime ?: $this->getVariable(self::CONFIG_ACCESS_LIFETIME)), + "access_token" => $accessToken, + "expires_in" => $access_token_lifetime, "token_type" => $this->getVariable(self::CONFIG_TOKEN_TYPE), "scope" => $scope, ); @@ -1344,18 +1406,32 @@ public function createAccessToken(IOAuth2Client $client, $data, $scope = null, $ $token["access_token"], $client, $data, - time() + ($access_token_lifetime ?: $this->getVariable(self::CONFIG_ACCESS_LIFETIME)), + time() + $access_token_lifetime, $scope ); // Issue a refresh token also, if we support them if ($this->storage instanceof IOAuth2RefreshTokens && $issue_refresh_token === true) { - $token["refresh_token"] = $this->genAccessToken(); + + if($refresh_token_lifetime === null) { + $refresh_token_lifetime = $this->getVariable(self::CONFIG_REFRESH_LIFETIME); + } + + // Trigger GENERATE_REFRESH_TOKEN event + $event = new GenerateTokenEvent($client, $data, $scope, $refresh_token_lifetime); + $this->eventDispatcher->dispatch(OAuth2Events::GENERATE_REFRESH_TOKEN, $event); + + $refreshToken = $event->getToken(); + if(empty($refreshToken)) { + $refreshToken = $this->genAccessToken(); //rollback to default refresh token generation + } + + $token["refresh_token"] = $refreshToken; $this->storage->createRefreshToken( $token["refresh_token"], $client, $data, - time() + ($refresh_token_lifetime ?: $this->getVariable(self::CONFIG_REFRESH_LIFETIME)), + time() + $refresh_token_lifetime, $scope ); @@ -1392,13 +1468,23 @@ public function createAccessToken(IOAuth2Client $client, $data, $scope = null, $ */ private function createAuthCode(IOAuth2Client $client, $data, $redirectUri, $scope = null) { - $code = $this->genAuthCode(); + $auth_code_lifetime = $this->getVariable(self::CONFIG_AUTH_LIFETIME); + + // Trigger GENERATE_AUTH_CODE event + $event = new GenerateTokenEvent($client, $data, $scope, $auth_code_lifetime); + $this->eventDispatcher->dispatch(OAuth2Events::GENERATE_AUTH_CODE, $event); + + $code = $event->getToken(); + if(empty($code)) { + $code = $this->genAuthCode(); //rollback to default access code generation + } + $this->storage->createAuthCode( $code, $client, $data, $redirectUri, - time() + $this->getVariable(self::CONFIG_AUTH_LIFETIME), + time() + $auth_code_lifetime, $scope ); diff --git a/lib/OAuth2Events.php b/lib/OAuth2Events.php new file mode 100644 index 0000000..55095c3 --- /dev/null +++ b/lib/OAuth2Events.php @@ -0,0 +1,87 @@ + + */ +class OAuth2Events +{ + /** + * The PRE_GRANT_AUTHORIZATION event occurs after the user autentication and client autorization, + * but before the auth code generation. + * + * This allows to modify the autorization parameters + * + * @Event(PreGrantAuthorizationEvent::class) + * @var string + */ + const PRE_GRANT_AUTHORIZATION = "oauth2.pre.grant.authorization"; + + /** + * The GENERATE_AUTH_CODE event occurs during the auth code generation. + * + * This allows to overwrite the auth code generation + * + * @Event(GenerateTokenEvent::class) + * @var string + */ + const GENERATE_AUTH_CODE = 'oauth2.generate.auth_code'; + + /** + * The POST_GRANT_AUTHORIZATION event occurs after the auth code generation. + * + * This allows to modify the autorization response variables + * + * @Event(PostGrantAuthorizationEvent::class) + * @var string + */ + const POST_GRANT_AUTHORIZATION = "oauth2.post.grant.authorization"; + + /** + * The PRE_GRANT_ACCESS_TOKEN event occurs before the access token generation. + * + * This allows to modify the grant access token parameters + * + * @Event(PreGrantAccessTokenEvent::class) + * @var string + */ + const PRE_GRANT_ACCESS_TOKEN = "oauth2.pre.grant.access_token"; + + /** + * The GENERATE_ACCESS_TOKEN event occurs during the access token generation. + * + * This allows to overwrite the access token generation + * + * @Event(GenerateTokenEvent::class) + * @var string + */ + const GENERATE_ACCESS_TOKEN = 'oauth2.generate.access_token'; + + /** + * The GENERATE_REFRESH_TOKEN event occurs during the refresh token generation. + * + * This allows to overwrite the refresh token generation + * + * @Event(GenerateTokenEvent::class) + * @var string + */ + const GENERATE_REFRESH_TOKEN = 'oauth2.generate.refresh_token'; + + /** + * The POST_GRANT_ACCESS_TOKEN event occurs after the access token generation. + * + * This allows to modify the grant access token response variables + * + * @Event(PostGrantAccessTokenEvent::class) + * @var string + */ + const POST_GRANT_ACCESS_TOKEN = "oauth2.post.grant.access_token"; +} \ No newline at end of file diff --git a/tests/Fixtures/OAuth2EventSubscriberStub.php b/tests/Fixtures/OAuth2EventSubscriberStub.php new file mode 100644 index 0000000..44194fd --- /dev/null +++ b/tests/Fixtures/OAuth2EventSubscriberStub.php @@ -0,0 +1,84 @@ + + */ +class OAuth2EventSubscriberStub implements EventSubscriberInterface +{ + protected $events = [ + OAuth2Events::PRE_GRANT_AUTHORIZATION => false, + OAuth2Events::GENERATE_AUTH_CODE => false, + OAuth2Events::POST_GRANT_AUTHORIZATION => false, + OAuth2Events::PRE_GRANT_ACCESS_TOKEN => false, + OAuth2Events::GENERATE_ACCESS_TOKEN => false, + OAuth2Events::GENERATE_REFRESH_TOKEN => false, + OAuth2Events::POST_GRANT_ACCESS_TOKEN => false, + ]; + + public static function getSubscribedEvents() + { + return [ + OAuth2Events::PRE_GRANT_AUTHORIZATION => 'preGrantAuthorization', + OAuth2Events::GENERATE_AUTH_CODE => 'generateAuthCode', + OAuth2Events::POST_GRANT_AUTHORIZATION => 'postGrantAuthorization', + OAuth2Events::PRE_GRANT_ACCESS_TOKEN => 'preGrantAccessToken', + OAuth2Events::GENERATE_ACCESS_TOKEN => 'generateAccessToken', + OAuth2Events::GENERATE_REFRESH_TOKEN => 'generateRefreshToken', + OAuth2Events::POST_GRANT_ACCESS_TOKEN => 'postGrantAccessToken', + ]; + } + + public function preGrantAuthorization(PreGrantAuthorizationEvent $event) + { + $this->events[OAuth2Events::PRE_GRANT_AUTHORIZATION] = true; + } + + public function generateAuthCode(GenerateTokenEvent $event) + { + $this->events[OAuth2Events::GENERATE_AUTH_CODE] = true; + } + + public function postGrantAuthorization(PostGrantAuthorizationEvent $event) + { + $this->events[OAuth2Events::POST_GRANT_AUTHORIZATION] = true; + } + + public function preGrantAccessToken(PreGrantAccessTokenEvent $event) + { + $this->events[OAuth2Events::PRE_GRANT_ACCESS_TOKEN] = true; + } + + public function generateAccessToken(GenerateTokenEvent $event) + { + $this->events[OAuth2Events::GENERATE_ACCESS_TOKEN] = true; + } + + public function generateRefreshToken(GenerateTokenEvent $event) + { + $this->events[OAuth2Events::GENERATE_REFRESH_TOKEN] = true; + } + + public function postGrantAccessToken(PostGrantAccessTokenEvent $event) + { + $this->events[OAuth2Events::POST_GRANT_ACCESS_TOKEN] = true; + } + + /** + * @return array + */ + public function getEvents() + { + return $this->events; + } +} \ No newline at end of file diff --git a/tests/OAuth2EventTest.php b/tests/OAuth2EventTest.php new file mode 100644 index 0000000..a2383ae --- /dev/null +++ b/tests/OAuth2EventTest.php @@ -0,0 +1,64 @@ + + */ +class OAuth2EventTest extends \PHPUnit_Framework_TestCase +{ + /** + * Test event triggering in default flow + * + */ + public function testEventsTriggered() + { + $stub = new OAuth2GrantCodeStub(); + $stub->addClient(new OAuth2Client('blah', 'foo', ['http://www.example.com/'])); + $eventDispatcher = new EventDispatcher(); + $subscriber=new OAuth2EventSubscriberStub(); + $eventDispatcher->addSubscriber($subscriber); + $oauth2 = new OAuth2($stub, [], $eventDispatcher); + + $data = new \stdClass; + + $oauth2->finishClientAuthorization(true, $data, new Request([ + 'client_id' => 'blah', + 'redirect_uri' => 'http://www.example.com/?foo=bar', + 'response_type' => 'code', + 'state' => '42', + ])); + + $code = $stub->getLastAuthCode(); + + $inputData = [ + 'grant_type' => OAuth2::GRANT_TYPE_AUTH_CODE, + 'client_id' => 'blah', + 'client_secret' => 'foo', + 'redirect_uri' => 'http://www.example.com/?foo=bars', + 'code'=> $code->getToken(), + ]; + $request = new Request($inputData); + + // Grant an access token with the auth code + $oauth2->grantAccessToken($request); + + $events = $subscriber->getEvents(); + $this->assertTrue($events[OAuth2Events::PRE_GRANT_AUTHORIZATION], "preGrantAuthorization not triggered"); + $this->assertTrue($events[OAuth2Events::GENERATE_AUTH_CODE], "generateAuthCode not triggered"); + $this->assertTrue($events[OAuth2Events::POST_GRANT_AUTHORIZATION], "postGrantAuthorization not triggered"); + $this->assertTrue($events[OAuth2Events::PRE_GRANT_ACCESS_TOKEN], "preGrantAccessToken not triggered"); + $this->assertTrue($events[OAuth2Events::GENERATE_ACCESS_TOKEN], "generateAccessToken not triggered"); + $this->assertTrue($events[OAuth2Events::GENERATE_REFRESH_TOKEN], "generateRefreshToken not triggered"); + $this->assertTrue($events[OAuth2Events::POST_GRANT_ACCESS_TOKEN], "postGrantAccessToken not triggered"); + } +} \ No newline at end of file From 8e23de620eca2b0f68f9568c42f786aa922c8563 Mon Sep 17 00:00:00 2001 From: "Charles J. C. Elling" Date: Fri, 22 Mar 2019 11:13:18 -0600 Subject: [PATCH 2/4] Update .travis.yml Allow HHVM failure. --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index 6c9d90a..bc61e44 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,8 +6,13 @@ php: - 7.0 - 7.1 - 7.2 + - 7.3 - hhvm +matrix: + allow_failures: + - php: hhvm + install: - composer install From d0d48ccc980e51f85ab1f76d4e2dd6ee2d2bf241 Mon Sep 17 00:00:00 2001 From: "Charles J. C. Elling" Date: Tue, 31 Mar 2020 13:23:13 -0600 Subject: [PATCH 3/4] Compatibilidad con php 5.5 y 5.6 --- lib/OAuth2.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/OAuth2.php b/lib/OAuth2.php index 99dd5a0..31824b3 100644 --- a/lib/OAuth2.php +++ b/lib/OAuth2.php @@ -1538,7 +1538,7 @@ protected function validateRedirectUri($inputUri, $storedUris) protected function dispatch($eventName, $event = null) { $method = new \ReflectionMethod(EventDispatcher::class,"dispatch"); $parameters =$method->getParameters(); - if($parameters[0]->getType() == "object") { + if($parameters[0]->getName() == "event") { $this->eventDispatcher->dispatch($event, $eventName); } else { $this->eventDispatcher->dispatch($eventName, $event); From 5dd3c5f074e9f61b78a919ebfdf6fde394adca11 Mon Sep 17 00:00:00 2001 From: "Charles J. C. Elling" Date: Tue, 31 Mar 2020 13:33:40 -0600 Subject: [PATCH 4/4] Remove travis test for php 7.4 --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 96921d1..325eff8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,6 @@ php: - 7.1 - 7.2 - 7.3 - - 7.4 install: - composer install