Nortoneo_TwoFactorAuth - Version 0.1.0

Version Notes

Nortoneo_TwoFactorAuth v0.1.0

Download this release

Release Info

Developer Lukasz Szczedzina
Extension Nortoneo_TwoFactorAuth
Version 0.1.0
Comparing to
See all releases


Version 0.1.0

Files changed (27) hide show
  1. app/code/community/Nortoneo/TwoFactorAuth/Block/Adminhtml/UserSettings/Edit.php +42 -0
  2. app/code/community/Nortoneo/TwoFactorAuth/Block/Adminhtml/UserSettings/Edit/Form.php +22 -0
  3. app/code/community/Nortoneo/TwoFactorAuth/Block/Adminhtml/UserSettings/Edit/Tab/Form.php +101 -0
  4. app/code/community/Nortoneo/TwoFactorAuth/Block/Adminhtml/UserSettings/Edit/Tabs.php +30 -0
  5. app/code/community/Nortoneo/TwoFactorAuth/Block/Adminhtml/UserSettings/Validate.php +33 -0
  6. app/code/community/Nortoneo/TwoFactorAuth/Block/Adminhtml/UserSettings/Validate/Form.php +22 -0
  7. app/code/community/Nortoneo/TwoFactorAuth/Block/Adminhtml/UserSettings/Validate/Tab/Form.php +62 -0
  8. app/code/community/Nortoneo/TwoFactorAuth/Block/Adminhtml/UserSettings/Validate/Tabs.php +29 -0
  9. app/code/community/Nortoneo/TwoFactorAuth/Helper/Data.php +96 -0
  10. app/code/community/Nortoneo/TwoFactorAuth/Model/Lib/GoogleAuthenticator.php +252 -0
  11. app/code/community/Nortoneo/TwoFactorAuth/Model/Observer.php +71 -0
  12. app/code/community/Nortoneo/TwoFactorAuth/Model/Resource/UserSettings.php +53 -0
  13. app/code/community/Nortoneo/TwoFactorAuth/Model/Resource/UserSettings/Collection.php +14 -0
  14. app/code/community/Nortoneo/TwoFactorAuth/Model/UserSettings.php +216 -0
  15. app/code/community/Nortoneo/TwoFactorAuth/controllers/Adminhtml/LoginController.php +54 -0
  16. app/code/community/Nortoneo/TwoFactorAuth/controllers/Adminhtml/UserSettingsController.php +104 -0
  17. app/code/community/Nortoneo/TwoFactorAuth/etc/adminhtml.xml +30 -0
  18. app/code/community/Nortoneo/TwoFactorAuth/etc/config.xml +90 -0
  19. app/code/community/Nortoneo/TwoFactorAuth/sql/nortoneo_twofactorauth_setup/install-0.1.0.php +58 -0
  20. app/design/adminhtml/default/default/layout/nortoneo/twofactorauth.xml +10 -0
  21. app/design/adminhtml/default/default/template/nortoneo/twofactorauth/login.phtml +49 -0
  22. app/design/adminhtml/default/default/template/nortoneo/twofactorauth/usersettings.phtml +35 -0
  23. app/etc/modules/Nortoneo_TwoFactorAuth.xml +9 -0
  24. app/locale/en_US/nortoneo/twofactorauth.csv +33 -0
  25. app/locale/en_US/template/email/nortoneo/twofactorauth/code.html +4 -0
  26. app/locale/pl_PL/nortoneo/twofactorauth.csv +33 -0
  27. package.xml +24 -0
