Skip to content

Commit

Permalink
Remove the id_token storage, store the id_token with the authorizatio…
Browse files Browse the repository at this point in the history
…n code when needed. Have the code grant type return an id_token when found.
  • Loading branch information
bojanz authored and bshaffer committed Mar 18, 2014
1 parent b175366 commit 719ebaf
Show file tree
Hide file tree
Showing 16 changed files with 46 additions and 108 deletions.
10 changes: 5 additions & 5 deletions src/OAuth2/Controller/AuthorizeController.php
Original file line number Diff line number Diff line change
Expand Up @@ -95,14 +95,14 @@ public function handleAuthorizeRequest(RequestInterface $request, ResponseInterf
'response_type' => $this->response_type,
'nonce' => $this->nonce,
);
// Generate an id token if needed.
if ($this->needsIdToken($this->scope) && $this->response_type == self::RESPONSE_TYPE_AUTHORIZATION_CODE) {
$params['id_token'] = $this->responseTypes['id_token']->createIdToken($this->client_id, $user_id, $this->nonce);
}

$authResult = $this->responseTypes[$this->response_type]->getAuthorizeResponse($params, $user_id);

list($redirect_uri, $uri_params) = $authResult;
// Generate and save an id token for the token request.
if ($this->needsIdToken($this->scope) && $this->response_type == self::RESPONSE_TYPE_AUTHORIZATION_CODE) {
$code = $uri_params['query']['code'];
$this->responseTypes['id_token']->createIdToken($this->client_id, $user_id, $this->nonce, $code);
}

if (empty($redirect_uri) && !empty($registered_redirect_uri)) {
$redirect_uri = $registered_redirect_uri;
Expand Down
3 changes: 3 additions & 0 deletions src/OAuth2/GrantType/AuthorizationCode.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ public function getUserId()
public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope)
{
$token = $accessToken->createAccessToken($client_id, $user_id, $scope);
if (isset($this->authCode['id_token'])) {
$token['id_token'] = $this->authCode['id_token'];
}
$this->storage->expireAuthorizationCode($this->authCode['code']);

return $token;
Expand Down
12 changes: 7 additions & 5 deletions src/OAuth2/ResponseType/AuthorizationCode.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ public function getAuthorizeResponse($params, $user_id = null)
// build the URL to redirect to
$result = array('query' => array());

$params += array('scope' => null, 'state' => null);
$params += array('scope' => null, 'state' => null, 'id_token' => null);

$result["query"]["code"] = $this->createAuthorizationCode($params['client_id'], $user_id, $params['redirect_uri'], $params['scope']);
$result['query']['code'] = $this->createAuthorizationCode($params['client_id'], $user_id, $params['redirect_uri'], $params['scope'], $params['id_token']);

if (isset($params['state'])) {
$result["query"]["state"] = $params['state'];
$result['query']['state'] = $params['state'];
}

return array($params['redirect_uri'], $result);
Expand All @@ -50,14 +50,16 @@ public function getAuthorizeResponse($params, $user_id = null)
* user-agent to when the end-user authorization step is completed.
* @param $scope
* (optional) Scopes to be stored in space-separated string.
* @param $id_token
* (optional) The OpenID Connect id_token.
*
* @see http://tools.ietf.org/html/rfc6749#section-4
* @ingroup oauth2_section_4
*/
public function createAuthorizationCode($client_id, $user_id, $redirect_uri, $scope = null)
public function createAuthorizationCode($client_id, $user_id, $redirect_uri, $scope = null, $id_token = null)
{
$code = $this->generateAuthorizationCode();
$this->storage->setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, time() + $this->config['auth_code_lifetime'], $scope);
$this->storage->setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, time() + $this->config['auth_code_lifetime'], $scope, $id_token);

return $code;
}
Expand Down
4 changes: 3 additions & 1 deletion src/OAuth2/ResponseType/AuthorizationCodeInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@ public function enforceRedirect();
* user-agent to when the end-user authorization step is completed.
* @param $scope
* (optional) Scopes to be stored in space-separated string.
* @param $id_token
* (optional) The OpenID Connect id_token.
*
* @see http://tools.ietf.org/html/rfc6749#section-4
* @ingroup oauth2_section_4
*/
public function createAuthorizationCode($client_id, $user_id, $redirect_uri, $scope = null);
public function createAuthorizationCode($client_id, $user_id, $redirect_uri, $scope = null, $id_token = null);
}
13 changes: 3 additions & 10 deletions src/OAuth2/ResponseType/IdToken.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,17 @@

