Upgrade oauth2-server to 8.0.0 version, rewrite repositories and entities, start rewriting tests. Intermediate commit [skip ci]

This commit is contained in:
ErickSkrauch
2019-08-23 11:28:04 +03:00
parent 23a220637c
commit 0b63dc2d84
33 changed files with 604 additions and 363 deletions

View File

@@ -1,10 +1,13 @@
<?php
declare(strict_types=1);
namespace api\components\OAuth2;
use api\components\OAuth2\Keys\EmptyKey;
use api\components\OAuth2\Repositories;
use DateInterval;
use League\OAuth2\Server\AuthorizationServer;
use League\OAuth2\Server\Storage\AccessTokenInterface;
use League\OAuth2\Server\Storage\RefreshTokenInterface;
use League\OAuth2\Server\Storage\SessionInterface;
use League\OAuth2\Server\Grant;
use yii\base\Component as BaseComponent;
/**
@@ -19,18 +22,27 @@ class Component extends BaseComponent {
public function getAuthServer(): AuthorizationServer {
if ($this->_authServer === null) {
$authServer = new AuthorizationServer();
$authServer->setAccessTokenStorage(new Storage\AccessTokenStorage());
$authServer->setClientStorage(new Storage\ClientStorage());
$authServer->setScopeStorage(new Storage\ScopeStorage());
$authServer->setSessionStorage(new Storage\SessionStorage());
$authServer->setAuthCodeStorage(new Storage\AuthCodeStorage());
$authServer->setRefreshTokenStorage(new Storage\RefreshTokenStorage());
$authServer->setAccessTokenTTL(86400); // 1d
$clientsRepo = new Repositories\ClientRepository();
$accessTokensRepo = new Repositories\AccessTokenRepository();
$scopesRepo = new Repositories\ScopeRepository();
$authCodesRepo = new Repositories\AuthCodeRepository();
$refreshTokensRepo = new Repositories\RefreshTokenRepository();
$authServer->addGrantType(new Grants\AuthCodeGrant());
$authServer->addGrantType(new Grants\RefreshTokenGrant());
$authServer->addGrantType(new Grants\ClientCredentialsGrant());
$accessTokenTTL = new DateInterval('P1D');
$authServer = new AuthorizationServer(
$clientsRepo,
$accessTokensRepo,
$scopesRepo,
new EmptyKey(),
'123' // TODO: extract to the variable
);
/** @noinspection PhpUnhandledExceptionInspection */
$authCodeGrant = new Grant\AuthCodeGrant($authCodesRepo, $refreshTokensRepo, new DateInterval('PT10M'));
$authCodeGrant->disableRequireCodeChallengeForPublicClients();
$authServer->enableGrantType($authCodeGrant, $accessTokenTTL);
$authServer->enableGrantType(new Grant\RefreshTokenGrant($refreshTokensRepo), $accessTokenTTL);
$authServer->enableGrantType(new Grant\ClientCredentialsGrant(), $accessTokenTTL);
$this->_authServer = $authServer;
}
@@ -38,16 +50,4 @@ class Component extends BaseComponent {
return $this->_authServer;
}
public function getAccessTokenStorage(): AccessTokenInterface {
return $this->getAuthServer()->getAccessTokenStorage();
}
public function getRefreshTokenStorage(): RefreshTokenInterface {
return $this->getAuthServer()->getRefreshTokenStorage();
}
public function getSessionStorage(): SessionInterface {
return $this->getAuthServer()->getSessionStorage();
}
}

View File

@@ -1,7 +1,7 @@
<?php
namespace api\components\OAuth2\Entities;
use api\components\OAuth2\Storage\SessionStorage;
use api\components\OAuth2\Repositories\SessionStorage;
use ErrorException;
use League\OAuth2\Server\Entity\SessionEntity as OriginalSessionEntity;

View File

