Skip to content

Commit

Permalink
Merge pull request #572 from bshaffer/develop
Browse files Browse the repository at this point in the history
Tag v1.7.0
  • Loading branch information
bshaffer committed Apr 24, 2015
2 parents 7b083b7 + 1f91815 commit 8878e19
Show file tree
Hide file tree
Showing 26 changed files with 457 additions and 54 deletions.
16 changes: 15 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,21 @@ To see the files changed for a given bug, go to https://github.com/bshaffer/oaut
To get the diff between two versions, go to https://github.com/bshaffer/oauth2-server-php/compare/v1.0...v1.1
To get the diff for a specific change, go to https://github.com/bshaffer/oauth2-server-php/commit/XXX where XXX is the change hash

* 1.6 (2014-01-16)
* 1.7.0 (2015-04-23)

PR: https://github.com/bshaffer/oauth2-server-php/pull/572

* bug #500 - PDO fetch mode changed from FETCH_BOTH to FETCH_ASSOC
* bug #508 - Case insensitive for Bearer token header name ba716d4
* bug #512 - validateRedirectUri is now public
* bug #530 - Add PublicKeyInterface, UserClaimsInterface to Cassandra Storage
* bug #505 - DynamoDB storage fixes
* bug #556 - adds "code id_token" return type to openid connect
* bug #563 - Include "issuer" config key for JwtAccessToken
* bug #564 - Fixes JWT vulnerability
* bug #571 - Added unset_refresh_token_after_use option

* 1.6 (2015-01-16)

PR: https://github.com/bshaffer/oauth2-server-php/pull/496