use OAuth2\Encryption\EncryptionInterface;
use OAuth2\Encryption\Jwt;
use OAuth2\Storage\IdTokenInterface as IdTokenStorageInterface;
use OAuth2\Storage\RefreshTokenInterface;
use OAuth2\Storage\PublicKeyInterface;

class IdToken implements IdTokenInterface
{
protected $tokenStorage;
protected $publicKeyStorage;
protected $config;
protected $encryptionUtil;

public function __construct(IdTokenStorageInterface $tokenStorage, PublicKeyInterface $publicKeyStorage = null, array $config = array(), EncryptionInterface $encryptionUtil = null)
public function __construct(PublicKeyInterface $publicKeyStorage = null, array $config = array(), EncryptionInterface $encryptionUtil = null)
{
$this->tokenStorage = $tokenStorage;
$this->publicKeyStorage = $publicKeyStorage;
if (is_null($encryptionUtil)) {
$encryptionUtil = new Jwt();
Expand Down Expand Up @@ -48,7 +45,7 @@ public function getAuthorizeResponse($params, $user_id = null)
return array($params['redirect_uri'], $result);
}

public function createIdToken($client_id, $user_id, $nonce = null, $code = null, $access_token = null)
public function createIdToken($client_id, $user_id, $nonce = null, $access_token = null)
{
$token = array(
'iss' => $this->config['issuer'],
Expand All @@ -65,11 +62,7 @@ public function createIdToken($client_id, $user_id, $nonce = null, $code = null,
$token['at_hash'] = $this->createAtHash($access_token, $client_id);
}

// encode the id_token and save it.
$id_token = $this->encodeToken($token, $client_id);
$this->tokenStorage->setIdToken($id_token, $client_id, $user_id, $token['exp'], $code);

return $id_token;
return $this->encodeToken($token, $client_id);
}

protected function createAtHash($access_token, $client_id = null) {
Expand Down
3 changes: 1 addition & 2 deletions src/OAuth2/ResponseType/IdTokenInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,11 @@ interface IdTokenInterface extends ResponseTypeInterface
* @param string $client_id The client id.
* @param string $user_id The user id.
* @param string $nonce OPTIONAL The nonce.
* @param string $code OPTIONAL The authorization code, if known.
* @param string $access_token OPTIONAL The access token, if known.
*
* @return string The ID Token represented as a JSON Web Token (JWT).
*
* @see http://openid.net/specs/openid-connect-core-1_0.html#IDToken
*/
public function createIdToken($client_id, $user_id, $nonce = null, $code = null, $access_token = null);
public function createIdToken($client_id, $user_id, $nonce = null, $access_token = null);
}
2 changes: 1 addition & 1 deletion src/OAuth2/ResponseType/TokenIdToken.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public function getAuthorizeResponse($params, $user_id = null)
{
$result = $this->accessToken->getAuthorizeResponse($params, $user_id);
$access_token = $result[1]['fragment']['access_token'];
$id_token = $this->idToken->createIdToken($params['client_id'], $user_id, $params['nonce'], null, $access_token);
$id_token = $this->idToken->createIdToken($params['client_id'], $user_id, $params['nonce'], $access_token);
$result[1]['fragment']['id_token'] = $id_token;

return $result;
Expand Down
6 changes: 1 addition & 5 deletions src/OAuth2/Server.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ class Server implements ResourceControllerInterface,

protected $storageMap = array(
'access_token' => 'OAuth2\Storage\AccessTokenInterface',
'id_token' => 'OAuth2\Storage\IdTokenInterface',
'authorization_code' => 'OAuth2\Storage\AuthorizationCodeInterface',
'client_credentials' => 'OAuth2\Storage\ClientCredentialsInterface',
'client' => 'OAuth2\Storage\ClientInterface',
Expand Down Expand Up @@ -613,15 +612,12 @@ protected function createDefaultAccessTokenResponseType()

protected function createDefaultIdTokenResponseType()
{
if (!isset($this->storages['id_token'])) {
throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\IdTokenInterface to use openid connect");
}
if (!isset($this->storages['public_key'])) {
throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\PublicKeyInterface to use openid connect");
}

$config = array_intersect_key($this->config, array_flip(explode(' ', 'issuer id_lifetime')));
return new IdToken($this->storages['id_token'], $this->storages['public_key'], $config);
return new IdToken($this->storages['public_key'], $config);
}

public function getResponse()
Expand Down
4 changes: 2 additions & 2 deletions src/OAuth2/Storage/Cassandra.php
Original file line number Diff line number Diff line change
Expand Up @@ -145,11 +145,11 @@ public function getAuthorizationCode($code)
return $this->getValue($this->config['code_key'] . $code);
}

public function setAuthorizationCode($authorization_code, $client_id, $user_id, $redirect_uri, $expires, $scope = null)
public function setAuthorizationCode($authorization_code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null)
{
return $this->setValue(
$this->config['code_key'] . $authorization_code,
compact('authorization_code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope'),
compact('authorization_code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope', 'id_token'),
$expires
);
}
Expand Down
43 changes: 0 additions & 43 deletions src/OAuth2/Storage/IdTokenInterface.php

This file was deleted.

20 changes: 2 additions & 18 deletions src/OAuth2/Storage/Memory.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
class Memory implements AuthorizationCodeInterface,
UserCredentialsInterface,
AccessTokenInterface,
IdTokenInterface,
ClientCredentialsInterface,
RefreshTokenInterface,
JwtBearerInterface,
Expand All @@ -25,7 +24,6 @@ class Memory implements AuthorizationCodeInterface,
public $clientCredentials;
public $refreshTokens;
public $accessTokens;
public $idTokens;
public $jwt;
public $jti;
public $supportedScopes;
Expand Down Expand Up @@ -71,9 +69,9 @@ public function getAuthorizationCode($code)
), $this->authorizationCodes[$code]);
}

public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null)
public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null)
{
$this->authorizationCodes[$code] = compact('code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope');
$this->authorizationCodes[$code] = compact('code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope', 'id_token');

return true;
}
Expand Down Expand Up @@ -227,20 +225,6 @@ public function getDefaultScope($client_id = null)
return $this->defaultScope;
}

