[TASK] Speed up salted password unit test
[Packages/TYPO3.CMS.git] / typo3 / sysext / saltedpasswords / Tests / Unit / Salt / PhpassSaltTest.php
1 <?php
2 namespace TYPO3\CMS\Saltedpasswords\Tests\Unit\Salt;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2009-2011 Marcus Krause <marcus#exp2009@t3sec.info>
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 * A copy is found in the textfile GPL.txt and important notices to the license
19 * from the author is found in LICENSE.txt distributed with these scripts.
20 *
21 *
22 * This script is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * This copyright notice MUST APPEAR in all copies of the script!
28 ***************************************************************/
29
30 /**
31 * Testcase for PhpassSalt
32 *
33 * @author Marcus Krause <marcus#exp2009@t3sec.info>
34 * @package TYPO3
35 * @subpackage tx_saltedpasswords
36 */
37 class PhpassSaltTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
38
39 /**
40 * Keeps instance of object to test.
41 *
42 * @var \TYPO3\CMS\Saltedpasswords\Salt\PhpassSalt
43 */
44 protected $objectInstance = NULL;
45
46 /**
47 * Sets up the fixtures for this testcase.
48 *
49 * @return void
50 */
51 public function setUp() {
52 $this->objectInstance = $this->getMock('TYPO3\\CMS\\Saltedpasswords\\Salt\\PhpassSalt', array('dummy'));
53 }
54
55 /**
56 * Tears down objects and settings created in this testcase.
57 *
58 * @return void
59 */
60 public function tearDown() {
61 $this->objectInstance = NULL;
62 }
63
64 /**
65 * @test
66 */
67 public function hasCorrectBaseClass() {
68 $hasCorrectBaseClass = 0 === strcmp('TYPO3\\CMS\\Saltedpasswords\\Salt\\PhpassSalt', get_class($this->objectInstance)) ? TRUE : FALSE;
69 // XCLASS ?
70 if (!$hasCorrectBaseClass && FALSE != get_parent_class($this->objectInstance)) {
71 $hasCorrectBaseClass = is_subclass_of($this->objectInstance, 'TYPO3\\CMS\\Saltedpasswords\\Salt\\PhpassSalt');
72 }
73 $this->assertTrue($hasCorrectBaseClass);
74 }
75
76 /**
77 * @test
78 */
79 public function nonZeroSaltLength() {
80 $this->assertTrue($this->objectInstance->getSaltLength() > 0);
81 }
82
83 /**
84 * @test
85 */
86 public function emptyPasswordResultsInNullSaltedPassword() {
87 $password = '';
88 $this->assertNull($this->objectInstance->getHashedPassword($password));
89 }
90
91 /**
92 * @test
93 */
94 public function nonEmptyPasswordResultsInNonNullSaltedPassword() {
95 $password = 'a';
96 $this->assertNotNull($this->objectInstance->getHashedPassword($password));
97 }
98
99 /**
100 * @test
101 */
102 public function createdSaltedHashOfProperStructure() {
103 $password = 'password';
104 $saltedHashPassword = $this->objectInstance->getHashedPassword($password);
105 $this->assertTrue($this->objectInstance->isValidSaltedPW($saltedHashPassword));
106 }
107
108 /**
109 * @test
110 */
111 public function createdSaltedHashOfProperStructureForCustomSaltWithoutSetting() {
112 $password = 'password';
113 // custom salt without setting
114 $randomBytes = \TYPO3\CMS\Core\Utility\GeneralUtility::generateRandomBytes($this->objectInstance->getSaltLength());
115 $salt = $this->objectInstance->base64Encode($randomBytes, $this->objectInstance->getSaltLength());
116 $this->assertTrue($this->objectInstance->isValidSalt($salt));
117 $saltedHashPassword = $this->objectInstance->getHashedPassword($password, $salt);
118 $this->assertTrue($this->objectInstance->isValidSaltedPW($saltedHashPassword));
119 }
120
121 /**
122 * @test
123 */
124 public function createdSaltedHashOfProperStructureForMinimumHashCount() {
125 $password = 'password';
126 $minHashCount = $this->objectInstance->getMinHashCount();
127 $this->objectInstance->setHashCount($minHashCount);
128 $saltedHashPassword = $this->objectInstance->getHashedPassword($password);
129 $this->assertTrue($this->objectInstance->isValidSaltedPW($saltedHashPassword));
130 // reset hashcount
131 $this->objectInstance->setHashCount(NULL);
132 }
133
134 /**
135 * Tests authentication procedure with alphabet characters.
136 *
137 * Checks if a "plain-text password" is everytime mapped to the
138 * same "salted password hash" when using the same salt.
139 *
140 * @test
141 */
142 public function authenticationWithValidAlphaCharClassPassword() {
143 $password = 'aEjOtY';
144 $saltedHashPassword = $this->objectInstance->getHashedPassword($password);
145 $this->assertTrue($this->objectInstance->checkPassword($password, $saltedHashPassword));
146 }
147
148 /**
149 * Tests authentication procedure with numeric characters.
150 *
151 * Checks if a "plain-text password" is everytime mapped to the
152 * same "salted password hash" when using the same salt.
153 *
154 * @test
155 */
156 public function authenticationWithValidNumericCharClassPassword() {
157 $password = '01369';
158 $saltedHashPassword = $this->objectInstance->getHashedPassword($password);
159 $this->assertTrue($this->objectInstance->checkPassword($password, $saltedHashPassword));
160 }
161
162 /**
163 * Tests authentication procedure with US-ASCII special characters.
164 *
165 * Checks if a "plain-text password" is everytime mapped to the
166 * same "salted password hash" when using the same salt.
167 *
168 * @test
169 */
170 public function authenticationWithValidAsciiSpecialCharClassPassword() {
171 $password = ' !"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~';
172 $saltedHashPassword = $this->objectInstance->getHashedPassword($password);
173 $this->assertTrue($this->objectInstance->checkPassword($password, $saltedHashPassword));
174 }
175
176 /**
177 * Tests authentication procedure with latin1 special characters.
178 *
179 * Checks if a "plain-text password" is everytime mapped to the
180 * same "salted password hash" when using the same salt.
181 *
182 * @test
183 */
184 public function authenticationWithValidLatin1SpecialCharClassPassword() {
185 $password = '';
186 for ($i = 160; $i <= 191; $i++) {
187 $password .= chr($i);
188 }
189 $password .= chr(215) . chr(247);
190 $saltedHashPassword = $this->objectInstance->getHashedPassword($password);
191 $this->assertTrue($this->objectInstance->checkPassword($password, $saltedHashPassword));
192 }
193
194 /**
195 * Tests authentication procedure with latin1 umlauts.
196 *
197 * Checks if a "plain-text password" is everytime mapped to the
198 * same "salted password hash" when using the same salt.
199 *
200 * @test
201 */
202 public function authenticationWithValidLatin1UmlautCharClassPassword() {
203 $password = '';
204 for ($i = 192; $i <= 214; $i++) {
205 $password .= chr($i);
206 }
207 for ($i = 216; $i <= 246; $i++) {
208 $password .= chr($i);
209 }
210 for ($i = 248; $i <= 255; $i++) {
211 $password .= chr($i);
212 }
213 $saltedHashPassword = $this->objectInstance->getHashedPassword($password);
214 $this->assertTrue($this->objectInstance->checkPassword($password, $saltedHashPassword));
215 }
216
217 /**
218 * @test
219 */
220 public function authenticationWithNonValidPassword() {
221 $password = 'password';
222 $password1 = $password . 'INVALID';
223 $saltedHashPassword = $this->objectInstance->getHashedPassword($password);
224 $this->assertFalse($this->objectInstance->checkPassword($password1, $saltedHashPassword));
225 }
226
227 /**
228 * @test
229 */
230 public function passwordVariationsResultInDifferentHashes() {
231 $pad = 'a';
232 $criticalPwLength = 0;
233 // We're using a constant salt.
234 $saltedHashPasswordCurrent = $salt = $this->objectInstance->getHashedPassword($pad);
235 for ($i = 0; $i <= 128; $i += 8) {
236 $password = str_repeat($pad, max($i, 1));
237 $saltedHashPasswordPrevious = $saltedHashPasswordCurrent;
238 $saltedHashPasswordCurrent = $this->objectInstance->getHashedPassword($password, $salt);
239 if ($i > 0 && 0 == strcmp($saltedHashPasswordPrevious, $saltedHashPasswordCurrent)) {
240 $criticalPwLength = $i;
241 break;
242 }
243 }
244 $this->assertTrue($criticalPwLength == 0 || $criticalPwLength > 32, 'Duplicates of hashed passwords with plaintext password of length ' . $criticalPwLength . '+.');
245 }
246
247 /**
248 * @test
249 */
250 public function modifiedMinHashCount() {
251 $minHashCount = $this->objectInstance->getMinHashCount();
252 $this->objectInstance->setMinHashCount($minHashCount - 1);
253 $this->assertTrue($this->objectInstance->getMinHashCount() < $minHashCount);
254 $this->objectInstance->setMinHashCount($minHashCount + 1);
255 $this->assertTrue($this->objectInstance->getMinHashCount() > $minHashCount);
256 }
257
258 /**
259 * @test
260 */
261 public function modifiedMaxHashCount() {
262 $maxHashCount = $this->objectInstance->getMaxHashCount();
263 $this->objectInstance->setMaxHashCount($maxHashCount + 1);
264 $this->assertTrue($this->objectInstance->getMaxHashCount() > $maxHashCount);
265 $this->objectInstance->setMaxHashCount($maxHashCount - 1);
266 $this->assertTrue($this->objectInstance->getMaxHashCount() < $maxHashCount);
267 }
268
269 /**
270 * @test
271 */
272 public function modifiedHashCount() {
273 $hashCount = $this->objectInstance->getHashCount();
274 $this->objectInstance->setMaxHashCount($hashCount + 1);
275 $this->objectInstance->setHashCount($hashCount + 1);
276 $this->assertTrue($this->objectInstance->getHashCount() > $hashCount);
277 $this->objectInstance->setMinHashCount($hashCount - 1);
278 $this->objectInstance->setHashCount($hashCount - 1);
279 $this->assertTrue($this->objectInstance->getHashCount() < $hashCount);
280 // reset hashcount
281 $this->objectInstance->setHashCount(NULL);
282 }
283
284 /**
285 * @test
286 */
287 public function updateNecessityForValidSaltedPassword() {
288 $password = 'password';
289 $saltedHashPassword = $this->objectInstance->getHashedPassword($password);
290 $this->assertFalse($this->objectInstance->isHashUpdateNeeded($saltedHashPassword));
291 }
292
293 /**
294 * @test
295 */
296 public function updateNecessityForIncreasedHashcount() {
297 $password = 'password';
298 $saltedHashPassword = $this->objectInstance->getHashedPassword($password);
299 $increasedHashCount = $this->objectInstance->getHashCount() + 1;
300 $this->objectInstance->setMaxHashCount($increasedHashCount);
301 $this->objectInstance->setHashCount($increasedHashCount);
302 $this->assertTrue($this->objectInstance->isHashUpdateNeeded($saltedHashPassword));
303 // reset hashcount
304 $this->objectInstance->setHashCount(NULL);
305 }
306
307 /**
308 * @test
309 */
310 public function updateNecessityForDecreasedHashcount() {
311 $password = 'password';
312 $saltedHashPassword = $this->objectInstance->getHashedPassword($password);
313 $decreasedHashCount = $this->objectInstance->getHashCount() - 1;
314 $this->objectInstance->setMinHashCount($decreasedHashCount);
315 $this->objectInstance->setHashCount($decreasedHashCount);
316 $this->assertFalse($this->objectInstance->isHashUpdateNeeded($saltedHashPassword));
317 // reset hashcount
318 $this->objectInstance->setHashCount(NULL);
319 }
320
321 }
322
323 ?>