From cb068b9dc0b5b84ba6e3c320d6a9b87e86622b89 Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Sat, 17 Jun 2017 21:05:36 +0300 Subject: [PATCH] =?UTF-8?q?=D0=92=D1=81=D0=B5=20=D1=80=D0=B5=D0=B0=D0=BB?= =?UTF-8?q?=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D0=B8=20Grant'=D0=BE=D0=B2=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20oAuth=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BD?= =?UTF-8?q?=D0=B5=D1=81=D0=B5=D0=BD=D1=8B=20=D0=B2=20=D0=BF=D1=80=D0=BE?= =?UTF-8?q?=D0=B5=D0=BA=D1=82.=20=D0=A4=D0=BE=D1=80=D0=BA=20league/oauth2-?= =?UTF-8?q?client=20=D0=B1=D0=BE=D0=BB=D1=8C=D1=88=D0=B5=20=D0=BD=D0=B5=20?= =?UTF-8?q?=D0=B8=D1=81=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D1=83=D0=B5=D1=82?= =?UTF-8?q?=D1=81=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/components/OAuth2/Component.php | 55 ++--- .../OAuth2/Grants/AuthCodeGrant.php | 218 +++++++++++++++++- .../OAuth2/Grants/AuthorizeParams.php | 58 +++++ .../OAuth2/Grants/ClientCredentialsGrant.php | 73 +++++- .../OAuth2/Grants/RefreshTokenGrant.php | 86 ++++--- api/models/OauthProcess.php | 77 ++----- common/config/config.php | 6 - composer.json | 6 +- 8 files changed, 415 insertions(+), 164 deletions(-) create mode 100644 api/components/OAuth2/Grants/AuthorizeParams.php diff --git a/api/components/OAuth2/Component.php b/api/components/OAuth2/Component.php index d6ad066..f5be5d9 100644 --- a/api/components/OAuth2/Component.php +++ b/api/components/OAuth2/Component.php @@ -1,67 +1,40 @@ class - */ - public $grantMap = [ - 'authorization_code' => Grant\AuthCodeGrant::class, - 'client_credentials' => Grant\ClientCredentialsGrant::class, - 'password' => Grant\PasswordGrant::class, - 'refresh_token' => Grant\RefreshTokenGrant::class, - ]; - - public function getAuthServer() { + public function getAuthServer(): AuthorizationServer { if ($this->_authServer === null) { $authServer = new AuthorizationServer(); - $authServer->setAccessTokenStorage(new AccessTokenStorage()); - $authServer->setClientStorage(new ClientStorage()); - $authServer->setScopeStorage(new ScopeStorage()); - $authServer->setSessionStorage(new SessionStorage()); - $authServer->setAuthCodeStorage(new AuthCodeStorage()); - $authServer->setRefreshTokenStorage(new RefreshTokenStorage()); + $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->setScopeDelimiter(','); $authServer->setAccessTokenTTL(86400); // 1d + $authServer->addGrantType(new Grants\AuthCodeGrant()); + $authServer->addGrantType(new Grants\RefreshTokenGrant()); + $authServer->addGrantType(new Grants\ClientCredentialsGrant()); + $this->_authServer = $authServer; - foreach ($this->grantTypes as $grantType) { - if (!isset($this->grantMap[$grantType])) { - throw new InvalidConfigException('Invalid grant type'); - } - - /** @var Grant\GrantTypeInterface $grant */ - $grant = new $this->grantMap[$grantType](); - $this->_authServer->addGrantType($grant); - } - SecureKey::setAlgorithm(new UuidAlgorithm()); } diff --git a/api/components/OAuth2/Grants/AuthCodeGrant.php b/api/components/OAuth2/Grants/AuthCodeGrant.php index 134421a..f8f17e0 100644 --- a/api/components/OAuth2/Grants/AuthCodeGrant.php +++ b/api/components/OAuth2/Grants/AuthCodeGrant.php @@ -1,21 +1,221 @@ server); + protected $identifier = 'authorization_code'; + + protected $responseType = 'code'; + + protected $authTokenTTL = 600; + + protected $requireClientSecret = true; + + public function setAuthTokenTTL(int $authTokenTTL): void { + $this->authTokenTTL = $authTokenTTL; } - protected function createRefreshTokenEntity() { - return new Entities\RefreshTokenEntity($this->server); + public function setRequireClientSecret(bool $required): void { + $this->requireClientSecret = $required; } - protected function createSessionEntity() { - return new Entities\SessionEntity($this->server); + public function shouldRequireClientSecret(): bool { + return $this->requireClientSecret; + } + + /** + * Check authorize parameters + * + * @return AuthorizeParams Authorize request parameters + * @throws Exception\OAuthException + * + * @throws + */ + public function checkAuthorizeParams(): AuthorizeParams { + // Get required params + $clientId = $this->server->getRequest()->query->get('client_id'); + if ($clientId === null) { + throw new Exception\InvalidRequestException('client_id'); + } + + $redirectUri = $this->server->getRequest()->query->get('redirect_uri'); + if ($redirectUri === null) { + throw new Exception\InvalidRequestException('redirect_uri'); + } + + // Validate client ID and redirect URI + $client = $this->server->getClientStorage()->get($clientId, null, $redirectUri, $this->getIdentifier()); + if (!$client instanceof ClientEntity) { + $this->server->getEventEmitter()->emit(new ClientAuthenticationFailedEvent($this->server->getRequest())); + throw new Exception\InvalidClientException(); + } + + $state = $this->server->getRequest()->query->get('state'); + if ($state === null && $this->server->stateParamRequired()) { + throw new Exception\InvalidRequestException('state', $redirectUri); + } + + $responseType = $this->server->getRequest()->query->get('response_type'); + if ($responseType === null) { + throw new Exception\InvalidRequestException('response_type', $redirectUri); + } + + // Ensure response type is one that is recognised + if (!in_array($responseType, $this->server->getResponseTypes(), true)) { + throw new Exception\UnsupportedResponseTypeException($responseType, $redirectUri); + } + + // Validate any scopes that are in the request + $scopeParam = $this->server->getRequest()->query->get('scope', ''); + $scopes = $this->validateScopes($scopeParam, $client, $redirectUri); + + return new AuthorizeParams($client, $redirectUri, $state, $responseType, $scopes); + } + + /** + * Parse a new authorize request + * + * @param string $type The session owner's type + * @param string $typeId The session owner's ID + * @param AuthorizeParams $authParams The authorize request $_GET parameters + * + * @return string An authorisation code + */ + public function newAuthorizeRequest(string $type, string $typeId, AuthorizeParams $authParams): string { + // Create a new session + $session = new SessionEntity($this->server); + $session->setOwner($type, $typeId); + $session->associateClient($authParams->getClient()); + + // Create a new auth code + $authCode = new AuthCodeEntity($this->server); + $authCode->setId(SecureKey::generate()); + $authCode->setRedirectUri($authParams->getRedirectUri()); + $authCode->setExpireTime(time() + $this->authTokenTTL); + + foreach ($authParams->getScopes() as $scope) { + $authCode->associateScope($scope); + $session->associateScope($scope); + } + + $session->save(); + $authCode->setSession($session); + $authCode->save(); + + return $authCode->generateRedirectUri($authParams->getState()); + } + + /** + * Complete the auth code grant + * + * @return array + * + * @throws Exception\OAuthException + */ + public function completeFlow(): array { + // Get the required params + $clientId = $this->server->getRequest()->request->get('client_id', $this->server->getRequest()->getUser()); + if ($clientId === null) { + throw new Exception\InvalidRequestException('client_id'); + } + + $clientSecret = $this->server->getRequest()->request->get('client_secret', + $this->server->getRequest()->getPassword()); + if ($clientSecret === null && $this->shouldRequireClientSecret()) { + throw new Exception\InvalidRequestException('client_secret'); + } + + $redirectUri = $this->server->getRequest()->request->get('redirect_uri'); + if ($redirectUri === null) { + throw new Exception\InvalidRequestException('redirect_uri'); + } + + // Validate client ID and client secret + $client = $this->server->getClientStorage()->get($clientId, $clientSecret, $redirectUri, $this->getIdentifier()); + if (!$client instanceof BaseClientEntity) { + $this->server->getEventEmitter()->emit(new ClientAuthenticationFailedEvent($this->server->getRequest())); + throw new Exception\InvalidClientException(); + } + + // Validate the auth code + $authCode = $this->server->getRequest()->request->get('code'); + if ($authCode === null) { + throw new Exception\InvalidRequestException('code'); + } + + $code = $this->server->getAuthCodeStorage()->get($authCode); + if (($code instanceof BaseAuthCodeEntity) === false) { + throw new Exception\InvalidRequestException('code'); + } + + // Ensure the auth code hasn't expired + if ($code->isExpired()) { + throw new Exception\InvalidRequestException('code'); + } + + // Check redirect URI presented matches redirect URI originally used in authorize request + if ($code->getRedirectUri() !== $redirectUri) { + throw new Exception\InvalidRequestException('redirect_uri'); + } + + $session = $code->getSession(); + $session->associateClient($client); + + $authCodeScopes = $code->getScopes(); + + // Generate the access token + $accessToken = new AccessTokenEntity($this->server); + $accessToken->setId(SecureKey::generate()); // TODO: generate code based on permissions + $accessToken->setExpireTime($this->getAccessTokenTTL() + time()); + + foreach ($authCodeScopes as $authCodeScope) { + $session->associateScope($authCodeScope); + } + + foreach ($session->getScopes() as $scope) { + $accessToken->associateScope($scope); + } + + $this->server->getTokenType()->setSession($session); + $this->server->getTokenType()->setParam('access_token', $accessToken->getId()); + $this->server->getTokenType()->setParam('expires_in', $this->getAccessTokenTTL()); + + // Выдаём refresh_token, если запрошен offline_access + if (isset($accessToken->getScopes()[OauthScope::OFFLINE_ACCESS])) { + /** @var RefreshTokenGrant $refreshTokenGrant */ + $refreshTokenGrant = $this->server->getGrantType('refresh_token'); + $refreshToken = new RefreshTokenEntity($this->server); + $refreshToken->setId(SecureKey::generate()); + $refreshToken->setExpireTime($refreshTokenGrant->getRefreshTokenTTL() + time()); + $this->server->getTokenType()->setParam('refresh_token', $refreshToken->getId()); + } + + // Expire the auth code + $code->expire(); + + // Save all the things + $accessToken->setSession($session); + $accessToken->save(); + + if (isset($refreshToken)) { + $refreshToken->setAccessToken($accessToken); + $refreshToken->save(); + } + + return $this->server->getTokenType()->generateResponse(); } /** diff --git a/api/components/OAuth2/Grants/AuthorizeParams.php b/api/components/OAuth2/Grants/AuthorizeParams.php new file mode 100644 index 0000000..c47e90a --- /dev/null +++ b/api/components/OAuth2/Grants/AuthorizeParams.php @@ -0,0 +1,58 @@ +client = $client; + $this->redirectUri = $redirectUri; + $this->state = $state; + $this->responseType = $responseType; + $this->scopes = $scopes; + } + + public function getClient(): ClientEntity { + return $this->client; + } + + public function getRedirectUri(): string { + return $this->redirectUri; + } + + public function getState(): ?string { + return $this->state; + } + + public function getResponseType(): string { + return $this->responseType; + } + + /** + * @return \api\components\OAuth2\Entities\ScopeEntity[] + */ + public function getScopes(): array { + return $this->scopes ?? []; + } + +} diff --git a/api/components/OAuth2/Grants/ClientCredentialsGrant.php b/api/components/OAuth2/Grants/ClientCredentialsGrant.php index ef80342..e0303bd 100644 --- a/api/components/OAuth2/Grants/ClientCredentialsGrant.php +++ b/api/components/OAuth2/Grants/ClientCredentialsGrant.php @@ -1,21 +1,72 @@ server); - } + protected $identifier = 'client_credentials'; - protected function createRefreshTokenEntity() { - return new Entities\RefreshTokenEntity($this->server); - } + /** + * @return array + * @throws \League\OAuth2\Server\Exception\OAuthException + */ + public function completeFlow(): array { + // Get the required params + $clientId = $this->server->getRequest()->request->get('client_id', $this->server->getRequest()->getUser()); + if ($clientId === null) { + throw new Exception\InvalidRequestException('client_id'); + } - protected function createSessionEntity() { - return new Entities\SessionEntity($this->server); + $clientSecret = $this->server->getRequest()->request->get('client_secret', + $this->server->getRequest()->getPassword()); + if ($clientSecret === null) { + throw new Exception\InvalidRequestException('client_secret'); + } + + // Validate client ID and client secret + $client = $this->server->getClientStorage()->get($clientId, $clientSecret, null, $this->getIdentifier()); + if (!$client instanceof BaseClientEntity) { + $this->server->getEventEmitter()->emit(new Event\ClientAuthenticationFailedEvent($this->server->getRequest())); + throw new Exception\InvalidClientException(); + } + + // Validate any scopes that are in the request + $scopeParam = $this->server->getRequest()->request->get('scope', ''); + $scopes = $this->validateScopes($scopeParam, $client); + + // Create a new session + $session = new SessionEntity($this->server); + $session->setOwner('client', $client->getId()); + $session->associateClient($client); + + // Generate an access token + $accessToken = new AccessTokenEntity($this->server); + $accessToken->setId(SecureKey::generate()); + $accessToken->setExpireTime($this->getAccessTokenTTL() + time()); + + // Associate scopes with the session and access token + foreach ($scopes as $scope) { + $session->associateScope($scope); + $accessToken->associateScope($scope); + } + + // Save everything + $session->save(); + $accessToken->setSession($session); + $accessToken->save(); + + $this->server->getTokenType()->setSession($session); + $this->server->getTokenType()->setParam('access_token', $accessToken->getId()); + $this->server->getTokenType()->setParam('expires_in', $this->getAccessTokenTTL()); + + return $this->server->getTokenType()->generateResponse(); } /** diff --git a/api/components/OAuth2/Grants/RefreshTokenGrant.php b/api/components/OAuth2/Grants/RefreshTokenGrant.php index d6e0161..9062aa7 100644 --- a/api/components/OAuth2/Grants/RefreshTokenGrant.php +++ b/api/components/OAuth2/Grants/RefreshTokenGrant.php @@ -1,29 +1,49 @@ server); + protected $refreshTokenTTL = 604800; + + protected $refreshTokenRotate = false; + + protected $requireClientSecret = true; + + public function setRefreshTokenTTL($refreshTokenTTL): void { + $this->refreshTokenTTL = $refreshTokenTTL; } - protected function createRefreshTokenEntity() { - return new Entities\RefreshTokenEntity($this->server); + public function getRefreshTokenTTL(): int { + return $this->refreshTokenTTL; } - protected function createSessionEntity() { - return new Entities\SessionEntity($this->server); + public function setRefreshTokenRotation(bool $refreshTokenRotate = true): void { + $this->refreshTokenRotate = $refreshTokenRotate; + } + + public function shouldRotateRefreshTokens(): bool { + return $this->refreshTokenRotate; + } + + public function setRequireClientSecret(string $required): void { + $this->requireClientSecret = $required; + } + + public function shouldRequireClientSecret(): bool { + return $this->requireClientSecret; } /** @@ -47,10 +67,11 @@ class RefreshTokenGrant extends \League\OAuth2\Server\Grant\RefreshTokenGrant { * Поэтому мы расширили логику RefreshTokenEntity и она теперь знает о сессии, в рамках которой была создана * * @inheritdoc + * @throws \League\OAuth2\Server\Exception\OAuthException */ - public function completeFlow() { + public function completeFlow(): array { $clientId = $this->server->getRequest()->request->get('client_id', $this->server->getRequest()->getUser()); - if (is_null($clientId)) { + if ($clientId === null) { throw new Exception\InvalidRequestException('client_id'); } @@ -58,31 +79,25 @@ class RefreshTokenGrant extends \League\OAuth2\Server\Grant\RefreshTokenGrant { 'client_secret', $this->server->getRequest()->getPassword() ); - if ($this->shouldRequireClientSecret() && is_null($clientSecret)) { + if ($clientSecret === null && $this->shouldRequireClientSecret()) { throw new Exception\InvalidRequestException('client_secret'); } // Validate client ID and client secret - $client = $this->server->getClientStorage()->get( - $clientId, - $clientSecret, - null, - $this->getIdentifier() - ); - - if (($client instanceof OriginalClientEntity) === false) { - $this->server->getEventEmitter()->emit(new Event\ClientAuthenticationFailedEvent($this->server->getRequest())); + $client = $this->server->getClientStorage()->get($clientId, $clientSecret, null, $this->getIdentifier()); + if (($client instanceof BaseClientEntity) === false) { + $this->server->getEventEmitter()->emit(new ClientAuthenticationFailedEvent($this->server->getRequest())); throw new Exception\InvalidClientException(); } - $oldRefreshTokenParam = $this->server->getRequest()->request->get('refresh_token', null); + $oldRefreshTokenParam = $this->server->getRequest()->request->get('refresh_token'); if ($oldRefreshTokenParam === null) { throw new Exception\InvalidRequestException('refresh_token'); } // Validate refresh token $oldRefreshToken = $this->server->getRefreshTokenStorage()->get($oldRefreshTokenParam); - if (($oldRefreshToken instanceof OriginalRefreshTokenEntity) === false) { + if (($oldRefreshToken instanceof BaseRefreshTokenEntity) === false) { throw new Exception\InvalidRefreshException(); } @@ -91,14 +106,15 @@ class RefreshTokenGrant extends \League\OAuth2\Server\Grant\RefreshTokenGrant { throw new Exception\InvalidRefreshException(); } - /** @var Entities\AccessTokenEntity|null $oldAccessToken */ + /** @var AccessTokenEntity|null $oldAccessToken */ $oldAccessToken = $oldRefreshToken->getAccessToken(); - if ($oldAccessToken instanceof Entities\AccessTokenEntity) { + if ($oldAccessToken instanceof AccessTokenEntity) { // Get the scopes for the original session $session = $oldAccessToken->getSession(); } else { - if (!$oldRefreshToken instanceof Entities\RefreshTokenEntity) { - throw new ErrorException('oldRefreshToken must be instance of ' . Entities\RefreshTokenEntity::class); + if (!$oldRefreshToken instanceof RefreshTokenEntity) { + /** @noinspection ExceptionsAnnotatingAndHandlingInspection */ + throw new ErrorException('oldRefreshToken must be instance of ' . RefreshTokenEntity::class); } $session = $oldRefreshToken->getSession(); @@ -126,8 +142,8 @@ class RefreshTokenGrant extends \League\OAuth2\Server\Grant\RefreshTokenGrant { } // Generate a new access token and assign it the correct sessions - $newAccessToken = $this->createAccessTokenEntity(); - $newAccessToken->setId(SecureKey::generate()); + $newAccessToken = new AccessTokenEntity($this->server); + $newAccessToken->setId(SecureKey::generate()); // TODO: generate based on permissions $newAccessToken->setExpireTime($this->getAccessTokenTTL() + time()); $newAccessToken->setSession($session); @@ -136,7 +152,7 @@ class RefreshTokenGrant extends \League\OAuth2\Server\Grant\RefreshTokenGrant { } // Expire the old token and save the new one - ($oldAccessToken instanceof Entities\AccessTokenEntity) && $oldAccessToken->expire(); + $oldAccessToken instanceof BaseAccessTokenEntity && $oldAccessToken->expire(); $newAccessToken->save(); $this->server->getTokenType()->setSession($session); @@ -148,7 +164,7 @@ class RefreshTokenGrant extends \League\OAuth2\Server\Grant\RefreshTokenGrant { $oldRefreshToken->expire(); // Generate a new refresh token - $newRefreshToken = $this->createRefreshTokenEntity(); + $newRefreshToken = new RefreshTokenEntity($this->server); $newRefreshToken->setId(SecureKey::generate()); $newRefreshToken->setExpireTime($this->getRefreshTokenTTL() + time()); $newRefreshToken->setAccessToken($newAccessToken); diff --git a/api/models/OauthProcess.php b/api/models/OauthProcess.php index bf598a4..02a5ddb 100644 --- a/api/models/OauthProcess.php +++ b/api/models/OauthProcess.php @@ -3,13 +3,13 @@ namespace api\models; use api\components\OAuth2\Exception\AcceptRequiredException; use api\components\OAuth2\Exception\AccessDeniedException; +use api\components\OAuth2\Grants\AuthCodeGrant; +use api\components\OAuth2\Grants\AuthorizeParams; use common\models\Account; use common\models\OauthClient; -use common\models\OauthScope; use League\OAuth2\Server\AuthorizationServer; use League\OAuth2\Server\Exception\InvalidGrantException; use League\OAuth2\Server\Exception\OAuthException; -use League\OAuth2\Server\Grant\AuthCodeGrant; use League\OAuth2\Server\Grant\GrantTypeInterface; use Yii; use yii\helpers\ArrayHelper; @@ -45,14 +45,13 @@ class OauthProcess { public function validate(): array { try { $authParams = $this->getAuthorizationCodeGrant()->checkAuthorizeParams(); - /** @var \League\OAuth2\Server\Entity\ClientEntity $client */ - $client = $authParams['client']; + $client = $authParams->getClient(); /** @var \common\models\OauthClient $clientModel */ $clientModel = OauthClient::findOne($client->getId()); $response = $this->buildSuccessResponse( Yii::$app->request->getQueryParams(), $clientModel, - $authParams['scopes'] + $authParams->getScopes() ); } catch (OAuthException $e) { $response = $this->buildErrorResponse($e); @@ -85,10 +84,8 @@ class OauthProcess { $grant = $this->getAuthorizationCodeGrant(); $authParams = $grant->checkAuthorizeParams(); $account = Yii::$app->user->identity; - /** @var \League\OAuth2\Server\Entity\ClientEntity $client */ - $client = $authParams['client']; /** @var \common\models\OauthClient $clientModel */ - $clientModel = OauthClient::findOne($client->getId()); + $clientModel = OauthClient::findOne($authParams->getClient()->getId()); if (!$this->canAutoApprove($account, $clientModel, $authParams)) { $isAccept = Yii::$app->request->post('accept'); @@ -97,7 +94,7 @@ class OauthProcess { } if (!$isAccept) { - throw new AccessDeniedException($authParams['redirect_uri']); + throw new AccessDeniedException($authParams->getRedirectUri()); } } @@ -135,7 +132,6 @@ class OauthProcess { * @return array */ public function getToken(): array { - $this->attachRefreshTokenGrantIfNeeded(); try { $response = $this->server->issueAccessToken(); } catch (OAuthException $e) { @@ -149,66 +145,26 @@ class OauthProcess { return $response; } - /** - * Этот метод нужен за тем, что \League\OAuth2\Server\AuthorizationServer не предоставляет - * метода для проверки, можно ли выдавать refresh_token для пришедшего токена. Он просто - * выдаёт refresh_token, если этот grant присутствует в конфигурации сервера. Так что чтобы - * как-то решить эту проблему, мы не включаем RefreshTokenGrant в базовую конфигурацию сервера, - * а подключаем его только в том случае, если у auth_token есть право на рефреш или если это - * и есть запрос на refresh токена. - */ - private function attachRefreshTokenGrantIfNeeded(): void { - if ($this->server->hasGrantType('refresh_token')) { - return; - } - - $grantType = Yii::$app->request->post('grant_type'); - if ($grantType === 'authorization_code' && Yii::$app->request->post('code')) { - $authCode = Yii::$app->request->post('code'); - $codeModel = $this->server->getAuthCodeStorage()->get($authCode); - if ($codeModel === null) { - return; - } - - $scopes = $codeModel->getScopes(); - if (!array_key_exists(OauthScope::OFFLINE_ACCESS, $scopes)) { - return; - } - } elseif ($grantType === 'refresh_token') { - // Это валидный кейс - } else { - return; - } - - $grantClass = Yii::$app->oauth->grantMap['refresh_token']; - /** @var \League\OAuth2\Server\Grant\RefreshTokenGrant $grant */ - $grant = new $grantClass; - - $this->server->addGrantType($grant); - } - /** * Метод проверяет, может ли текущий пользователь быть автоматически авторизован * для указанного клиента без запроса доступа к необходимому списку прав * - * @param Account $account + * @param Account $account * @param OauthClient $client - * @param array $oauthParams + * @param AuthorizeParams $oauthParams * * @return bool */ - private function canAutoApprove(Account $account, OauthClient $client, array $oauthParams): bool { + private function canAutoApprove(Account $account, OauthClient $client, AuthorizeParams $oauthParams): bool { if ($client->is_trusted) { return true; } - /** @var \League\OAuth2\Server\Entity\ScopeEntity[] $scopes */ - $scopes = $oauthParams['scopes']; /** @var \common\models\OauthSession|null $session */ $session = $account->getOauthSessions()->andWhere(['client_id' => $client->id])->one(); if ($session !== null) { $existScopes = $session->getScopes()->members(); - if (empty(array_diff(array_keys($scopes), $existScopes))) { + if (empty(array_diff(array_keys($oauthParams->getScopes()), $existScopes))) { return true; } } @@ -216,11 +172,18 @@ class OauthProcess { return false; } - private function buildSuccessResponse(array $params, OauthClient $client, array $scopes): array { + /** + * @param array $queryParams + * @param OauthClient $client + * @param \api\components\OAuth2\Entities\ScopeEntity[] $scopes + * + * @return array + */ + private function buildSuccessResponse(array $queryParams, OauthClient $client, array $scopes): array { return [ 'success' => true, // Возвращаем только те ключи, которые имеют реальное отношение к oAuth параметрам - 'oAuth' => array_intersect_key($params, array_flip([ + 'oAuth' => array_intersect_key($queryParams, array_flip([ 'client_id', 'redirect_uri', 'response_type', @@ -230,7 +193,7 @@ class OauthProcess { 'client' => [ 'id' => $client->id, 'name' => $client->name, - 'description' => ArrayHelper::getValue($params, 'description', $client->description), + 'description' => ArrayHelper::getValue($queryParams, 'description', $client->description), ], 'session' => [ 'scopes' => array_keys($scopes), diff --git a/common/config/config.php b/common/config/config.php index 19168d0..6b35122 100644 --- a/common/config/config.php +++ b/common/config/config.php @@ -71,12 +71,6 @@ return [ ], 'oauth' => [ 'class' => api\components\OAuth2\Component::class, - 'grantTypes' => ['authorization_code', 'client_credentials'], - 'grantMap' => [ - 'authorization_code' => api\components\OAuth2\Grants\AuthCodeGrant::class, - 'refresh_token' => api\components\OAuth2\Grants\RefreshTokenGrant::class, - 'client_credentials' => api\components\OAuth2\Grants\ClientCredentialsGrant::class, - ], ], ], 'container' => [ diff --git a/composer.json b/composer.json index 6dc66a0..7ab0e6c 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,7 @@ "yiisoft/yii2": "2.0.12", "yiisoft/yii2-swiftmailer": "*", "ramsey/uuid": "^3.5.0", - "league/oauth2-server": "dev-improvements#fbaa9b0bd3d8050235ba7dde90f731764122bc20", + "league/oauth2-server": "^4.1", "yiisoft/yii2-redis": "~2.0.0", "guzzlehttp/guzzle": "^6.0.0", "php-amqplib/php-amqplib": "^2.6.2", @@ -51,10 +51,6 @@ "type": "git", "url": "git@gitlab.ely.by:elyby/email-renderer.git" }, - { - "type": "git", - "url": "git@gitlab.ely.by:elyby/oauth2-server.git" - }, { "type": "git", "url": "git@github.com:erickskrauch/php-mock-mockery.git"