/* IdTokenInterface */
public function getIdToken($code)
{
return isset($this->idTokens[$code]) ? $this->idTokens[$code] : false;
}

public function setIdToken($id_token, $client_id, $user_id, $expires, $code = null)
{
$key = isset($code) ? $code : count($this->idTokens);
$this->idTokens[$key] = compact('id_token', 'client_id', 'user_id', 'expires');

return true;
}

/*JWTBearerInterface */
public function getClientKey($client_id, $subject)
{
Expand Down
8 changes: 5 additions & 3 deletions src/OAuth2/Storage/Mongo.php
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ public function getAuthorizationCode($code)
return is_null($code) ? false : $code;
}

public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null)
public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null)
{
// if it exists, update it.
if ($this->getAuthorizationCode($code)) {
Expand All @@ -182,7 +182,8 @@ public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri,
'user_id' => $user_id,
'redirect_uri' => $redirect_uri,
'expires' => $expires,
'scope' => $scope
'scope' => $scope,
'id_token' => $id_token,
))
);
} else {
Expand All @@ -193,7 +194,8 @@ public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri,
'user_id' => $user_id,
'redirect_uri' => $redirect_uri,
'expires' => $expires,
'scope' => $scope
'scope' => $scope,
'id_token' => $id_token,
)
);
}
Expand Down
8 changes: 4 additions & 4 deletions src/OAuth2/Storage/Pdo.php
Original file line number Diff line number Diff line change
Expand Up @@ -162,19 +162,19 @@ public function getAuthorizationCode($code)
return $code;
}

