[FEATURE] Ask for old password when changing 24/10224/12
authorGeorg Ringer <mail@ringerge.org>
Thu, 25 Dec 2014 20:36:03 +0000 (21:36 +0100)
committerHelmut Hummel <helmut.hummel@typo3.org>
Mon, 9 Mar 2015 15:14:17 +0000 (16:14 +0100)
Following security best practices, a user should
to be able to update his password only when giving
the previous password. Currently no need to know
the current password when changing it.

Change-Id: Id0c52d8f7e0d06177c0e4f7076b71d5e6fbca466
Resolves: #35807
Releases: master
Reviewed-on: http://review.typo3.org/10224
Reviewed-by: Markus Klein <klein.t3@reelworx.at>
Tested-by: Markus Klein <klein.t3@reelworx.at>
Reviewed-by: Frederic Gaus <frederic.gaus@flagbit.de>
Tested-by: Frederic Gaus <frederic.gaus@flagbit.de>
Reviewed-by: Nicole Cordes <typo3@cordes.co>
Tested-by: Nicole Cordes <typo3@cordes.co>
Reviewed-by: Helmut Hummel <helmut.hummel@typo3.org>
typo3/sysext/rsaauth/Classes/Hook/UserSetupHook.php
typo3/sysext/rsaauth/Resources/Public/JavaScript/rsaauth.js
typo3/sysext/rsaauth/Resources/Public/JavaScript/rsaauth_min.js
typo3/sysext/setup/Classes/Controller/SetupModuleController.php
typo3/sysext/setup/ext_tables.php
typo3/sysext/setup/mod/locallang.xlf

index ab65fba..814aa91 100644 (file)
@@ -38,8 +38,10 @@ class UserSetupHook {
                                $key = $storage->get();
                                $password = $backend->decrypt($key, substr($be_user_data['password'], 4));
                                $password2 = $backend->decrypt($key, substr($be_user_data['password2'], 4));
+                               $passwordCurrent = $backend->decrypt($key, substr($be_user_data['passwordCurrent'], 4));
                                $be_user_data['password'] = $password ?: $be_user_data['password'];
                                $be_user_data['password2'] = $password2 ?: $be_user_data['password2'];
+                               $be_user_data['passwordCurrent'] = $passwordCurrent ?: $be_user_data['passwordCurrent'];
                        }
                }
        }
