Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow to set a TokenGenerator to override default implementation. #94

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 39 additions & 3 deletions lib/OAuth2.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use OAuth2\Model\IOAuth2AccessToken;
use OAuth2\Model\IOAuth2AuthCode;
use OAuth2\Model\IOAuth2Client;
use OAuth2\TokenGenerator\TokenGeneratorInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

Expand Down Expand Up @@ -61,6 +62,13 @@ class OAuth2
*/
protected $storage;

/**
* Token Generator (Random, JWT, etc.)
*
* @var TokenGeneratorInterface
*/
private $tokenGenerator;

/**
* Keep track of the old refresh token. So we can unset
* the old refresh tokens when a new one is issued.
Expand Down Expand Up @@ -405,6 +413,20 @@ public function __construct(IOAuth2Storage $storage, $config = array())
}
}

/**
* Sets a TokenGenerator to override default implementation.
*
* @param TokenGeneratorInterface $tokenGenerator
*
* @return OAuth2 The application (for chained calls of this method)
*/
public function setTokenGenerator(TokenGeneratorInterface $tokenGenerator)
{
$this->tokenGenerator = $tokenGenerator;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The DI container should inject the specific generator so the value is set.
If no specific generator is available, then the default generator should be used.


return $this;
}

/**
* Default configuration options are specified here.
*/
Expand Down Expand Up @@ -1331,8 +1353,12 @@ 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)
{
$genAccessToken = $this->tokenGenerator
? $this->tokenGenerator->genAccessToken($client, $data, $scope, $access_token_lifetime, $issue_refresh_token, $refresh_token_lifetime)
: $this->genAccessToken()
;
$token = array(
"access_token" => $this->genAccessToken(),
"access_token" => $genAccessToken,
"expires_in" => ($access_token_lifetime ?: $this->getVariable(self::CONFIG_ACCESS_LIFETIME)),
"token_type" => $this->getVariable(self::CONFIG_TOKEN_TYPE),
"scope" => $scope,
Expand All @@ -1348,7 +1374,10 @@ public function createAccessToken(IOAuth2Client $client, $data, $scope = null, $

// Issue a refresh token also, if we support them
if ($this->storage instanceof IOAuth2RefreshTokens && $issue_refresh_token === true) {
$token["refresh_token"] = $this->genAccessToken();
$token["refresh_token"] = $this->tokenGenerator
? $this->tokenGenerator->genRefreshToken($client, $data, $scope, $access_token_lifetime, $issue_refresh_token, $refresh_token_lifetime)
: $this->genAccessToken()
;
$this->storage->createRefreshToken(
$token["refresh_token"],
$client,
Expand Down Expand Up @@ -1390,7 +1419,10 @@ public function createAccessToken(IOAuth2Client $client, $data, $scope = null, $
*/
private function createAuthCode(IOAuth2Client $client, $data, $redirectUri, $scope = null)
{
$code = $this->genAuthCode();
$code = $this->tokenGenerator
? $this->tokenGenerator->genAuthCode($client, $data, $scope, $redirectUri)
: $this->genAuthCode()
;
$this->storage->createAuthCode(
$code,
$client,
Expand All @@ -1413,6 +1445,8 @@ private function createAuthCode(IOAuth2Client $client, $data, $redirectUri, $sco
*
* @ingroup oauth2_section_4
* @see OAuth2::genAuthCode()
*
* @deprecated since 1.3, will be removed in 2.0. Use a TokenGenerator instead.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method should be call the default generator method internally.

*/
protected function genAccessToken()
{
Expand Down Expand Up @@ -1446,6 +1480,8 @@ protected function genAccessToken()
* @see OAuth2::genAccessToken()
*
* @ingroup oauth2_section_4
*
* @deprecated since 1.3, will be removed in 2.0. Use a TokenGenerator instead.
*/
protected function genAuthCode()
{
Expand Down
39 changes: 39 additions & 0 deletions lib/TokenGenerator/RandomTokenGenerator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

namespace OAuth2\TokenGenerator;

use OAuth2\Model\IOAuth2Client;

class RandomTokenGenerator implements TokenGeneratorInterface
{
public function genAccessToken(IOAuth2Client $client, $data, $scope = null, $access_token_lifetime = null, $issue_refresh_token = true, $refresh_token_lifetime = null)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This parameters should be extraced as class members and set over an constructor or setter methods.

{
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
);
}

return rtrim(strtr(base64_encode(hash('sha256', $randomData)), '+/', '-_'), '=');
}

public function genRefreshToken(IOAuth2Client $client, $data, $scope = null, $access_token_lifetime = null, $issue_refresh_token = true, $refresh_token_lifetime = null)
{
return $this->genAccessToken($client, $data);
}

public function genAuthCode(IOAuth2Client $client, $data, $scope = null, $redirectUri = null)
{
return $this->genAccessToken($client, $data);
}
}
14 changes: 14 additions & 0 deletions lib/TokenGenerator/TokenGeneratorInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

namespace OAuth2\TokenGenerator;

use OAuth2\Model\IOAuth2Client;

interface TokenGeneratorInterface
{
public function genAccessToken(IOAuth2Client $client, $data, $scope = null, $access_token_lifetime = null, $issue_refresh_token = true, $refresh_token_lifetime = null);

public function genRefreshToken(IOAuth2Client $client, $data, $scope = null, $access_token_lifetime = null, $issue_refresh_token = true, $refresh_token_lifetime = null);

public function genAuthCode(IOAuth2Client $client, $data, $scope = null, $redirectUri = null);
}
22 changes: 22 additions & 0 deletions tests/OAuth2Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -1057,6 +1057,28 @@ public function testGetBearerToken(Request $request, $token, $remove = false, $e
}
}

public function testSetTokenGenerator()
{
$request = new Request(
array('grant_type' => OAuth2::GRANT_TYPE_CLIENT_CREDENTIALS, 'client_id' => 'my_little_app', 'client_secret' => 'b')
);

$storage = new OAuth2StorageStub;
$storage->addClient(new OAuth2Client('my_little_app', 'b'));
$storage->setAllowedGrantTypes(array(OAuth2::GRANT_TYPE_CLIENT_CREDENTIALS));

$tokenGenerator = $this->getMockBuilder('OAuth2\TokenGenerator\TokenGeneratorInterface')->getMock();
$tokenGenerator->expects($this->once())->method('genAccessToken')->willReturn('aa.bb.cc');

$this->fixture = new OAuth2($storage);
$this->fixture->setTokenGenerator($tokenGenerator);

$response = $this->fixture->grantAccessToken($request);

// Successful token grant will return a JSON encoded token WITHOUT a refresh token:
$this->assertRegExp('/^{"access_token":"aa\.bb\.cc","expires_in":[^"]+,"token_type":"bearer","scope":null}$/', $response->getContent());
}

public function getTestGetBearerTokenData()
{
$data = array();
Expand Down
30 changes: 30 additions & 0 deletions tests/TokenGenerator/RandomTokenGeneratorTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

use OAuth2\TokenGenerator\RandomTokenGenerator;

class RandomTokenGeneratorTest extends PHPUnit_Framework_TestCase
{
public function testGenerateAccessToken()
{
$tokenGenerator = new RandomTokenGenerator();
$client = $this->getMockBuilder('OAuth2\Model\IOAuth2Client')->getMock();

$this->assertNotEmpty($tokenGenerator->genAccessToken($client, null));
}

public function testGenerateRefreshToken()
{
$tokenGenerator = new RandomTokenGenerator();
$client = $this->getMockBuilder('OAuth2\Model\IOAuth2Client')->getMock();

$this->assertNotEmpty($tokenGenerator->genRefreshToken($client, null));
}

public function testGenerateAuthCode()
{
$tokenGenerator = new RandomTokenGenerator();
$client = $this->getMockBuilder('OAuth2\Model\IOAuth2Client')->getMock();

$this->assertNotEmpty($tokenGenerator->genAuthCode($client, null));
}
}