Skip to content

Commit

Permalink
Merge pull request #16 from zf-fr/evm
Browse files Browse the repository at this point in the history
Move the EVM to the ZfrOAuth2
  • Loading branch information
bakura10 committed May 14, 2014
2 parents 68ca5f1 + 9bfb6fa commit 6938b06
Show file tree
Hide file tree
Showing 11 changed files with 499 additions and 4 deletions.
89 changes: 89 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,3 +148,92 @@ if (!$token = $resourceServer->getAccessToken($request, ['write']) {

ZfrOAuth2Server is built to be used with Doctrine (either ORM or ODM). Out of the box, it provides ORM mapping for
Doctrine (in the `config/doctrine` folder).

### Event manager

There are a lot of use cases where you would like to execute specific code when a token is created (or when it
could not be created). Such use cases include: log login, modify generic OAuth2 response to include additional fields...

To that extent, ZfrOAuth2 trigger various events in the `AuthorizationServer`. Four events are triggered:

* `ZfrOAuth2\Server\Event\AuthorizationCodeEvent::EVENT_CODE_CREATED`: event that is triggered when the auth code has
been properly created and persisted.
* `ZfrOAuth2\Server\Event\AuthorizationCodeEvent::EVENT_CODE_FAILED`: event that is triggered when an error has occurred (
wrong credentials, missing grant...).
* `ZfrOAuth2\Server\Event\TokenEvent::EVENT_TOKEN_CREATED`: event that is triggered when the access token has
been properly created and persisted.
* `ZfrOAuth2\Server\Event\TokenEvent::EVENT_TOKEN_FAILED`: event that is triggered when an error has occurred (
wrong credentials, missing grant...).

In both cases, the `TokenEvent` or `AuthorizationCodeEvent` event lets you access to the request, the response body
and the access token/authorization code (if available).

Here is an example:

#### Zend Framework 2 users

Zend Framework 2 users can take advantage of the shared event manager, and attach listeners in their Module.php
class as shown below:

```php
use ZfrOAuth2\Server\Event\TokenEvent;

class Module
{
public function onBootstrap(EventInterface $event)
{
/* @var \Zend\Mvc\Application $application */
$application = $event->getTarget();
$eventManager = $application->getEventManager();
$sharedManager = $eventManager->getSharedManager();

$sharedManager->attach(
'ZfrOAuth2\Server\AuthorizationServer',
TokenEvent::EVENT_TOKEN_CREATED,
[$this, 'tokenCreated']
);

$sharedManager->attach(
'ZfrOAuth2\Server\AuthorizationServer',
TokenEvent::EVENT_TOKEN_FAILED,
[$this, 'tokenFailed']
);
}

public function tokenCreated(TokenEvent $event)
{
// We can log the access token
$accessToken = $event->getAccessToken();
// ...

// Or we can alter the response body, if we need to
$body = $event->getResponseBody();
$body['custom_field'] = 'bar';

// Update the body
$event->setResponseBody($body);
}

public function tokenFailed(TokenEvent $event)
{
// We can inspect the response to know what happen and log the failure
$body = $event->getResponseBody();
}
}
```

#### Other users

For other users, you can manually retrieve the event manager from the authorization server, and attach
your listener there:

```php
use ZfrOAuth2\Server\Event\TokenEvent;

$eventManager = $authorizationServer->getEventManager();
$eventManager->attach(TokenEvent::EVENT_TOKEN_CREATED, function(TokenEvent $event) {
// Do things
}
```

You are responsible to wire everything in your application.
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
"doctrine/common": "~2.4",
"zendframework/zend-http": "~2.2",
"zendframework/zend-crypt": "~2.2",
"zendframework/zend-math": "~2.2"
"zendframework/zend-math": "~2.2",
"zendframework/zend-eventmanager": "~2.2"
},
"require-dev": {
"phpunit/phpunit": "~3.7",
Expand Down
36 changes: 35 additions & 1 deletion src/ZfrOAuth2/Server/AuthorizationServer.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,14 @@

namespace ZfrOAuth2\Server;

use Zend\EventManager\EventManagerAwareInterface;
use Zend\EventManager\EventManagerAwareTrait;
use Zend\Http\Request as HttpRequest;
use Zend\Http\Response as HttpResponse;
use ZfrOAuth2\Server\Entity\Client;
use ZfrOAuth2\Server\Entity\TokenOwnerInterface;
use ZfrOAuth2\Server\Event\AuthorizationCodeEvent;
use ZfrOAuth2\Server\Event\TokenEvent;
use ZfrOAuth2\Server\Exception\OAuth2Exception;
use ZfrOAuth2\Server\Grant\AuthorizationServerAwareInterface;
use ZfrOAuth2\Server\Grant\GrantInterface;
Expand All @@ -33,8 +37,10 @@
* @author Michaël Gallego <[email protected]>
* @licence MIT
*/
class AuthorizationServer
class AuthorizationServer implements EventManagerAwareInterface
{
use EventManagerAwareTrait;

/**
* @var ClientService
*/
Expand Down Expand Up @@ -162,6 +168,20 @@ public function handleAuthorizationRequest(HttpRequest $request, TokenOwnerInter

$response->getHeaders()->addHeaderLine('Content-Type', 'application/json');

$responseBody = json_decode($response->getContent(), true);

$event = new AuthorizationCodeEvent($request, $responseBody, $response->getMetadata('authorizationCode'));
$event->setTarget($this);

if ($response->isSuccess()) {
$this->getEventManager()->trigger(AuthorizationCodeEvent::EVENT_CODE_CREATED, $event);
} else {
$this->getEventManager()->trigger(AuthorizationCodeEvent::EVENT_CODE_FAILED, $event);
}

// We re-encode the content back into the response in case it changed
$response->setContent(json_encode($event->getResponseBody()));

return $response;
}

Expand Down Expand Up @@ -193,6 +213,20 @@ public function handleTokenRequest(HttpRequest $request, TokenOwnerInterface $ow
->addHeaderLine('Cache-Control', 'no-store')
->addHeaderLine('Pragma', 'no-cache');

$responseBody = json_decode($response->getContent(), true);

$event = new TokenEvent($request, $responseBody, $response->getMetadata('accessToken'));
$event->setTarget($this);

if ($response->isSuccess()) {
$this->getEventManager()->trigger(TokenEvent::EVENT_TOKEN_CREATED, $event);
} else {
$this->getEventManager()->trigger(TokenEvent::EVENT_TOKEN_FAILED, $event);
}

// We re-encode the content back into the response in case it changed
$response->setContent(json_encode($event->getResponseBody()));

return $response;
}

Expand Down
94 changes: 94 additions & 0 deletions src/ZfrOAuth2/Server/Event/AuthorizationCodeEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license.
*/

namespace ZfrOAuth2\Server\Event;

use Zend\EventManager\Event;
use Zend\Http\Request as HttpRequest;
use Zend\Http\Response as HttpResponse;
use ZfrOAuth2\Server\Entity\AuthorizationCode;

/**
* @author Michaël Gallego <[email protected]>
* @licence MIT
*/
class AuthorizationCodeEvent extends Event
{
const EVENT_CODE_CREATED = 'authorizationCode.created';
const EVENT_CODE_FAILED = 'authorizationCode.failed';

/**
* @var HttpRequest
*/
protected $request;

/**
* @var array
*/
protected $responseBody;

/**
* @var AuthorizationCode|null
*/
protected $authorizationCode;

/**
* @param HttpRequest $request
* @param array $responseBody
* @param AuthorizationCode|null $authorizationCode
*/
public function __construct(HttpRequest $request, array $responseBody, AuthorizationCode $authorizationCode = null)
{
$this->request = $request;
$this->responseBody = $responseBody;
$this->authorizationCode = $authorizationCode;
}

/**
* @return HttpRequest
*/
public function getRequest()
{
return $this->request;
}

/**
* @param array $responseBody
* @return void
*/
public function setResponseBody(array $responseBody)
{
$this->responseBody = $responseBody;
}

/**
* @return array
*/
public function getResponseBody()
{
return $this->responseBody;
}

/**
* @return AuthorizationCode|null
*/
public function getAuthorizationCode()
{
return $this->authorizationCode;
}
}
94 changes: 94 additions & 0 deletions src/ZfrOAuth2/Server/Event/TokenEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license.
*/

namespace ZfrOAuth2\Server\Event;

use Zend\EventManager\Event;
use Zend\Http\Request as HttpRequest;
use Zend\Http\Response as HttpResponse;
use ZfrOAuth2\Server\Entity\AccessToken;

/**
* @author Michaël Gallego <[email protected]>
* @licence MIT
*/
class TokenEvent extends Event
{
const EVENT_TOKEN_CREATED = 'token.created';
const EVENT_TOKEN_FAILED = 'token.failed';

/**
* @var HttpRequest
*/
protected $request;

/**
* @var array
*/
protected $responseBody;

/**
* @var AccessToken|null
*/
protected $accessToken;

/**
* @param HttpRequest $request
* @param array $responseBody
* @param AccessToken|null $accessToken
*/
public function __construct(HttpRequest $request, array $responseBody, AccessToken $accessToken = null)
{
$this->request = $request;
$this->responseBody = $responseBody;
$this->accessToken = $accessToken;
}

/**
* @return HttpRequest
*/
public function getRequest()
{
return $this->request;
}

/**
* @param array $responseBody
* @return void
*/
public function setResponseBody(array $responseBody)
{
$this->responseBody = $responseBody;
}

/**
* @return array
*/
public function getResponseBody()
{
return $this->responseBody;
}

/**
* @return AccessToken|null
*/
public function getAccessToken()
{
return $this->accessToken;
}
}
5 changes: 3 additions & 2 deletions src/ZfrOAuth2/Server/Grant/AbstractGrant.php
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,9 @@ protected function prepareTokenResponse(
}

$response = new HttpResponse();
$response->setMetadata('accessToken', $accessToken); // Set the access token in metadata so it
// can be retrieved for events

// Set the access token in metadata so it can be retrieved for events
$response->setMetadata('accessToken', $accessToken);
$response->setContent(json_encode(array_filter($responseBody)));

return $response;
Expand Down
3 changes: 3 additions & 0 deletions src/ZfrOAuth2/Server/Grant/AuthorizationGrant.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ public function createAuthorizationResponse(HttpRequest $request, Client $client
$response->getHeaders()->addHeaderLine('Location', $redirectUri . '?' . $uri);
$response->setStatusCode(302); // here it's a redirection!

// Set the authorization code in metadata so it can be retrieved for events
$response->setMetadata('authorizationCode', $authorizationCode);

return $response;
}

Expand Down
Loading

0 comments on commit 6938b06

Please sign in to comment.