Close #15 added two factor authentication
This commit is contained in:
@ -1,6 +1,7 @@
|
||||
# CHANGELOG
|
||||
|
||||
## 1.0.14 - Work in progress
|
||||
- Enh #56: Added two factor authentication (tonydspaniard)
|
||||
- Fix #63: Fix selectize version (tonydspaniard)
|
||||
- Enh #65: Updated Romanian translation (mrbig00)
|
||||
- Enh #61: Updated Russian translation (faenir)
|
||||
|
||||
@ -47,10 +47,12 @@
|
||||
"prefer-stable": true,
|
||||
"require": {
|
||||
"php": ">=5.5",
|
||||
"2amigos/yii2-selectize-widget": "~1.1",
|
||||
"2amigos/yii2-selectize-widget": "^1.1",
|
||||
"yiisoft/yii2-authclient": "^2.1.0",
|
||||
"yiisoft/yii2-bootstrap": "^2.0.0",
|
||||
"yiisoft/yii2-swiftmailer": "^2.0.0"
|
||||
"yiisoft/yii2-swiftmailer": "^2.0.0",
|
||||
"2amigos/2fa-library": "^1.0",
|
||||
"2amigos/qrcode-library": "^1.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"cebe/assetfree-yii2": "~2.0.0",
|
||||
@ -71,14 +73,12 @@
|
||||
"Da\\User\\": "./src/User"
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"fxp-asset": {
|
||||
"installer-paths": {
|
||||
"npm-asset-library": "vendor/npm",
|
||||
"bower-asset-library": "vendor/bower"
|
||||
}
|
||||
"repositories": [
|
||||
{
|
||||
"type": "composer",
|
||||
"url": "https://asset-packagist.org"
|
||||
}
|
||||
},
|
||||
],
|
||||
"extra": {
|
||||
"bootstrap": "Da\\User\\Bootstrap"
|
||||
}
|
||||
|
||||
1756
composer.lock
generated
1756
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -15,7 +15,6 @@ use Da\User\Contracts\AuthClientInterface;
|
||||
use Da\User\Event\FormEvent;
|
||||
use Da\User\Event\UserEvent;
|
||||
use Da\User\Form\LoginForm;
|
||||
use Da\User\Model\User;
|
||||
use Da\User\Query\SocialNetworkAccountQuery;
|
||||
use Da\User\Service\SocialNetworkAccountConnectService;
|
||||
use Da\User\Service\SocialNetworkAuthenticateService;
|
||||
@ -38,10 +37,10 @@ class SecurityController extends Controller
|
||||
/**
|
||||
* SecurityController constructor.
|
||||
*
|
||||
* @param string $id
|
||||
* @param Module $module
|
||||
* @param string $id
|
||||
* @param Module $module
|
||||
* @param SocialNetworkAccountQuery $socialNetworkAccountQuery
|
||||
* @param array $config
|
||||
* @param array $config
|
||||
*/
|
||||
public function __construct(
|
||||
$id,
|
||||
@ -64,7 +63,7 @@ class SecurityController extends Controller
|
||||
'rules' => [
|
||||
[
|
||||
'allow' => true,
|
||||
'actions' => ['login', 'auth', 'blocked'],
|
||||
'actions' => ['login', 'confirm', 'auth', 'blocked'],
|
||||
'roles' => ['?'],
|
||||
],
|
||||
[
|
||||
@ -113,16 +112,27 @@ class SecurityController extends Controller
|
||||
|
||||
/** @var LoginForm $form */
|
||||
$form = $this->make(LoginForm::class);
|
||||
|
||||
/** @var FormEvent $event */
|
||||
$event = $this->make(FormEvent::class, [$form]);
|
||||
|
||||
if (Yii::$app->request->isAjax && $form->load(Yii::$app->request->post())) {
|
||||
|
||||
Yii::$app->response->format = Response::FORMAT_JSON;
|
||||
|
||||
return ActiveForm::validate($form);
|
||||
}
|
||||
|
||||
if ($form->load(Yii::$app->request->post())) {
|
||||
|
||||
if ($this->module->enableTwoFactorAuthentication && $form->validate()) {
|
||||
if ($form->getUser()->auth_tf_enabled) {
|
||||
Yii::$app->session->set('credentials', ['login' => $form->login, 'pwd' => $form->password]);
|
||||
|
||||
return $this->redirect(['confirm']);
|
||||
}
|
||||
}
|
||||
|
||||
$this->trigger(FormEvent::EVENT_BEFORE_LOGIN, $event);
|
||||
if ($form->login()) {
|
||||
$form->getUser()->updateAttributes(['last_login_at' => time()]);
|
||||
@ -142,6 +152,59 @@ class SecurityController extends Controller
|
||||
);
|
||||
}
|
||||
|
||||
public function actionConfirm()
|
||||
{
|
||||
if (!Yii::$app->user->getIsGuest()) {
|
||||
return $this->goHome();
|
||||
}
|
||||
|
||||
if (!Yii::$app->session->has('credentials')) {
|
||||
return $this->redirect(['login']);
|
||||
}
|
||||
|
||||
$credentials = Yii::$app->session->get('credentials');
|
||||
/** @var LoginForm $form */
|
||||
$form = $this->make(LoginForm::class);
|
||||
$form->login = $credentials['login'];
|
||||
$form->password = $credentials['pwd'];
|
||||
$form->setScenario('2fa');
|
||||
|
||||
/** @var FormEvent $event */
|
||||
$event = $this->make(FormEvent::class, [$form]);
|
||||
|
||||
if (Yii::$app->request->isAjax && $form->load(Yii::$app->request->post())) {
|
||||
|
||||
Yii::$app->response->format = Response::FORMAT_JSON;
|
||||
|
||||
return ActiveForm::validate($form);
|
||||
}
|
||||
|
||||
if ($form->load(Yii::$app->request->post())) {
|
||||
|
||||
$this->trigger(FormEvent::EVENT_BEFORE_LOGIN, $event);
|
||||
|
||||
if ($form->login()) {
|
||||
|
||||
Yii::$app->session->set('credentials', null);
|
||||
|
||||
$form->getUser()->updateAttributes(['last_login_at' => time()]);
|
||||
|
||||
$this->trigger(FormEvent::EVENT_AFTER_LOGIN, $event);
|
||||
|
||||
return $this->goBack();
|
||||
}
|
||||
}
|
||||
|
||||
return $this->render(
|
||||
'confirm',
|
||||
[
|
||||
'model' => $form,
|
||||
'module' => $this->module,
|
||||
]
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
public function actionLogout()
|
||||
{
|
||||
$event = $this->make(UserEvent::class, [Yii::$app->getUser()->getIdentity()]);
|
||||
|
||||
@ -24,14 +24,17 @@ use Da\User\Query\ProfileQuery;
|
||||
use Da\User\Query\SocialNetworkAccountQuery;
|
||||
use Da\User\Query\UserQuery;
|
||||
use Da\User\Service\EmailChangeService;
|
||||
use Da\User\Service\TwoFactorQrCodeUriGeneratorService;
|
||||
use Da\User\Traits\ContainerAwareTrait;
|
||||
use Da\User\Validator\AjaxRequestModelValidator;
|
||||
use Da\User\Validator\TwoFactorCodeValidator;
|
||||
use Yii;
|
||||
use yii\filters\AccessControl;
|
||||
use yii\filters\VerbFilter;
|
||||
use yii\web\Controller;
|
||||
use yii\web\ForbiddenHttpException;
|
||||
use yii\web\NotFoundHttpException;
|
||||
use yii\web\Response;
|
||||
|
||||
class SettingsController extends Controller
|
||||
{
|
||||
@ -49,12 +52,12 @@ class SettingsController extends Controller
|
||||
/**
|
||||
* SettingsController constructor.
|
||||
*
|
||||
* @param string $id
|
||||
* @param Module $module
|
||||
* @param ProfileQuery $profileQuery
|
||||
* @param UserQuery $userQuery
|
||||
* @param string $id
|
||||
* @param Module $module
|
||||
* @param ProfileQuery $profileQuery
|
||||
* @param UserQuery $userQuery
|
||||
* @param SocialNetworkAccountQuery $socialNetworkAccountQuery
|
||||
* @param array $config
|
||||
* @param array $config
|
||||
*/
|
||||
public function __construct(
|
||||
$id,
|
||||
@ -81,6 +84,7 @@ class SettingsController extends Controller
|
||||
'actions' => [
|
||||
'disconnect' => ['post'],
|
||||
'delete' => ['post'],
|
||||
'two-factor-disable' => ['post']
|
||||
],
|
||||
],
|
||||
'access' => [
|
||||
@ -88,7 +92,16 @@ class SettingsController extends Controller
|
||||
'rules' => [
|
||||
[
|
||||
'allow' => true,
|
||||
'actions' => ['profile', 'account', 'networks', 'disconnect', 'delete'],
|
||||
'actions' => [
|
||||
'profile',
|
||||
'account',
|
||||
'networks',
|
||||
'disconnect',
|
||||
'delete',
|
||||
'two-factor',
|
||||
'two-factor-enable',
|
||||
'two-factor-disable'
|
||||
],
|
||||
'roles' => ['@'],
|
||||
],
|
||||
[
|
||||
@ -228,4 +241,70 @@ class SettingsController extends Controller
|
||||
|
||||
return $this->goHome();
|
||||
}
|
||||
|
||||
public function actionTwoFactor($id)
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = $this->userQuery->whereId($id)->one();
|
||||
|
||||
if (null === $user) {
|
||||
throw new NotFoundHttpException();
|
||||
}
|
||||
|
||||
$uri = $this->make(TwoFactorQrCodeUriGeneratorService::class, [$user])->run();
|
||||
|
||||
return $this->renderAjax('two-factor', ['id' => $id, 'uri' => $uri]);
|
||||
}
|
||||
|
||||
public function actionTwoFactorEnable($id)
|
||||
{
|
||||
Yii::$app->response->format = Response::FORMAT_JSON;
|
||||
|
||||
/** @var User $user */
|
||||
$user = $this->userQuery->whereId($id)->one();
|
||||
|
||||
if (null === $user) {
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => Yii::t('usuario', 'User not found.')
|
||||
];
|
||||
}
|
||||
$code = Yii::$app->request->get('code');
|
||||
|
||||
$success = $this
|
||||
->make(TwoFactorCodeValidator::class, [$user, $code, $this->module->twoFactorAuthenticationCycles])
|
||||
->validate();
|
||||
|
||||
$success = $success && $user->updateAttributes(['auth_tf_enabled' => '1']);
|
||||
|
||||
return [
|
||||
'success' => $success,
|
||||
'message' => $success
|
||||
? Yii::t('usuario', 'Two factor successfully enabled.')
|
||||
: Yii::t('usuario', 'Verification failed. Please, enter new code.')
|
||||
];
|
||||
}
|
||||
|
||||
public function actionTwoFactorDisable($id)
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = $this->userQuery->whereId($id)->one();
|
||||
|
||||
if (null === $user) {
|
||||
throw new NotFoundHttpException();
|
||||
}
|
||||
|
||||
if($user->updateAttributes(['auth_tf_enabled' => '0']))
|
||||
{
|
||||
Yii::$app
|
||||
->getSession()
|
||||
->setFlash('success', Yii::t('usuario', 'Two-factor authorization has been disabled.'));
|
||||
} else {
|
||||
Yii::$app
|
||||
->getSession()
|
||||
->setFlash('danger', Yii::t('usuario', 'Unable to disable two-factor authorization.'));
|
||||
}
|
||||
|
||||
$this->redirect(['account']);
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,6 +15,7 @@ use Da\User\Helper\SecurityHelper;
|
||||
use Da\User\Model\User;
|
||||
use Da\User\Query\UserQuery;
|
||||
use Da\User\Traits\ModuleAwareTrait;
|
||||
use Da\User\Validator\TwoFactorCodeValidator;
|
||||
use Yii;
|
||||
use yii\base\Model;
|
||||
|
||||
@ -30,6 +31,10 @@ class LoginForm extends Model
|
||||
* @var string User's password
|
||||
*/
|
||||
public $password;
|
||||
/**
|
||||
* @var string User's two-factor authentication code
|
||||
*/
|
||||
public $twoFactorAuthenticationCode;
|
||||
/**
|
||||
* @var bool whether to remember User's login
|
||||
*/
|
||||
@ -48,9 +53,9 @@ class LoginForm extends Model
|
||||
protected $securityHelper;
|
||||
|
||||
/**
|
||||
* @param UserQuery $query
|
||||
* @param UserQuery $query
|
||||
* @param SecurityHelper $securityHelper
|
||||
* @param array $config
|
||||
* @param array $config
|
||||
*/
|
||||
public function __construct(UserQuery $query, SecurityHelper $securityHelper, $config = [])
|
||||
{
|
||||
@ -68,6 +73,7 @@ class LoginForm extends Model
|
||||
'login' => Yii::t('usuario', 'Login'),
|
||||
'password' => Yii::t('usuario', 'Password'),
|
||||
'rememberMe' => Yii::t('usuario', 'Remember me next time'),
|
||||
'twoFactorAuthenticationCode' => Yii::t('usuario', 'Two-factor authentication code')
|
||||
];
|
||||
}
|
||||
|
||||
@ -78,7 +84,13 @@ class LoginForm extends Model
|
||||
{
|
||||
return [
|
||||
'requiredFields' => [['login', 'password'], 'required'],
|
||||
'requiredFieldsTwoFactor' => [
|
||||
['login', 'password', 'twoFactorAuthenticationCode'],
|
||||
'required',
|
||||
'on' => '2fa'
|
||||
],
|
||||
'loginTrim' => ['login', 'trim'],
|
||||
'twoFactorAuthenticationCodeTrim' => ['twoFactorAuthenticationCode', 'trim'],
|
||||
'passwordValidate' => [
|
||||
'password',
|
||||
function ($attribute) {
|
||||
@ -89,6 +101,20 @@ class LoginForm extends Model
|
||||
}
|
||||
},
|
||||
],
|
||||
'twoFactorAuthenticationCodeValidate' => [
|
||||
'twoFactorAuthenticationCode',
|
||||
function ($attribute) {
|
||||
if ($this->user === null ||
|
||||
!(new TwoFactorCodeValidator(
|
||||
$this->user,
|
||||
$this->twoFactorAuthenticationCode,
|
||||
$this->module->twoFactorAuthenticationCycles
|
||||
))
|
||||
->validate()) {
|
||||
$this->addError($attribute, Yii::t('usuario', 'Invalid two-factor code'));
|
||||
}
|
||||
}
|
||||
],
|
||||
'confirmationValidate' => [
|
||||
'login',
|
||||
function ($attribute) {
|
||||
|
||||
29
src/User/Migration/m000000_000006_add_two_factor_fields.php
Normal file
29
src/User/Migration/m000000_000006_add_two_factor_fields.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the 2amigos/yii2-usuario project.
|
||||
*
|
||||
* (c) 2amigOS! <http://2amigos.us/>
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Da\User\Migration;
|
||||
|
||||
use yii\db\Migration;
|
||||
|
||||
class m000000_000006_add_two_factor_fields extends Migration
|
||||
{
|
||||
public function safeUp()
|
||||
{
|
||||
$this->addColumn('{{%user}}', 'auth_tf_key', $this->string(16));
|
||||
$this->addColumn('{{%user}}', 'auth_tf_enabled', $this->boolean()->defaultValue(0));
|
||||
}
|
||||
|
||||
public function safeDown()
|
||||
{
|
||||
$this->dropColumn('{{%user}}', 'auth_tf_key');
|
||||
$this->dropColumn('{{%user}}', 'auth_tf_enabled');
|
||||
}
|
||||
}
|
||||
@ -37,6 +37,8 @@ use yii\web\IdentityInterface;
|
||||
* @property string $unconfirmed_email
|
||||
* @property string $password_hash
|
||||
* @property string $auth_key
|
||||
* @property string $auth_tf_key
|
||||
* @property int $auth_tf_enabled
|
||||
* @property int $registration_ip
|
||||
* @property int $confirmed_at
|
||||
* @property int $blocked_at
|
||||
@ -188,6 +190,11 @@ class User extends ActiveRecord implements IdentityInterface
|
||||
'passwordTrim' => ['password', 'trim'],
|
||||
'passwordRequired' => ['password', 'required', 'on' => ['register']],
|
||||
'passwordLength' => ['password', 'string', 'min' => 6, 'max' => 72, 'on' => ['register', 'create']],
|
||||
|
||||
// two factor auth rules
|
||||
'twoFactorSecretTrim' => ['auth_tf_key', 'trim'],
|
||||
'twoFactorSecretLength' => ['auth_tf_key', 'string', 'max' => 16],
|
||||
'twoFactorEnabledNumber' => ['auth_tf_enabled', 'integer']
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@ -19,6 +19,15 @@ use yii\base\Module as BaseModule;
|
||||
*/
|
||||
class Module extends BaseModule
|
||||
{
|
||||
/**
|
||||
* @var bool whether to enable two factor authentication or not
|
||||
*/
|
||||
public $enableTwoFactorAuthentication = false;
|
||||
/**
|
||||
* @var int cycles of key generation are set on 30 sec. To avoid sync issues, increased validity up to 60 sec.
|
||||
* @see http://2fa-library.readthedocs.io/en/latest/
|
||||
*/
|
||||
public $twoFactorAuthenticationCycles = 1;
|
||||
/**
|
||||
* @var bool whether to allow registration process or not
|
||||
*/
|
||||
|
||||
46
src/User/Service/TwoFactorQrCodeUriGeneratorService.php
Normal file
46
src/User/Service/TwoFactorQrCodeUriGeneratorService.php
Normal file
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace Da\User\Service;
|
||||
|
||||
use Da\TwoFA\Manager;
|
||||
use Da\TwoFA\Service\QrCodeDataUriGeneratorService;
|
||||
use Da\TwoFA\Service\TOTPSecretKeyUriGeneratorService;
|
||||
use Da\User\Contracts\ServiceInterface;
|
||||
use Da\User\Model\User;
|
||||
use Yii;
|
||||
|
||||
class TwoFactorQrCodeUriGeneratorService implements ServiceInterface
|
||||
{
|
||||
/**
|
||||
* @var User
|
||||
*/
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* TwoFactorQrCodeUriGeneratorService constructor.
|
||||
*
|
||||
* @param User $user
|
||||
*/
|
||||
public function __construct(User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$user = $this->user;
|
||||
if (!$user->auth_tf_key) {
|
||||
$user->auth_tf_key = (new Manager())->generateSecretKey();
|
||||
$user->updateAttributes(['auth_tf_key']);
|
||||
}
|
||||
|
||||
$totpUri = (new TOTPSecretKeyUriGeneratorService(Yii::$app->name, $user->email, $user->auth_tf_key))->run();
|
||||
$dataUri = (new QrCodeDataUriGeneratorService($totpUri))->run();
|
||||
|
||||
return $dataUri;
|
||||
}
|
||||
|
||||
}
|
||||
37
src/User/Validator/TwoFactorCodeValidator.php
Normal file
37
src/User/Validator/TwoFactorCodeValidator.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Da\User\Validator;
|
||||
|
||||
use Da\TwoFA\Manager;
|
||||
use Da\User\Contracts\ValidatorInterface;
|
||||
use Da\User\Model\User;
|
||||
|
||||
class TwoFactorCodeValidator implements ValidatorInterface
|
||||
{
|
||||
protected $user;
|
||||
protected $code;
|
||||
protected $cycles;
|
||||
|
||||
/**
|
||||
* TwoFactorCodeValidator constructor.
|
||||
*
|
||||
* @param User $user
|
||||
* @param $code
|
||||
* @param int $cycles
|
||||
*/
|
||||
public function __construct(User $user, $code, $cycles = 0)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->code = $code;
|
||||
$this->cycles = $cycles;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool|int
|
||||
*/
|
||||
public function validate()
|
||||
{
|
||||
$manager = new Manager();
|
||||
return $manager->setCycles($this->cycles)->verify($this->code, $this->user->auth_tf_key);
|
||||
}
|
||||
}
|
||||
70
src/User/resources/views/security/confirm.php
Normal file
70
src/User/resources/views/security/confirm.php
Normal file
@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the 2amigos/yii2-usuario project.
|
||||
*
|
||||
* (c) 2amigOS! <http://2amigos.us/>
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Da\User\Widget\ConnectWidget;
|
||||
use yii\helpers\Html;
|
||||
use yii\widgets\ActiveForm;
|
||||
|
||||
/**
|
||||
* @var yii\web\View $this
|
||||
* @var \Da\User\Form\LoginForm $model
|
||||
* @var \Da\User\Module $module
|
||||
*/
|
||||
|
||||
$this->title = Yii::t('usuario', 'Sign in');
|
||||
$this->params['breadcrumbs'][] = $this->title;
|
||||
?>
|
||||
|
||||
<?= $this->render('/shared/_alert', ['module' => Yii::$app->getModule('user')]) ?>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-4 col-md-offset-4 col-sm-6 col-sm-offset-3">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title"><?= Html::encode($this->title) ?></h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<?php $form = ActiveForm::begin(
|
||||
[
|
||||
'id' => $model->formName(),
|
||||
'enableAjaxValidation' => true,
|
||||
'enableClientValidation' => false,
|
||||
'validateOnBlur' => false,
|
||||
'validateOnType' => false,
|
||||
'validateOnChange' => false,
|
||||
]
|
||||
) ?>
|
||||
<?= $form->field(
|
||||
$model,
|
||||
'twoFactorAuthenticationCode',
|
||||
['inputOptions' => ['autofocus' => 'autofocus', 'class' => 'form-control', 'tabindex' => '1']]
|
||||
) ?>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<?= Html::a(
|
||||
Yii::t('usuario', 'Cancel'),
|
||||
['login'],
|
||||
['class' => 'btn btn-default btn-block', 'tabindex' => '3']
|
||||
) ?>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<?= Html::submitButton(
|
||||
Yii::t('usuario', 'Confirm'),
|
||||
['class' => 'btn btn-primary btn-block', 'tabindex' => '3']
|
||||
) ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php ActiveForm::end(); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -10,16 +10,20 @@
|
||||
*/
|
||||
|
||||
use yii\helpers\Html;
|
||||
use yii\helpers\Url;
|
||||
use yii\widgets\ActiveForm;
|
||||
|
||||
/**
|
||||
* @var yii\web\View $this
|
||||
* @var yii\widgets\ActiveForm $form
|
||||
* @var yii\web\View $this
|
||||
* @var yii\widgets\ActiveForm $form
|
||||
* @var \Da\User\Form\SettingsForm $model
|
||||
*/
|
||||
|
||||
$this->title = Yii::t('usuario', 'Account settings');
|
||||
$this->params['breadcrumbs'][] = $this->title;
|
||||
|
||||
/** @var \Da\User\Module $module */
|
||||
$module = Yii::$app->getModule('user');
|
||||
?>
|
||||
<div class="clearfix"></div>
|
||||
|
||||
@ -68,7 +72,61 @@ $this->params['breadcrumbs'][] = $this->title;
|
||||
<?php ActiveForm::end(); ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ($module->enableTwoFactorAuthentication): ?>
|
||||
<div class="modal fade" id="tfmodal" tabindex="-1" role="dialog" aria-labelledby="tfamodalLabel"
|
||||
aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
|
||||
aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title" id="myModalLabel">
|
||||
<?= Yii::t('usuario', 'Two Factor Authentication') ?></h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
...
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">
|
||||
<?= Yii::t('usuario', 'Close') ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-info">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title"><?= Yii::t('usuario', 'Two-Factor Authentication') ?></h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<p>
|
||||
<?= Yii::t('usuario', 'Two-factor auth protects you against stolen credentials') ?>.
|
||||
</p>
|
||||
<div class="text-right">
|
||||
<?= Html::a(
|
||||
Yii::t('usuario', 'Disable Two-Factor Auth'),
|
||||
['two-factor-disable', 'id' => $model->getUser()->id],
|
||||
[
|
||||
'id' => 'disable_tf_btn',
|
||||
'class' => 'btn btn-warning ' . ($model->getUser()->auth_tf_enabled ? '' : 'hide'),
|
||||
'data-method' => 'post',
|
||||
'data-confirm' => Yii::t('usuario', 'This will disable two-factor auth. Are you sure?'),
|
||||
]
|
||||
) ?>
|
||||
<?= Html::a(
|
||||
Yii::t('usuario', 'Enable Two-factor auth'),
|
||||
'#tfmodal',
|
||||
[
|
||||
'id' => 'enable_tf_btn',
|
||||
'class' => 'btn btn-info ' . ($model->getUser()->auth_tf_enabled ? 'hide' : ''),
|
||||
'data-toggle' => 'modal',
|
||||
'data-target' => '#tfmodal'
|
||||
]
|
||||
) ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if ($model->module->allowAccountDelete): ?>
|
||||
<div class="panel panel-danger">
|
||||
<div class="panel-heading">
|
||||
@ -80,17 +138,59 @@ $this->params['breadcrumbs'][] = $this->title;
|
||||
<?= Yii::t('usuario', 'It will be deleted forever') ?>.
|
||||
<?= Yii::t('usuario', 'Please be certain') ?>.
|
||||
</p>
|
||||
<?= Html::a(
|
||||
Yii::t('usuario', 'Delete account'),
|
||||
['delete'],
|
||||
[
|
||||
'class' => 'btn btn-danger',
|
||||
'data-method' => 'post',
|
||||
'data-confirm' => Yii::t('usuario', 'Are you sure? There is no going back'),
|
||||
]
|
||||
) ?>
|
||||
<div class="text-right">
|
||||
<?= Html::a(
|
||||
Yii::t('usuario', 'Delete account'),
|
||||
['delete'],
|
||||
[
|
||||
'class' => 'btn btn-danger',
|
||||
'data-method' => 'post',
|
||||
'data-confirm' => Yii::t('usuario', 'Are you sure? There is no going back'),
|
||||
]
|
||||
) ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php if ($module->enableTwoFactorAuthentication): ?>
|
||||
|
||||
<?php
|
||||
// This script should be in fact in a module as an external file
|
||||
// consider overriding this view and include your very own approach
|
||||
$uri = Url::to(['two-factor', 'id' => $model->getUser()->id]);
|
||||
$verify = Url::to(['two-factor-enable', 'id' => $model->getUser()->id]);
|
||||
$js = <<<JS
|
||||
$('#tfmodal')
|
||||
.on('show.bs.modal', function(){
|
||||
if(!$('img#qrCode').length) {
|
||||
$(this).find('.modal-body').load('{$uri}');
|
||||
} else {
|
||||
$('input#tfcode').val('');
|
||||
}
|
||||
});
|
||||
|
||||
$(document)
|
||||
.on('click', '.btn-submit-code', function(e) {
|
||||
e.preventDefault();
|
||||
var btn = $(this);
|
||||
btn.prop('disabled', true);
|
||||
|
||||
$.getJSON('{$verify}', {code: $('#tfcode').val()}, function(data){
|
||||
btn.prop('disabled', false);
|
||||
if(data.success) {
|
||||
$('#enable_tf_btn, #disable_tf_btn').toggleClass('hide');
|
||||
$('#tfmessage').removeClass('alert-danger').addClass('alert-success').find('p').text(data.message);
|
||||
setTimeout(function() { $('#tfmodal').modal('hide'); }, 2000);
|
||||
} else {
|
||||
$('input#tfcode').val('');
|
||||
$('#tfmessage').removeClass('alert-info').addClass('alert-danger').find('p').text(data.message);
|
||||
}
|
||||
}).fail(function(){ btn.prop('disabled', false); });
|
||||
});
|
||||
JS;
|
||||
|
||||
$this->registerJs($js);
|
||||
?>
|
||||
<?php endif; ?>
|
||||
|
||||
40
src/User/resources/views/settings/two-factor.php
Normal file
40
src/User/resources/views/settings/two-factor.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of the 2amigos/yii2-usuario-app project.
|
||||
*
|
||||
* (c) 2amigOS! <http://2amigos.us/>
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/** @var string $id */
|
||||
/** @var string $uri */
|
||||
?>
|
||||
|
||||
<div class="alert alert-info" id="tfmessage">
|
||||
<p>
|
||||
<?= Yii::t(
|
||||
'usuario',
|
||||
'Scan the QrCode with Google Authenticator App, then insert its temporary code on the box and submit.'
|
||||
) ?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-offset-3 col-md-6 text-center">
|
||||
<img id="qrCode" src="<?= $uri ?>"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-offset-3 col-md-6 text-center">
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control" id="tfcode" placeholder="<?= Yii::t('usuario', 'Two-factor code') ?>"/>
|
||||
<span class="input-group-btn">
|
||||
<button type="button" class="btn btn-primary btn-submit-code">
|
||||
<?= Yii::t('usuario', 'Enable') ?>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -8,7 +8,7 @@ return [
|
||||
'@Da/User' => dirname(dirname(dirname(__DIR__))) . '/src/User',
|
||||
'@tests' => dirname(dirname(__DIR__)),
|
||||
'@vendor' => VENDOR_DIR,
|
||||
'@bower' => VENDOR_DIR . '/bower',
|
||||
'@bower' => VENDOR_DIR . '/bower-asset',
|
||||
],
|
||||
'bootstrap' => ['Da\User\Bootstrap'],
|
||||
'modules' => [
|
||||
|
||||
Reference in New Issue
Block a user