mirror of
https://github.com/elyby/accounts.git
synced 2025-05-31 14:11:46 +05:30
Upgrade oauth2-server to 8.0.0 version, rewrite repositories and entities, start rewriting tests. Intermediate commit [skip ci]
This commit is contained in:
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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
|
||||
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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;
|
||||
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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.');
|
||||
}
|
||||
|
||||
}
|
@@ -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;
|
||||
}
|
||||
|
||||
}
|
@@ -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;
|
||||
|
18
api/components/OAuth2/Keys/EmptyKey.php
Normal file
18
api/components/OAuth2/Keys/EmptyKey.php
Normal 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 '';
|
||||
}
|
||||
|
||||
}
|
56
api/components/OAuth2/Repositories/AccessTokenRepository.php
Normal file
56
api/components/OAuth2/Repositories/AccessTokenRepository.php
Normal 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.
|
||||
}
|
||||
|
||||
}
|
@@ -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;
|
26
api/components/OAuth2/Repositories/AuthCodeRepository.php
Normal file
26
api/components/OAuth2/Repositories/AuthCodeRepository.php
Normal 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;
|
||||
}
|
||||
|
||||
}
|
@@ -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;
|
41
api/components/OAuth2/Repositories/ClientRepository.php
Normal file
41
api/components/OAuth2/Repositories/ClientRepository.php
Normal 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]);
|
||||
}
|
||||
|
||||
}
|
@@ -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;
|
@@ -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.
|
||||
}
|
||||
|
||||
}
|
@@ -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;
|
37
api/components/OAuth2/Repositories/ScopeRepository.php
Normal file
37
api/components/OAuth2/Repositories/ScopeRepository.php
Normal 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.
|
||||
}
|
||||
|
||||
}
|
@@ -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;
|
@@ -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;
|
Reference in New Issue
Block a user