Skip to content

Commit

Permalink
Add support for user claims.
Browse files Browse the repository at this point in the history
  • Loading branch information
bojanz authored and bshaffer committed Mar 18, 2014
1 parent d8ba6f5 commit dd4004c
Show file tree
Hide file tree
Showing 7 changed files with 43 additions and 15 deletions.
13 changes: 10 additions & 3 deletions src/OAuth2/ResponseType/IdToken.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,18 @@
use OAuth2\Encryption\Jwt;
use OAuth2\Storage\RefreshTokenInterface;
use OAuth2\Storage\PublicKeyInterface;
use OAuth2\Storage\UserClaimsInterface;

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

public function __construct(PublicKeyInterface $publicKeyStorage, array $config = array(), EncryptionInterface $encryptionUtil = null)
public function __construct(UserClaimsInterface $userClaimsStorage, PublicKeyInterface $publicKeyStorage, array $config = array(), EncryptionInterface $encryptionUtil = null)
{
$this->userClaimsStorage = $userClaimsStorage;
$this->publicKeyStorage = $publicKeyStorage;
if (is_null($encryptionUtil)) {
$encryptionUtil = new Jwt();
Expand All @@ -36,7 +39,8 @@ public function getAuthorizeResponse($params, $user_id = null)
$params += array('scope' => null, 'state' => null);

// create the id token.
$id_token = $this->createIdToken($params['client_id'], $user_id, $params['nonce']);
$userClaims = $this->userClaimsStorage->getUserClaims($user_id, $params['scope']);
$id_token = $this->createIdToken($params['client_id'], $user_id, $params['nonce'], $userClaims);
$result["fragment"] = array('id_token' => $id_token);
if (isset($params['state'])) {
$result["fragment"]["state"] = $params['state'];
Expand All @@ -45,7 +49,7 @@ public function getAuthorizeResponse($params, $user_id = null)
return array($params['redirect_uri'], $result);
}

public function createIdToken($client_id, $user_id, $nonce = null, $access_token = null)
public function createIdToken($client_id, $user_id, $nonce = null, $userClaims = null, $access_token = null)
{
$token = array(
'iss' => $this->config['issuer'],
Expand All @@ -61,6 +65,9 @@ public function createIdToken($client_id, $user_id, $nonce = null, $access_token
if ($access_token) {
$token['at_hash'] = $this->createAtHash($access_token, $client_id);
}
if ($userClaims) {
$token += $userClaims;
}

return $this->encodeToken($token, $client_id);
}
Expand Down
3 changes: 2 additions & 1 deletion src/OAuth2/ResponseType/IdTokenInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@ 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 $userClaims OPTIONAL Claims about the user.
* @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, $access_token = null);
public function createIdToken($client_id, $user_id, $nonce = null, $userClaims = 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'], $access_token);
$id_token = $this->idToken->createIdToken($params['client_id'], $user_id, $params['nonce'], null, $access_token);
$result[1]['fragment']['id_token'] = $id_token;

return $result;
Expand Down
6 changes: 5 additions & 1 deletion src/OAuth2/Server.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class Server implements ResourceControllerInterface,
'client' => 'OAuth2\Storage\ClientInterface',
'refresh_token' => 'OAuth2\Storage\RefreshTokenInterface',
'user_credentials' => 'OAuth2\Storage\UserCredentialsInterface',
'user_claims' => 'OAuth2\Storage\UserClaimsInterface',
'public_key' => 'OAuth2\Storage\PublicKeyInterface',
'jwt_bearer' => 'OAuth2\Storage\JWTBearerInterface',
'scope' => 'OAuth2\Storage\ScopeInterface',
Expand Down Expand Up @@ -612,12 +613,15 @@ protected function createDefaultAccessTokenResponseType()

protected function createDefaultIdTokenResponseType()
{
if (!isset($this->storages['user_claims'])) {
throw new \LogicException("You must supply a storage object implementing OAuth2\Storage\UserClaimsInterface 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['public_key'], $config);
return new IdToken($this->storages['user_claims'], $this->storages['public_key'], $config);
}

public function getResponse()
Expand Down
17 changes: 17 additions & 0 deletions src/OAuth2/Storage/Memory.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*/
class Memory implements AuthorizationCodeInterface,
UserCredentialsInterface,
UserClaimsInterface,
AccessTokenInterface,
ClientCredentialsInterface,
RefreshTokenInterface,
Expand Down Expand Up @@ -119,6 +120,22 @@ public function getUserDetails($username)
), $this->userCredentials[$username]);
}

/* UserClaimsInterface */
public function getUserClaims($user_id, $scope)
{
// A real implementation would fetch the user information from a
// separate storage, and then return the appropriate claims.
// For test purposes it's okay to return the same data for all users.
$scope = explode(' ', trim($scope));
$claims = array();
if (in_array('email', $scope)) {
$claims['email'] = 'testuser@ourdomain.com';
$claims['email_verified'] = false;
}

return $claims;
}

/* ClientCredentialsInterface */
public function checkClientCredentials($client_id, $client_secret = null)
{
Expand Down
8 changes: 6 additions & 2 deletions test/OAuth2/ResponseType/IdTokenTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public function testHandleAuthorizeRequest()
'response_type' => 'id_token',
'redirect_uri' => 'http://adobe.com',
'client_id' => 'Test Client ID',
'scope' => 'openid',
'scope' => 'openid email',
'state' => 'test',
'nonce' => 'test',
));
Expand Down Expand Up @@ -81,10 +81,13 @@ private function validateIdToken($id_token)
$this->assertArrayHasKey('exp', $claims);
$this->assertArrayHasKey('auth_time', $claims);
$this->assertArrayHasKey('nonce', $claims);
$this->assertArrayHasKey('email', $claims);
$this->assertArrayHasKey('email_verified', $claims);

$this->assertEquals($claims['iss'], 'test');
$this->assertEquals($claims['aud'], 'Test Client ID');
$this->assertEquals($claims['nonce'], 'test');
$this->assertEquals($claims['email'], 'testuser@ourdomain.com');
$duration = $claims['exp'] - $claims['iat'];
$this->assertEquals($duration, 3600);
}
Expand All @@ -98,12 +101,13 @@ private function getTestServer($config = array())
);

