[BUGFIX] Prevent saltedpasswords destroying the password
authorXavier Perseguers <xavier@typo3.org>
Tue, 16 Oct 2012 07:09:59 +0000 (09:09 +0200)
committerXavier Perseguers <xavier@typo3.org>
Tue, 16 Oct 2012 07:16:26 +0000 (09:16 +0200)
When a record is using a plain MD5 password, EXT:saltedpasswords will
destroy the password after the second successive edit.

Add check for already temporarily hashed passwords to prevent that.

Change-Id: I487cbb335616c1d378a704845d5cc96e4ad6cb62
Fixes: #41828
Releases: 4.5, 4.6, 4.7, 6.0
Reviewed-on: http://review.typo3.org/15674
Reviewed-by: Xavier Perseguers
Tested-by: Xavier Perseguers
tests/typo3/sysext/saltedpasswords/classes/eval/class.tx_saltedpasswords_evalTest.php [new file with mode: 0644]
typo3/sysext/saltedpasswords/classes/eval/class.tx_saltedpasswords_eval.php

diff --git a/tests/typo3/sysext/saltedpasswords/classes/eval/class.tx_saltedpasswords_evalTest.php b/tests/typo3/sysext/saltedpasswords/classes/eval/class.tx_saltedpasswords_evalTest.php
new file mode 100644 (file)
index 0000000..c044085
--- /dev/null
@@ -0,0 +1,91 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2012 Marcus Krause <marcus#exp2009@t3sec.info>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *  A copy is found in the textfile GPL.txt and important notices to the license
+ *  from the author is found in LICENSE.txt distributed with these scripts.
+ *
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * Testcase for tx_saltedpasswords_eval
+ *
+ * @author Marcus Krause <marcus#exp2009@t3sec.info>
+ * @package TYPO3
+ * @subpackage tx_saltedpasswords
+ */
+class tx_saltedpasswords_evalTest extends tx_phpunit_testcase {
+
+       /**
+        * Enable backup of global and system variables
+        *
+        * @var boolean
+        */
+       protected $backupGlobals = TRUE;
+
+       /**
+        * @var tx_saltedpasswords_eval
+        */
+       protected $fixture;
+
+       public function setUp() {
+               $this->fixture = $this->getMock('tx_saltedpasswords_eval', array('dummy'));
+               unset($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['saltedpasswords']);
+       }
+
+       /**
+        * @test
+        */
+       public function passwordIsTurnedIntoSaltedString() {
+               $isSet = NULL;
+               $originalPassword = 'password';
+               $saltedPassword = $this->fixture->evaluateFieldValue($originalPassword, '', $isSet);
+               $this->assertTrue($isSet);
+               $this->assertNotEquals($originalPassword, $saltedPassword);
+               $this->assertTrue(t3lib_div::inList('$1$,$2$,$2a,$P$', substr($saltedPassword, 0, 3)));
+       }
+
+       /**
+        * @test
+        */
+       public function md5HashIsUpdatedToTemporarySaltedString() {
+               $isSet = NULL;
+               $originalPassword = '5f4dcc3b5aa765d61d8327deb882cf99';
+               $saltedPassword = $this->fixture->evaluateFieldValue($originalPassword, '', $isSet);
+               $this->assertTrue($isSet);
+               $this->assertNotEquals($originalPassword, $saltedPassword);
+               $this->assertTrue(t3lib_div::isFirstPartOfStr($saltedPassword, 'M$'));
+       }
+
+       /**
+        * @test
+        */
+       public function temporarySaltedStringIsNotTouched() {
+               $isSet = NULL;
+               $originalPassword = 'M$P$CibIRipvLfaPlaaeH8ifu9g21BrPjp.';
+               $saltedPassword = $this->fixture->evaluateFieldValue($originalPassword, '', $isSet);
+               $this->assertFalse($isSet);
+               $this->assertSame($originalPassword, $saltedPassword);
+       }
+}
+
+
+?>
\ No newline at end of file
index b360353..51fae39 100644 (file)
@@ -70,16 +70,22 @@ class tx_saltedpasswords_eval {
                if ($isEnabled) {
                        $set = FALSE;
                        $isMD5 = preg_match('/[0-9abcdef]{32,32}/', $value);
-                       $isSaltedHash = t3lib_div::inList('$1$,$2$,$2a,$P$', substr($value, 0, 3));
+                       $isDeprecatedSaltedHash = t3lib_div::inList('C$,M$', substr($value, 0, 2));
 
-                       $this->objInstanceSaltedPW = tx_saltedpasswords_salts_factory::getSaltingInstance(NULL, $this->mode);
+                       /** @var $objInstanceSaltedPW tx_saltedpasswords_salts */
+                       $objInstanceSaltedPW = tx_saltedpasswords_salts_factory::getSaltingInstance(NULL, $this->mode);
 
                        if ($isMD5) {
                                $set = TRUE;
-                               $value = 'M' . $this->objInstanceSaltedPW->getHashedPassword($value);
-                       } else if (!$isSaltedHash) {
-                               $set = TRUE;
-                               $value = $this->objInstanceSaltedPW->getHashedPassword($value);
+                               $value = 'M' . $objInstanceSaltedPW->getHashedPassword($value);
+                       } else {
+                                       // Determine method used for the (possibly) salted hashed password
+                               $tempValue = $isDeprecatedSaltedHash ? substr($value, 1) : $value;
+                               $tempObjInstanceSaltedPW = tx_saltedpasswords_salts_factory::getSaltingInstance($tempValue);
+                               if (!is_object($tempObjInstanceSaltedPW)) {
+                                       $set = TRUE;
+                                       $value = $objInstanceSaltedPW->getHashedPassword($value);
+                               }
                        }
                }