public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null)
public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null)
{
// convert expires to datestring
$expires = date('Y-m-d H:i:s', $expires);

// if it exists, update it.
if ($this->getAuthorizationCode($code)) {
$stmt = $this->db->prepare($sql = sprintf('UPDATE %s SET client_id=:client_id, user_id=:user_id, redirect_uri=:redirect_uri, expires=:expires, scope=:scope where authorization_code=:code', $this->config['code_table']));
$stmt = $this->db->prepare($sql = sprintf('UPDATE %s SET client_id=:client_id, user_id=:user_id, redirect_uri=:redirect_uri, expires=:expires, scope=:scope, id_token =:id_token where authorization_code=:code', $this->config['code_table']));
} else {
$stmt = $this->db->prepare(sprintf('INSERT INTO %s (authorization_code, client_id, user_id, redirect_uri, expires, scope) VALUES (:code, :client_id, :user_id, :redirect_uri, :expires, :scope)', $this->config['code_table']));
$stmt = $this->db->prepare(sprintf('INSERT INTO %s (authorization_code, client_id, user_id, redirect_uri, expires, scope, id_token) VALUES (:code, :client_id, :user_id, :redirect_uri, :expires, :scope, :id_token)', $this->config['code_table']));
}

return $stmt->execute(compact('code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope'));
return $stmt->execute(compact('code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope', 'id_token'));
}

public function expireAuthorizationCode($code)
Expand Down
4 changes: 2 additions & 2 deletions src/OAuth2/Storage/Redis.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,11 @@ public function getAuthorizationCode($code)
return $this->getValue($this->config['code_key'] . $code);
}

public function setAuthorizationCode($authorization_code, $client_id, $user_id, $redirect_uri, $expires, $scope = null)
public function setAuthorizationCode($authorization_code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null)
{
return $this->setValue(
$this->config['code_key'] . $authorization_code,
compact('authorization_code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope'),
compact('authorization_code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope', 'id_token'),
$expires
);
}
Expand Down
12 changes: 6 additions & 6 deletions test/OAuth2/Controller/AuthorizeControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -355,9 +355,9 @@ public function testCodeQueryParamIsSet()
$this->assertArrayHasKey('code', $query);

// ensure no id_token was saved, since the openid scope wasn't requested
$storage = $server->getStorage('id_token');
$token = $storage->getIdToken($query['code']);
$this->assertTrue(empty($token));
$storage = $server->getStorage('authorization_code');
$code = $storage->getAuthorizationCode($query['code']);
$this->assertTrue(empty($code['id_token']));

// ensure no error was returned
$this->assertFalse(isset($query['error']));
Expand Down Expand Up @@ -448,9 +448,9 @@ public function testSuccessfulOpenidConnectRequest()
$this->assertFalse(isset($query['error_description']));

// confirm that the id_token has been created.
$storage = $server->getStorage('id_token');
$token = $storage->getIdToken($query['code']);
$this->assertTrue(!empty($token));
$storage = $server->getStorage('authorization_code');
$code = $storage->getAuthorizationCode($query['code']);
$this->assertTrue(!empty($code['id_token']));
}

public function testCreateController()
Expand Down
2 changes: 1 addition & 1 deletion test/lib/OAuth2/Storage/Bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ public function runPdoSql(\PDO $pdo)
{
$pdo->exec('CREATE TABLE oauth_clients (client_id TEXT, client_secret TEXT, redirect_uri TEXT, grant_types TEXT, scope TEXT, user_id TEXT, public_key TEXT)');
$pdo->exec('CREATE TABLE oauth_access_tokens (access_token TEXT, client_id TEXT, user_id TEXT, expires DATETIME, scope TEXT)');
$pdo->exec('CREATE TABLE oauth_authorization_codes (authorization_code TEXT, client_id TEXT, user_id TEXT, redirect_uri TEXT, expires DATETIME, scope TEXT)');
$pdo->exec('CREATE TABLE oauth_authorization_codes (authorization_code TEXT, client_id TEXT, user_id TEXT, redirect_uri TEXT, expires DATETIME, scope TEXT, id_token TEXT)');
$pdo->exec('CREATE TABLE oauth_users (username TEXT, password TEXT, first_name TEXT, last_name TEXT, scope TEXT)');
$pdo->exec('CREATE TABLE oauth_refresh_tokens (refresh_token TEXT, client_id TEXT, user_id TEXT, expires DATETIME, scope TEXT)');
$pdo->exec('CREATE TABLE oauth_scopes (scope TEXT, is_default BOOLEAN)');
Expand Down

0 comments on commit 719ebaf

Please sign in to comment.