Expand Down
2 changes: 1 addition & 1 deletion src/OAuth2/Controller/AuthorizeController.php
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ protected function getValidResponseTypes()
*
* @see http://tools.ietf.org/html/rfc6749#section-3.1.2
*/
private function validateRedirectUri($inputUri, $registeredUriString)
protected function validateRedirectUri($inputUri, $registeredUriString)
{
if (!$inputUri || !$registeredUriString) {
return false; // if either one is missing, assume INVALID
Expand Down
9 changes: 7 additions & 2 deletions src/OAuth2/Encryption/Jwt.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public function encode($payload, $key, $algo = 'HS256')
return implode('.', $segments);
}

public function decode($jwt, $key = null, $verify = true)
public function decode($jwt, $key = null, $allowedAlgorithms = true)
{
if (!strpos($jwt, '.')) {
return false;
Expand All @@ -49,11 +49,16 @@ public function decode($jwt, $key = null, $verify = true)

$sig = $this->urlSafeB64Decode($cryptob64);

if ($verify) {
if ((bool) $allowedAlgorithms) {
if (!isset($header['alg'])) {
return false;
}

// check if bool arg supplied here to maintain BC
if (is_array($allowedAlgorithms) && !in_array($header['alg'], $allowedAlgorithms)) {
return false;
}

if (!$this->verifySignature($sig, "$headb64.$payloadb64", $key, $header['alg'])) {
return false;
}
Expand Down
18 changes: 13 additions & 5 deletions src/OAuth2/GrantType/JwtBearer.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,17 @@ class JwtBearer implements GrantTypeInterface, ClientAssertionTypeInterface
protected $storage;
protected $audience;
protected $jwtUtil;
protected $allowedAlgorithms;

/**
* Creates an instance of the JWT bearer grant type.
*
* @param OAuth2\Storage\JWTBearerInterface $storage A valid storage interface that implements storage hooks for the JWT bearer grant type.
* @param string $audience The audience to validate the token against. This is usually the full URI of the OAuth token requests endpoint.
* @param OAuth2\Encryption\JWT $jwtUtil OPTONAL The class used to decode, encode and verify JWTs.
* @param OAuth2\Storage\JWTBearerInterface|JwtBearerInterface $storage A valid storage interface that implements storage hooks for the JWT bearer grant type.
* @param string $audience The audience to validate the token against. This is usually the full URI of the OAuth token requests endpoint.
* @param EncryptionInterface|OAuth2\Encryption\JWT $jwtUtil OPTONAL The class used to decode, encode and verify JWTs.
* @param array $config
*/
public function __construct(JwtBearerInterface $storage, $audience, EncryptionInterface $jwtUtil = null)
public function __construct(JwtBearerInterface $storage, $audience, EncryptionInterface $jwtUtil = null, array $config = array())
{
$this->storage = $storage;
$this->audience = $audience;
Expand All @@ -42,7 +44,13 @@ public function __construct(JwtBearerInterface $storage, $audience, EncryptionIn
$jwtUtil = new Jwt();
}

$this->config = array_merge(array(
'allowed_algorithms' => array('RS256', 'RS384', 'RS512')
), $config);

$this->jwtUtil = $jwtUtil;

$this->allowedAlgorithms = $this->config['allowed_algorithms'];
}

/**
Expand Down Expand Up @@ -177,7 +185,7 @@ public function validateRequest(RequestInterface $request, ResponseInterface $re
}

// Verify the JWT
if (!$this->jwtUtil->decode($undecodedJWT, $key, true)) {
if (!$this->jwtUtil->decode($undecodedJWT, $key, $this->allowedAlgorithms)) {
$response->setError(400, 'invalid_grant', "JWT failed signature verification");

return null;
Expand Down
7 changes: 5 additions & 2 deletions src/OAuth2/GrantType/RefreshToken.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,15 @@ class RefreshToken implements GrantTypeInterface
* <code>
* $config = array(
* 'always_issue_new_refresh_token' => true, // whether to issue a new refresh token upon successful token request
* 'unset_refresh_token_after_use' => true // whether to unset the refresh token after after using
* );
* </code>
*/
public function __construct(RefreshTokenInterface $storage, $config = array())
{
$this->config = array_merge(array(
'always_issue_new_refresh_token' => false
'always_issue_new_refresh_token' => false,
'unset_refresh_token_after_use' => true
), $config);
$this->storage = $storage;
}
Expand Down Expand Up @@ -89,9 +91,10 @@ public function createAccessToken(AccessTokenInterface $accessToken, $client_id,
* @see http://tools.ietf.org/html/rfc6749#section-6
*/
$issueNewRefreshToken = $this->config['always_issue_new_refresh_token'];
$unsetRefreshToken = $this->config['unset_refresh_token_after_use'];
$token = $accessToken->createAccessToken($client_id, $user_id, $scope, $issueNewRefreshToken);

if ($issueNewRefreshToken) {
if ($unsetRefreshToken) {
$this->storage->unsetRefreshToken($this->refreshToken['refresh_token']);
}

Expand Down
1 change: 1 addition & 0 deletions src/OAuth2/OpenID/Controller/AuthorizeController.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ protected function getValidResponseTypes()
self::RESPONSE_TYPE_AUTHORIZATION_CODE,
self::RESPONSE_TYPE_ID_TOKEN,
self::RESPONSE_TYPE_ID_TOKEN_TOKEN,
self::RESPONSE_TYPE_CODE_ID_TOKEN,
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ interface AuthorizeControllerInterface
{
const RESPONSE_TYPE_ID_TOKEN = 'id_token';
const RESPONSE_TYPE_ID_TOKEN_TOKEN = 'id_token token';
const RESPONSE_TYPE_CODE_ID_TOKEN = 'code id_token';
}
24 changes: 24 additions & 0 deletions src/OAuth2/OpenID/ResponseType/CodeIdToken.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

namespace OAuth2\OpenID\ResponseType;

class CodeIdToken implements CodeIdTokenInterface
{
protected $authCode;
protected $idToken;

public function __construct(AuthorizationCodeInterface $authCode, IdTokenInterface $idToken)
{
$this->authCode = $authCode;
$this->idToken = $idToken;
}

public function getAuthorizeResponse($params, $user_id = null)
{
$result = $this->authCode->getAuthorizeResponse($params, $user_id);
$id_token = $this->idToken->createIdToken($params['client_id'], $user_id, $params['nonce']);
$result[1]['query']['id_token'] = $id_token;

return $result;
}
}
9 changes: 9 additions & 0 deletions src/OAuth2/OpenID/ResponseType/CodeIdTokenInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace OAuth2\OpenID\ResponseType;

use OAuth2\ResponseType\ResponseTypeInterface;

interface CodeIdTokenInterface extends ResponseTypeInterface
{
}
2 changes: 1 addition & 1 deletion src/OAuth2/OpenID/ResponseType/IdTokenToken.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class IdTokenToken implements IdTokenTokenInterface
protected $accessToken;
protected $idToken;

public function __construct(AccessTokenInterface $accessToken, IdToken $idToken)
public function __construct(AccessTokenInterface $accessToken, IdTokenInterface $idToken)
{
$this->accessToken = $accessToken;
$this->idToken = $idToken;
Expand Down
2 changes: 1 addition & 1 deletion src/OAuth2/Request.php
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ private function getHeadersFromServer($server)
*/
public static function createFromGlobals()
{
$class = __CLASS__;
$class = get_called_class();
$request = new $class($_GET, $_POST, array(), $_COOKIE, $_FILES, $_SERVER);

$contentType = $request->server('CONTENT_TYPE', '');
Expand Down
20 changes: 18 additions & 2 deletions src/OAuth2/Server.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
use OAuth2\ResponseType\AuthorizationCode as AuthorizationCodeResponseType;
use OAuth2\ResponseType\AccessToken;
use OAuth2\ResponseType\JwtAccessToken;
use OAuth2\OpenID\ResponseType\CodeIdToken;
use OAuth2\OpenID\ResponseType\IdToken;
use OAuth2\OpenID\ResponseType\IdTokenToken;
use OAuth2\TokenType\TokenTypeInterface;
Expand Down Expand Up @@ -81,6 +82,7 @@ class Server implements ResourceControllerInterface,
'code' => 'OAuth2\ResponseType\AuthorizationCodeInterface',
'id_token' => 'OAuth2\OpenID\ResponseType\IdTokenInterface',
'id_token token' => 'OAuth2\OpenID\ResponseType\IdTokenTokenInterface',
'code id_token' => 'OAuth2\OpenID\ResponseType\CodeIdTokenInterface',
);

/**
Expand Down Expand Up @@ -120,6 +122,7 @@ public function __construct($storage = array(), array $config = array(), array $
'allow_credentials_in_request_body' => true,
'allow_public_clients' => true,
'always_issue_new_refresh_token' => false,
'unset_refresh_token_after_use' => true,
), $config);

foreach ($grantTypes as $key => $grantType) {
Expand All @@ -133,6 +136,10 @@ public function __construct($storage = array(), array $config = array(), array $
$this->tokenType = $tokenType;
$this->scopeUtil = $scopeUtil;
$this->clientAssertionType = $clientAssertionType;

if ($this->config['use_openid_connect']) {
$this->validateOpenIdConnect();
}
}

public function getAuthorizeController()
Expand Down Expand Up @@ -571,6 +578,7 @@ protected function getDefaultResponseTypes()
throw new \LogicException("Your authorization_code storage must implement OAuth2\OpenID\Storage\AuthorizationCodeInterface to work when 'use_openid_connect' is true");
}
$responseTypes['code'] = new OpenIDAuthorizationCodeResponseType($this->storages['authorization_code'], $config);
$responseTypes['code id_token'] = new CodeIdToken($responseTypes['code'], $responseTypes['id_token']);
} else {
$responseTypes['code'] = new AuthorizationCodeResponseType($this->storages['authorization_code'], $config);
}
Expand All @@ -597,7 +605,7 @@ protected function getDefaultGrantTypes()
}

if (isset($this->storages['refresh_token'])) {
$config = array_intersect_key($this->config, array('always_issue_new_refresh_token' => ''));
$config = array_intersect_key($this->config, array_flip(explode(' ', 'always_issue_new_refresh_token unset_refresh_token_after_use')));
$grantTypes['refresh_token'] = new RefreshToken($this->storages['refresh_token'], $config);
}

Expand Down Expand Up @@ -685,7 +693,7 @@ protected function createDefaultJwtAccessTokenResponseType()
$refreshStorage = $this->storages['refresh_token'];
}

$config = array_intersect_key($this->config, array_flip(explode(' ', 'store_encrypted_token_string')));
$config = array_intersect_key($this->config, array_flip(explode(' ', 'store_encrypted_token_string issuer')));

return new JwtAccessToken($this->storages['public_key'], $tokenStorage, $refreshStorage, $config);
}
Expand Down Expand Up @@ -726,6 +734,14 @@ protected function createDefaultIdTokenTokenResponseType()
return new IdTokenToken($this->getAccessTokenResponseType(), $this->getIdTokenResponseType());
}

protected function validateOpenIdConnect()
{
$authCodeGrant = $this->getGrantType('authorization_code');
if (!empty($authCodeGrant) && !$authCodeGrant instanceof OpenIDAuthorizationCodeGrantType) {
throw new \InvalidArgumentException('You have enabled OpenID Connect, but supplied a grant type that does not support it.');
}
}

protected function normalizeResponseType($name)
{
// for multiple-valued response types - make them alphabetical
Expand Down
Loading

0 comments on commit 8878e19

Please sign in to comment.