@@ -1,29 +1,18 @@
<?php
declare(strict_types=1);
namespace api\components\OAuth2\Entities;
use League\OAuth2\Server\Entity\SessionEntity as OriginalSessionEntity;
use League\OAuth2\Server\Entities\AuthCodeEntityInterface;
use League\OAuth2\Server\Entities\Traits\AuthCodeTrait;
use League\OAuth2\Server\Entities\Traits\EntityTrait;
use League\OAuth2\Server\Entities\Traits\TokenEntityTrait;
class AuthCodeEntity extends \League\OAuth2\Server\Entity\AuthCodeEntity {
class AuthCodeEntity implements AuthCodeEntityInterface {
use EntityTrait;
use AuthCodeTrait;
use TokenEntityTrait;
protected $sessionId;
public function getSessionId() {
return $this->sessionId;
}
/**
* @inheritdoc
* @return static
*/
public function setSession(OriginalSessionEntity $session) {
parent::setSession($session);
$this->sessionId = $session->getId();
return $this;
}
public function setSessionId(string $sessionId) {
$this->sessionId = $sessionId;
}
// TODO: constructor
}

View File

@@ -1,32 +1,21 @@
<?php
declare(strict_types=1);
namespace api\components\OAuth2\Entities;
class ClientEntity extends \League\OAuth2\Server\Entity\ClientEntity {
use League\OAuth2\Server\Entities\ClientEntityInterface;
use League\OAuth2\Server\Entities\Traits\ClientTrait;
use League\OAuth2\Server\Entities\Traits\EntityTrait;
private $isTrusted;
class ClientEntity implements ClientEntityInterface {
use EntityTrait;
use ClientTrait;
public function setId(string $id) {
$this->id = $id;
}
public function setName(string $name) {
public function __construct(string $id, string $name, $redirectUri, bool $isTrusted = false) {
$this->identifier = $id;
$this->name = $name;
}
public function setSecret(string $secret) {
$this->secret = $secret;
}
public function setRedirectUri($redirectUri) {
$this->redirectUri = $redirectUri;
}
public function setIsTrusted(bool $isTrusted) {
$this->isTrusted = $isTrusted;
}
public function isTrusted(): bool {
return $this->isTrusted;
$this->isConfidential = $isTrusted;
}
}

View File

@@ -3,43 +3,12 @@ declare(strict_types=1);
namespace api\components\OAuth2\Entities;
use api\components\OAuth2\Storage\SessionStorage;
use League\OAuth2\Server\Entity\SessionEntity as OriginalSessionEntity;
use Webmozart\Assert\Assert;
use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
use League\OAuth2\Server\Entities\Traits\EntityTrait;
use League\OAuth2\Server\Entities\Traits\RefreshTokenTrait;
class RefreshTokenEntity extends \League\OAuth2\Server\Entity\RefreshTokenEntity {
private $sessionId;
public function isExpired(): bool {
return false;
}
public function getSession(): SessionEntity {
if ($this->session instanceof SessionEntity) {
return $this->session;
}
/** @var SessionStorage $sessionStorage */
$sessionStorage = $this->server->getSessionStorage();
Assert::isInstanceOf($sessionStorage, SessionStorage::class);
return $sessionStorage->getById($this->sessionId);
}
public function getSessionId(): int {
return $this->sessionId;
}
public function setSession(OriginalSessionEntity $session): self {
parent::setSession($session);
$this->setSessionId((int)$session->getId());
return $this;
}
public function setSessionId(int $sessionId): void {
$this->sessionId = $sessionId;
}
class RefreshTokenEntity implements RefreshTokenEntityInterface {
use EntityTrait;
use RefreshTokenTrait;
}

View File

@@ -1,10 +1,18 @@
<?php
declare(strict_types=1);
namespace api\components\OAuth2\Entities;
class ScopeEntity extends \League\OAuth2\Server\Entity\ScopeEntity {
use League\OAuth2\Server\Entities\ScopeEntityInterface;
use League\OAuth2\Server\Entities\Traits\EntityTrait;
use League\OAuth2\Server\Entities\Traits\ScopeTrait;
public function setId(string $id) {
$this->id = $id;
class ScopeEntity implements ScopeEntityInterface {
use EntityTrait;
use ScopeTrait;
public function __construct(string $id) {
$this->identifier = $id;
}
}

View File

@@ -1,22 +0,0 @@
<?php
namespace api\components\OAuth2\Exception;
use League\OAuth2\Server\Exception\OAuthException;
class AcceptRequiredException extends OAuthException {
public $httpStatusCode = 401;
/**
* {@inheritdoc}
*/
public $errorType = 'accept_required';
/**
* {@inheritdoc}
*/
public function __construct() {
parent::__construct('Client must accept authentication request.');
}
}

View File

@@ -1,11 +0,0 @@
<?php
namespace api\components\OAuth2\Exception;
class AccessDeniedException extends \League\OAuth2\Server\Exception\AccessDeniedException {
public function __construct($redirectUri = null) {
parent::__construct();
$this->redirectUri = $redirectUri;
}
}

View File

@@ -6,7 +6,7 @@ use api\components\OAuth2\Entities\AuthCodeEntity;
use api\components\OAuth2\Entities\ClientEntity;
use api\components\OAuth2\Entities\RefreshTokenEntity;
use api\components\OAuth2\Entities\SessionEntity;
use api\components\OAuth2\Storage\ScopeStorage;
use api\components\OAuth2\Repositories\ScopeStorage;
use api\components\OAuth2\Utils\Scopes;
use League\OAuth2\Server\Entity\AuthCodeEntity as BaseAuthCodeEntity;
use League\OAuth2\Server\Entity\ClientEntity as BaseClientEntity;

View File

@@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
namespace api\components\OAuth2\Keys;
use League\OAuth2\Server\CryptKeyInterface;
class EmptyKey implements CryptKeyInterface {
public function getKeyPath(): string {
return '';
}
public function getPassPhrase(): ?string {
return '';
}
}

View File

@@ -0,0 +1,56 @@
<?php
declare(strict_types=1);
namespace api\components\OAuth2\Repositories;
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
use League\OAuth2\Server\Entities\ClientEntityInterface;
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
class AccessTokenRepository implements AccessTokenRepositoryInterface {
/**
* Create a new access token
*
* @param ClientEntityInterface $clientEntity
* @param \League\OAuth2\Server\Entities\ScopeEntityInterface $scopes
* @param mixed $userIdentifier
*
* @return AccessTokenEntityInterface
*/
public function getNewToken(ClientEntityInterface $clientEntity, array $scopes, $userIdentifier = null) {
// TODO: Implement getNewToken() method.
}
/**
* Persists a new access token to permanent storage.
*
* @param AccessTokenEntityInterface $accessTokenEntity
*
* @throws \League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException
*/
public function persistNewAccessToken(AccessTokenEntityInterface $accessTokenEntity) {
// TODO: Implement persistNewAccessToken() method.
}
/**
* Revoke an access token.
*
* @param string $tokenId
*/
public function revokeAccessToken($tokenId) {
// TODO: Implement revokeAccessToken() method.
}
/**
* Check if the access token has been revoked.
*
* @param string $tokenId
*
* @return bool Return true if this token has been revoked
*/
public function isAccessTokenRevoked($tokenId) {
// TODO: Implement isAccessTokenRevoked() method.
}
}

View File

@@ -1,5 +1,5 @@
<?php
namespace api\components\OAuth2\Storage;
namespace api\components\OAuth2\Repositories;
use api\components\OAuth2\Entities\AccessTokenEntity;
use common\components\Redis\Key;

View File

@@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
namespace api\components\OAuth2\Repositories;
use api\components\OAuth2\Entities\AuthCodeEntity;
use League\OAuth2\Server\Entities\AuthCodeEntityInterface;
use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface;
class AuthCodeRepository implements AuthCodeRepositoryInterface {
public function getNewAuthCode(): AuthCodeEntityInterface {
return new AuthCodeEntity();
}
public function persistNewAuthCode(AuthCodeEntityInterface $authCodeEntity): void {
}
public function revokeAuthCode($codeId): void {
}
public function isAuthCodeRevoked($codeId): bool {
return false;
}
}

View File

@@ -1,5 +1,5 @@
<?php
namespace api\components\OAuth2\Storage;
namespace api\components\OAuth2\Repositories;
use api\components\OAuth2\Entities\AuthCodeEntity;
use common\components\Redis\Key;

View File

@@ -0,0 +1,41 @@
<?php
declare(strict_types=1);
namespace api\components\OAuth2\Repositories;
use api\components\OAuth2\Entities\ClientEntity;
use common\models\OauthClient;
use League\OAuth2\Server\Entities\ClientEntityInterface;
use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
class ClientRepository implements ClientRepositoryInterface {
public function getClientEntity($clientId): ?ClientEntityInterface {
$client = $this->findModel($clientId);
if ($client === null) {
return null;
}
return new ClientEntity($client->id, $client->name, $client->redirect_uri, (bool)$client->is_trusted);
}
public function validateClient($clientId, $clientSecret, $grantType): bool {
$client = $this->findModel($clientId);
if ($client === null) {
return false;
}
if ($clientSecret !== null && $clientSecret !== $client->secret) {
return false;
}
// TODO: there is missing behavior of checking redirectUri. Is it now bundled into grant?
return true;
}
private function findModel(string $id): ?OauthClient {
return OauthClient::findOne(['id' => $id]);
}
}

View File

@@ -1,5 +1,5 @@
<?php
namespace api\components\OAuth2\Storage;
namespace api\components\OAuth2\Repositories;
use api\components\OAuth2\Entities\ClientEntity;
use api\components\OAuth2\Entities\SessionEntity;

View File

@@ -0,0 +1,51 @@
<?php
declare(strict_types=1);
namespace api\components\OAuth2\Repositories;
use League\OAuth2\Server\Entities\RefreshTokenEntityInterface;
use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
class RefreshTokenRepository implements RefreshTokenRepositoryInterface {
/**
* Creates a new refresh token
*
* @return RefreshTokenEntityInterface|null
*/
public function getNewRefreshToken(): RefreshTokenEntityInterface {
// TODO: Implement getNewRefreshToken() method.
}
/**
* Create a new refresh token_name.
*
* @param RefreshTokenEntityInterface $refreshTokenEntity
*
* @throws \League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException
*/
public function persistNewRefreshToken(RefreshTokenEntityInterface $refreshTokenEntity) {
// TODO: Implement persistNewRefreshToken() method.
}
/**
* Revoke the refresh token.
*
* @param string $tokenId
*/
public function revokeRefreshToken($tokenId) {
// TODO: Implement revokeRefreshToken() method.
}
/**
* Check if the refresh token has been revoked.
*
* @param string $tokenId
*
* @return bool Return true if this token has been revoked
*/
public function isRefreshTokenRevoked($tokenId) {
// TODO: Implement isRefreshTokenRevoked() method.
}
}

View File

@@ -1,5 +1,5 @@
<?php
namespace api\components\OAuth2\Storage;
namespace api\components\OAuth2\Repositories;
use api\components\OAuth2\Entities\RefreshTokenEntity;
use common\components\Redis\Key;

View File

@@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
namespace api\components\OAuth2\Repositories;
use api\components\OAuth2\Entities\ScopeEntity;
use League\OAuth2\Server\Entities\ScopeEntityInterface;
use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
class ScopeRepository implements ScopeRepositoryInterface {
public function getScopeEntityByIdentifier($identifier): ?ScopeEntityInterface {
// TODO: validate not exists scopes
return new ScopeEntity($identifier);
}
/**
* Given a client, grant type and optional user identifier validate the set of scopes requested are valid and optionally
* append additional scopes or remove requested scopes.
*
* @param ScopeEntityInterface $scopes
* @param string $grantType
* @param \League\OAuth2\Server\Entities\ClientEntityInterface $clientEntity
* @param null|string $userIdentifier
*
* @return ScopeEntityInterface
*/
public function finalizeScopes(
array $scopes,
$grantType,
\League\OAuth2\Server\Entities\ClientEntityInterface $clientEntity,
$userIdentifier = null
): array {
// TODO: Implement finalizeScopes() method.
}
}

View File

@@ -1,5 +1,5 @@
<?php
namespace api\components\OAuth2\Storage;
namespace api\components\OAuth2\Repositories;
use api\components\OAuth2\Entities\ClientEntity;
use api\components\OAuth2\Entities\ScopeEntity;

View File

@@ -1,5 +1,5 @@
<?php
namespace api\components\OAuth2\Storage;
namespace api\components\OAuth2\Repositories;
use api\components\OAuth2\Entities\AuthCodeEntity;
use api\components\OAuth2\Entities\SessionEntity;