diff options
author | Frederic Guillot <fred@kanboard.net> | 2015-03-31 22:48:14 -0400 |
---|---|---|
committer | Frederic Guillot <fred@kanboard.net> | 2015-03-31 22:48:14 -0400 |
commit | abeeba71672a711dab98194bb8ae751ee95e3385 (patch) | |
tree | 26838682b1ab13611b9697d1b8900122409dbf47 /app/Controller | |
parent | 5d393ed9962ebe18a162cb09b08eaea9359df2cc (diff) |
Add two factor authentication
Diffstat (limited to 'app/Controller')
-rw-r--r-- | app/Controller/Base.php | 21 | ||||
-rw-r--r-- | app/Controller/Twofactor.php | 137 |
2 files changed, 158 insertions, 0 deletions
diff --git a/app/Controller/Base.php b/app/Controller/Base.php index 6420e0ee..f498c3ce 100644 --- a/app/Controller/Base.php +++ b/app/Controller/Base.php @@ -176,6 +176,7 @@ abstract class Base if (! $this->acl->isPublicAction($controller, $action)) { $this->handleAuthentication(); + $this->handle2FA($controller, $action); $this->handleAuthorization($controller, $action); $this->session['has_subtask_inprogress'] = $this->subtask->hasSubtaskInProgress($this->userSession->getId()); @@ -200,6 +201,26 @@ abstract class Base } /** + * Check 2FA + * + * @access public + */ + public function handle2FA($controller, $action) + { + $controllers = array('twofactor', 'user'); + $actions = array('code', 'check', 'logout'); + + if ($this->userSession->has2FA() && ! $this->userSession->check2FA() && ! in_array($controller, $controllers) && ! in_array($action, $actions)) { + + if ($this->request->isAjax()) { + $this->response->text('Not Authorized', 401); + } + + $this->response->redirect($this->helper->url('twofactor', 'code', array('user_id' => $user['id']))); + } + } + + /** * Check page access and authorization * * @access public diff --git a/app/Controller/Twofactor.php b/app/Controller/Twofactor.php new file mode 100644 index 00000000..7711666b --- /dev/null +++ b/app/Controller/Twofactor.php @@ -0,0 +1,137 @@ +<?php + +namespace Controller; + +use Otp\Otp; +use Otp\GoogleAuthenticator; +use Base32\Base32; + +/** + * Two Factor Auth controller + * + * @package controller + * @author Frederic Guillot + */ +class Twofactor extends User +{ + /** + * Only the current user can access to 2FA settings + * + * @access private + */ + private function checkCurrentUser(array $user) + { + if ($user['id'] != $this->userSession->getId()) { + $this->forbidden(); + } + } + + /** + * Index + * + * @access public + */ + public function index() + { + $user = $this->getUser(); + $this->checkCurrentUser($user); + + $label = $user['email'] ?: $user['username']; + + $this->response->html($this->layout('twofactor/index', array( + 'user' => $user, + 'qrcode_url' => $user['twofactor_activated'] == 1 ? GoogleAuthenticator::getQrCodeUrl('totp', $label, $user['twofactor_secret']) : '', + 'key_url' => $user['twofactor_activated'] == 1 ? GoogleAuthenticator::getKeyUri('totp', $label, $user['twofactor_secret']) : '', + ))); + } + + /** + * Enable/disable 2FA + * + * @access public + */ + public function save() + { + $user = $this->getUser(); + $this->checkCurrentUser($user); + + $values = $this->request->getValues(); + + if (isset($values['twofactor_activated']) && $values['twofactor_activated'] == 1) { + $this->user->update(array( + 'id' => $user['id'], + 'twofactor_activated' => 1, + 'twofactor_secret' => GoogleAuthenticator::generateRandom(), + )); + } + else { + $this->user->update(array( + 'id' => $user['id'], + 'twofactor_activated' => 0, + 'twofactor_secret' => '', + )); + } + + $this->session->flash(t('User updated successfully.')); + $this->response->redirect($this->helper->url('twofactor', 'index', array('user_id' => $user['id']))); + } + + /** + * Test 2FA + * + * @access public + */ + public function test() + { + $user = $this->getUser(); + $this->checkCurrentUser($user); + + $otp = new Otp; + $values = $this->request->getValues(); + + if (! empty($values['code']) && $otp->checkTotp(Base32::decode($user['twofactor_secret']), $values['code'])) { + $this->session->flash(t('The two factor authentication code is valid.')); + } + else { + $this->session->flashError(t('The two factor authentication code is not valid.')); + } + + $this->response->redirect($this->helper->url('twofactor', 'index', array('user_id' => $user['id']))); + } + + /** + * Check 2FA + * + * @access public + */ + public function check() + { + $user = $this->getUser(); + $this->checkCurrentUser($user); + + $otp = new Otp; + $values = $this->request->getValues(); + + if (! empty($values['code']) && $otp->checkTotp(Base32::decode($user['twofactor_secret']), $values['code'])) { + $this->session['2fa_validated'] = true; + $this->session->flash(t('The two factor authentication code is valid.')); + $this->response->redirect($this->helper->url('app', 'index')); + } + else { + $this->session->flashError(t('The two factor authentication code is not valid.')); + $this->response->redirect($this->helper->url('twofactor', 'code')); + } + } + + /** + * Ask the 2FA code + * + * @access public + */ + public function code() + { + $this->response->html($this->template->layout('twofactor/check', array( + 'title' => t('Check two factor authentication code'), + ))); + } +} |