Skip to content

Commit

Permalink
Refactor ResourceServer
Browse files Browse the repository at this point in the history
  • Loading branch information
bakura10 committed Apr 26, 2014
1 parent d029e67 commit a45281e
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 39 deletions.
12 changes: 3 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ Please note that until I reach 1.0, I **WILL NOT** follow semantic version. This
Installation is only officially supported using Composer:

```sh
php composer.phar require zfr/zfr-oauth2-server:0.1.*
php composer.phar require zfr/zfr-oauth2-server:0.2.*
```

## Framework integration
Expand Down Expand Up @@ -132,24 +132,18 @@ $response = $authorizationServer->handleRequest($request, $user);
### Using the resource server

You can use the resource server to retrieve the access token (by automatically extracting the data from the HTTP
headers). You can also use the resource server to validate the access token against scopes:
headers). You can also specify scope constraints when retrieving the token:

```php
$accessTokenService = new TokenService($objectManager, $accessTokenRepository, $scopeRepository);
$resourceServer = new ResourceServer($accessTokenService);

if (!$resourceServer->isRequestValid($request, ['write']) {
if (!$token = $resourceServer->getAccessToken($request, ['write']) {
// there is either no access token, or the access token is expired, or the access token does not have
// the `write` scope
}
```

You can also manually retrieve the access token:

```php
$accessToken = $resourceServer->getAccessToken($request);
```

### Doctrine

ZfrOAuth2Server is built to be used with Doctrine (either ORM or ODM). Out of the box, it provides ORM mapping for
Expand Down
61 changes: 38 additions & 23 deletions src/ZfrOAuth2/Server/ResourceServer.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,40 +49,39 @@ public function __construct(TokenService $accessTokenService)
}

/**
* Check if the request is valid
* Get the access token
*
* If the scope parameter is given, it will also check that the token has enough permissions
* Note that this method will only match tokens that are not expired and match the given scopes (if any).
* Otherwise, null will be returned
*
* @param HttpRequest $request
* @param array|string $scopes
* @return bool
* @link http://tools.ietf.org/html/rfc6750#page-5
* @param HttpRequest $request
* @param array $scopes
* @return AccessToken|null
*/
public function isRequestValid(HttpRequest $request, $scopes = [])
public function getAccessToken(HttpRequest $request, $scopes = [])
{
// We extract the token and get the actual instance from storage
$accessToken = $this->getAccessToken($request);

// It must exist and must not be outdated, otherwise it's wrong!
if (null === $accessToken || $accessToken->isExpired()) {
return false;
if (!$token = $this->extractAccessToken($request)) {
return null;
}

if (!empty($scopes) && !$accessToken->matchScopes($scopes)) {
return false;
$token = $this->accessTokenService->getToken($token);

if ($token === null || !$this->isTokenValid($token, $scopes)) {
return null;
}

return true;
return $token;
}

/**
* Extract the access token from the Authorization header of the request
* Extract the token either from Authorization header or query params
*
* @link http://tools.ietf.org/html/rfc6750#page-5
* @param HttpRequest $request
* @return AccessToken|null
* @throws InvalidAccessTokenException If no access token could be found
* @return string|null
* @throws Exception\InvalidAccessTokenException If access token is malformed in the Authorization header
*/
public function getAccessToken(HttpRequest $request)
private function extractAccessToken(HttpRequest $request)
{
$headers = $request->getHeaders();

Expand All @@ -99,10 +98,26 @@ public function getAccessToken(HttpRequest $request)
$token = $request->getQuery('access_token');
}

if (null === $token) {
return null;
return $token;
}

/**
* Check if the given token is valid (not expired and/or match the given scopes)
*
* @param AccessToken $accessToken
* @param array $scopes
* @return bool
*/
private function isTokenValid(AccessToken $accessToken, $scopes = [])
{
if ($accessToken->isExpired()) {
return false;
}

return $this->accessTokenService->getToken($token);
if (!empty($scopes) && !$accessToken->matchScopes($scopes)) {
return false;
}

return true;
}
}
22 changes: 15 additions & 7 deletions tests/ZfrOAuth2Test/Server/ResourceServerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ public function testCanExtractAccessTokenFromAuthorizationHeader()
$request = new HttpRequest();
$request->getHeaders()->addHeaderLine('Authorization', 'Bearer token');

$token = $this->getMock('ZfrOAuth2\Server\Entity\AbstractToken');
$token = $this->getMock('ZfrOAuth2\Server\Entity\AccessToken');
$token->expects($this->once())->method('isExpired')->will($this->returnValue(false));

$this->tokenService->expects($this->once())
->method('getToken')
Expand All @@ -68,7 +69,8 @@ public function testCanExtractAccessTokenFromQueryString()
$request = new HttpRequest();
$request->getQuery()->fromArray(['access_token' => 'token']);

$token = $this->getMock('ZfrOAuth2\Server\Entity\AbstractToken');
$token = $this->getMock('ZfrOAuth2\Server\Entity\AccessToken');
$token->expects($this->once())->method('isExpired')->will($this->returnValue(false));

$this->tokenService->expects($this->once())
->method('getToken')
Expand Down Expand Up @@ -96,31 +98,31 @@ public function requestProvider()
'expired_token' => true,
'token_scope' => 'read',
'desired_scope' => 'read write',
'result' => false
'match' => false
],

// Should return false because we are asking more permissions than the token scope
[
'expired_token' => false,
'token_scope' => 'read',
'desired_scope' => 'read write',
'result' => false
'match' => false
],

// Should return true
[
'expired_token' => false,
'token_scope' => 'read',
'desired_scope' => 'read',
'result' => true
'match' => true
],
];
}

/**
* @dataProvider requestProvider
*/
public function testCanValidateAccessToResource($expiredToken, $tokenScope, $desiredScope, $result)
public function testCanValidateAccessToResource($expiredToken, $tokenScope, $desiredScope, $match)
{
$request = new HttpRequest();
$request->getHeaders()->addHeaderLine('Authorization', 'Bearer token');
Expand All @@ -142,6 +144,12 @@ public function testCanValidateAccessToResource($expiredToken, $tokenScope, $des
->with('token')
->will($this->returnValue($accessToken));

$this->assertEquals($result, $this->resourceServer->isRequestValid($request, $desiredScope));
$tokenResult = $this->resourceServer->getAccessToken($request, $desiredScope);

if ($match) {
$this->assertInstanceOf('ZfrOAuth2\Server\Entity\AccessToken', $tokenResult);
} else {
$this->assertNull($tokenResult);
}
}
}

0 comments on commit a45281e

Please sign in to comment.