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