$memoryStorage = Bootstrap::getInstance()->getMemoryStorage();
$memoryStorage->supportedScopes[] = 'email';
$storage = array(
'client' => $memoryStorage,
'scope' => $memoryStorage,
);
$responseTypes = array(
'id_token' => new IdToken($memoryStorage, $config),
'id_token' => new IdToken($memoryStorage, $memoryStorage, $config),
);

$server = new Server($storage, $config, array(), $responseTypes);
Expand Down
9 changes: 2 additions & 7 deletions test/OAuth2/ResponseType/TokenIdTokenTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,18 +78,13 @@ private function getTestServer($config = array())
);

$memoryStorage = Bootstrap::getInstance()->getMemoryStorage();
$storage = array(
'access_token' => $memoryStorage,
'client' => $memoryStorage,
'scope' => $memoryStorage,
);
$responseTypes = array(
'token' => new AccessToken($memoryStorage, $memoryStorage),
'id_token' => new IdToken($memoryStorage, $config),
'id_token' => new IdToken($memoryStorage, $memoryStorage, $config),
);
$responseTypes['token id_token'] = new TokenIdToken($responseTypes['token'], $responseTypes['id_token']);

$server = new Server($storage, $config, array(), $responseTypes);
$server = new Server($memoryStorage, $config, array(), $responseTypes);
$server->addGrantType(new ClientCredentials($memoryStorage));

return $server;
Expand Down

0 comments on commit dd4004c

Please sign in to comment.