Merge remote-tracking branch 'upstream/master' into phpstan-level-7

This commit is contained in:
Andrew Millington 2018-04-21 21:37:24 +01:00
commit 491c23c1e9
No known key found for this signature in database
GPG Key ID: 815DE090877B53F3
14 changed files with 67 additions and 16 deletions

View File

@ -29,7 +29,6 @@ enabled:
- phpdoc_inline_tag - phpdoc_inline_tag
- phpdoc_no_access - phpdoc_no_access
- phpdoc_no_simplified_null_return - phpdoc_no_simplified_null_return
- phpdoc_order
- phpdoc_property - phpdoc_property
- phpdoc_scalar - phpdoc_scalar
- phpdoc_separation - phpdoc_separation

View File

@ -6,7 +6,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
## [Unreleased] ## [Unreleased]
## [7.0.0] - released 2018-02-17 ### Added
- Added event emitters for issued access and refresh tokens (PR #860)
- Can now use Defuse\Crypto\Key for encryption/decryption of keys which is faster than the Cryto class (PR #812)
### Removed
- Remove paragone/random_compat from dependencies
## [7.0.0] - released 2018-02-18
### Added ### Added
- Use PHPStan for static analysis of code (PR #848) - Use PHPStan for static analysis of code (PR #848)

View File

@ -8,7 +8,6 @@
"ext-openssl": "*", "ext-openssl": "*",
"league/event": "^2.1", "league/event": "^2.1",
"lcobucci/jwt": "^3.2.2", "lcobucci/jwt": "^3.2.2",
"paragonie/random_compat": "^2.0",
"psr/http-message": "^1.0.1", "psr/http-message": "^1.0.1",
"defuse/php-encryption": "^2.1" "defuse/php-encryption": "^2.1"
}, },

View File

@ -17,7 +17,7 @@ class ClientRepository implements ClientRepositoryInterface
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function getClientEntity($clientIdentifier, $grantType, $clientSecret = null, $mustValidateSecret = true) public function getClientEntity($clientIdentifier, $grantType = null, $clientSecret = null, $mustValidateSecret = true)
{ {
$clients = [ $clients = [
'myawesomeapp' => [ 'myawesomeapp' => [

View File

@ -9,6 +9,7 @@
namespace League\OAuth2\Server; namespace League\OAuth2\Server;
use Defuse\Crypto\Key;
use League\Event\EmitterAwareInterface; use League\Event\EmitterAwareInterface;
use League\Event\EmitterAwareTrait; use League\Event\EmitterAwareTrait;
use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Exception\OAuthServerException;
@ -68,7 +69,7 @@ class AuthorizationServer implements EmitterAwareInterface
private $scopeRepository; private $scopeRepository;
/** /**
* @var string * @var string|Key
*/ */
private $encryptionKey; private $encryptionKey;
@ -84,7 +85,7 @@ class AuthorizationServer implements EmitterAwareInterface
* @param AccessTokenRepositoryInterface $accessTokenRepository * @param AccessTokenRepositoryInterface $accessTokenRepository
* @param ScopeRepositoryInterface $scopeRepository * @param ScopeRepositoryInterface $scopeRepository
* @param CryptKey|string $privateKey * @param CryptKey|string $privateKey
* @param string $encryptionKey * @param string|Key $encryptionKey
* @param null|ResponseTypeInterface $responseType * @param null|ResponseTypeInterface $responseType
*/ */
public function __construct( public function __construct(

View File

@ -12,11 +12,12 @@
namespace League\OAuth2\Server; namespace League\OAuth2\Server;
use Defuse\Crypto\Crypto; use Defuse\Crypto\Crypto;
use Defuse\Crypto\Key;
trait CryptTrait trait CryptTrait
{ {
/** /**
* @var string * @var string|Key
*/ */
protected $encryptionKey; protected $encryptionKey;
@ -32,6 +33,10 @@ trait CryptTrait
protected function encrypt($unencryptedData) protected function encrypt($unencryptedData)
{ {
try { try {
if ($this->encryptionKey instanceof Key) {
return Crypto::encrypt($unencryptedData, $this->encryptionKey);
}
return Crypto::encryptWithPassword($unencryptedData, $this->encryptionKey); return Crypto::encryptWithPassword($unencryptedData, $this->encryptionKey);
} catch (\Exception $e) { } catch (\Exception $e) {
throw new \LogicException($e->getMessage()); throw new \LogicException($e->getMessage());
@ -50,6 +55,10 @@ trait CryptTrait
protected function decrypt($encryptedData) protected function decrypt($encryptedData)
{ {
try { try {
if ($this->encryptionKey instanceof Key) {
return Crypto::decrypt($encryptedData, $this->encryptionKey);
}
return Crypto::decryptWithPassword($encryptedData, $this->encryptionKey); return Crypto::decryptWithPassword($encryptedData, $this->encryptionKey);
} catch (\Exception $e) { } catch (\Exception $e) {
throw new \LogicException($e->getMessage()); throw new \LogicException($e->getMessage());
@ -59,7 +68,7 @@ trait CryptTrait
/** /**
* Set the encryption key * Set the encryption key
* *
* @param string $key * @param string|Key $key
*/ */
public function setEncryptionKey($key = null) public function setEncryptionKey($key = null)
{ {

View File

@ -176,6 +176,10 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, $authCodePayload->user_id, $scopes); $accessToken = $this->issueAccessToken($accessTokenTTL, $client, $authCodePayload->user_id, $scopes);
$refreshToken = $this->issueRefreshToken($accessToken); $refreshToken = $this->issueRefreshToken($accessToken);
// Send events to emitter
$this->getEmitter()->emit(new RequestEvent(RequestEvent::ACCESS_TOKEN_ISSUED, $request));
$this->getEmitter()->emit(new RequestEvent(RequestEvent::REFRESH_TOKEN_ISSUED, $request));
// Inject tokens into response type // Inject tokens into response type
$responseType->setAccessToken($accessToken); $responseType->setAccessToken($accessToken);
$responseType->setRefreshToken($refreshToken); $responseType->setRefreshToken($refreshToken);
@ -218,6 +222,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
$request, $request,
$this->getServerParameter('PHP_AUTH_USER', $request) $this->getServerParameter('PHP_AUTH_USER', $request)
); );
if (is_null($clientId)) { if (is_null($clientId)) {
throw OAuthServerException::invalidRequest('client_id'); throw OAuthServerException::invalidRequest('client_id');
} }
@ -235,6 +240,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
} }
$redirectUri = $this->getQueryStringParameter('redirect_uri', $request); $redirectUri = $this->getQueryStringParameter('redirect_uri', $request);
if ($redirectUri !== null) { if ($redirectUri !== null) {
if ( if (
is_string($client->getRedirectUri()) is_string($client->getRedirectUri())
@ -284,6 +290,7 @@ class AuthCodeGrant extends AbstractAuthorizeGrant
} }
$codeChallengeMethod = $this->getQueryStringParameter('code_challenge_method', $request, 'plain'); $codeChallengeMethod = $this->getQueryStringParameter('code_challenge_method', $request, 'plain');
if (in_array($codeChallengeMethod, ['plain', 'S256'], true) === false) { if (in_array($codeChallengeMethod, ['plain', 'S256'], true) === false) {
throw OAuthServerException::invalidRequest( throw OAuthServerException::invalidRequest(
'code_challenge_method', 'code_challenge_method',

View File

@ -11,6 +11,7 @@
namespace League\OAuth2\Server\Grant; namespace League\OAuth2\Server\Grant;
use League\OAuth2\Server\RequestEvent;
use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface;
@ -37,6 +38,9 @@ class ClientCredentialsGrant extends AbstractGrant
// Issue and persist access token // Issue and persist access token
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, null, $finalizedScopes); $accessToken = $this->issueAccessToken($accessTokenTTL, $client, null, $finalizedScopes);
// Send event to emitter
$this->getEmitter()->emit(new RequestEvent(RequestEvent::ACCESS_TOKEN_ISSUED, $request));
// Inject access token into response type // Inject access token into response type
$responseType->setAccessToken($accessToken); $responseType->setAccessToken($accessToken);

View File

@ -11,6 +11,7 @@
namespace League\OAuth2\Server\Grant; namespace League\OAuth2\Server\Grant;
use Defuse\Crypto\Key;
use League\Event\EmitterAwareInterface; use League\Event\EmitterAwareInterface;
use League\OAuth2\Server\CryptKey; use League\OAuth2\Server\CryptKey;
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface; use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
@ -136,7 +137,7 @@ interface GrantTypeInterface extends EmitterAwareInterface
/** /**
* Set the encryption key * Set the encryption key
* *
* @param string|null $key * @param string|Key|null $key
*/ */
public function setEncryptionKey($key = null); public function setEncryptionKey($key = null);
} }

View File

@ -59,6 +59,10 @@ class PasswordGrant extends AbstractGrant
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, $user->getIdentifier(), $finalizedScopes); $accessToken = $this->issueAccessToken($accessTokenTTL, $client, $user->getIdentifier(), $finalizedScopes);
$refreshToken = $this->issueRefreshToken($accessToken); $refreshToken = $this->issueRefreshToken($accessToken);
// Send events to emitter
$this->getEmitter()->emit(new RequestEvent(RequestEvent::ACCESS_TOKEN_ISSUED, $request));
$this->getEmitter()->emit(new RequestEvent(RequestEvent::REFRESH_TOKEN_ISSUED, $request));
// Inject tokens into response // Inject tokens into response
$responseType->setAccessToken($accessToken); $responseType->setAccessToken($accessToken);
$responseType->setRefreshToken($refreshToken); $responseType->setRefreshToken($refreshToken);

View File

@ -65,6 +65,10 @@ class RefreshTokenGrant extends AbstractGrant
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, $oldRefreshToken['user_id'], $scopes); $accessToken = $this->issueAccessToken($accessTokenTTL, $client, $oldRefreshToken['user_id'], $scopes);
$refreshToken = $this->issueRefreshToken($accessToken); $refreshToken = $this->issueRefreshToken($accessToken);
// Send events to emitter
$this->getEmitter()->emit(new RequestEvent(RequestEvent::ACCESS_TOKEN_ISSUED, $request));
$this->getEmitter()->emit(new RequestEvent(RequestEvent::REFRESH_TOKEN_ISSUED, $request));
// Inject tokens into response // Inject tokens into response
$responseType->setAccessToken($accessToken); $responseType->setAccessToken($accessToken);
$responseType->setRefreshToken($refreshToken); $responseType->setRefreshToken($refreshToken);

View File

@ -18,6 +18,9 @@ class RequestEvent extends Event
const USER_AUTHENTICATION_FAILED = 'user.authentication.failed'; const USER_AUTHENTICATION_FAILED = 'user.authentication.failed';
const REFRESH_TOKEN_CLIENT_FAILED = 'refresh_token.client.failed'; const REFRESH_TOKEN_CLIENT_FAILED = 'refresh_token.client.failed';
const REFRESH_TOKEN_ISSUED = 'refresh_token.issued';
const ACCESS_TOKEN_ISSUED = 'access_token.issued';
/** /**
* @var ServerRequestInterface * @var ServerRequestInterface
*/ */

View File

@ -11,6 +11,7 @@
namespace League\OAuth2\Server\ResponseTypes; namespace League\OAuth2\Server\ResponseTypes;
use Defuse\Crypto\Key;
use League\OAuth2\Server\Entities\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
use League\OAuth2\Server\Entities\RefreshTokenEntityInterface; use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ResponseInterface;
@ -37,7 +38,7 @@ interface ResponseTypeInterface
/** /**
* Set the encryption key * Set the encryption key
* *
* @param string|null $key * @param string|Key|null $key
*/ */
public function setEncryptionKey($key = null); public function setEncryptionKey($key = null);
} }

View File

@ -2,22 +2,34 @@
namespace LeagueTests\Utils; namespace LeagueTests\Utils;
use Defuse\Crypto\Key;
use LeagueTests\Stubs\CryptTraitStub; use LeagueTests\Stubs\CryptTraitStub;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
class CryptTraitTest extends TestCase class CryptTraitTest extends TestCase
{ {
/**
* @var \LeagueTests\Stubs\CryptTraitStub
*/
protected $cryptStub; protected $cryptStub;
public function setUp() protected function setUp()
{ {
$this->cryptStub = new CryptTraitStub; $this->cryptStub = new CryptTraitStub();
} }
public function testEncryptDecrypt() public function testEncryptDecryptWithPassword()
{
$this->cryptStub->setEncryptionKey(base64_encode(random_bytes(36)));
$this->encryptDecrypt();
}
public function testEncryptDecryptWithKey()
{
$this->cryptStub->setEncryptionKey(Key::createNewRandomKey());
$this->encryptDecrypt();
}
private function encryptDecrypt()
{ {
$payload = 'alex loves whisky'; $payload = 'alex loves whisky';
$encrypted = $this->cryptStub->doEncrypt($payload); $encrypted = $this->cryptStub->doEncrypt($payload);