mirror of
https://github.com/elyby/accounts.git
synced 2025-05-31 14:11:46 +05:30
Объединены сущности для авторизации посредством JWT токенов и токенов, выданных через oAuth2.
Все действия, связанные с аккаунтами, теперь вызываются через url `/api/v1/accounts/<id>/<action>`. Добавлена вменяемая система разграничения прав на основе RBAC. Теперь oAuth2 токены генерируются как случайная строка в 40 символов длинной, а не UUID. Исправлен баг с неправильным временем жизни токена в ответе успешного запроса аутентификации. Теперь все unit тесты можно успешно прогнать без наличия интернета.
This commit is contained in:
@@ -1,35 +1,34 @@
|
||||
<?php
|
||||
namespace codeception\api\unit\models;
|
||||
|
||||
use api\models\AccountIdentity;
|
||||
use api\components\User\IdentityInterface;
|
||||
use api\components\User\Jwt;
|
||||
use api\components\User\JwtIdentity;
|
||||
use Codeception\Specify;
|
||||
use Emarref\Jwt\Claim;
|
||||
use Emarref\Jwt\Encryption\Factory as EncryptionFactory;
|
||||
use Emarref\Jwt\Jwt;
|
||||
use Emarref\Jwt\Token;
|
||||
use tests\codeception\api\unit\TestCase;
|
||||
use tests\codeception\common\_support\ProtectedCaller;
|
||||
use tests\codeception\common\fixtures\AccountFixture;
|
||||
use Yii;
|
||||
use yii\web\IdentityInterface;
|
||||
|
||||
/**
|
||||
* @property AccountIdentity $accounts
|
||||
*/
|
||||
class AccountIdentityTest extends TestCase {
|
||||
class JwtIdentityTest extends TestCase {
|
||||
use Specify;
|
||||
use ProtectedCaller;
|
||||
|
||||
public function _fixtures() {
|
||||
public function _fixtures(): array {
|
||||
return [
|
||||
'accounts' => AccountFixture::class,
|
||||
];
|
||||
}
|
||||
|
||||
public function testFindIdentityByAccessToken() {
|
||||
$identity = AccountIdentity::findIdentityByAccessToken($this->generateToken());
|
||||
$token = $this->generateToken();
|
||||
$identity = JwtIdentity::findIdentityByAccessToken($token);
|
||||
$this->assertInstanceOf(IdentityInterface::class, $identity);
|
||||
$this->assertEquals($this->tester->grabFixture('accounts', 'admin')['id'], $identity->getId());
|
||||
$this->assertEquals($token, $identity->getId());
|
||||
$this->assertEquals($this->tester->grabFixture('accounts', 'admin')['id'], $identity->getAccount()->id);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -42,10 +41,10 @@ class AccountIdentityTest extends TestCase {
|
||||
$token->addClaim(new Claim\Issuer('http://localhost'));
|
||||
$token->addClaim(new Claim\IssuedAt(1464593193));
|
||||
$token->addClaim(new Claim\Expiration(1464596793));
|
||||
$token->addClaim(new Claim\JwtId($this->tester->grabFixture('accounts', 'admin')['id']));
|
||||
$token->addClaim(new Claim\Subject('ely|' . $this->tester->grabFixture('accounts', 'admin')['id']));
|
||||
$expiredToken = (new Jwt())->serialize($token, EncryptionFactory::create(Yii::$app->user->getAlgorithm()));
|
||||
|
||||
AccountIdentity::findIdentityByAccessToken($expiredToken);
|
||||
JwtIdentity::findIdentityByAccessToken($expiredToken);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -53,15 +52,14 @@ class AccountIdentityTest extends TestCase {
|
||||
* @expectedExceptionMessage Incorrect token
|
||||
*/
|
||||
public function testFindIdentityByAccessTokenWithEmptyToken() {
|
||||
AccountIdentity::findIdentityByAccessToken('');
|
||||
JwtIdentity::findIdentityByAccessToken('');
|
||||
}
|
||||
|
||||
protected function generateToken() {
|
||||
/** @var \api\components\User\Component $component */
|
||||
$component = Yii::$app->user;
|
||||
/** @var AccountIdentity $account */
|
||||
$account = AccountIdentity::findOne($this->tester->grabFixture('accounts', 'admin')['id']);
|
||||
|
||||
/** @var \common\models\Account $account */
|
||||
$account = $this->tester->grabFixture('accounts', 'admin');
|
||||
$token = $this->callProtected($component, 'createToken', $account);
|
||||
|
||||
return $this->callProtected($component, 'serializeToken', $token);
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
namespace tests\codeception\api\models\authentication;
|
||||
|
||||
use api\components\User\LoginResult;
|
||||
use api\components\User\AuthenticationResult;
|
||||
use api\models\authentication\ConfirmEmailForm;
|
||||
use common\models\Account;
|
||||
use common\models\AccountSession;
|
||||
@@ -21,7 +21,7 @@ class ConfirmEmailFormTest extends TestCase {
|
||||
$fixture = $this->tester->grabFixture('emailActivations', 'freshRegistrationConfirmation');
|
||||
$model = $this->createModel($fixture['key']);
|
||||
$result = $model->confirm();
|
||||
$this->assertInstanceOf(LoginResult::class, $result);
|
||||
$this->assertInstanceOf(AuthenticationResult::class, $result);
|
||||
$this->assertInstanceOf(AccountSession::class, $result->getSession(), 'session was generated');
|
||||
$activationExists = EmailActivation::find()->andWhere(['key' => $fixture['key']])->exists();
|
||||
$this->assertFalse($activationExists, 'email activation key is not exist');
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
<?php
|
||||
namespace tests\codeception\api\models\authentication;
|
||||
|
||||
use api\components\User\LoginResult;
|
||||
use api\models\AccountIdentity;
|
||||
use api\components\User\AuthenticationResult;
|
||||
use api\models\authentication\LoginForm;
|
||||
use Codeception\Specify;
|
||||
use common\models\Account;
|
||||
@@ -45,7 +44,7 @@ class LoginFormTest extends TestCase {
|
||||
$this->specify('no errors if login exists', function () {
|
||||
$model = $this->createModel([
|
||||
'login' => 'mr-test',
|
||||
'account' => new AccountIdentity(),
|
||||
'account' => new Account(),
|
||||
]);
|
||||
$model->validateLogin('login');
|
||||
$this->assertEmpty($model->getErrors('login'));
|
||||
@@ -56,7 +55,7 @@ class LoginFormTest extends TestCase {
|
||||
$this->specify('error.password_incorrect if password invalid', function () {
|
||||
$model = $this->createModel([
|
||||
'password' => '87654321',
|
||||
'account' => new AccountIdentity(['password' => '12345678']),
|
||||
'account' => new Account(['password' => '12345678']),
|
||||
]);
|
||||
$model->validatePassword('password');
|
||||
$this->assertEquals(['error.password_incorrect'], $model->getErrors('password'));
|
||||
@@ -65,7 +64,7 @@ class LoginFormTest extends TestCase {
|
||||
$this->specify('no errors if password valid', function () {
|
||||
$model = $this->createModel([
|
||||
'password' => '12345678',
|
||||
'account' => new AccountIdentity(['password' => '12345678']),
|
||||
'account' => new Account(['password' => '12345678']),
|
||||
]);
|
||||
$model->validatePassword('password');
|
||||
$this->assertEmpty($model->getErrors('password'));
|
||||
@@ -73,7 +72,7 @@ class LoginFormTest extends TestCase {
|
||||
}
|
||||
|
||||
public function testValidateTotp() {
|
||||
$account = new AccountIdentity(['password' => '12345678']);
|
||||
$account = new Account(['password' => '12345678']);
|
||||
$account->password = '12345678';
|
||||
$account->is_otp_enabled = true;
|
||||
$account->otp_secret = 'AAAA';
|
||||
@@ -103,7 +102,7 @@ class LoginFormTest extends TestCase {
|
||||
public function testValidateActivity() {
|
||||
$this->specify('error.account_not_activated if account in not activated state', function () {
|
||||
$model = $this->createModel([
|
||||
'account' => new AccountIdentity(['status' => Account::STATUS_REGISTERED]),
|
||||
'account' => new Account(['status' => Account::STATUS_REGISTERED]),
|
||||
]);
|
||||
$model->validateActivity('login');
|
||||
$this->assertEquals(['error.account_not_activated'], $model->getErrors('login'));
|
||||
@@ -111,7 +110,7 @@ class LoginFormTest extends TestCase {
|
||||
|
||||
$this->specify('error.account_banned if account has banned status', function () {
|
||||
$model = $this->createModel([
|
||||
'account' => new AccountIdentity(['status' => Account::STATUS_BANNED]),
|
||||
'account' => new Account(['status' => Account::STATUS_BANNED]),
|
||||
]);
|
||||
$model->validateActivity('login');
|
||||
$this->assertEquals(['error.account_banned'], $model->getErrors('login'));
|
||||
@@ -119,7 +118,7 @@ class LoginFormTest extends TestCase {
|
||||
|
||||
$this->specify('no errors if account active', function () {
|
||||
$model = $this->createModel([
|
||||
'account' => new AccountIdentity(['status' => Account::STATUS_ACTIVE]),
|
||||
'account' => new Account(['status' => Account::STATUS_ACTIVE]),
|
||||
]);
|
||||
$model->validateActivity('login');
|
||||
$this->assertEmpty($model->getErrors('login'));
|
||||
@@ -130,13 +129,13 @@ class LoginFormTest extends TestCase {
|
||||
$model = $this->createModel([
|
||||
'login' => 'erickskrauch',
|
||||
'password' => '12345678',
|
||||
'account' => new AccountIdentity([
|
||||
'account' => new Account([
|
||||
'username' => 'erickskrauch',
|
||||
'password' => '12345678',
|
||||
'status' => Account::STATUS_ACTIVE,
|
||||
]),
|
||||
]);
|
||||
$this->assertInstanceOf(LoginResult::class, $model->login(), 'model should login user');
|
||||
$this->assertInstanceOf(AuthenticationResult::class, $model->login(), 'model should login user');
|
||||
$this->assertEmpty($model->getErrors(), 'error message should not be set');
|
||||
}
|
||||
|
||||
@@ -145,7 +144,7 @@ class LoginFormTest extends TestCase {
|
||||
'login' => $this->tester->grabFixture('accounts', 'user-with-old-password-type')['username'],
|
||||
'password' => '12345678',
|
||||
]);
|
||||
$this->assertInstanceOf(LoginResult::class, $model->login());
|
||||
$this->assertInstanceOf(AuthenticationResult::class, $model->login());
|
||||
$this->assertEmpty($model->getErrors());
|
||||
$this->assertEquals(
|
||||
Account::PASS_HASH_STRATEGY_YII2,
|
||||
@@ -166,7 +165,7 @@ class LoginFormTest extends TestCase {
|
||||
$this->_account = $value;
|
||||
}
|
||||
|
||||
public function getAccount() {
|
||||
public function getAccount(): ?Account {
|
||||
return $this->_account;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
namespace tests\codeception\api\models\authentication;
|
||||
|
||||
use api\components\User\Component;
|
||||
use api\models\AccountIdentity;
|
||||
use api\components\User\Identity;
|
||||
use api\models\authentication\LogoutForm;
|
||||
use Codeception\Specify;
|
||||
use common\models\AccountSession;
|
||||
@@ -59,7 +59,7 @@ class LogoutFormTest extends TestCase {
|
||||
|
||||
private function getComponentArgs() {
|
||||
return [
|
||||
'identityClass' => AccountIdentity::class,
|
||||
'identityClass' => Identity::class,
|
||||
'enableSession' => false,
|
||||
'loginUrl' => null,
|
||||
'secret' => 'secret',
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
namespace tests\codeception\api\models\authentication;
|
||||
|
||||
use api\components\User\LoginResult;
|
||||
use api\components\User\AuthenticationResult;
|
||||
use api\models\authentication\RecoverPasswordForm;
|
||||
use Codeception\Specify;
|
||||
use common\models\Account;
|
||||
@@ -26,7 +26,7 @@ class RecoverPasswordFormTest extends TestCase {
|
||||
'newRePassword' => '12345678',
|
||||
]);
|
||||
$result = $model->recoverPassword();
|
||||
$this->assertInstanceOf(LoginResult::class, $result);
|
||||
$this->assertInstanceOf(AuthenticationResult::class, $result);
|
||||
$this->assertNull($result->getSession(), 'session was not generated');
|
||||
$this->assertFalse(EmailActivation::find()->andWhere(['key' => $fixture['key']])->exists());
|
||||
/** @var Account $account */
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
namespace codeception\api\unit\models\authentication;
|
||||
|
||||
use api\components\User\RenewResult;
|
||||
use api\components\User\AuthenticationResult;
|
||||
use api\models\authentication\RefreshTokenForm;
|
||||
use Codeception\Specify;
|
||||
use common\models\AccountSession;
|
||||
@@ -26,7 +26,7 @@ class RefreshTokenFormTest extends TestCase {
|
||||
}
|
||||
};
|
||||
$model->validateRefreshToken();
|
||||
expect($model->getErrors('refresh_token'))->equals(['error.refresh_token_not_exist']);
|
||||
$this->assertEquals(['error.refresh_token_not_exist'], $model->getErrors('refresh_token'));
|
||||
});
|
||||
|
||||
$this->specify('no errors if token exists', function() {
|
||||
@@ -37,14 +37,14 @@ class RefreshTokenFormTest extends TestCase {
|
||||
}
|
||||
};
|
||||
$model->validateRefreshToken();
|
||||
expect($model->getErrors('refresh_token'))->isEmpty();
|
||||
$this->assertEmpty($model->getErrors('refresh_token'));
|
||||
});
|
||||
}
|
||||
|
||||
public function testRenew() {
|
||||
$model = new RefreshTokenForm();
|
||||
$model->refresh_token = $this->tester->grabFixture('sessions', 'admin')['refresh_token'];
|
||||
$this->assertInstanceOf(RenewResult::class, $model->renew());
|
||||
$this->assertInstanceOf(AuthenticationResult::class, $model->renew());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,12 +8,13 @@ use common\models\Account;
|
||||
use common\models\EmailActivation;
|
||||
use common\models\UsernameHistory;
|
||||
use GuzzleHttp\ClientInterface;
|
||||
use ReflectionClass;
|
||||
use tests\codeception\api\unit\TestCase;
|
||||
use tests\codeception\common\fixtures\AccountFixture;
|
||||
use tests\codeception\common\fixtures\EmailActivationFixture;
|
||||
use tests\codeception\common\fixtures\UsernameHistoryFixture;
|
||||
use tests\codeception\common\helpers\Mock;
|
||||
use Yii;
|
||||
use yii\validators\EmailValidator;
|
||||
use yii\web\Request;
|
||||
use const common\LATEST_RULES_VERSION;
|
||||
|
||||
@@ -59,6 +60,7 @@ class RegistrationFormTest extends TestCase {
|
||||
}
|
||||
|
||||
public function testSignup() {
|
||||
Mock::func(EmailValidator::class, 'checkdnsrr')->andReturnTrue();
|
||||
$model = new RegistrationForm([
|
||||
'username' => 'some_username',
|
||||
'email' => 'some_email@example.com',
|
||||
@@ -75,6 +77,7 @@ class RegistrationFormTest extends TestCase {
|
||||
}
|
||||
|
||||
public function testSignupWithDefaultLanguage() {
|
||||
Mock::func(EmailValidator::class, 'checkdnsrr')->andReturnTrue();
|
||||
$model = new RegistrationForm([
|
||||
'username' => 'some_username',
|
||||
'email' => 'some_email@example.com',
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
<?php
|
||||
namespace codeception\api\unit\models\profile;
|
||||
|
||||
use api\models\profile\AcceptRulesForm;
|
||||
use common\models\Account;
|
||||
use tests\codeception\api\unit\TestCase;
|
||||
use tests\codeception\common\fixtures\AccountFixture;
|
||||
use const common\LATEST_RULES_VERSION;
|
||||
|
||||
class AcceptRulesFormTest extends TestCase {
|
||||
|
||||
public function _fixtures() {
|
||||
return [
|
||||
'accounts' => AccountFixture::class,
|
||||
];
|
||||
}
|
||||
|
||||
public function testAgreeWithLatestRules() {
|
||||
/** @var Account $account */
|
||||
$account = Account::findOne($this->tester->grabFixture('accounts', 'account-with-old-rules-version'));
|
||||
$model = new AcceptRulesForm($account);
|
||||
$this->assertTrue($model->agreeWithLatestRules());
|
||||
$this->assertEquals(LATEST_RULES_VERSION, $account->rules_agreement_version);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
<?php
|
||||
namespace codeception\api\unit\models\profile\ChangeEmail;
|
||||
|
||||
use api\models\profile\ChangeEmail\ConfirmNewEmailForm;
|
||||
use common\models\Account;
|
||||
use common\models\EmailActivation;
|
||||
use tests\codeception\api\unit\TestCase;
|
||||
use tests\codeception\common\fixtures\AccountFixture;
|
||||
use tests\codeception\common\fixtures\EmailActivationFixture;
|
||||
|
||||
class ConfirmNewEmailFormTest extends TestCase {
|
||||
|
||||
public function _fixtures() {
|
||||
return [
|
||||
'accounts' => AccountFixture::class,
|
||||
'emailActivations' => EmailActivationFixture::class,
|
||||
];
|
||||
}
|
||||
|
||||
public function testChangeEmail() {
|
||||
/** @var Account $account */
|
||||
$account = Account::findOne($this->getAccountId());
|
||||
$newEmailConfirmationFixture = $this->tester->grabFixture('emailActivations', 'newEmailConfirmation');
|
||||
$model = new ConfirmNewEmailForm($account, [
|
||||
'key' => $newEmailConfirmationFixture['key'],
|
||||
]);
|
||||
$this->assertTrue($model->changeEmail());
|
||||
$this->assertNull(EmailActivation::findOne([
|
||||
'account_id' => $account->id,
|
||||
'type' => EmailActivation::TYPE_NEW_EMAIL_CONFIRMATION,
|
||||
]));
|
||||
$data = unserialize($newEmailConfirmationFixture['_data']);
|
||||
$this->assertEquals($data['newEmail'], $account->email);
|
||||
$this->tester->canSeeAmqpMessageIsCreated('events');
|
||||
}
|
||||
|
||||
public function testCreateTask() {
|
||||
/** @var Account $account */
|
||||
$account = Account::findOne($this->getAccountId());
|
||||
$model = new ConfirmNewEmailForm($account);
|
||||
$model->createTask(1, 'test1@ely.by', 'test@ely.by');
|
||||
$message = $this->tester->grabLastSentAmqpMessage('events');
|
||||
$body = json_decode($message->getBody(), true);
|
||||
$this->assertEquals(1, $body['accountId']);
|
||||
$this->assertEquals('test1@ely.by', $body['newEmail']);
|
||||
$this->assertEquals('test@ely.by', $body['oldEmail']);
|
||||
}
|
||||
|
||||
private function getAccountId() {
|
||||
return $this->tester->grabFixture('accounts', 'account-with-change-email-finish-state')['id'];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
<?php
|
||||
namespace codeception\api\unit\models\profile\ChangeEmail;
|
||||
|
||||
use api\models\profile\ChangeEmail\InitStateForm;
|
||||
use common\models\Account;
|
||||
use common\models\confirmations\CurrentEmailConfirmation;
|
||||
use common\models\EmailActivation;
|
||||
use tests\codeception\api\unit\TestCase;
|
||||
use tests\codeception\common\fixtures\AccountFixture;
|
||||
use tests\codeception\common\fixtures\EmailActivationFixture;
|
||||
|
||||
class InitStateFormTest extends TestCase {
|
||||
|
||||
public function _fixtures() {
|
||||
return [
|
||||
'accounts' => AccountFixture::class,
|
||||
'emailActivations' => EmailActivationFixture::class,
|
||||
];
|
||||
}
|
||||
|
||||
public function testCreateCode() {
|
||||
/** @var Account $account */
|
||||
$account = $this->tester->grabFixture('accounts', 'admin');
|
||||
$model = new InitStateForm($account);
|
||||
$activationModel = $model->createCode();
|
||||
$this->assertInstanceOf(CurrentEmailConfirmation::class, $activationModel);
|
||||
$this->assertEquals($account->id, $activationModel->account_id);
|
||||
$this->assertNotNull(EmailActivation::findOne($activationModel->key));
|
||||
}
|
||||
|
||||
public function testSendCurrentEmailConfirmation() {
|
||||
/** @var Account $account */
|
||||
$account = $this->tester->grabFixture('accounts', 'admin');
|
||||
$model = new InitStateForm($account, [
|
||||
'password' => 'password_0',
|
||||
]);
|
||||
$this->assertTrue($model->sendCurrentEmailConfirmation());
|
||||
$this->assertTrue(EmailActivation::find()->andWhere([
|
||||
'account_id' => $account->id,
|
||||
'type' => EmailActivation::TYPE_CURRENT_EMAIL_CONFIRMATION,
|
||||
])->exists());
|
||||
$this->tester->canSeeEmailIsSent();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
<?php
|
||||
namespace codeception\api\unit\models\profile\ChangeEmail;
|
||||
|
||||
use api\models\profile\ChangeEmail\NewEmailForm;
|
||||
use common\models\Account;
|
||||
use common\models\confirmations\NewEmailConfirmation;
|
||||
use common\models\EmailActivation;
|
||||
use tests\codeception\api\unit\TestCase;
|
||||
use tests\codeception\common\fixtures\AccountFixture;
|
||||
use tests\codeception\common\fixtures\EmailActivationFixture;
|
||||
|
||||
class NewEmailFormTest extends TestCase {
|
||||
|
||||
public function _fixtures() {
|
||||
return [
|
||||
'accounts' => AccountFixture::class,
|
||||
'emailActivations' => EmailActivationFixture::class,
|
||||
];
|
||||
}
|
||||
|
||||
public function testCreateCode() {
|
||||
/** @var Account $account */
|
||||
$account = $this->tester->grabFixture('accounts', 'admin');
|
||||
$model = new NewEmailForm($account);
|
||||
$model->email = 'my-new-email@ely.by';
|
||||
$activationModel = $model->createCode();
|
||||
$this->assertInstanceOf(NewEmailConfirmation::class, $activationModel);
|
||||
$this->assertEquals($account->id, $activationModel->account_id);
|
||||
$this->assertEquals($model->email, $activationModel->newEmail);
|
||||
$this->assertNotNull(EmailActivation::findOne($activationModel->key));
|
||||
}
|
||||
|
||||
public function testSendNewEmailConfirmation() {
|
||||
/** @var Account $account */
|
||||
$account = $this->tester->grabFixture('accounts', 'account-with-change-email-init-state');
|
||||
/** @var NewEmailForm $model */
|
||||
$key = $this->tester->grabFixture('emailActivations', 'currentChangeEmailConfirmation')['key'];
|
||||
$model = new NewEmailForm($account, [
|
||||
'key' => $key,
|
||||
'email' => 'my-new-email@ely.by',
|
||||
]);
|
||||
$this->assertTrue($model->sendNewEmailConfirmation());
|
||||
$this->assertNull(EmailActivation::findOne($key));
|
||||
$this->assertNotNull(EmailActivation::findOne([
|
||||
'account_id' => $account->id,
|
||||
'type' => EmailActivation::TYPE_NEW_EMAIL_CONFIRMATION,
|
||||
]));
|
||||
$this->tester->canSeeEmailIsSent();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
<?php
|
||||
namespace codeception\api\unit\models\profile;
|
||||
|
||||
use api\models\profile\ChangeLanguageForm;
|
||||
use common\models\Account;
|
||||
use tests\codeception\api\unit\TestCase;
|
||||
use tests\codeception\common\fixtures\AccountFixture;
|
||||
|
||||
class ChangeLanguageFormTest extends TestCase {
|
||||
|
||||
public function _fixtures() {
|
||||
return [
|
||||
'accounts' => AccountFixture::class
|
||||
];
|
||||
}
|
||||
|
||||
public function testApplyLanguage() {
|
||||
/** @var Account $account */
|
||||
$account = $this->tester->grabFixture('accounts', 'admin');
|
||||
$model = new ChangeLanguageForm($account);
|
||||
$model->lang = 'ru';
|
||||
$this->assertTrue($model->applyLanguage());
|
||||
$this->assertEquals('ru', $account->lang);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,135 +0,0 @@
|
||||
<?php
|
||||
namespace tests\codeception\api\models\profile;
|
||||
|
||||
use api\components\User\Component;
|
||||
use api\models\AccountIdentity;
|
||||
use api\models\profile\ChangePasswordForm;
|
||||
use Codeception\Specify;
|
||||
use common\models\Account;
|
||||
use common\models\AccountSession;
|
||||
use tests\codeception\api\unit\TestCase;
|
||||
use tests\codeception\common\fixtures\AccountFixture;
|
||||
use tests\codeception\common\fixtures\AccountSessionFixture;
|
||||
use Yii;
|
||||
|
||||
class ChangePasswordFormTest extends TestCase {
|
||||
use Specify;
|
||||
|
||||
public function _fixtures() {
|
||||
return [
|
||||
'accounts' => AccountFixture::class,
|
||||
'accountSessions' => AccountSessionFixture::class,
|
||||
];
|
||||
}
|
||||
|
||||
public function testValidatePasswordAndRePasswordMatch() {
|
||||
$this->specify('error.rePassword_does_not_match expected if passwords not match', function() {
|
||||
$account = new Account();
|
||||
$account->setPassword('12345678');
|
||||
$model = new ChangePasswordForm($account, [
|
||||
'password' => '12345678',
|
||||
'newPassword' => 'my-new-password',
|
||||
'newRePassword' => 'another-password',
|
||||
]);
|
||||
$model->validatePasswordAndRePasswordMatch('newRePassword');
|
||||
expect($model->getErrors('newRePassword'))->equals(['error.rePassword_does_not_match']);
|
||||
});
|
||||
|
||||
$this->specify('no errors expected if passwords are valid', function() {
|
||||
$account = new Account();
|
||||
$account->setPassword('12345678');
|
||||
$model = new ChangePasswordForm($account, [
|
||||
'password' => '12345678',
|
||||
'newPassword' => 'my-new-password',
|
||||
'newRePassword' => 'my-new-password',
|
||||
]);
|
||||
$model->validatePasswordAndRePasswordMatch('newRePassword');
|
||||
expect($model->getErrors('newRePassword'))->isEmpty();
|
||||
});
|
||||
|
||||
$this->specify('error.rePassword_does_not_match expected even if there are errors on other attributes', function() {
|
||||
// this is very important, because password change flow may be combined of two steps
|
||||
// therefore we need to validate password sameness before we will validate current account password
|
||||
$account = new Account();
|
||||
$account->setPassword('12345678');
|
||||
$model = new ChangePasswordForm($account, [
|
||||
'newPassword' => 'my-new-password',
|
||||
'newRePassword' => 'another-password',
|
||||
]);
|
||||
$model->validate();
|
||||
expect($model->getErrors('newRePassword'))->equals(['error.rePassword_does_not_match']);
|
||||
});
|
||||
}
|
||||
|
||||
public function testChangePassword() {
|
||||
$this->specify('successfully change password with modern hash strategy', function() {
|
||||
/** @var Account $account */
|
||||
$account = Account::findOne($this->tester->grabFixture('accounts', 'admin')['id']);
|
||||
$model = new ChangePasswordForm($account, [
|
||||
'password' => 'password_0',
|
||||
'newPassword' => 'my-new-password',
|
||||
'newRePassword' => 'my-new-password',
|
||||
]);
|
||||
|
||||
$callTime = time();
|
||||
expect('form should return true', $model->changePassword())->true();
|
||||
expect('new password should be successfully stored into account', $account->validatePassword('my-new-password'))->true();
|
||||
expect('password change time updated', $account->password_changed_at)->greaterOrEquals($callTime);
|
||||
});
|
||||
|
||||
$this->specify('successfully change password with legacy hash strategy', function() {
|
||||
/** @var Account $account */
|
||||
$account = Account::findOne($this->tester->grabFixture('accounts', 'user-with-old-password-type')['id']);
|
||||
$model = new ChangePasswordForm($account, [
|
||||
'password' => '12345678',
|
||||
'newPassword' => 'my-new-password',
|
||||
'newRePassword' => 'my-new-password',
|
||||
]);
|
||||
|
||||
$callTime = time();
|
||||
expect($model->changePassword())->true();
|
||||
expect($account->validatePassword('my-new-password'))->true();
|
||||
expect($account->password_changed_at)->greaterOrEquals($callTime);
|
||||
expect($account->password_hash_strategy)->equals(Account::PASS_HASH_STRATEGY_YII2);
|
||||
});
|
||||
}
|
||||
|
||||
public function testChangePasswordWithLogout() {
|
||||
/** @var Component|\PHPUnit_Framework_MockObject_MockObject $component */
|
||||
$component = $this->getMockBuilder(Component::class)
|
||||
->setMethods(['getActiveSession', 'terminateSessions'])
|
||||
->setConstructorArgs([[
|
||||
'identityClass' => AccountIdentity::class,
|
||||
'enableSession' => false,
|
||||
'loginUrl' => null,
|
||||
'secret' => 'secret',
|
||||
]])
|
||||
->getMock();
|
||||
|
||||
/** @var AccountSession $session */
|
||||
$session = AccountSession::findOne($this->tester->grabFixture('accountSessions', 'admin2')['id']);
|
||||
|
||||
$component
|
||||
->expects($this->any())
|
||||
->method('getActiveSession')
|
||||
->will($this->returnValue($session));
|
||||
|
||||
$component
|
||||
->expects($this->once())
|
||||
->method('terminateSessions');
|
||||
|
||||
Yii::$app->set('user', $component);
|
||||
|
||||
/** @var Account $account */
|
||||
$account = $this->tester->grabFixture('accounts', 'admin');
|
||||
$model = new ChangePasswordForm($account, [
|
||||
'password' => 'password_0',
|
||||
'newPassword' => 'my-new-password',
|
||||
'newRePassword' => 'my-new-password',
|
||||
'logoutAll' => true,
|
||||
]);
|
||||
|
||||
$this->assertTrue($model->changePassword());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
<?php
|
||||
namespace tests\codeception\api\models\profile;
|
||||
|
||||
use api\models\AccountIdentity;
|
||||
use api\models\profile\ChangeUsernameForm;
|
||||
use Codeception\Specify;
|
||||
use common\models\Account;
|
||||
use common\models\UsernameHistory;
|
||||
use tests\codeception\api\unit\TestCase;
|
||||
use tests\codeception\common\fixtures\AccountFixture;
|
||||
use tests\codeception\common\fixtures\UsernameHistoryFixture;
|
||||
use Yii;
|
||||
|
||||
class ChangeUsernameFormTest extends TestCase {
|
||||
use Specify;
|
||||
|
||||
public function _fixtures() {
|
||||
return [
|
||||
'accounts' => AccountFixture::class,
|
||||
'history' => UsernameHistoryFixture::class,
|
||||
];
|
||||
}
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
Yii::$app->user->setIdentity($this->getAccount());
|
||||
}
|
||||
|
||||
public function testChange() {
|
||||
$model = new ChangeUsernameForm($this->getAccount(), [
|
||||
'password' => 'password_0',
|
||||
'username' => 'my_new_nickname',
|
||||
]);
|
||||
$this->assertTrue($model->change());
|
||||
$this->assertEquals('my_new_nickname', Account::findOne($this->getAccountId())->username);
|
||||
$this->assertInstanceOf(UsernameHistory::class, UsernameHistory::findOne(['username' => 'my_new_nickname']));
|
||||
$this->tester->canSeeAmqpMessageIsCreated('events');
|
||||
}
|
||||
|
||||
public function testChangeWithoutChange() {
|
||||
$account = $this->getAccount();
|
||||
$username = $account->username;
|
||||
$model = new ChangeUsernameForm($account, [
|
||||
'password' => 'password_0',
|
||||
'username' => $username,
|
||||
]);
|
||||
$callTime = time();
|
||||
$this->assertTrue($model->change());
|
||||
$this->assertNull(UsernameHistory::findOne([
|
||||
'AND',
|
||||
'username' => $username,
|
||||
['>=', 'applied_in', $callTime],
|
||||
]), 'no new UsernameHistory record, if we don\'t change username');
|
||||
$this->tester->cantSeeAmqpMessageIsCreated('events');
|
||||
}
|
||||
|
||||
public function testChangeCase() {
|
||||
$newUsername = mb_strtoupper($this->tester->grabFixture('accounts', 'admin')['username']);
|
||||
$model = new ChangeUsernameForm($this->getAccount(), [
|
||||
'password' => 'password_0',
|
||||
'username' => $newUsername,
|
||||
]);
|
||||
$this->assertTrue($model->change());
|
||||
$this->assertEquals($newUsername, Account::findOne($this->getAccountId())->username);
|
||||
$this->assertInstanceOf(
|
||||
UsernameHistory::class,
|
||||
UsernameHistory::findOne(['username' => $newUsername]),
|
||||
'username should change, if we change case of some letters'
|
||||
);
|
||||
$this->tester->canSeeAmqpMessageIsCreated('events');
|
||||
}
|
||||
|
||||
public function testCreateTask() {
|
||||
$model = new ChangeUsernameForm($this->getAccount());
|
||||
$model->createEventTask(1, 'test1', 'test');
|
||||
$message = $this->tester->grabLastSentAmqpMessage('events');
|
||||
$body = json_decode($message->getBody(), true);
|
||||
$this->assertEquals(1, $body['accountId']);
|
||||
$this->assertEquals('test1', $body['newUsername']);
|
||||
$this->assertEquals('test', $body['oldUsername']);
|
||||
}
|
||||
|
||||
private function getAccount(): AccountIdentity {
|
||||
return AccountIdentity::findOne($this->getAccountId());
|
||||
}
|
||||
|
||||
private function getAccountId() {
|
||||
return $this->tester->grabFixture('accounts', 'admin')->id;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,208 +0,0 @@
|
||||
<?php
|
||||
namespace tests\codeception\api\unit\models\profile;
|
||||
|
||||
use api\components\User\Component;
|
||||
use api\models\AccountIdentity;
|
||||
use api\models\profile\TwoFactorAuthForm;
|
||||
use common\helpers\Error as E;
|
||||
use common\models\Account;
|
||||
use OTPHP\TOTP;
|
||||
use tests\codeception\api\unit\TestCase;
|
||||
use tests\codeception\common\_support\ProtectedCaller;
|
||||
use Yii;
|
||||
|
||||
class TwoFactorAuthFormTest extends TestCase {
|
||||
use ProtectedCaller;
|
||||
|
||||
public function testGetCredentials() {
|
||||
/** @var Account|\PHPUnit_Framework_MockObject_MockObject $account */
|
||||
$account = $this->getMockBuilder(Account::class)
|
||||
->setMethods(['save'])
|
||||
->getMock();
|
||||
|
||||
$account->expects($this->once())
|
||||
->method('save')
|
||||
->willReturn(true);
|
||||
|
||||
$account->email = 'mock@email.com';
|
||||
$account->otp_secret = null;
|
||||
|
||||
/** @var TwoFactorAuthForm|\PHPUnit_Framework_MockObject_MockObject $model */
|
||||
$model = $this->getMockBuilder(TwoFactorAuthForm::class)
|
||||
->setConstructorArgs([$account])
|
||||
->setMethods(['drawQrCode'])
|
||||
->getMock();
|
||||
|
||||
$model->expects($this->once())
|
||||
->method('drawQrCode')
|
||||
->willReturn('<_/>');
|
||||
|
||||
$result = $model->getCredentials();
|
||||
$this->assertTrue(is_array($result));
|
||||
$this->assertArrayHasKey('qr', $result);
|
||||
$this->assertArrayHasKey('uri', $result);
|
||||
$this->assertArrayHasKey('secret', $result);
|
||||
$this->assertNotNull($account->otp_secret);
|
||||
$this->assertEquals($account->otp_secret, $result['secret']);
|
||||
$this->assertEquals('data:image/svg+xml,<_/>', $result['qr']);
|
||||
|
||||
/** @var Account|\PHPUnit_Framework_MockObject_MockObject $account */
|
||||
$account = $this->getMockBuilder(Account::class)
|
||||
->setMethods(['save'])
|
||||
->getMock();
|
||||
|
||||
$account->expects($this->never())
|
||||
->method('save');
|
||||
|
||||
$account->email = 'mock@email.com';
|
||||
$account->otp_secret = 'some valid totp secret value';
|
||||
|
||||
/** @var TwoFactorAuthForm|\PHPUnit_Framework_MockObject_MockObject $model */
|
||||
$model = $this->getMockBuilder(TwoFactorAuthForm::class)
|
||||
->setConstructorArgs([$account])
|
||||
->setMethods(['drawQrCode'])
|
||||
->getMock();
|
||||
|
||||
$model->expects($this->once())
|
||||
->method('drawQrCode')
|
||||
->willReturn('this is qr code, trust me');
|
||||
|
||||
$result = $model->getCredentials();
|
||||
$this->assertEquals('some valid totp secret value', $result['secret']);
|
||||
}
|
||||
|
||||
public function testActivate() {
|
||||
/** @var Component|\PHPUnit_Framework_MockObject_MockObject $component */
|
||||
$component = $this->getMockBuilder(Component::class)
|
||||
->setMethods(['terminateSessions'])
|
||||
->setConstructorArgs([[
|
||||
'identityClass' => AccountIdentity::class,
|
||||
'enableSession' => false,
|
||||
'loginUrl' => null,
|
||||
'secret' => 'secret',
|
||||
]])
|
||||
->getMock();
|
||||
|
||||
$component
|
||||
->expects($this->once())
|
||||
->method('terminateSessions');
|
||||
|
||||
Yii::$app->set('user', $component);
|
||||
|
||||
/** @var Account|\PHPUnit_Framework_MockObject_MockObject $account */
|
||||
$account = $this->getMockBuilder(Account::class)
|
||||
->setMethods(['save'])
|
||||
->getMock();
|
||||
|
||||
$account->expects($this->once())
|
||||
->method('save')
|
||||
->willReturn(true);
|
||||
|
||||
$account->is_otp_enabled = false;
|
||||
$account->otp_secret = 'mock secret';
|
||||
|
||||
/** @var TwoFactorAuthForm|\PHPUnit_Framework_MockObject_MockObject $model */
|
||||
$model = $this->getMockBuilder(TwoFactorAuthForm::class)
|
||||
->setMethods(['validate'])
|
||||
->setConstructorArgs([$account, ['scenario' => TwoFactorAuthForm::SCENARIO_ACTIVATE]])
|
||||
->getMock();
|
||||
|
||||
$model->expects($this->once())
|
||||
->method('validate')
|
||||
->willReturn(true);
|
||||
|
||||
$this->assertTrue($model->activate());
|
||||
$this->assertTrue($account->is_otp_enabled);
|
||||
}
|
||||
|
||||
public function testDisable() {
|
||||
/** @var Account|\PHPUnit_Framework_MockObject_MockObject $account */
|
||||
$account = $this->getMockBuilder(Account::class)
|
||||
->setMethods(['save'])
|
||||
->getMock();
|
||||
|
||||
$account->expects($this->once())
|
||||
->method('save')
|
||||
->willReturn(true);
|
||||
|
||||
$account->is_otp_enabled = true;
|
||||
$account->otp_secret = 'mock secret';
|
||||
|
||||
/** @var TwoFactorAuthForm|\PHPUnit_Framework_MockObject_MockObject $model */
|
||||
$model = $this->getMockBuilder(TwoFactorAuthForm::class)
|
||||
->setMethods(['validate'])
|
||||
->setConstructorArgs([$account, ['scenario' => TwoFactorAuthForm::SCENARIO_DISABLE]])
|
||||
->getMock();
|
||||
|
||||
$model->expects($this->once())
|
||||
->method('validate')
|
||||
->willReturn(true);
|
||||
|
||||
$this->assertTrue($model->disable());
|
||||
$this->assertNull($account->otp_secret);
|
||||
$this->assertFalse($account->is_otp_enabled);
|
||||
}
|
||||
|
||||
public function testValidateOtpDisabled() {
|
||||
$account = new Account();
|
||||
$account->is_otp_enabled = true;
|
||||
$model = new TwoFactorAuthForm($account);
|
||||
$model->validateOtpDisabled('account');
|
||||
$this->assertEquals([E::OTP_ALREADY_ENABLED], $model->getErrors('account'));
|
||||
|
||||
$account = new Account();
|
||||
$account->is_otp_enabled = false;
|
||||
$model = new TwoFactorAuthForm($account);
|
||||
$model->validateOtpDisabled('account');
|
||||
$this->assertEmpty($model->getErrors('account'));
|
||||
}
|
||||
|
||||
public function testValidateOtpEnabled() {
|
||||
$account = new Account();
|
||||
$account->is_otp_enabled = false;
|
||||
$model = new TwoFactorAuthForm($account);
|
||||
$model->validateOtpEnabled('account');
|
||||
$this->assertEquals([E::OTP_NOT_ENABLED], $model->getErrors('account'));
|
||||
|
||||
$account = new Account();
|
||||
$account->is_otp_enabled = true;
|
||||
$model = new TwoFactorAuthForm($account);
|
||||
$model->validateOtpEnabled('account');
|
||||
$this->assertEmpty($model->getErrors('account'));
|
||||
}
|
||||
|
||||
public function testGetTotp() {
|
||||
$account = new Account();
|
||||
$account->otp_secret = 'mock secret';
|
||||
$account->email = 'check@this.email';
|
||||
|
||||
$model = new TwoFactorAuthForm($account);
|
||||
$totp = $model->getTotp();
|
||||
$this->assertInstanceOf(TOTP::class, $totp);
|
||||
$this->assertEquals('check@this.email', $totp->getLabel());
|
||||
$this->assertEquals('mock secret', $totp->getSecret());
|
||||
$this->assertEquals('Ely.by', $totp->getIssuer());
|
||||
}
|
||||
|
||||
public function testSetOtpSecret() {
|
||||
/** @var Account|\PHPUnit_Framework_MockObject_MockObject $account */
|
||||
$account = $this->getMockBuilder(Account::class)
|
||||
->setMethods(['save'])
|
||||
->getMock();
|
||||
|
||||
$account->expects($this->exactly(2))
|
||||
->method('save')
|
||||
->willReturn(true);
|
||||
|
||||
$model = new TwoFactorAuthForm($account);
|
||||
$this->callProtected($model, 'setOtpSecret');
|
||||
$this->assertEquals(24, strlen($model->getAccount()->otp_secret));
|
||||
$this->assertSame(strtoupper($model->getAccount()->otp_secret), $model->getAccount()->otp_secret);
|
||||
|
||||
$model = new TwoFactorAuthForm($account);
|
||||
$this->callProtected($model, 'setOtpSecret', 25);
|
||||
$this->assertEquals(25, strlen($model->getAccount()->otp_secret));
|
||||
$this->assertSame(strtoupper($model->getAccount()->otp_secret), $model->getAccount()->otp_secret);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user