diff --git a/src/Module.php b/src/Module.php index a58394a..667c850 100644 --- a/src/Module.php +++ b/src/Module.php @@ -11,6 +11,8 @@ namespace hiqdev\yii2\mfa; use hiqdev\yii2\mfa\base\Totp; +use hiqdev\yii2\mfa\exceptions\IpNotAllowedException; +use hiqdev\yii2\mfa\exceptions\TotpVerificationFailedException; use Yii; use yii\di\Instance; use yii\helpers\StringHelper; @@ -87,8 +89,7 @@ public function validateIps(IdentityInterface $identity) return; } - Yii::$app->response->redirect('/mfa/allowed-ips/not-allowed-ip'); - Yii::$app->end(); + throw new IpNotAllowedException(); } public function validateTotp(IdentityInterface $identity) @@ -100,7 +101,6 @@ public function validateTotp(IdentityInterface $identity) return; } - Yii::$app->response->redirect('/mfa/totp/check'); - Yii::$app->end(); + throw new TotpVerificationFailedException(); } } diff --git a/src/behaviors/ValidateMfaBehavior.php b/src/behaviors/ValidateMfaBehavior.php index 1d20ae8..2e7f815 100644 --- a/src/behaviors/ValidateMfaBehavior.php +++ b/src/behaviors/ValidateMfaBehavior.php @@ -10,6 +10,8 @@ namespace hiqdev\yii2\mfa\behaviors; +use hiqdev\yii2\mfa\exceptions\AuthenticationException; +use hiqdev\yii2\mfa\Module; use Yii; use yii\base\Event; use yii\web\User; @@ -25,10 +27,16 @@ public function events() public function beforeLogin(Event $event) { + /** @var Module $module */ $module = Yii::$app->getModule('mfa'); $identity = $event->identity; $module->setHalfUser($identity); - $module->validateIps($identity); - $module->validateTotp($identity); + + try { + $module->validateIps($identity); + $module->validateTotp($identity); + } catch (AuthenticationException $e) { + $e->redirect(); + } } } diff --git a/src/controllers/AllowedIpsController.php b/src/controllers/AllowedIpsController.php index 8ab7b02..9fffa16 100644 --- a/src/controllers/AllowedIpsController.php +++ b/src/controllers/AllowedIpsController.php @@ -10,6 +10,8 @@ namespace hiqdev\yii2\mfa\controllers; +use hiqdev\yii2\mfa\exceptions\AuthenticationException; +use hiqdev\yii2\mfa\filters\ValidateAuthenticationFilter; use Yii; use yii\filters\AccessControl; @@ -28,18 +30,21 @@ public function behaviors() return $this->goHome(); }, 'rules' => [ - // ? - guest [ 'actions' => ['not-allowed-ip'], - 'roles' => ['?'], 'allow' => true, - ], - // @ - authenticated - [ - 'actions' => ['other'], - 'roles' => ['@'], - 'allow' => true, - ], + 'matchCallback' => function ($action) { + $filter = new ValidateAuthenticationFilter(); + try { + $filter->validateAuthentication(Yii::$app->user->identity); + } catch (AuthenticationException $e) { + // Show this page only when user have problems with IP + return true; + } + + return false; + } + ] ], ], ]; diff --git a/src/exceptions/AuthenticationException.php b/src/exceptions/AuthenticationException.php new file mode 100644 index 0000000..9e87382 --- /dev/null +++ b/src/exceptions/AuthenticationException.php @@ -0,0 +1,10 @@ +response->redirect('/mfa/allowed-ips/not-allowed-ip'); + Yii::$app->end(); + } +} diff --git a/src/exceptions/NotAuthenticatedException.php b/src/exceptions/NotAuthenticatedException.php new file mode 100644 index 0000000..23bd4d0 --- /dev/null +++ b/src/exceptions/NotAuthenticatedException.php @@ -0,0 +1,19 @@ +response->redirect('/site/login'); + Yii::$app->end(); + } +} diff --git a/src/exceptions/TotpVerificationFailedException.php b/src/exceptions/TotpVerificationFailedException.php new file mode 100644 index 0000000..1a4859e --- /dev/null +++ b/src/exceptions/TotpVerificationFailedException.php @@ -0,0 +1,19 @@ +response->redirect('/mfa/totp/check'); + Yii::$app->end(); + } +} diff --git a/src/filters/ValidateAuthenticationFilter.php b/src/filters/ValidateAuthenticationFilter.php new file mode 100644 index 0000000..d8691a2 --- /dev/null +++ b/src/filters/ValidateAuthenticationFilter.php @@ -0,0 +1,63 @@ +user->isGuest) { + return $this->denyAccess(new NotAuthenticatedException()); + } + + $identity = Yii::$app->user->identity; + try { + $this->validateAuthentication($identity); + } catch (AuthenticationException $e) { + return $this->denyAccess($e); + } + + return true; + } + + public function validateAuthentication(IdentityInterface $identity) + { + /** @var Module $module */ + $module = Yii::$app->getModule('mfa'); + + $module->validateIps($identity); + $module->validateTotp($identity); + } + + /** + * @param AuthenticationException $exception + * @return mixed + */ + protected function denyAccess($exception) + { + if ($this->denyCallback instanceof Closure) { + return call_user_func($this->denyCallback, $exception); + } + + $exception->redirect(); + } + +}