mirror of
https://github.com/elyby/accounts.git
synced 2024-12-02 11:41:05 +05:30
Добавлен контроллер для блокировки аккаунта
Добавлен client_credentials grant для oAuth Рефакторинг структуры OauthScopes чтобы можно было разделить владельца прав на пользовательские и общие (машинные) Исправлена стилистика кода, внедряются фишки PHP 7.1
This commit is contained in:
parent
1e7039c05c
commit
79bbc12206
@ -6,8 +6,8 @@ use yii\web\User as YiiUserComponent;
|
|||||||
/**
|
/**
|
||||||
* @property Identity|null $identity
|
* @property Identity|null $identity
|
||||||
*
|
*
|
||||||
* @method Identity|null getIdentity()
|
* @method Identity|null getIdentity($autoRenew = true)
|
||||||
* @method Identity|null loginByAccessToken(string $token, $type = null)
|
* @method Identity|null loginByAccessToken($token, $type = null)
|
||||||
*/
|
*/
|
||||||
class Component extends YiiUserComponent {
|
class Component extends YiiUserComponent {
|
||||||
|
|
||||||
|
@ -26,7 +26,8 @@ class Identity implements IdentityInterface {
|
|||||||
/**
|
/**
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
public static function findIdentityByAccessToken($token, $type = null) {
|
public static function findIdentityByAccessToken($token, $type = null): self {
|
||||||
|
/** @var AccessTokenEntity|null $model */
|
||||||
$model = Yii::$app->oauth->getAuthServer()->getAccessTokenStorage()->get($token);
|
$model = Yii::$app->oauth->getAuthServer()->getAccessTokenStorage()->get($token);
|
||||||
if ($model === null) {
|
if ($model === null) {
|
||||||
throw new UnauthorizedHttpException('Incorrect token');
|
throw new UnauthorizedHttpException('Incorrect token');
|
||||||
@ -41,19 +42,19 @@ class Identity implements IdentityInterface {
|
|||||||
$this->_accessToken = $accessToken;
|
$this->_accessToken = $accessToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAccount() : Account {
|
public function getAccount(): Account {
|
||||||
return $this->getSession()->account;
|
return $this->getSession()->account;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getClient() : OauthClient {
|
public function getClient(): OauthClient {
|
||||||
return $this->getSession()->client;
|
return $this->getSession()->client;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSession() : OauthSession {
|
public function getSession(): OauthSession {
|
||||||
return OauthSession::findOne($this->_accessToken->getSessionId());
|
return OauthSession::findOne($this->_accessToken->getSessionId());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAccessToken() : AccessTokenEntity {
|
public function getAccessToken(): AccessTokenEntity {
|
||||||
return $this->_accessToken;
|
return $this->_accessToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,7 +63,7 @@ class Identity implements IdentityInterface {
|
|||||||
* У нас права привязываются к токенам, так что возвращаем именно его id.
|
* У нас права привязываются к токенам, так что возвращаем именно его id.
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
public function getId() {
|
public function getId(): string {
|
||||||
return $this->_accessToken->getId();
|
return $this->_accessToken->getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,8 @@ namespace api\components\OAuth2\Entities;
|
|||||||
|
|
||||||
class ClientEntity extends \League\OAuth2\Server\Entity\ClientEntity {
|
class ClientEntity extends \League\OAuth2\Server\Entity\ClientEntity {
|
||||||
|
|
||||||
|
private $isTrusted;
|
||||||
|
|
||||||
public function setId(string $id) {
|
public function setId(string $id) {
|
||||||
$this->id = $id;
|
$this->id = $id;
|
||||||
}
|
}
|
||||||
@ -19,4 +21,12 @@ class ClientEntity extends \League\OAuth2\Server\Entity\ClientEntity {
|
|||||||
$this->redirectUri = $redirectUri;
|
$this->redirectUri = $redirectUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setIsTrusted(bool $isTrusted) {
|
||||||
|
$this->isTrusted = $isTrusted;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isTrusted(): bool {
|
||||||
|
return $this->isTrusted;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
20
api/components/OAuth2/Grants/ClientCredentialsGrant.php
Normal file
20
api/components/OAuth2/Grants/ClientCredentialsGrant.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
namespace api\components\OAuth2\Grants;
|
||||||
|
|
||||||
|
use api\components\OAuth2\Entities;
|
||||||
|
|
||||||
|
class ClientCredentialsGrant extends \League\OAuth2\Server\Grant\ClientCredentialsGrant {
|
||||||
|
|
||||||
|
protected function createAccessTokenEntity() {
|
||||||
|
return new Entities\AccessTokenEntity($this->server);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function createRefreshTokenEntity() {
|
||||||
|
return new Entities\RefreshTokenEntity($this->server);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function createSessionEntity() {
|
||||||
|
return new Entities\SessionEntity($this->server);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -74,6 +74,7 @@ class ClientStorage extends AbstractStorage implements ClientInterface {
|
|||||||
$entity->setId($model->id);
|
$entity->setId($model->id);
|
||||||
$entity->setName($model->name);
|
$entity->setName($model->name);
|
||||||
$entity->setSecret($model->secret);
|
$entity->setSecret($model->secret);
|
||||||
|
$entity->setIsTrusted($model->is_trusted);
|
||||||
$entity->setRedirectUri($model->redirect_uri);
|
$entity->setRedirectUri($model->redirect_uri);
|
||||||
|
|
||||||
return $entity;
|
return $entity;
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace api\components\OAuth2\Storage;
|
namespace api\components\OAuth2\Storage;
|
||||||
|
|
||||||
|
use api\components\OAuth2\Entities\ClientEntity;
|
||||||
use api\components\OAuth2\Entities\ScopeEntity;
|
use api\components\OAuth2\Entities\ScopeEntity;
|
||||||
use common\models\OauthScope;
|
use common\models\OauthScope;
|
||||||
use League\OAuth2\Server\Storage\AbstractStorage;
|
use League\OAuth2\Server\Storage\AbstractStorage;
|
||||||
use League\OAuth2\Server\Storage\ScopeInterface;
|
use League\OAuth2\Server\Storage\ScopeInterface;
|
||||||
|
use yii\base\ErrorException;
|
||||||
|
|
||||||
class ScopeStorage extends AbstractStorage implements ScopeInterface {
|
class ScopeStorage extends AbstractStorage implements ScopeInterface {
|
||||||
|
|
||||||
@ -12,7 +14,27 @@ class ScopeStorage extends AbstractStorage implements ScopeInterface {
|
|||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
public function get($scope, $grantType = null, $clientId = null) {
|
public function get($scope, $grantType = null, $clientId = null) {
|
||||||
$scopes = $grantType === 'authorization_code' ? OauthScope::getPublicScopes() : OauthScope::getScopes();
|
$query = OauthScope::find();
|
||||||
|
if ($grantType === 'authorization_code') {
|
||||||
|
$query->onlyPublic()->usersScopes();
|
||||||
|
} elseif ($grantType === 'client_credentials') {
|
||||||
|
$query->machineScopes();
|
||||||
|
$isTrusted = false;
|
||||||
|
if ($clientId !== null) {
|
||||||
|
$client = $this->server->getClientStorage()->get($clientId);
|
||||||
|
if (!$client instanceof ClientEntity) {
|
||||||
|
throw new ErrorException('client storage must return instance of ' . ClientEntity::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
$isTrusted = $client->isTrusted();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$isTrusted) {
|
||||||
|
$query->onlyPublic();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$scopes = $query->all();
|
||||||
if (!in_array($scope, $scopes, true)) {
|
if (!in_array($scope, $scopes, true)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ $params = array_merge(
|
|||||||
return [
|
return [
|
||||||
'id' => 'accounts-site-api',
|
'id' => 'accounts-site-api',
|
||||||
'basePath' => dirname(__DIR__),
|
'basePath' => dirname(__DIR__),
|
||||||
'bootstrap' => ['log', 'authserver'],
|
'bootstrap' => ['log', 'authserver', 'internal'],
|
||||||
'controllerNamespace' => 'api\controllers',
|
'controllerNamespace' => 'api\controllers',
|
||||||
'params' => $params,
|
'params' => $params,
|
||||||
'components' => [
|
'components' => [
|
||||||
@ -75,10 +75,11 @@ return [
|
|||||||
],
|
],
|
||||||
'oauth' => [
|
'oauth' => [
|
||||||
'class' => api\components\OAuth2\Component::class,
|
'class' => api\components\OAuth2\Component::class,
|
||||||
'grantTypes' => ['authorization_code'],
|
'grantTypes' => ['authorization_code', 'client_credentials'],
|
||||||
'grantMap' => [
|
'grantMap' => [
|
||||||
'authorization_code' => api\components\OAuth2\Grants\AuthCodeGrant::class,
|
'authorization_code' => api\components\OAuth2\Grants\AuthCodeGrant::class,
|
||||||
'refresh_token' => api\components\OAuth2\Grants\RefreshTokenGrant::class,
|
'refresh_token' => api\components\OAuth2\Grants\RefreshTokenGrant::class,
|
||||||
|
'client_credentials' => api\components\OAuth2\Grants\ClientCredentialsGrant::class,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'errorHandler' => [
|
'errorHandler' => [
|
||||||
@ -96,5 +97,8 @@ return [
|
|||||||
'mojang' => [
|
'mojang' => [
|
||||||
'class' => api\modules\mojang\Module::class,
|
'class' => api\modules\mojang\Module::class,
|
||||||
],
|
],
|
||||||
|
'internal' => [
|
||||||
|
'class' => api\modules\internal\Module::class,
|
||||||
|
],
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
@ -7,7 +7,9 @@ use api\components\OAuth2\Exception\AccessDeniedException;
|
|||||||
use common\models\Account;
|
use common\models\Account;
|
||||||
use common\models\OauthClient;
|
use common\models\OauthClient;
|
||||||
use common\models\OauthScope;
|
use common\models\OauthScope;
|
||||||
|
use League\OAuth2\Server\AuthorizationServer;
|
||||||
use League\OAuth2\Server\Exception\OAuthException;
|
use League\OAuth2\Server\Exception\OAuthException;
|
||||||
|
use League\OAuth2\Server\Grant\AuthCodeGrant;
|
||||||
use Yii;
|
use Yii;
|
||||||
use yii\filters\AccessControl;
|
use yii\filters\AccessControl;
|
||||||
use yii\helpers\ArrayHelper;
|
use yii\helpers\ArrayHelper;
|
||||||
@ -274,17 +276,12 @@ class OauthController extends Controller {
|
|||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private function getServer(): AuthorizationServer {
|
||||||
* @return \League\OAuth2\Server\AuthorizationServer
|
|
||||||
*/
|
|
||||||
private function getServer() {
|
|
||||||
return Yii::$app->oauth->authServer;
|
return Yii::$app->oauth->authServer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private function getGrantType(): AuthCodeGrant {
|
||||||
* @return \League\OAuth2\Server\Grant\AuthCodeGrant
|
/** @noinspection PhpIncompatibleReturnTypeInspection */
|
||||||
*/
|
|
||||||
private function getGrantType() {
|
|
||||||
return $this->getServer()->getGrantType('authorization_code');
|
return $this->getServer()->getGrantType('authorization_code');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
19
api/modules/internal/Module.php
Normal file
19
api/modules/internal/Module.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
namespace api\modules\internal;
|
||||||
|
|
||||||
|
use yii\base\BootstrapInterface;
|
||||||
|
|
||||||
|
class Module extends \yii\base\Module implements BootstrapInterface {
|
||||||
|
|
||||||
|
public $id = 'internal';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \yii\base\Application $app the application currently running
|
||||||
|
*/
|
||||||
|
public function bootstrap($app) {
|
||||||
|
$app->getUrlManager()->addRules([
|
||||||
|
'/internal/<controller>/<accountId>/<action>' => "{$this->id}/<controller>/<action>",
|
||||||
|
], false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -3,7 +3,7 @@ namespace api\modules\internal\controllers;
|
|||||||
|
|
||||||
use api\components\ApiUser\AccessControl;
|
use api\components\ApiUser\AccessControl;
|
||||||
use api\controllers\Controller;
|
use api\controllers\Controller;
|
||||||
use api\modules\internal\models\BlockForm;
|
use api\modules\internal\models\BanForm;
|
||||||
use common\models\Account;
|
use common\models\Account;
|
||||||
use common\models\OauthScope as S;
|
use common\models\OauthScope as S;
|
||||||
use Yii;
|
use Yii;
|
||||||
@ -14,11 +14,14 @@ class AccountsController extends Controller {
|
|||||||
|
|
||||||
public function behaviors() {
|
public function behaviors() {
|
||||||
return ArrayHelper::merge(parent::behaviors(), [
|
return ArrayHelper::merge(parent::behaviors(), [
|
||||||
|
'authenticator' => [
|
||||||
|
'user' => Yii::$app->apiUser,
|
||||||
|
],
|
||||||
'access' => [
|
'access' => [
|
||||||
'class' => AccessControl::class,
|
'class' => AccessControl::class,
|
||||||
'rules' => [
|
'rules' => [
|
||||||
[
|
[
|
||||||
'actions' => ['block'],
|
'actions' => ['ban'],
|
||||||
'allow' => true,
|
'allow' => true,
|
||||||
'roles' => [S::ACCOUNT_BLOCK],
|
'roles' => [S::ACCOUNT_BLOCK],
|
||||||
],
|
],
|
||||||
@ -27,9 +30,9 @@ class AccountsController extends Controller {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function actionBlock(int $accountId) {
|
public function actionBan(int $accountId) {
|
||||||
$account = $this->findAccount($accountId);
|
$account = $this->findAccount($accountId);
|
||||||
$model = new BlockForm($account);
|
$model = new BanForm($account);
|
||||||
$model->load(Yii::$app->request->post());
|
$model->load(Yii::$app->request->post());
|
||||||
if (!$model->ban()) {
|
if (!$model->ban()) {
|
||||||
return [
|
return [
|
||||||
|
8
api/modules/internal/helpers/Error.php
Normal file
8
api/modules/internal/helpers/Error.php
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
namespace api\modules\internal\helpers;
|
||||||
|
|
||||||
|
final class Error {
|
||||||
|
|
||||||
|
public const ACCOUNT_ALREADY_BANNED = 'error.account_already_banned';
|
||||||
|
|
||||||
|
}
|
@ -2,6 +2,7 @@
|
|||||||
namespace api\modules\internal\models;
|
namespace api\modules\internal\models;
|
||||||
|
|
||||||
use api\models\base\ApiForm;
|
use api\models\base\ApiForm;
|
||||||
|
use api\modules\internal\helpers\Error as E;
|
||||||
use common\helpers\Amqp;
|
use common\helpers\Amqp;
|
||||||
use common\models\Account;
|
use common\models\Account;
|
||||||
use common\models\amqp\AccountBanned;
|
use common\models\amqp\AccountBanned;
|
||||||
@ -9,14 +10,14 @@ use PhpAmqpLib\Message\AMQPMessage;
|
|||||||
use Yii;
|
use Yii;
|
||||||
use yii\base\ErrorException;
|
use yii\base\ErrorException;
|
||||||
|
|
||||||
class BlockForm extends ApiForm {
|
class BanForm extends ApiForm {
|
||||||
|
|
||||||
const DURATION_FOREVER = -1;
|
public const DURATION_FOREVER = -1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Нереализованный функционал блокировки аккаунта на определённый период времени.
|
* Нереализованный функционал блокировки аккаунта на определённый период времени.
|
||||||
* Сейчас установка этого параметра ничего не даст, аккаунт будет заблокирован навечно,
|
* Сейчас установка этого параметра ничего не даст, аккаунт будет заблокирован навечно,
|
||||||
* но по задумке, здесь необходимо передать количество секунд, на которое будет
|
* но, по задумке, здесь можно передать количество секунд, на которое будет
|
||||||
* заблокирован аккаунт пользователя.
|
* заблокирован аккаунт пользователя.
|
||||||
*
|
*
|
||||||
* @var int
|
* @var int
|
||||||
@ -35,10 +36,11 @@ class BlockForm extends ApiForm {
|
|||||||
*/
|
*/
|
||||||
private $account;
|
private $account;
|
||||||
|
|
||||||
public function rules() {
|
public function rules(): array {
|
||||||
return [
|
return [
|
||||||
[['duration'], 'integer', 'min' => self::DURATION_FOREVER],
|
[['duration'], 'integer', 'min' => self::DURATION_FOREVER],
|
||||||
[['message'], 'string'],
|
[['message'], 'string'],
|
||||||
|
[['account'], 'validateAccountActivity'],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,7 +48,17 @@ class BlockForm extends ApiForm {
|
|||||||
return $this->account;
|
return $this->account;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function validateAccountActivity() {
|
||||||
|
if ($this->account->status === Account::STATUS_BANNED) {
|
||||||
|
$this->addError('account', E::ACCOUNT_ALREADY_BANNED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function ban(): bool {
|
public function ban(): bool {
|
||||||
|
if (!$this->validate()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
$transaction = Yii::$app->db->beginTransaction();
|
$transaction = Yii::$app->db->beginTransaction();
|
||||||
|
|
||||||
$account = $this->account;
|
$account = $this->account;
|
||||||
@ -62,7 +74,7 @@ class BlockForm extends ApiForm {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createTask() {
|
public function createTask(): void {
|
||||||
$model = new AccountBanned();
|
$model = new AccountBanned();
|
||||||
$model->accountId = $this->account->id;
|
$model->accountId = $this->account->id;
|
||||||
$model->duration = $this->duration;
|
$model->duration = $this->duration;
|
@ -4,32 +4,33 @@ namespace common\models;
|
|||||||
use common\components\Annotations\Reader;
|
use common\components\Annotations\Reader;
|
||||||
use ReflectionClass;
|
use ReflectionClass;
|
||||||
use Yii;
|
use Yii;
|
||||||
use yii\helpers\ArrayHelper;
|
|
||||||
|
|
||||||
class OauthScope {
|
class OauthScope {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @owner user
|
||||||
|
*/
|
||||||
const OFFLINE_ACCESS = 'offline_access';
|
const OFFLINE_ACCESS = 'offline_access';
|
||||||
|
/**
|
||||||
|
* @owner user
|
||||||
|
*/
|
||||||
const MINECRAFT_SERVER_SESSION = 'minecraft_server_session';
|
const MINECRAFT_SERVER_SESSION = 'minecraft_server_session';
|
||||||
|
/**
|
||||||
|
* @owner user
|
||||||
|
*/
|
||||||
const ACCOUNT_INFO = 'account_info';
|
const ACCOUNT_INFO = 'account_info';
|
||||||
|
/**
|
||||||
|
* @owner user
|
||||||
|
*/
|
||||||
const ACCOUNT_EMAIL = 'account_email';
|
const ACCOUNT_EMAIL = 'account_email';
|
||||||
|
/**
|
||||||
/** @internal */
|
* @internal
|
||||||
|
* @owner machine
|
||||||
|
*/
|
||||||
const ACCOUNT_BLOCK = 'account_block';
|
const ACCOUNT_BLOCK = 'account_block';
|
||||||
|
|
||||||
public static function getScopes(): array {
|
public static function find(): OauthScopeQuery {
|
||||||
return ArrayHelper::getColumn(static::queryScopes(), 'value');
|
return new OauthScopeQuery(static::queryScopes());
|
||||||
}
|
|
||||||
|
|
||||||
public static function getPublicScopes(): array {
|
|
||||||
return ArrayHelper::getColumn(array_filter(static::queryScopes(), function($value) {
|
|
||||||
return !isset($value['internal']);
|
|
||||||
}), 'value');
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getInternalScopes(): array {
|
|
||||||
return ArrayHelper::getColumn(array_filter(static::queryScopes(), function($value) {
|
|
||||||
return isset($value['internal']);
|
|
||||||
}), 'value');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function queryScopes(): array {
|
private static function queryScopes(): array {
|
||||||
@ -43,12 +44,12 @@ class OauthScope {
|
|||||||
foreach ($constants as $constName => $value) {
|
foreach ($constants as $constName => $value) {
|
||||||
$annotations = $reader->getConstantAnnotations(static::class, $constName);
|
$annotations = $reader->getConstantAnnotations(static::class, $constName);
|
||||||
$isInternal = $annotations->get('internal', false);
|
$isInternal = $annotations->get('internal', false);
|
||||||
|
$owner = $annotations->get('owner', 'user');
|
||||||
$keyValue = [
|
$keyValue = [
|
||||||
'value' => $value,
|
'value' => $value,
|
||||||
|
'internal' => $isInternal,
|
||||||
|
'owner' => $owner,
|
||||||
];
|
];
|
||||||
if ($isInternal) {
|
|
||||||
$keyValue['internal'] = true;
|
|
||||||
}
|
|
||||||
$scopes[$constName] = $keyValue;
|
$scopes[$constName] = $keyValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
50
common/models/OauthScopeQuery.php
Normal file
50
common/models/OauthScopeQuery.php
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
namespace common\models;
|
||||||
|
|
||||||
|
use yii\helpers\ArrayHelper;
|
||||||
|
|
||||||
|
class OauthScopeQuery {
|
||||||
|
|
||||||
|
private $scopes;
|
||||||
|
|
||||||
|
private $internal;
|
||||||
|
|
||||||
|
private $owner;
|
||||||
|
|
||||||
|
public function onlyPublic(): self {
|
||||||
|
$this->internal = false;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function onlyInternal(): self {
|
||||||
|
$this->internal = true;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function usersScopes(): self {
|
||||||
|
$this->owner = 'user';
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function machineScopes(): self {
|
||||||
|
$this->owner = 'machine';
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function all(): array {
|
||||||
|
return ArrayHelper::getColumn(array_filter($this->scopes, function($value) {
|
||||||
|
$shouldCheckInternal = $this->internal !== null;
|
||||||
|
$isInternalMatch = $value['internal'] === $this->internal;
|
||||||
|
$shouldCheckOwner = $this->owner !== null;
|
||||||
|
$isOwnerMatch = $value['owner'] === $this->owner;
|
||||||
|
|
||||||
|
return (!$shouldCheckInternal || $isInternalMatch)
|
||||||
|
&& (!$shouldCheckOwner || $isOwnerMatch);
|
||||||
|
}), 'value');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __construct(array $scopes) {
|
||||||
|
$this->scopes = $scopes;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use console\db\Migration;
|
||||||
|
|
||||||
|
class m161228_101022_oauth_clients_allow_null_redirect_uri extends Migration {
|
||||||
|
|
||||||
|
public function safeUp() {
|
||||||
|
$this->alterColumn('{{%oauth_clients}}', 'redirect_uri', $this->string());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function safeDown() {
|
||||||
|
$this->alterColumn('{{%oauth_clients}}', 'redirect_uri', $this->string()->notNull());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
16
tests/codeception/api/_pages/InternalRoute.php
Normal file
16
tests/codeception/api/_pages/InternalRoute.php
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
namespace tests\codeception\api\_pages;
|
||||||
|
|
||||||
|
use yii\codeception\BasePage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property \tests\codeception\api\FunctionalTester $actor
|
||||||
|
*/
|
||||||
|
class InternalRoute extends BasePage {
|
||||||
|
|
||||||
|
public function ban($accountId) {
|
||||||
|
$this->route = '/internal/accounts/' . $accountId . '/ban';
|
||||||
|
$this->actor->sendPOST($this->getUrl());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -3,11 +3,12 @@ namespace tests\codeception\api\functional\_steps;
|
|||||||
|
|
||||||
use common\models\OauthScope as S;
|
use common\models\OauthScope as S;
|
||||||
use tests\codeception\api\_pages\OauthRoute;
|
use tests\codeception\api\_pages\OauthRoute;
|
||||||
|
use tests\codeception\api\FunctionalTester;
|
||||||
|
|
||||||
class OauthSteps extends \tests\codeception\api\FunctionalTester {
|
class OauthSteps extends FunctionalTester {
|
||||||
|
|
||||||
public function getAuthCode(array $permissions = []) {
|
public function getAuthCode(array $permissions = []) {
|
||||||
// TODO: по идее можно напрямую сделать зпись в базу, что ускорит процесс тестирования
|
// TODO: по идее можно напрямую сделать запись в базу, что ускорит процесс тестирования
|
||||||
$this->loggedInAsActiveAccount();
|
$this->loggedInAsActiveAccount();
|
||||||
$route = new OauthRoute($this);
|
$route = new OauthRoute($this);
|
||||||
$route->complete([
|
$route->complete([
|
||||||
@ -31,7 +32,7 @@ class OauthSteps extends \tests\codeception\api\FunctionalTester {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getRefreshToken(array $permissions = []) {
|
public function getRefreshToken(array $permissions = []) {
|
||||||
// TODO: по идее можно напрямую сделать зпись в базу, что ускорит процесс тестирования
|
// TODO: по идее можно напрямую сделать запись в базу, что ускорит процесс тестирования
|
||||||
$authCode = $this->getAuthCode(array_merge([S::OFFLINE_ACCESS], $permissions));
|
$authCode = $this->getAuthCode(array_merge([S::OFFLINE_ACCESS], $permissions));
|
||||||
$response = $this->issueToken($authCode);
|
$response = $this->issueToken($authCode);
|
||||||
|
|
||||||
@ -51,4 +52,18 @@ class OauthSteps extends \tests\codeception\api\FunctionalTester {
|
|||||||
return json_decode($this->grabResponse(), true);
|
return json_decode($this->grabResponse(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getAccessTokenByClientCredentialsGrant(array $permissions = [], $useTrusted = true) {
|
||||||
|
$route = new OauthRoute($this);
|
||||||
|
$route->issueToken([
|
||||||
|
'client_id' => $useTrusted ? 'trusted-client' : 'default-client',
|
||||||
|
'client_secret' => $useTrusted ? 'tXBbyvMcyaOgHMOAXBpN2EC7uFoJAaL9' : 'AzWRy7ZjS1yRQUk2vRBDic8fprOKDB1W',
|
||||||
|
'grant_type' => 'client_credentials',
|
||||||
|
'scope' => implode(',', $permissions),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response = json_decode($this->grabResponse(), true);
|
||||||
|
|
||||||
|
return $response['access_token'];
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
47
tests/codeception/api/functional/internal/BanCest.php
Normal file
47
tests/codeception/api/functional/internal/BanCest.php
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
namespace tests\codeception\api\functional\internal;
|
||||||
|
|
||||||
|
use common\models\OauthScope as S;
|
||||||
|
use tests\codeception\api\_pages\InternalRoute;
|
||||||
|
use tests\codeception\api\functional\_steps\OauthSteps;
|
||||||
|
use tests\codeception\api\FunctionalTester;
|
||||||
|
|
||||||
|
class BanCest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var InternalRoute
|
||||||
|
*/
|
||||||
|
private $route;
|
||||||
|
|
||||||
|
public function _before(FunctionalTester $I) {
|
||||||
|
$this->route = new InternalRoute($I);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testBanAccount(OauthSteps $I) {
|
||||||
|
$accessToken = $I->getAccessTokenByClientCredentialsGrant([S::ACCOUNT_BLOCK]);
|
||||||
|
$I->amBearerAuthenticated($accessToken);
|
||||||
|
|
||||||
|
$this->route->ban(1);
|
||||||
|
$I->canSeeResponseCodeIs(200);
|
||||||
|
$I->canSeeResponseIsJson();
|
||||||
|
$I->canSeeResponseContainsJson([
|
||||||
|
'success' => true,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testBanBannedAccount(OauthSteps $I) {
|
||||||
|
$accessToken = $I->getAccessTokenByClientCredentialsGrant([S::ACCOUNT_BLOCK]);
|
||||||
|
$I->amBearerAuthenticated($accessToken);
|
||||||
|
|
||||||
|
$this->route->ban(10);
|
||||||
|
$I->canSeeResponseCodeIs(200);
|
||||||
|
$I->canSeeResponseIsJson();
|
||||||
|
$I->canSeeResponseContainsJson([
|
||||||
|
'success' => false,
|
||||||
|
'errors' => [
|
||||||
|
'account' => 'error.account_already_banned',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,11 +1,26 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace tests\codeception\api\unit\modules\internal\models;
|
namespace tests\codeception\api\unit\modules\internal\models;
|
||||||
|
|
||||||
use api\modules\internal\models\BlockForm;
|
use api\modules\internal\helpers\Error as E;
|
||||||
|
use api\modules\internal\models\BanForm;
|
||||||
use common\models\Account;
|
use common\models\Account;
|
||||||
use tests\codeception\api\unit\TestCase;
|
use tests\codeception\api\unit\TestCase;
|
||||||
|
|
||||||
class BlockFormTest extends TestCase {
|
class BanFormTest extends TestCase {
|
||||||
|
|
||||||
|
public function testValidateAccountActivity() {
|
||||||
|
$account = new Account();
|
||||||
|
$account->status = Account::STATUS_ACTIVE;
|
||||||
|
$form = new BanForm($account);
|
||||||
|
$form->validateAccountActivity();
|
||||||
|
$this->assertEmpty($form->getErrors('account'));
|
||||||
|
|
||||||
|
$account = new Account();
|
||||||
|
$account->status = Account::STATUS_BANNED;
|
||||||
|
$form = new BanForm($account);
|
||||||
|
$form->validateAccountActivity();
|
||||||
|
$this->assertEquals([E::ACCOUNT_ALREADY_BANNED], $form->getErrors('account'));
|
||||||
|
}
|
||||||
|
|
||||||
public function testBan() {
|
public function testBan() {
|
||||||
/** @var Account|\PHPUnit_Framework_MockObject_MockObject $account */
|
/** @var Account|\PHPUnit_Framework_MockObject_MockObject $account */
|
||||||
@ -17,7 +32,7 @@ class BlockFormTest extends TestCase {
|
|||||||
->method('save')
|
->method('save')
|
||||||
->willReturn(true);
|
->willReturn(true);
|
||||||
|
|
||||||
$model = new BlockForm($account);
|
$model = new BanForm($account);
|
||||||
$this->assertTrue($model->ban());
|
$this->assertTrue($model->ban());
|
||||||
$this->assertEquals(Account::STATUS_BANNED, $account->status);
|
$this->assertEquals(Account::STATUS_BANNED, $account->status);
|
||||||
$this->tester->canSeeAmqpMessageIsCreated('events');
|
$this->tester->canSeeAmqpMessageIsCreated('events');
|
||||||
@ -27,14 +42,14 @@ class BlockFormTest extends TestCase {
|
|||||||
$account = new Account();
|
$account = new Account();
|
||||||
$account->id = 3;
|
$account->id = 3;
|
||||||
|
|
||||||
$model = new BlockForm($account);
|
$model = new BanForm($account);
|
||||||
$model->createTask();
|
$model->createTask();
|
||||||
$message = json_decode($this->tester->grabLastSentAmqpMessage('events')->body, true);
|
$message = json_decode($this->tester->grabLastSentAmqpMessage('events')->body, true);
|
||||||
$this->assertSame(3, $message['accountId']);
|
$this->assertSame(3, $message['accountId']);
|
||||||
$this->assertSame(-1, $message['duration']);
|
$this->assertSame(-1, $message['duration']);
|
||||||
$this->assertSame('', $message['message']);
|
$this->assertSame('', $message['message']);
|
||||||
|
|
||||||
$model = new BlockForm($account);
|
$model = new BanForm($account);
|
||||||
$model->duration = 123;
|
$model->duration = 123;
|
||||||
$model->message = 'test';
|
$model->message = 'test';
|
||||||
$model->createTask();
|
$model->createTask();
|
@ -30,4 +30,24 @@ return [
|
|||||||
'is_trusted' => 0,
|
'is_trusted' => 0,
|
||||||
'created_at' => 1479937982,
|
'created_at' => 1479937982,
|
||||||
],
|
],
|
||||||
|
'trustedClient' => [
|
||||||
|
'id' => 'trusted-client',
|
||||||
|
'secret' => 'tXBbyvMcyaOgHMOAXBpN2EC7uFoJAaL9',
|
||||||
|
'name' => 'Trusted client',
|
||||||
|
'description' => 'Это клиент, которому мы доверяем',
|
||||||
|
'redirect_uri' => null,
|
||||||
|
'account_id' => null,
|
||||||
|
'is_trusted' => 1,
|
||||||
|
'created_at' => 1482922663,
|
||||||
|
],
|
||||||
|
'defaultClient' => [
|
||||||
|
'id' => 'default-client',
|
||||||
|
'secret' => 'AzWRy7ZjS1yRQUk2vRBDic8fprOKDB1W',
|
||||||
|
'name' => 'Default client',
|
||||||
|
'description' => 'Это обычный клиент, каких может быть много',
|
||||||
|
'redirect_uri' => null,
|
||||||
|
'account_id' => null,
|
||||||
|
'is_trusted' => 0,
|
||||||
|
'created_at' => 1482922711,
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace tests\codeception\common\unit\models;
|
|
||||||
|
|
||||||
use tests\codeception\common\unit\TestCase;
|
|
||||||
|
|
||||||
class OauthScopeTest extends TestCase {
|
|
||||||
|
|
||||||
public function testTest() {
|
|
||||||
$scopes = \common\models\OauthScope::getScopes();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user