index 6300b90..caeb309 100644 (file)
@@ -5,13 +5,18 @@ function tx_rsaauth_encryptUserSetup() {
 
        var password = document.getElementById('field_password').value;
        var password2 = document.getElementById('field_password2').value;
+       var passwordCurrent = document.getElementById('field_passwordCurrent').value;
 
-       if (password || password2) {
-               var res = rsa.encrypt(password);
-               var res2 = rsa.encrypt(password2);
-               if (res && res2) {
+       if (password || password2 || passwordCurrent) {
+               var res;
+               if (res = rsa.encrypt(password)) {
                        document.getElementById('field_password').value = 'rsa:' + hex2b64(res);
-                       document.getElementById('field_password2').value = 'rsa:' + hex2b64(res2);
+               }
+               if (res = rsa.encrypt(password2)) {
+                       document.getElementById('field_password2').value = 'rsa:' + hex2b64(res);
+               }
+               if (res = rsa.encrypt(passwordCurrent)) {
+                       document.getElementById('field_passwordCurrent').value = 'rsa:' + hex2b64(res);
                }
        }
        return false;
index d8d21de..fe707d9 100644 (file)
@@ -1 +1 @@
-function tx_rsaauth_encryptUserSetup(){var rsa=new RSAKey();rsa.setPublic(document.usersetup.n.value,document.usersetup.e.value);var password=document.getElementById("field_password").value;var password2=document.getElementById("field_password2").value;if(password||password2){var res=rsa.encrypt(password);var res2=rsa.encrypt(password2);if(res&&res2){document.getElementById("field_password").value="rsa:"+hex2b64(res);document.getElementById("field_password2").value="rsa:"+hex2b64(res2)}}return false};
+function tx_rsaauth_encryptUserSetup(){var e=new RSAKey;e.setPublic(document.usersetup.n.value,document.usersetup.e.value);var t=document.getElementById("field_password").value;var n=document.getElementById("field_password2").value;var r=document.getElementById("field_passwordCurrent").value;if(t||n||r){var i;if(i=e.encrypt(t)){document.getElementById("field_password").value="rsa:"+hex2b64(i)}if(i=e.encrypt(n)){document.getElementById("field_password2").value="rsa:"+hex2b64(i)}if(i=e.encrypt(r)){document.getElementById("field_passwordCurrent").value="rsa:"+hex2b64(i)}}return false}
index 7262d49..ee36e4c 100644 (file)
@@ -25,6 +25,11 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
  */
 class SetupModuleController {
 
+       const PASSWORD_NOT_UPDATED = 0;
+       const PASSWORD_UPDATED = 1;
+       const PASSWORD_NOT_THE_SAME = 2;
+       const PASSWORD_OLD_WRONG = 3;
+
        /**
         * @var array
         */
@@ -83,9 +88,9 @@ class SetupModuleController {
        protected $saveData = FALSE;
 
        /**
-        * @var bool
+        * @var int
         */
-       protected $passwordIsUpdated = FALSE;
+       protected $passwordIsUpdated = self::PASSWORD_NOT_UPDATED;
 
        /**
         * @var bool
@@ -192,7 +197,7 @@ class SetupModuleController {
                                                continue;
                                        }
                                        if ($config['table']) {
-                                               if ($config['table'] === 'be_users' && !in_array($field, array('password', 'password2', 'email', 'realName', 'admin'))) {
+                                               if ($config['table'] === 'be_users' && !in_array($field, array('password', 'password2', 'passwordCurrent', 'email', 'realName', 'admin'))) {
                                                        if (!isset($config['access']) || $this->checkAccess($config) && $beUser->user[$field] !== $d['be_users'][$field]) {
                                                                if ($config['type'] === 'check') {
                                                                        $fieldValue = isset($d['be_users'][$field]) ? 1 : 0;
@@ -232,8 +237,16 @@ class SetupModuleController {
                                }
                                // Update the password:
                                if ($passwordIsConfirmed) {
-                                       $storeRec['be_users'][$beUserId]['password'] = $be_user_data['password2'];
-                                       $this->passwordIsUpdated = TRUE;
+                                       $currentPasswordHashed = $GLOBALS['BE_USER']->user['password'];
+                                       $saltFactory = \TYPO3\CMS\Saltedpasswords\Salt\SaltFactory::getSaltingInstance($currentPasswordHashed);
+                                       if ($saltFactory->checkPassword($be_user_data['passwordCurrent'], $currentPasswordHashed)) {
+                                               $this->passwordIsUpdated = self::PASSWORD_UPDATED;
+                                               $storeRec['be_users'][$beUserId]['password'] = $be_user_data['password'];
+                                       } else {
+                                               $this->passwordIsUpdated = self::PASSWORD_OLD_WRONG;
+                                       }
+                               } else {
+                                       $this->passwordIsUpdated = self::PASSWORD_NOT_THE_SAME;
                                }
                                $this->saveData = TRUE;
                        }
@@ -262,7 +275,7 @@ class SetupModuleController {
                                $tce->bypassWorkspaceRestrictions = TRUE;
                                $tce->process_datamap();
                                unset($tce);
-                               if (!$this->passwordIsUpdated || count($storeRec['be_users'][$beUserId]) > 1) {
+                               if ($this->passwordIsUpdated === self::PASSWORD_NOT_UPDATED || count($storeRec['be_users'][$beUserId]) > 1) {
                                        $this->setupIsUpdated = TRUE;
                                }
                        }
@@ -293,6 +306,7 @@ class SetupModuleController {
                // id password is disabled, disable repeat of password too (password2)
                if (isset($this->tsFieldConf['password.']) && $this->tsFieldConf['password.']['disabled']) {
                        $this->tsFieldConf['password2.']['disabled'] = 1;
+                       $this->tsFieldConf['passwordCurrent.']['disabled'] = 1;
                }
                // Create instance of object for output of data
                $this->doc = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Template\DocumentTemplate::class);
@@ -368,12 +382,21 @@ class SetupModuleController {
                }
                // If password is updated, output whether it failed or was OK.
                if ($this->passwordIsSubmitted) {
-                       if ($this->passwordIsUpdated) {
-                               $flashMessage = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessage::class, $this->getLanguageService()->getLL('newPassword_ok'), $this->getLanguageService()->getLL('newPassword'));
-                       } else {
-                               $flashMessage = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessage::class, $this->getLanguageService()->getLL('newPassword_failed'), $this->getLanguageService()->getLL('newPassword'), \TYPO3\CMS\Core\Messaging\FlashMessage::ERROR);
+                       $flashMessage = NULL;
+                       switch ($this->passwordIsUpdated) {
+                               case self::PASSWORD_OLD_WRONG:
+                                       $flashMessage = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessage::class, $this->getLanguageService()->getLL('oldPassword_failed'), $this->getLanguageService()->getLL('newPassword'), \TYPO3\CMS\Core\Messaging\FlashMessage::ERROR);
+                                       break;
+                               case self::PASSWORD_NOT_THE_SAME:
+                                       $flashMessage = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessage::class, $this->getLanguageService()->getLL('newPassword_failed'), $this->getLanguageService()->getLL('newPassword'), \TYPO3\CMS\Core\Messaging\FlashMessage::ERROR);
+                                       break;
+                               case self::PASSWORD_UPDATED:
+                                       $flashMessage = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessage::class, $this->getLanguageService()->getLL('newPassword_ok'), $this->getLanguageService()->getLL('newPassword'));
+                                       break;
+                       }
+                       if ($flashMessage) {
+                               $this->content .= $flashMessage->render();
                        }
-                       $this->content .= $flashMessage->render();
                }
 
                // Render user switch
index 5734970..7a3c355 100644 (file)
@@ -55,6 +55,12 @@ if (TYPO3_MODE === 'BE') {
                                'table' => 'be_users',
                                'csh' => 'newPasswordAgain',
                        ),
+                       'passwordCurrent' => array(
+                               'type' => 'password',
+                               'label' => 'LLL:EXT:setup/mod/locallang.xlf:passwordCurrent',
+                               'table' => 'be_users',
+                               'csh' => 'passwordCurrent',
+                       ),
                        'lang' => array(
                                'type' => 'select',
                                'itemsProcFunc' => \TYPO3\CMS\Setup\Controller\SetupModuleController::class . '->renderLanguageSelect',
@@ -139,7 +145,8 @@ if (TYPO3_MODE === 'BE') {
                                'access' => 'admin'
                        )
                ),
-               'showitem' => '--div--;LLL:EXT:setup/mod/locallang.xlf:personal_data,realName,email,emailMeAtLogin,password,password2,lang,
+               'showitem' => '--div--;LLL:EXT:setup/mod/locallang.xlf:personal_data,realName,email,emailMeAtLogin,lang,
+                               --div--;LLL:EXT:setup/mod/locallang.xml:passwordHeader,passwordCurrent,password,password2,
                                --div--;LLL:EXT:setup/mod/locallang.xlf:opening,startModule,thumbnailsByDefault,titleLen,
                                --div--;LLL:EXT:setup/mod/locallang.xlf:editFunctionsTab,edit_RTE,edit_docModuleUpload,showHiddenFilesAndFolders,resizeTextareas_Flexible,resizeTextareas_MaxHeight,copyLevels,recursiveDelete,resetConfiguration,clearSessionVars,
                                --div--;LLL:EXT:setup/mod/locallang.xlf:adminFunctions,debugInWindow'
index a394a98..a03c55c 100644 (file)
                        <trans-unit id="newPassword_ok" xml:space="preserve">
                                <source>Password was updated.</source>
                        </trans-unit>
+                       <trans-unit id="passwordCurrent" xml:space="preserve">
+                               <source>Current password</source>
+                       </trans-unit>
+                       <trans-unit id="passwordHeader" xml:space="preserve">
+                               <source>Password</source>
+                       </trans-unit>
                        <trans-unit id="setupWasUpdated" xml:space="preserve">
                                <source>User settings were updated.</source>
                        </trans-unit>
                        <trans-unit id="newPassword_failed" xml:space="preserve">
                                <source>Password was NOT updated because you didn't enter the same password twice.</source>
                        </trans-unit>
+                       <trans-unit id="oldPassword_failed" xml:space="preserve">
+                               <source>Password was NOT updated because you didn't enter the correct current password.</source>
+                       </trans-unit>
                        <trans-unit id="adminFunctions" xml:space="preserve">
                                <source>Admin functions</source>
                        </trans-unit>