app/code/community/Nortoneo/TwoFactorAuth/Block/Adminhtml/UserSettings/Edit.php ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Nortoneo_TwoFactorAuth
4
+ * @author Lukasz Szczedzina <contact@nortoneo.com>
5
+ * @website http://nortoneo.com
6
+ */
7
+ class Nortoneo_TwoFactorAuth_Block_Adminhtml_UserSettings_Edit extends Mage_Adminhtml_Block_Widget_Form_Container
8
+ {
9
+ public function __construct()
10
+ {
11
+ $this->_objectId = 'id';
12
+ $this->_blockGroup = 'nortoneo_twofactorauth';
13
+ $this->_controller = 'adminhtml_userSettings';
14
+ $this->_mode = 'edit';
15
+
16
+ $confirmationMessage = Mage::helper('core')->jsQuoteEscape(
17
+ Mage::helper('core')->__('Are you sure? If you are using mobile app you will have to rescan QR code. For safety reasons you will have to enable protection again.')
18
+ );
19
+ $onclickJs = 'deleteConfirm(\'' . $confirmationMessage . '\', \'' . $this->getUrl('*/*/regenerateSecret') . '\');';
20
+ $this->_addButton('regenerate_secret', array(
21
+ 'label' => Mage::helper('sales')->__('Regenerate secret key'),
22
+ 'onclick' => $onclickJs,
23
+ ));
24
+
25
+ parent::__construct();
26
+ $this->removeButton('back');
27
+ }
28
+
29
+ /**
30
+ * Get form action URL
31
+ *
32
+ */
33
+ public function getFormActionUrl()
34
+ {
35
+ return $this->getUrl('*/*/save');
36
+ }
37
+
38
+ public function getHeaderText()
39
+ {
40
+ return Mage::helper('nortoneo_twofactorauth')->__('Two Factor Authentication Settings');
41
+ }
42
+ }
app/code/community/Nortoneo/TwoFactorAuth/Block/Adminhtml/UserSettings/Edit/Form.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Nortoneo_TwoFactorAuth
4
+ * @author Lukasz Szczedzina <contact@nortoneo.com>
5
+ * @website http://nortoneo.com
6
+ */
7
+ class Nortoneo_TwoFactorAuth_Block_Adminhtml_UserSettings_Edit_Form extends Mage_Adminhtml_Block_Widget_Form
8
+ {
9
+ protected function _prepareForm()
10
+ {
11
+ $form = new Varien_Data_Form(array(
12
+ 'id' => 'edit_form',
13
+ 'enctype' => 'multipart/form-data',
14
+ 'action' => $this->getData('action'),
15
+ 'method' => 'post'
16
+ ));
17
+ $form->setUseContainer(true);
18
+ $this->setForm($form);
19
+
20
+ return parent::_prepareForm();
21
+ }
22
+ }
app/code/community/Nortoneo/TwoFactorAuth/Block/Adminhtml/UserSettings/Edit/Tab/Form.php ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Nortoneo_TwoFactorAuth
4
+ * @author Lukasz Szczedzina <contact@nortoneo.com>
5
+ * @website http://nortoneo.com
6
+ */
7
+ class Nortoneo_TwoFactorAuth_Block_Adminhtml_UserSettings_Edit_Tab_Form extends Mage_Adminhtml_Block_Widget_Form
8
+ implements Mage_Adminhtml_Block_Widget_Tab_Interface
9
+ {
10
+ /**
11
+ * Prepare content for tab
12
+ * @return string
13
+ */
14
+ public function getTabLabel()
15
+ {
16
+ return Mage::helper('nortoneo_twofactorauth')->__('User Settings');
17
+ }
18
+
19
+ /**
20
+ * Prepare title for tab
21
+ * @return string
22
+ */
23
+ public function getTabTitle()
24
+ {
25
+ return $this->getTabLabel();
26
+ }
27
+
28
+ /**
29
+ * Returns status flag about this tab can be showen or not
30
+ * @return true
31
+ */
32
+ public function canShowTab()
33
+ {
34
+ return true;
35
+ }
36
+
37
+ /**
38
+ * Returns status flag about this tab hidden or not
39
+ * @return true
40
+ */
41
+ public function isHidden()
42
+ {
43
+ return false;
44
+ }
45
+
46
+ /**
47
+ * @return Nortoneo_TwoFactorAuth_Model_UserSettings
48
+ */
49
+ protected function getUserSettingsModel()
50
+ {
51
+ return Mage::helper('nortoneo_twofactorauth')->getCurrentUserSettingsModel();
52
+ }
53
+
54
+ protected function _prepareForm()
55
+ {
56
+ $helper = Mage::helper('nortoneo_twofactorauth');
57
+ $userSettingsModel = $this->getUserSettingsModel();
58
+ $form = new Varien_Data_Form();
59
+ $this->setForm($form);
60
+ $fieldset = $form->addFieldset('nortoneo_twofactorauth_usersettings', array('legend' => $helper->__('Two Factor Authentication Settings')));
61
+
62
+ $fieldset->addField('is_active', 'select', array(
63
+ 'label' => $helper->__('Status'),
64
+ 'title' => $helper->__('Status'),
65
+ 'name' => 'is_active',
66
+ 'required' => true,
67
+ 'options' => array(0 => $helper->__('Disabled'), 1 => $helper->__('Enabled')),
68
+ ));
69
+
70
+ $fieldset->addField('trust_last_ip', 'select', array(
71
+ 'label' => $helper->__('Trust last IP address'),
72
+ 'title' => $helper->__('Trust last IP address'),
73
+ 'name' => 'trust_last_ip',
74
+ 'required' => true,
75
+ 'options' => $userSettingsModel->getTrustLastIpOptions(),
76
+ 'note' => $helper->__('Ask for code only if IP has changed since last successful login?'),
77
+ ));
78
+
79
+ $fieldset->addField('discrepancy', 'select', array(
80
+ 'label' => $helper->__('Discrepancy'),
81
+ 'title' => $helper->__('Discrepancy'),
82
+ 'name' => 'discrepancy',
83
+ 'required' => true,
84
+ 'options' => $userSettingsModel->getDiscrepancyOptions(),
85
+ 'note' => $helper->__('How long your code should be valid.'),
86
+ ));
87
+
88
+ $fieldset->addField('method', 'select', array(
89
+ 'label' => $helper->__('Authentication Method'),
90
+ 'title' => $helper->__('Authentication Method'),
91
+ 'name' => 'method',
92
+ 'required' => true,
93
+ 'options' => $userSettingsModel->getMethodOptions(),
94
+ 'style' => 'width:400px;',
95
+ ));
96
+
97
+ $form->setValues($userSettingsModel);
98
+
99
+ return parent::_prepareForm();
100
+ }
101
+ }
app/code/community/Nortoneo/TwoFactorAuth/Block/Adminhtml/UserSettings/Edit/Tabs.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Nortoneo_TwoFactorAuth
4
+ * @author Lukasz Szczedzina <contact@nortoneo.com>
5
+ * @website http://nortoneo.com
6
+ */
7
+ class Nortoneo_TwoFactorAuth_Block_Adminhtml_UserSettings_Edit_Tabs extends Mage_Adminhtml_Block_Widget_Tabs
8
+ {
9
+ public function __construct()
10
+ {
11
+ parent::__construct();
12
+ $this->setId('userSettings_edit_tabs');
13
+ $this->setDestElementId('edit_form');
14
+ $this->setTitle(Mage::helper('nortoneo_twofactorauth')->__('Settings'));
15
+ }
16
+
17
+ protected function _beforeToHtml()
18
+ {
19
+ $settingsFormBlock = $this->getLayout()->createBlock('nortoneo_twofactorauth/adminhtml_userSettings_edit_tab_form');
20
+ $settingsFormBlock->setTemplate('nortoneo/twofactorauth/usersettings.phtml');
21
+
22
+ $this->addTab('form_section', array(
23
+ 'label' => Mage::helper('nortoneo_twofactorauth')->__('User Settings'),
24
+ 'title' => Mage::helper('nortoneo_twofactorauth')->__('User Settings'),
25
+ 'content' => $settingsFormBlock->toHtml(),
26
+ ));
27
+
28
+ return parent::_beforeToHtml();
29
+ }
30
+ }
app/code/community/Nortoneo/TwoFactorAuth/Block/Adminhtml/UserSettings/Validate.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Nortoneo_TwoFactorAuth
4
+ * @author Lukasz Szczedzina <contact@nortoneo.com>
5
+ * @website http://nortoneo.com
6
+ */
7
+ class Nortoneo_TwoFactorAuth_Block_Adminhtml_UserSettings_Validate extends Mage_Adminhtml_Block_Widget_Form_Container
8
+ {
9
+ public function __construct()
10
+ {
11
+ $this->_objectId = 'id';
12
+ $this->_blockGroup = 'nortoneo_twofactorauth';
13
+ $this->_controller = 'adminhtml_userSettings';
14
+ $this->_mode = 'validate';
15
+
16
+ parent::__construct();
17
+ $this->removeButton('reset');
18
+ }
19
+
20
+ /**
21
+ * Get form action URL
22
+ *
23
+ */
24
+ public function getFormActionUrl()
25
+ {
26
+ return $this->getUrl('*/*/validatePost');
27
+ }
28
+
29
+ public function getHeaderText()
30
+ {
31
+ return Mage::helper('nortoneo_twofactorauth')->__('Two Factor Authentication Settings');
32
+ }
33
+ }
app/code/community/Nortoneo/TwoFactorAuth/Block/Adminhtml/UserSettings/Validate/Form.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Nortoneo_TwoFactorAuth
4
+ * @author Lukasz Szczedzina <contact@nortoneo.com>
5
+ * @website http://nortoneo.com
6
+ */
7
+ class Nortoneo_TwoFactorAuth_Block_Adminhtml_UserSettings_Validate_Form extends Mage_Adminhtml_Block_Widget_Form
8
+ {
9
+ protected function _prepareForm()
10
+ {
11
+ $form = new Varien_Data_Form(array(
12
+ 'id' => 'edit_form',
13
+ 'enctype' => 'multipart/form-data',
14
+ 'action' => $this->getData('action'),
15
+ 'method' => 'post'
16
+ ));
17
+ $form->setUseContainer(true);
18
+ $this->setForm($form);
19
+
20
+ return parent::_prepareForm();
21
+ }
22
+ }
app/code/community/Nortoneo/TwoFactorAuth/Block/Adminhtml/UserSettings/Validate/Tab/Form.php ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Nortoneo_TwoFactorAuth
4
+ * @author Lukasz Szczedzina <contact@nortoneo.com>
5
+ * @website http://nortoneo.com
6
+ */
7
+ class Nortoneo_TwoFactorAuth_Block_Adminhtml_UserSettings_Validate_Tab_Form extends Mage_Adminhtml_Block_Widget_Form
8
+ implements Mage_Adminhtml_Block_Widget_Tab_Interface
9
+ {
10
+ /**
11
+ * Prepare content for tab
12
+ * @return string
13
+ */
14
+ public function getTabLabel()
15
+ {
16
+ return Mage::helper('nortoneo_twofactorauth')->__('User Settings');
17
+ }
18
+
19
+ /**
20
+ * Prepare title for tab
21
+ * @return string
22
+ */
23
+ public function getTabTitle()
24
+ {
25
+ return $this->getTabLabel();
26
+ }
27
+
28
+ /**
29
+ * Returns status flag about this tab can be showen or not
30
+ * @return true
31
+ */
32
+ public function canShowTab()
33
+ {
34
+ return true;
35
+ }
36
+
37
+ /**
38
+ * Returns status flag about this tab hidden or not
39
+ * @return true
40
+ */
41
+ public function isHidden()
42
+ {
43
+ return false;
44
+ }
45
+
46
+ protected function _prepareForm()
47
+ {
48
+ $helper = Mage::helper('nortoneo_twofactorauth');
49
+ $form = new Varien_Data_Form();
50
+ $this->setForm($form);
51
+ $fieldset = $form->addFieldset('nortoneo_twofactorauth_usersettings', array('legend' => $helper->__('Two Factor Authentication Validation')));
52
+
53
+ $fieldset->addField('code', 'text', array(
54
+ 'label' => $helper->__('Authentication Code'),
55
+ 'title' => $helper->__('Authentication Code'),
56
+ 'name' => 'code',
57
+ 'required' => true,
58
+ ));
59
+
60
+ return parent::_prepareForm();
61
+ }
62
+ }
app/code/community/Nortoneo/TwoFactorAuth/Block/Adminhtml/UserSettings/Validate/Tabs.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Nortoneo_TwoFactorAuth
4
+ * @author Lukasz Szczedzina <contact@nortoneo.com>
5
+ * @website http://nortoneo.com
6
+ */
7
+ class Nortoneo_TwoFactorAuth_Block_Adminhtml_UserSettings_Validate_Tabs extends Mage_Adminhtml_Block_Widget_Tabs
8
+ {
9
+ public function __construct()
10
+ {
11
+ parent::__construct();
12
+ $this->setId('userSettings_validate_tabs');
13
+ $this->setDestElementId('edit_form');
14
+ $this->setTitle(Mage::helper('nortoneo_twofactorauth')->__('Settings'));
15
+ }
16
+
17
+ protected function _beforeToHtml()
18
+ {
19
+ $settingsFormBlock = $this->getLayout()->createBlock('nortoneo_twofactorauth/adminhtml_userSettings_validate_tab_form');
20
+
21
+ $this->addTab('form_section', array(
22
+ 'label' => Mage::helper('nortoneo_twofactorauth')->__('Code validation'),
23
+ 'title' => Mage::helper('nortoneo_twofactorauth')->__('Code validation'),
24
+ 'content' => $settingsFormBlock->toHtml(),
25
+ ));
26
+
27
+ return parent::_beforeToHtml();
28
+ }
29
+ }
app/code/community/Nortoneo/TwoFactorAuth/Helper/Data.php ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Nortoneo_TwoFactorAuth
4
+ * @author Lukasz Szczedzina <contact@nortoneo.com>
5
+ * @website http://nortoneo.com
6
+ */
7
+ class Nortoneo_TwoFactorAuth_Helper_Data extends Mage_Core_Helper_Abstract
8
+ {
9
+ protected $currentUserSettingsModel;
10
+
11
+ /**
12
+ * @return Nortoneo_TwoFactorAuth_Model_UserSettings
13
+ */
14
+ public function getCurrentUserSettingsModel()
15
+ {
16
+ if ($this->currentUserSettingsModel === null) {
17
+ $user = Mage::getSingleton('admin/session')->getUser();
18
+ if (!$user) {
19
+ Mage::throwException('Cant load user model.');
20
+ }
21
+ $userId = $user->getId();
22
+ /** @var Nortoneo_TwoFactorAuth_Model_UserSettings $userSettingsModel */
23
+ $userSettingsModel = Mage::getResourceModel('nortoneo_twofactorauth/userSettings_collection')
24
+ ->addFieldToFilter('user_id', $userId)
25
+ ->getFirstItem();
26
+ $userSettingsModel->afterLoad();
27
+ if (!$userSettingsModel->getId()) {
28
+ $data = array(
29
+ 'is_active' => 0,
30
+ 'secret' => $userSettingsModel->generateSecret(),
31
+ 'user_id' => $userId,
32
+ 'method' => Nortoneo_TwoFactorAuth_Model_UserSettings::TWO_FACTOR_AUTH_METHOD_EMAIL,
33
+ 'trust_last_ip' => Nortoneo_TwoFactorAuth_Model_UserSettings::TWO_FACTOR_AUTH_TRUST_LAST_IP_NO,
34
+ 'discrepancy' => 4, //2 minutes
35
+ 'last_ip' => Mage::helper('core/http')->getRemoteAddr()
36
+ );
37
+ $userSettingsModel->setData($data);
38
+ $userSettingsModel->save();
39
+ }
40
+ $this->currentUserSettingsModel = $userSettingsModel;
41
+ }
42
+
43
+ return $this->currentUserSettingsModel;
44
+ }
45
+
46
+ /**
47
+ * @return bool
48
+ */
49
+ public function isCurrentUserForAuthentication()
50
+ {
51
+ $session = Mage::getSingleton('admin/session');
52
+ if (!$session->isLoggedIn()) {
53
+ return false;
54
+ }
55
+
56
+ $authSettings = $this->getCurrentUserSettingsModel();
57
+ if (!$authSettings->getIsActive()) {
58
+ return false;
59
+ }
60
+
61
+ $currentIp = Mage::helper('core/http')->getRemoteAddr();
62
+ if ($authSettings->getTrustLastIp() && $authSettings->getLastIp() == $currentIp) {
63
+ return false;
64
+ }
65
+
66
+ if ($this->isCurrentUserValidated()) {
67
+ return false;
68
+ }
69
+
70
+ return true;
71
+ }
72
+
73
+ /**
74
+ * @return bool
75
+ */
76
+ public function isCurrentUserValidated()
77
+ {
78
+ $session = Mage::getSingleton('admin/session');
79
+ if (!$session->isLoggedIn()) {
80
+ return false;
81
+ }
82
+
83
+ return (bool)$session->getData('two_factor_auth_validated');
84
+ }
85
+
86
+ /**
87
+ * @param bool $status
88
+ */
89
+ public function setCurrentUserValidated($status)
90
+ {
91
+ $session = Mage::getSingleton('admin/session');
92
+ if ($session->isLoggedIn()) {
93
+ $session->setData('two_factor_auth_validated', (bool)$status);
94
+ }
95
+ }
96
+ }
app/code/community/Nortoneo/TwoFactorAuth/Model/Lib/GoogleAuthenticator.php ADDED
@@ -0,0 +1,252 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * PHP Class for handling Google Authenticator 2-factor authentication.
5
+ *
6
+ * @author Michael Kliewe
7
+ * @copyright 2012 Michael Kliewe
8
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
9
+ *
10
+ * @link http://www.phpgangsta.de/
11
+ */
12
+ class Nortoneo_TwoFactorAuth_Model_Lib_GoogleAuthenticator
13
+ {
14
+ protected $_codeLength = 6;
15
+
16
+ /**
17
+ * Create new secret.
18
+ * 16 characters, randomly chosen from the allowed base32 characters.
19
+ *
20
+ * @param int $secretLength
21
+ *
22
+ * @return string
23
+ */
24
+ public function createSecret($secretLength = 16)
25
+ {
26
+ $validChars = $this->_getBase32LookupTable();
27
+
28
+ // Valid secret lengths are 80 to 640 bits
29
+ if ($secretLength < 16 || $secretLength > 128) {
30
+ throw new Exception('Bad secret length');
31
+ }
32
+ $secret = '';
33
+ $rnd = false;
34
+ if (function_exists('random_bytes')) {
35
+ $rnd = random_bytes($secretLength);
36
+ } elseif (function_exists('mcrypt_create_iv')) {
37
+ $rnd = mcrypt_create_iv($secretLength, MCRYPT_DEV_URANDOM);
38
+ } elseif (function_exists('openssl_random_pseudo_bytes')) {
39
+ $rnd = openssl_random_pseudo_bytes($secretLength, $cryptoStrong);
40
+ if (!$cryptoStrong) {
41
+ $rnd = false;
42
+ }
43
+ }
44
+ if ($rnd !== false) {
45
+ for ($i = 0; $i < $secretLength; ++$i) {
46
+ $secret .= $validChars[ord($rnd[$i]) & 31];
47
+ }
48
+ } else {
49
+ throw new Exception('No source of secure random');
50
+ }
51
+
52
+ return $secret;
53
+ }
54
+
55
+ /**
56
+ * Calculate the code, with given secret and point in time.
57
+ *
58
+ * @param string $secret
59
+ * @param int|null $timeSlice
60
+ *
61
+ * @return string
62
+ */
63
+ public function getCode($secret, $timeSlice = null)
64
+ {
65
+ if ($timeSlice === null) {
66
+ $timeSlice = floor(time() / 30);
67
+ }
68
+
69
+ $secretkey = $this->_base32Decode($secret);
70
+
71
+ // Pack time into binary string
72
+ $time = chr(0).chr(0).chr(0).chr(0).pack('N*', $timeSlice);
73
+ // Hash it with users secret key
74
+ $hm = hash_hmac('SHA1', $time, $secretkey, true);
75
+ // Use last nipple of result as index/offset
76
+ $offset = ord(substr($hm, -1)) & 0x0F;
77
+ // grab 4 bytes of the result
78
+ $hashpart = substr($hm, $offset, 4);
79
+
80
+ // Unpak binary value
81
+ $value = unpack('N', $hashpart);
82
+ $value = $value[1];
83
+ // Only 32 bits
84
+ $value = $value & 0x7FFFFFFF;
85
+
86
+ $modulo = pow(10, $this->_codeLength);
87
+
88
+ return str_pad($value % $modulo, $this->_codeLength, '0', STR_PAD_LEFT);
89
+ }
90
+
91
+ /**
92
+ * Get QR-Code URL for image, from google charts.
93
+ *
94
+ * @param string $name
95
+ * @param string $secret
96
+ * @param string $title
97
+ * @param array $params
98
+ *
99
+ * @return string
100
+ */
101
+ public function getQRCodeGoogleUrl($name, $secret, $title = null, $params = array())
102
+ {
103
+ $width = !empty($params['width']) && (int) $params['width'] > 0 ? (int) $params['width'] : 200;
104
+ $height = !empty($params['height']) && (int) $params['height'] > 0 ? (int) $params['height'] : 200;
105
+ $level = !empty($params['level']) && array_search($params['level'], array('L', 'M', 'Q', 'H')) !== false ? $params['level'] : 'M';
106
+
107
+ $urlencoded = urlencode('otpauth://totp/'.$name.'?secret='.$secret.'');
108
+ if (isset($title)) {
109
+ $urlencoded .= urlencode('&issuer='.urlencode($title));
110
+ }
111
+
112
+ return 'https://chart.googleapis.com/chart?chs='.$width.'x'.$height.'&chld='.$level.'|0&cht=qr&chl='.$urlencoded.'';
113
+ }
114
+
115
+ /**
116
+ * Check if the code is correct. This will accept codes starting from $discrepancy*30sec ago to $discrepancy*30sec from now.
117
+ *
118
+ * @param string $secret
119
+ * @param string $code
120
+ * @param int $discrepancy This is the allowed time drift in 30 second units (8 means 4 minutes before or after)
121
+ * @param int|null $currentTimeSlice time slice if we want use other that time()
122
+ *
123
+ * @return bool
124
+ */
125
+ public function verifyCode($secret, $code, $discrepancy = 1, $currentTimeSlice = null)
126
+ {
127
+ if ($currentTimeSlice === null) {
128
+ $currentTimeSlice = floor(time() / 30);
129
+ }
130
+
131
+ if (strlen($code) != 6) {
132
+ return false;
133
+ }
134
+
135
+ for ($i = -$discrepancy; $i <= $discrepancy; ++$i) {
136
+ $calculatedCode = $this->getCode($secret, $currentTimeSlice + $i);
137
+ if ($this->timingSafeEquals($calculatedCode, $code)) {
138
+ return true;
139
+ }
140
+ }
141
+
142
+ return false;
143
+ }
144
+
145
+ /**
146
+ * Set the code length, should be >=6.
147
+ *
148
+ * @param int $length
149
+ *
150
+ * @return PHPGangsta_GoogleAuthenticator
151
+ */
152
+ public function setCodeLength($length)
153
+ {
154
+ $this->_codeLength = $length;
155
+
156
+ return $this;
157
+ }
158
+
159
+ /**
160
+ * Helper class to decode base32.
161
+ *
162
+ * @param $secret
163
+ *
164
+ * @return bool|string
165
+ */
166
+ protected function _base32Decode($secret)
167
+ {
168
+ if (empty($secret)) {
169
+ return '';
170
+ }
171
+
172
+ $base32chars = $this->_getBase32LookupTable();
173
+ $base32charsFlipped = array_flip($base32chars);
174
+
175
+ $paddingCharCount = substr_count($secret, $base32chars[32]);
176
+ $allowedValues = array(6, 4, 3, 1, 0);
177
+ if (!in_array($paddingCharCount, $allowedValues)) {
178
+ return false;
179
+ }
180
+ for ($i = 0; $i < 4; ++$i) {
181
+ if ($paddingCharCount == $allowedValues[$i] &&
182
+ substr($secret, -($allowedValues[$i])) != str_repeat($base32chars[32], $allowedValues[$i])) {
183
+ return false;
184
+ }
185
+ }
186
+ $secret = str_replace('=', '', $secret);
187
+ $secret = str_split($secret);
188
+ $binaryString = '';
189
+ for ($i = 0; $i < count($secret); $i = $i + 8) {
190
+ $x = '';
191
+ if (!in_array($secret[$i], $base32chars)) {
192
+ return false;
193
+ }
194
+ for ($j = 0; $j < 8; ++$j) {
195
+ $x .= str_pad(base_convert(@$base32charsFlipped[@$secret[$i + $j]], 10, 2), 5, '0', STR_PAD_LEFT);
196
+ }
197
+ $eightBits = str_split($x, 8);
198
+ for ($z = 0; $z < count($eightBits); ++$z) {
199
+ $binaryString .= (($y = chr(base_convert($eightBits[$z], 2, 10))) || ord($y) == 48) ? $y : '';
200
+ }
201
+ }
202
+
203
+ return $binaryString;
204
+ }
205
+
206
+ /**
207
+ * Get array with all 32 characters for decoding from/encoding to base32.
208
+ *
209
+ * @return array
210
+ */
211
+ protected function _getBase32LookupTable()
212
+ {
213
+ return array(
214
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // 7
215
+ 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // 15
216
+ 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', // 23
217
+ 'Y', 'Z', '2', '3', '4', '5', '6', '7', // 31
218
+ '=', // padding char
219
+ );
220
+ }
221
+
222
+ /**
223
+ * A timing safe equals comparison
224
+ * more info here: http://blog.ircmaxell.com/2014/11/its-all-about-time.html.
225
+ *
226
+ * @param string $safeString The internal (safe) value to be checked
227
+ * @param string $userString The user submitted (unsafe) value
228
+ *
229
+ * @return bool True if the two strings are identical
230
+ */
231
+ private function timingSafeEquals($safeString, $userString)
232
+ {
233
+ if (function_exists('hash_equals')) {
234
+ return hash_equals($safeString, $userString);
235
+ }
236
+ $safeLen = strlen($safeString);
237
+ $userLen = strlen($userString);
238
+
239
+ if ($userLen != $safeLen) {
240
+ return false;
241
+ }
242
+
243
+ $result = 0;
244
+
245
+ for ($i = 0; $i < $userLen; ++$i) {
246
+ $result |= (ord($safeString[$i]) ^ ord($userString[$i]));
247
+ }
248
+
249
+ // They are only identical strings if $result is exactly 0...
250
+ return $result === 0;
251
+ }
252
+ }
app/code/community/Nortoneo/TwoFactorAuth/Model/Observer.php ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * @package Nortoneo_TwoFactorAuth
5
+ * @author Lukasz Szczedzina <contact@nortoneo.com>
6
+ * @website http://nortoneo.com
7
+ */
8
+ class Nortoneo_TwoFactorAuth_Model_Observer
9
+ {
10
+ /**
11
+ * @param $observer
12
+ */
13
+ public function processAuthentication($observer)
14
+ {
15
+ /** @var Mage_Core_Controller_Request_Http $request */
16
+ $request = Mage::app()->getRequest();
17
+ if ($this->isRequestAlwaysAllowed($request)) {
18
+ return;
19
+ }
20
+
21
+ $helper = Mage::helper('nortoneo_twofactorauth');
22
+ if (!$helper->isCurrentUserForAuthentication()) {
23
+ return;
24
+ }
25
+
26
+ /** @var Nortoneo_TwoFactorAuth_Model_UserSettings $authSettings */
27
+ $authSettings = Mage::helper('nortoneo_twofactorauth')->getCurrentUserSettingsModel();
28
+ if ($authSettings->isCodeByEmailEnabled()) {
29
+ $url = Mage::helper("adminhtml")->getUrl('nortoneo_twofactorauth/login/resend');
30
+ } else {
31
+ $url = Mage::helper("adminhtml")->getUrl('nortoneo_twofactorauth/login');
32
+ }
33
+
34
+ $response = Mage::app()->getResponse();
35
+ $response->setRedirect($url);
36
+ $response->sendResponse();
37
+ /** @var $controllerAction Mage_Core_Controller_Varien_Action */
38
+ $controllerAction = $observer->getData('controller_action');
39
+ $controllerAction->setFlag(
40
+ $controllerAction->getRequest()->getActionName(),
41
+ Mage_Core_Controller_Varien_Action::FLAG_NO_DISPATCH,
42
+ true
43
+ );
44
+ }
45
+
46
+ /**
47
+ * @param Mage_Core_Controller_Request_Http $request
48
+ * @return bool
49
+ */
50
+ protected function isRequestAlwaysAllowed(Mage_Core_Controller_Request_Http $request)
51
+ {
52
+ $controller = $request->getControllerName();
53
+ $module = $request->getModuleName();
54
+ $action = $request->getActionName();
55
+
56
+ if ($module == 'nortoneo_twofactorauth' && $controller == 'login') {
57
+ return true;
58
+ } elseif ($module == 'admin' && $controller == 'index' && in_array($action, array(
59
+ 'login',
60
+ 'logout',
61
+ 'forgotpassword',
62
+ 'resetPassword',
63
+ 'resetPasswordPost'
64
+ ))
65
+ ) {
66
+ return true;
67
+ }
68
+
69
+ return false;
70
+ }
71
+ }
app/code/community/Nortoneo/TwoFactorAuth/Model/Resource/UserSettings.php ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Nortoneo_TwoFactorAuth
4
+ * @author Lukasz Szczedzina <contact@nortoneo.com>
5
+ * @website http://nortoneo.com
6
+ */
7
+ class Nortoneo_TwoFactorAuth_Model_Resource_UserSettings extends Mage_Core_Model_Resource_Db_Abstract
8
+ {
9
+ protected $encryptionModel;
10
+
11
+ protected function _construct()
12
+ {
13
+ $this->_init('nortoneo_twofactorauth/userSettings', 'settings_id');
14
+ }
15
+
16
+ protected function _beforeSave(Mage_Core_Model_Abstract $object)
17
+ {
18
+ $secret = $object->getSecret();
19
+ $object->setSecret($this->encrypt($secret));
20
+ }
21
+
22
+ protected function _afterSave(Mage_Core_Model_Abstract $object)
23
+ {
24
+ $secret = $object->getSecret();
25
+ $object->setSecret($this->decrypt($secret));
26
+ }
27
+
28
+ protected function _afterLoad(Mage_Core_Model_Abstract $object)
29
+ {
30
+ $secret = $object->getSecret();
31
+ $object->setSecret($this->decrypt($secret));
32
+ }
33
+
34
+ protected function encrypt($value)
35
+ {
36
+ return $this->getEncryptionModel()->encrypt($value);
37
+ }
38
+
39
+ protected function decrypt($value)
40
+ {
41
+ return $this->getEncryptionModel()->decrypt($value);
42
+ }
43
+
44
+ protected function getEncryptionModel()
45
+ {
46
+ if ($this->encryptionModel === null) {
47
+ $this->encryptionModel = Mage::getModel('core/encryption');
48
+ }
49
+
50
+ return $this->encryptionModel;
51
+ }
52
+
53
+ }
app/code/community/Nortoneo/TwoFactorAuth/Model/Resource/UserSettings/Collection.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Nortoneo_TwoFactorAuth
4
+ * @author Lukasz Szczedzina <contact@nortoneo.com>
5
+ * @website http://nortoneo.com
6
+ */
7
+ class Nortoneo_TwoFactorAuth_Model_Resource_UserSettings_Collection extends Mage_Core_Model_Resource_Db_Collection_Abstract
8
+ {
9
+ protected function _construct()
10
+ {
11
+ $this->_init('nortoneo_twofactorauth/userSettings');
12
+ }
13
+
14
+ }
app/code/community/Nortoneo/TwoFactorAuth/Model/UserSettings.php ADDED
@@ -0,0 +1,216 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Nortoneo_TwoFactorAuth
4
+ * @author Lukasz Szczedzina <contact@nortoneo.com>
5
+ * @website http://nortoneo.com
6
+ */
7
+ class Nortoneo_TwoFactorAuth_Model_UserSettings extends Mage_Core_Model_Abstract
8
+ {
9
+ const TWO_FACTOR_AUTH_METHOD_EMAIL = 0;
10
+ const TWO_FACTOR_AUTH_METHOD_APP = 1;
11
+
12
+ const TWO_FACTOR_AUTH_TRUST_LAST_IP_NO = 0;
13
+ const TWO_FACTOR_AUTH_TRUST_LAST_IP_YES = 1;
14
+
15
+ const TWO_FACTOR_AUTH_CODE_EMAIL_TEMPLATE = 'nortoneo_twofactorauth_code';
16
+ const TWO_FACTOR_AUTH_CODE_EMAIL_IDENTITY = 'general';
17
+
18
+
19
+ protected $authenticator;
20
+
21
+ protected function _construct()
22
+ {
23
+ $this->_init('nortoneo_twofactorauth/userSettings');
24
+ }
25
+
26
+ /**
27
+ * @param string $code
28
+ * @return bool
29
+ */
30
+ public function verifyCode($code)
31
+ {
32
+ $secret = $this->getSecret();
33
+ if (empty($secret)) {
34
+ return false;
35
+ }
36
+
37
+ $discrepancy = (int)$this->getDiscrepancy();
38
+
39
+ return $this->getAuthenticator()->verifyCode($secret, $code, $discrepancy);
40
+ }
41
+
42
+ /**
43
+ * @return bool|string
44
+ */
45
+ public function getCurrentCode()
46
+ {
47
+ $secret = $this->getSecret();
48
+ if (empty($secret)) {
49
+ return false;
50
+ }
51
+
52
+ return $this->getAuthenticator()->getCode($secret);
53
+ }
54
+
55
+ /**
56
+ * @param int $width
57
+ * @param int $height
58
+ * @return bool|string
59
+ */
60
+ public function getQRCodeGoogleUrl($width = 250, $height = 250)
61
+ {
62
+ $secret = $this->getSecret();
63
+ if (empty($secret)) {
64
+ return false;
65
+ }
66
+ $title = $this->getTitleForQRCode();
67
+ $name = $this->getNameForQRCode();
68
+ $params = array(
69
+ 'width' => $width,
70
+ 'height' => $height
71
+ );
72
+
73
+ return $this->getAuthenticator()->getQRCodeGoogleUrl($name, $secret, $title, $params);
74
+ }
75
+
76
+ /**
77
+ * @param int $secretLength
78
+ * @return string
79
+ */
80
+ public function generateSecret($secretLength = 16)
81
+ {
82
+ return $this->getAuthenticator()->createSecret($secretLength);
83
+ }
84
+
85
+ /**
86
+ * @return array
87
+ */
88
+ public function getMethodOptions()
89
+ {
90
+ $helper = Mage::helper('nortoneo_twofactorauth');
91
+ $userEmail = $this->getUser()->getEmail();
92
+
93
+ return array(
94
+ self::TWO_FACTOR_AUTH_METHOD_EMAIL => $helper->__('Send me codes by e-mail (%s)', $userEmail),
95
+ self::TWO_FACTOR_AUTH_METHOD_APP => $helper->__('I will use mobile application')
96
+ );
97
+ }
98
+
99
+ /**
100
+ * @return array
101
+ */
102
+ public function getDiscrepancyOptions()
103
+ {
104
+ $helper = Mage::helper('nortoneo_twofactorauth');
105
+
106
+ $options = array();
107
+ for ($i = 1; $i < 31; $i++) {
108
+ $seconds = $i * 30;
109
+ $options[$i] = $helper->__('%s seconds', $seconds);
110
+ }
111
+
112
+ return $options;
113
+ }
114
+
115
+ /**
116
+ * @return array
117
+ */
118
+ public function getTrustLastIpOptions()
119
+ {
120
+ $helper = Mage::helper('nortoneo_twofactorauth');
121
+
122
+ return array(
123
+ self::TWO_FACTOR_AUTH_TRUST_LAST_IP_NO => $helper->__('No'),
124
+ self::TWO_FACTOR_AUTH_TRUST_LAST_IP_YES => $helper->__('Yes')
125
+ );
126
+ }
127
+
128
+ /**
129
+ *
130
+ */
131
+ public function provideCurrentCode()
132
+ {
133
+ if ($this->isCodeByEmailEnabled()) {
134
+ $this->sendCodeByEmail();
135
+ }
136
+
137
+ //no other methods implemented
138
+ }
139
+
140
+ /**
141
+ * @return bool
142
+ */
143
+ public function isCodeByEmailEnabled()
144
+ {
145
+ return $this->getMethod() == self::TWO_FACTOR_AUTH_METHOD_EMAIL;
146
+ }
147
+
148
+ /**
149
+ * @return mixed
150
+ */
151
+ public function sendCodeByEmail()
152
+ {
153
+ $email = $this->getUser()->getEmail();
154
+ $templateId = self::TWO_FACTOR_AUTH_CODE_EMAIL_TEMPLATE;
155
+ $identity = self::TWO_FACTOR_AUTH_CODE_EMAIL_IDENTITY;
156
+
157
+ $discrepancyOptions = $this->getDiscrepancyOptions();
158
+ $discrepancyLabel = isset($discrepancyOptions[$this->getDiscrepancy()]) ? $discrepancyOptions[$this->getDiscrepancy()] : '';
159
+
160
+ $emailVariables = array(
161
+ 'auth_code' => $this->getCurrentCode(),
162
+ 'discrepancy_label' => $discrepancyLabel,
163
+ );
164
+
165
+ /* @var $emailTemplate Mage_Core_Model_Email_Template */
166
+ $emailTemplate = Mage::getModel('core/email_template');
167
+ $emailTemplate->sendTransactional($templateId, $identity, $email, null, $emailVariables);
168
+
169
+ $sentSuccess = $emailTemplate->getSentSuccess();
170
+
171
+ return $sentSuccess;
172
+ }
173
+
174
+ /**
175
+ * @return string
176
+ */
177
+ protected function getTitleForQRCode()
178
+ {
179
+ $name = Mage::getStoreConfig('general/store_information/name');
180
+
181
+ return $name;
182
+ }
183
+
184
+ /**
185
+ * @return string|null
186
+ */
187
+ protected function getNameForQRCode()
188
+ {
189
+ $user = $this->getUser();
190
+
191
+ return $user->getUsername();
192
+ }
193
+
194
+ /**
195
+ * @return Nortoneo_TwoFactorAuth_Model_Lib_GoogleAuthenticator
196
+ */
197
+ protected function getAuthenticator()
198
+ {
199
+ if ($this->authenticator === null) {
200
+ $this->authenticator = Mage::getModel('nortoneo_twofactorauth/lib_googleAuthenticator');
201
+ }
202
+
203
+ return $this->authenticator;
204
+ }
205
+
206
+ /**
207
+ * @return Mage_Admin_Model_User
208
+ */
209
+ protected function getUser()
210
+ {
211
+ $userId = $this->getUserId();
212
+ $user = Mage::getModel('admin/user')->load($userId);
213
+
214
+ return $user;
215
+ }
216
+ }
app/code/community/Nortoneo/TwoFactorAuth/controllers/Adminhtml/LoginController.php ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Nortoneo_TwoFactorAuth
4
+ * @author Lukasz Szczedzina <contact@nortoneo.com>
5
+ * @website http://nortoneo.com
6
+ */
7
+ class Nortoneo_TwoFactorAuth_Adminhtml_LoginController extends Mage_Adminhtml_Controller_Action
8
+ {
9
+ public function indexAction()
10
+ {
11
+ if ($code = $this->getRequest()->getPost('code')) {
12
+ $this->processCode($code);
13
+
14
+ return;
15
+ }
16
+
17
+ $this->loadLayout();
18
+ $this->renderLayout();
19
+ }
20
+
21
+ public function resendAction()
22
+ {
23
+ /** @var Nortoneo_TwoFactorAuth_Model_UserSettings $authSettings */
24
+ $authSettings = Mage::helper('nortoneo_twofactorauth')->getCurrentUserSettingsModel();
25
+ $authSettings->provideCurrentCode();
26
+
27
+ $this->_redirect('nortoneo_twofactorauth/login/index');
28
+ }
29
+
30
+ protected function processCode($code)
31
+ {
32
+ $code = str_replace(' ', '', $code);
33
+ /** @var Nortoneo_TwoFactorAuth_Model_UserSettings $authSettings */
34
+ $authSettings = Mage::helper('nortoneo_twofactorauth')->getCurrentUserSettingsModel();
35
+ $isCodeValid = $authSettings->verifyCode($code);
36
+ if ($isCodeValid) {
37
+ Mage::helper('nortoneo_twofactorauth')->setCurrentUserValidated(true);
38
+ $currentIp = Mage::helper('core/http')->getRemoteAddr();
39
+ $authSettings->setLastIp($currentIp);
40
+ $authSettings->save();
41
+ $this->_redirect('adminhtml');
42
+ return;
43
+ }
44
+
45
+ Mage::getSingleton('admin/session')->unsetAll();
46
+ $this->_redirect('adminhtml/index/logout');
47
+ }
48
+
49
+ protected function _isAllowed()
50
+ {
51
+ return true;
52
+ }
53
+
54
+ }
app/code/community/Nortoneo/TwoFactorAuth/controllers/Adminhtml/UserSettingsController.php ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Nortoneo_TwoFactorAuth
4
+ * @author Lukasz Szczedzina <contact@nortoneo.com>
5
+ * @website http://nortoneo.com
6
+ */
7
+ class Nortoneo_TwoFactorAuth_Adminhtml_UserSettingsController extends Mage_Adminhtml_Controller_Action
8
+ {
9
+ public function indexAction()
10
+ {
11
+ $this->loadLayout();
12
+ $this->_addContent($this->getLayout()->createBlock('nortoneo_twofactorauth/adminhtml_userSettings_edit'))
13
+ ->_addLeft($this->getLayout()->createBlock('nortoneo_twofactorauth/adminhtml_userSettings_edit_tabs'));
14
+ $this->renderLayout();
15
+ }
16
+
17
+ public function validateAction()
18
+ {
19
+ $this->loadLayout();
20
+ $this->_addContent($this->getLayout()->createBlock('nortoneo_twofactorauth/adminhtml_userSettings_validate'))
21
+ ->_addLeft($this->getLayout()->createBlock('nortoneo_twofactorauth/adminhtml_userSettings_validate_tabs'));
22
+ $this->renderLayout();
23
+ }
24
+
25
+ public function validatePostAction()
26
+ {
27
+ if ($code = $this->getRequest()->getPost('code')) {
28
+ $code = str_replace(' ', '', $code);
29
+ try {
30
+ $model = Mage::helper('nortoneo_twofactorauth')->getCurrentUserSettingsModel();
31
+ if (!$model->verifyCode($code)) {
32
+ $model->setData('is_active', 0);
33
+ $this->_getSession()->addError(Mage::helper('nortoneo_twofactorauth')->__('Code not validated. Protection disabled.'));
34
+ } else {
35
+ $this->_getSession()->addSuccess(Mage::helper('nortoneo_twofactorauth')->__('Code validated. Protection enabled.'));
36
+ $model->setData('is_active', 1);
37
+ Mage::helper('nortoneo_twofactorauth')->setCurrentUserValidated(true);
38
+ }
39
+ $model->save();
40
+ } catch (Mage_Core_Exception $e) {
41
+ $this->_getSession()->addError($e->getMessage());
42
+ } catch (Exception $e) {
43
+ $this->_getSession()->addError(Mage::helper('nortoneo_twofactorauth')->__('Unable to save settings.'));
44
+ Mage::logException($e);
45
+ }
46
+ }
47
+
48
+ $this->_redirect('*/*/index');
49
+ }
50
+
51
+ public function regenerateSecretAction()
52
+ {
53
+ $userSettingsModel = Mage::helper('nortoneo_twofactorauth')->getCurrentUserSettingsModel();
54
+ $userSettingsModel->setData('is_active', 0);
55
+ $userSettingsModel->setSecret($userSettingsModel->generateSecret());
56
+ $userSettingsModel->save();
57
+
58
+ $this->_redirect('*/*/index');
59
+ }
60
+
61
+ public function saveAction()
62
+ {
63
+ $requireValidation = false;
64
+ if ($data = $this->getRequest()->getPost()) {
65
+ try {
66
+ $model = Mage::helper('nortoneo_twofactorauth')->getCurrentUserSettingsModel();
67
+ if ($data['is_active'] && (!$model->getIsActive() || $model->getMethod() != $data['method'])) {
68
+ $requireValidation = true;
69
+ $model->setData('is_active', 0);
70
+ } else {
71
+ $model->setData('is_active', $data['is_active']);
72
+ }
73
+ $model->setData('trust_last_ip', $data['trust_last_ip']);
74
+ $model->setData('method', $data['method']);
75
+ $model->setData('discrepancy', $data['discrepancy']);
76
+ $model->save();
77
+
78
+ if ($requireValidation) {
79
+ $model->provideCurrentCode();
80
+ }
81
+
82
+ $this->_getSession()->addSuccess(
83
+ Mage::helper('nortoneo_twofactorauth')->__('Settings has been saved.')
84
+ );
85
+ } catch (Mage_Core_Exception $e) {
86
+ $this->_getSession()->addError($e->getMessage());
87
+ } catch (Exception $e) {
88
+ $this->_getSession()->addError(Mage::helper('nortoneo_twofactorauth')->__('Unable to save settings.'));
89
+ Mage::logException($e);
90
+ }
91
+ }
92
+ if ($requireValidation) {
93
+ $this->_redirect('*/*/validate');
94
+ } else {
95
+ $this->_redirect('*/*/index');
96
+ }
97
+ }
98
+
99
+ protected function _isAllowed()
100
+ {
101
+ return Mage::getSingleton('admin/session')->isAllowed('system/nortoneo_twofactor_auth');
102
+ }
103
+
104
+ }
app/code/community/Nortoneo/TwoFactorAuth/etc/adminhtml.xml ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+
3
+ <config>
4
+ <menu>
5
+ <system>
6
+ <children>
7
+ <nortoneo_twofactor_auth translate="title">
8
+ <title>Two Factor Authentication</title>
9
+ <action>nortoneo_twofactorauth/userSettings</action>
10
+ <sort_order>100</sort_order>
11
+ </nortoneo_twofactor_auth>
12
+ </children>
13
+ </system>
14
+ </menu>
15
+ <acl>
16
+ <resources>
17
+ <admin>
18
+ <children>
19
+ <system>
20
+ <children>
21
+ <nortoneo_twofactor_auth translate="title">
22
+ <title>Two Factor Authentication</title>
23
+ </nortoneo_twofactor_auth>
24
+ </children>
25
+ </system>
26
+ </children>
27
+ </admin>
28
+ </resources>
29
+ </acl>
30
+ </config>
app/code/community/Nortoneo/TwoFactorAuth/etc/config.xml ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <Nortoneo_TwoFactorAuth>
5
+ <version>0.1.0</version>
6
+ </Nortoneo_TwoFactorAuth>
7
+ </modules>
8
+ <global>
9
+ <models>
10
+ <nortoneo_twofactorauth>
11
+ <class>Nortoneo_TwoFactorAuth_Model</class>
12
+ <resourceModel>nortoneo_twofactorauth_resource</resourceModel>
13
+ </nortoneo_twofactorauth>
14
+ <nortoneo_twofactorauth_resource>
15
+ <class>Nortoneo_TwoFactorAuth_Model_Resource</class>
16
+ <entities>
17
+ <userSettings>
18
+ <table>nortoneo_twofactorauth_user_settings</table>
19
+ </userSettings>
20
+ </entities>
21
+ </nortoneo_twofactorauth_resource>
22
+ </models>
23
+ <blocks>
24
+ <nortoneo_twofactorauth>
25
+ <class>Nortoneo_TwoFactorAuth_Block</class>
26
+ </nortoneo_twofactorauth>
27
+ </blocks>
28
+ <helpers>
29
+ <nortoneo_twofactorauth>
30
+ <class>Nortoneo_TwoFactorAuth_Helper</class>
31
+ </nortoneo_twofactorauth>
32
+ </helpers>
33
+ <resources>
34
+ <nortoneo_twofactorauth_setup>
35
+ <setup>
36
+ <module>Nortoneo_TwoFactorAuth</module>
37
+ </setup>
38
+ </nortoneo_twofactorauth_setup>
39
+ </resources>
40
+ <template>
41
+ <email>
42
+ <nortoneo_twofactorauth_code translate="label" module="adminhtml">
43
+ <label>Two Factor Authentication Code</label>
44
+ <file>nortoneo/twofactorauth/code.html</file>
45
+ <type>html</type>
46
+ </nortoneo_twofactorauth_code>
47
+ </email>
48
+ </template>
49
+ </global>
50
+ <admin>
51
+ <routers>
52
+ <nortoneo_twofactorauth>
53
+ <use>admin</use>
54
+ <args>
55
+ <frontName>nortoneo_twofactorauth</frontName>
56
+ <module>Nortoneo_TwoFactorAuth_Adminhtml</module>
57
+ </args>
58
+ </nortoneo_twofactorauth>
59
+ </routers>
60
+ </admin>
61
+ <adminhtml>
62
+ <layout>
63
+ <updates>
64
+ <nortoneo_twofactorauth>
65
+ <file>nortoneo/twofactorauth.xml</file>
66
+ </nortoneo_twofactorauth>
67
+ </updates>
68
+ </layout>
69
+ <translate>
70
+ <modules>
71
+ <nortoneo_twofactorauth>
72
+ <files>
73
+ <default>nortoneo/twofactorauth.csv</default>
74
+ </files>
75
+ </nortoneo_twofactorauth>
76
+ </modules>
77
+ </translate>
78
+ <events>
79
+ <controller_action_predispatch>
80
+ <observers>
81
+ <nortoneo_twofactorauth_authentication>
82
+ <type>singleton</type>
83
+ <class>nortoneo_twofactorauth/observer</class>
84
+ <method>processAuthentication</method>
85
+ </nortoneo_twofactorauth_authentication>
86
+ </observers>
87
+ </controller_action_predispatch>
88
+ </events>
89
+ </adminhtml>
90
+ </config>
app/code/community/Nortoneo/TwoFactorAuth/sql/nortoneo_twofactorauth_setup/install-0.1.0.php ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Nortoneo_TwoFactorAuth
4
+ * @author Lukasz Szczedzina <contact@nortoneo.com>
5
+ * @website http://nortoneo.com
6
+ */
7
+ /* @var $installer Mage_Core_Model_Resource_Setup */
8
+ $installer = $this;
9
+
10
+ $connection = $installer->getConnection();
11
+ $tableName = $installer->getTable('nortoneo_twofactorauth/userSettings');
12
+ $isTableExists = $connection->isTableExists($tableName);
13
+ if (!$isTableExists) {
14
+ $table = $connection
15
+ ->newTable($tableName)
16
+ ->addColumn('settings_id', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array(
17
+ 'identity' => true,
18
+ 'unsigned' => true,
19
+ 'nullable' => false,
20
+ 'primary' => true,
21
+ ), 'SETTINGS ID')
22
+ ->addColumn('user_id', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array(
23
+ 'unsigned' => true,
24
+ 'nullable' => false,
25
+ ), 'USER ID')
26
+ ->addColumn('is_active', Varien_Db_Ddl_Table::TYPE_TINYINT, null, array(
27
+ 'unsigned' => true,
28
+ 'nullable' => false,
29
+ ), 'IS ACTIVE')
30
+ ->addColumn('method', Varien_Db_Ddl_Table::TYPE_TINYINT, null, array(
31
+ 'unsigned' => true,
32
+ 'nullable' => false,
33
+ ), 'METHOD')
34
+ ->addColumn('trust_last_ip', Varien_Db_Ddl_Table::TYPE_TINYINT, null, array(
35
+ 'unsigned' => true,
36
+ 'nullable' => false,
37
+ ), 'TRUST LAST IP')
38
+ ->addColumn('last_ip', Varien_Db_Ddl_Table::TYPE_VARCHAR, 15, array(
39
+ 'nullable' => true,
40
+ ), 'LAST IP')
41
+ ->addColumn('discrepancy', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array(
42
+ 'unsigned' => true,
43
+ 'nullable' => false,
44
+ ), 'DISCREPANCY')
45
+ ->addColumn('secret', Varien_Db_Ddl_Table::TYPE_VARCHAR, 255, array(
46
+ 'nullable' => false,
47
+ ), 'SECRET')
48
+ ->addForeignKey($installer->getFkName('nortoneo_twofactorauth/userSettings', 'user_id', 'admin/user', 'user_id'),
49
+ 'user_id', $installer->getTable('admin/user'), 'user_id',
50
+ Varien_Db_Ddl_Table::ACTION_CASCADE, Varien_Db_Ddl_Table::ACTION_CASCADE)
51
+ ->addIndex(
52
+ $this->getIdxName($tableName, 'user_id', Varien_Db_Adapter_Interface::INDEX_TYPE_UNIQUE),
53
+ 'user_id',
54
+ array('type' => Varien_Db_Adapter_Interface::INDEX_TYPE_UNIQUE)
55
+ );
56
+
57
+ $connection->createTable($table);
58
+ }
app/design/adminhtml/default/default/layout/nortoneo/twofactorauth.xml ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+
3
+ <layout>
4
+ <nortoneo_twofactorauth_login_index>
5
+ <block type="core/text_list" name="root" output="toHtml">
6
+ <block type="adminhtml/template" name="two_factor_authenticate_form"
7
+ template="nortoneo/twofactorauth/login.phtml"/>
8
+ </block>
9
+ </nortoneo_twofactorauth_login_index>
10
+ </layout>
app/design/adminhtml/default/default/template/nortoneo/twofactorauth/login.phtml ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2
+ <html xmlns="http://www.w3.org/1999/xhtml" lang="en">
3
+ <head>
4
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5
+ <title><?php echo Mage::helper('adminhtml')->__('Log into Magento Admin Page') ?></title>
6
+ <link type="text/css" rel="stylesheet" href="<?php echo $this->getSkinUrl('reset.css') ?>" media="all" />
7
+ <link type="text/css" rel="stylesheet" href="<?php echo $this->getSkinUrl('boxes.css') ?>" media="all" />
8
+ <link rel="icon" href="<?php echo $this->getSkinUrl('favicon.ico') ?>" type="image/x-icon" />
9
+ <link rel="shortcut icon" href="<?php echo $this->getSkinUrl('favicon.ico') ?>" type="image/x-icon" />
10
+
11
+ <script type="text/javascript" src="<?php echo $this->getJsUrl('prototype/prototype.js') ?>"></script>
12
+ <script type="text/javascript" src="<?php echo $this->getJsUrl('prototype/validation.js') ?>"></script>
13
+ <script type="text/javascript" src="<?php echo $this->getJsUrl('scriptaculous/effects.js') ?>"></script>
14
+ <script type="text/javascript" src="<?php echo $this->getJsUrl('mage/adminhtml/form.js') ?>"></script>
15
+ <script type="text/javascript" src="<?php echo $this->getJsUrl('mage/captcha.js') ?>"></script>
16
+
17
+ <!--[if IE]> <link rel="stylesheet" href="<?php echo $this->getSkinUrl('iestyles.css') ?>" type="text/css" media="all" /> <![endif]-->
18
+ <!--[if lt IE 7]> <link rel="stylesheet" href="<?php echo $this->getSkinUrl('below_ie7.css') ?>" type="text/css" media="all" /> <![endif]-->
19
+ <!--[if IE 7]> <link rel="stylesheet" href="<?php echo $this->getSkinUrl('ie7.css') ?>" type="text/css" media="all" /> <![endif]-->
20
+ </head>
21
+ <body id="page-login" onload="document.forms.loginForm.code.focus();">
22
+ <div class="login-container">
23
+ <div class="login-box">
24
+ <form method="post" action="" id="loginForm" autocomplete="off">
25
+ <div class="login-form">
26
+ <input name="form_key" type="hidden" value="<?php echo $this->getFormKey() ?>" />
27
+ <h2><?php echo Mage::helper('nortoneo_twofactorauth')->__('Two Factor Authentication') ?></h2>
28
+ <div id="messages">
29
+ <?php echo $this->getMessagesBlock()->toHtml() ?>
30
+ </div>
31
+ <div class="input-box input-left"><label for="code"><?php echo Mage::helper('nortoneo_twofactorauth')->__('Authentication Code:') ?></label><br/>
32
+ <input type="text" id="code" name="code" value="" class="required-entry input-text" /></div>
33
+ <div class="clear"></div>
34
+ <div class="form-buttons">
35
+ <?php if(Mage::helper('nortoneo_twofactorauth')->getCurrentUserSettingsModel()->isCodeByEmailEnabled()): ?>
36
+ <a class="left" href="<?php echo Mage::helper('adminhtml')->getUrl('nortoneo_twofactorauth/login/resend', array('_nosecret' => true)) ?>"><?php echo Mage::helper('nortoneo_twofactorauth')->__('Resend code') ?></a>
37
+ <?php endif; ?>
38
+ <input type="submit" class="form-button" value="<?php echo Mage::helper('core')->quoteEscape(Mage::helper('nortoneo_twofactorauth')->__('Enter Code')) ?>" title="<?php echo Mage::helper('core')->quoteEscape(Mage::helper('nortoneo_twofactorauth')->__('Authentication Code')) ?>" /></div>
39
+ </div>
40
+ </form>
41
+ <div class="bottom"></div>
42
+ <script type="text/javascript">
43
+ var loginForm = new varienForm('loginForm');
44
+ </script>
45
+ </div>
46
+ </div>
47
+ </body>
48
+ </html>
49
+
app/design/adminhtml/default/default/template/nortoneo/twofactorauth/usersettings.phtml ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ $helper = Mage::helper('nortoneo_twofactorauth');
3
+ /** @var Nortoneo_TwoFactorAuth_Model_UserSettings $settings */
4
+ $settings = $this->getUserSettingsModel();
5
+ ?>
6
+ <div class="entry-edit">
7
+ <?php echo $this->getFormHtml();?>
8
+ </div>
9
+ <?php echo $this->getChildHtml('form_after');?>
10
+
11
+ <div class="box-left">
12
+ <div class="entry-edit">
13
+ <div class="entry-edit-head">
14
+ <h4 class="icon-head head-account"><?php echo $helper->__('Mobile application setup') ?></h4>
15
+ </div>
16
+ <div class="fieldset">
17
+ <table cellspacing="0" class="form-list">
18
+ <tr>
19
+ <td class="label"><label>Your secret key</label></td>
20
+ <td class="value"><strong><?php echo $settings->getSecret(); ?></strong></td>
21
+ </tr>
22
+ <tr>
23
+ <td class="label"><label><?php echo $helper->__('QR Code for mobile app') ?></label></td>
24
+ <td class="value"><img src="<?php echo $settings->getQRCodeGoogleUrl(); ?>" /></td>
25
+ </tr>
26
+ </table>
27
+ <p><?php echo $helper->__('Install Google Authenticator app to generate tokens on your smartphone.') ?></p>
28
+ <p><?php echo $helper->__('Available for') ?>
29
+ <a href="https://m.google.com/authenticator" target="_blank">Android</a>
30
+ <a href="https://itunes.apple.com/pl/app/google-authenticator/id388497605" target="_blank">iOS</a>
31
+ Blackberry
32
+ </p>
33
+ </div>
34
+ </div>
35
+ </div>
app/etc/modules/Nortoneo_TwoFactorAuth.xml ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <Nortoneo_TwoFactorAuth>
5
+ <active>true</active>
6
+ <codePool>community</codePool>
7
+ </Nortoneo_TwoFactorAuth>
8
+ </modules>
9
+ </config>
app/locale/en_US/nortoneo/twofactorauth.csv ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "Are you sure? If you are using mobile app you will have to rescan QR code. For safety reasons you will have to enable protection again.","Are you sure? If you are using mobile app you will have to rescan QR code. For safety reasons you will have to enable protection again."
2
+ "Regenerate secret key","Regenerate secret key"
3
+ "Two Factor Authentication Settings","Two Factor Authentication Settings"
4
+ "Settings","Settings"
5
+ "User Settings","User Settings"
6
+ "Status","Status"
7
+ "Enabled","Enabled"
8
+ "Disabled","Disabled"
9
+ "Trust last IP address","Trust last IP address"
10
+ "Discrepancy","Discrepancy"
11
+ "How long your code should be valid.","How long your code should be valid."
12
+ "Authentication Method","Authentication Method"
13
+ "Ask for code only if IP has changed since last successful login?","Ask for code only if IP has changed since last successful login?"
14
+ "Code validation","Code validation"
15
+ "Two Factor Authentication Validation","Two Factor Authentication Validation"
16
+ "Authentication Code","Authentication Code"
17
+ "Code not validated. Protection disabled.","Code not validated. Protection disabled."
18
+ "Code validated. Protection enabled.","Code validated. Protection enabled."
19
+ "Unable to save settings.","Unable to save settings."
20
+ "Settings has been saved.","Settings has been saved."
21
+ "Send me codes by e-mail (%s)","Send me codes by e-mail (%s)"
22
+ "I will use mobile application","I will use mobile application"
23
+ "%s seconds","%s seconds"
24
+ "No","No"
25
+ "Yes","Yes"
26
+ "Two Factor Authentication","Two Factor Authentication"
27
+ "Authentication Code:","Authentication Code:"
28
+ "Enter Code","Enter Code"
29
+ "Resend code","Resend code"
30
+ "Mobile application setup","Mobile application setup"
31
+ "QR Code for mobile app","QR Code for mobile app"
32
+ "Install Google Authenticator app to generate tokens on your smartphone.","Install Google Authenticator app to generate tokens on your smartphone."
33
+ "Available for","Available for"
app/locale/en_US/template/email/nortoneo/twofactorauth/code.html ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <!--@subject Two Factor Authentication @-->
2
+
3
+ <p>Your code is: <strong>{{var auth_code}}</strong></p>
4
+ <p>This code is valid for {{var discrepancy_label}}</p>
app/locale/pl_PL/nortoneo/twofactorauth.csv ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "Are you sure? If you are using mobile app you will have to rescan QR code. For safety reasons you will have to enable protection again.","Jesteś pewien? Jeśli używasz apki mobilnej będziesz musiał ponownie zeskanować kod QR. Dla bezpieczeństwa ochrona zostanie wyłączona. Będziesz musiał włączyć ją ponownie."
2
+ "Regenerate secret key","Zmień swój klucz prywatny"
3
+ "Two Factor Authentication Settings","Ustawienia dwuetapowej weryfikacji"
4
+ "Settings","Ustawienia"
5
+ "User Settings","Ustawienia użytkownika"
6
+ "Status","Status"
7
+ "Enabled","Włączone"
8
+ "Disabled","Wyłączone"
9
+ "Trust last IP address","Ufaj ostatniemu adresowi IP"
10
+ "Discrepancy","Rozbieżność"
11
+ "How long your code should be valid.","Jak długo powinien być ważny twój kod."
12
+ "Authentication Method","Metoda weryfikacji"
13
+ "Ask for code only if IP has changed since last successful login?","Pytać o kod tylko gdy twój adres IP zmienił się od ostatniego poprawnego logowania?"
14
+ "Code validation","Weryfikacja kodu"
15
+ "Two Factor Authentication Validation","Walidacja weryfikacji dwuetapowej"
16
+ "Authentication Code","Kod autoryzacji"
17
+ "Code not validated. Protection disabled.","Kod niepoprawny. Ochrona wyłączona."
18
+ "Code validated. Protection enabled.","Kod poprawny. Ochrona włączona."
19
+ "Unable to save settings.","Nie udało się zapisać ustawień."
20
+ "Settings has been saved.","Ustawienia zostały zapisane."
21
+ "Send me codes by e-mail (%s)","Wysyłaj mi kody na e-mail (%s)"
22
+ "I will use mobile application","Będę używać aplikacji mobilnej"
23
+ "%s seconds","%s sekund"
24
+ "No","Nie"
25
+ "Yes","Tak"
26
+ "Two Factor Authentication","Weryfikacja dwuetapowa"
27
+ "Authentication Code:","Kod autoryzacyjny:"
28
+ "Enter Code","Wprowadź kod"
29
+ "Resend code","Wyślij kod ponownie"
30
+ "Mobile application setup","Ustawienia aplikacji mobilnej"
31
+ "QR Code for mobile app","Kod QR dla aplikacji mobilnej"
32
+ "Install Google Authenticator app to generate tokens on your smartphone.","Zainstaluj na swojego smartphone`a aplikację Google Authenticator."
33
+ "Available for","Dostępna dla"
package.xml ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <package>
3
+ <name>Nortoneo_TwoFactorAuth</name>
4
+ <version>0.1.0</version>
5
+ <stability>stable</stability>
6
+ <license uri="BSD">http://www.opensource.org/licenses/bsd-license.php</license>
7
+ <channel>community</channel>
8
+ <extends/>
9
+ <summary>Nortoneo TwoFactorAuth module helps you secure your admin panel from unauthorized access. Admin users will be able to set up two factor authorization.</summary>
10
+ <description>This module will give admin users possibility to set up Two Factor Authorization.&#xD;
11
+ Once enabled - when user will want to login to Magento back-office he will need to provide special code that can be delivered by email or generated by Google Authenticator app on his smartphone.&#xD;
12
+ Module include features like:&#xD;
13
+ - trust last IP (authorization codes will not be required until IP address has been changed since last successful login)&#xD;
14
+ - setting duration of how long codes will be valid&#xD;
15
+ - possibility to send authorization codes by email&#xD;
16
+ </description>
17
+ <notes>Nortoneo_TwoFactorAuth v0.1.0</notes>
18
+ <authors><author><name>Lukasz Szczedzina</name><user>lszczedzina</user><email>contact@nortoneo.com</email></author></authors>
19
+ <date>2016-11-17</date>
20
+ <time>10:04:51</time>
21
+ <contents><target name="magecommunity"><dir name="Nortoneo"><dir name="TwoFactorAuth"><dir name="Block"><dir name="Adminhtml"><dir name="UserSettings"><dir name="Edit"><file name="Form.php" hash="6f496577d5e3c08d3255e09680a46024"/><dir name="Tab"><file name="Form.php" hash="68d4bf0a3dbcfe3b7d3f9642c7302f29"/></dir><file name="Tabs.php" hash="cbae7c9720d0e1563f95f765a9010ad1"/></dir><file name="Edit.php" hash="bb939f512238135a65e88a60160d8ca6"/><dir name="Validate"><file name="Form.php" hash="34fab66cd41d5a5c055b37a6355784cf"/><dir name="Tab"><file name="Form.php" hash="64fe24aa9e214fa491c681e46b144fa3"/></dir><file name="Tabs.php" hash="4cf8bc00930be77d74250963d3be255f"/></dir><file name="Validate.php" hash="ba032a228478d3468242a2b927d6c972"/></dir></dir></dir><dir name="Helper"><file name="Data.php" hash="644f4c382330686b91f63a61ddfb9adb"/></dir><dir name="Model"><dir name="Lib"><file name="GoogleAuthenticator.php" hash="12828be6b50bd8920159e771b294969c"/></dir><file name="Observer.php" hash="2a23af96f0801a699e7f9ee30733a6a6"/><dir name="Resource"><dir name="UserSettings"><file name="Collection.php" hash="3d36a299e953a37e02dec181eb59b2db"/></dir><file name="UserSettings.php" hash="d0564bfa5ffefd69fffb5cc0ec0619e6"/></dir><file name="UserSettings.php" hash="8aa04e0bf992de4e67ed29015d0940fe"/></dir><dir name="controllers"><dir name="Adminhtml"><file name="LoginController.php" hash="01b20f0147be631b94c852c47838c426"/><file name="UserSettingsController.php" hash="e82198dc27f85cfab5a75c9ff67b5e2e"/></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="531ff30bba43ba97f8b63a393be53d61"/><file name="config.xml" hash="6c762368daff079846c907bc9575144d"/></dir><dir name="sql"><dir name="nortoneo_twofactorauth_setup"><file name="install-0.1.0.php" hash="2774d68ffc719f1f92bdd1dbfef82b9f"/></dir></dir></dir></dir></target><target name="magedesign"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="layout"><dir name="nortoneo"><file name="twofactorauth.xml" hash="f58a9b11f09c331778942c21afad1d7c"/></dir></dir><dir name="template"><dir name="nortoneo"><dir><dir name="twofactorauth"><file name="login.phtml" hash="36f70386c04eb13351cd9e35fcb3e313"/><file name="usersettings.phtml" hash="950db47334adcfb3965e9d33e34c2d1b"/></dir></dir></dir></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="Nortoneo_TwoFactorAuth.xml" hash="7b66a753a8a4aa8e1ecccb66a42e87dd"/></dir></target><target name="magelocale"><dir name="en_US"><dir name="nortoneo"><file name="twofactorauth.csv" hash="a5dac86614887d217c251dda7bc95d98"/></dir><dir name="template"><dir name="email"><dir name="nortoneo"><dir><dir name="twofactorauth"><file name="code.html" hash="9de7e2f2400073dbb918bccf5228b9ef"/></dir></dir></dir></dir></dir></dir><dir name="pl_PL"><dir name="nortoneo"><file name="twofactorauth.csv" hash="244c3c462fcd63b7f4427a29245773fb"/></dir></dir></target></contents>
22
+ <compatible/>
23
+ <dependencies><required><php><min>5.2.0</min><max>6.0.0</max></php></required></dependencies>
24
+ </package>