62653c0a40e3aaa0ca864d45e0794bb58137d256
[Packages/TYPO3.CMS.git] / typo3 / sysext / saltedpasswords / Tests / Unit / Salts / Md5SaltTest.php
1 <?php
2 namespace TYPO3\CMS\Saltedpasswords\Tests\Unit\Salts;
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 * Contains testcases for "tx_saltedpasswords_salts_md5"
31 * that provides MD5 salted hashing.
32 */
33 /**
34 * Testcases for class tx_saltedpasswords_salts_md5.
35 *
36 * @author Marcus Krause <marcus#exp2009@t3sec.info>
37 * @package TYPO3
38 * @subpackage tx_saltedpasswords
39 */
40 class Md5SaltTest extends \tx_phpunit_testcase {
41
42 /**
43 * Keeps instance of object to test.
44 *
45 * @var \TYPO3\CMS\Saltedpasswords\Salt\Md5Salt
46 */
47 protected $objectInstance = NULL;
48
49 /**
50 * Sets up the fixtures for this testcase.
51 *
52 * @return void
53 */
54 public function setUp() {
55 $this->objectInstance = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Saltedpasswords\\Salt\\Md5Salt');
56 }
57
58 /**
59 * Tears down objects and settings created in this testcase.
60 *
61 * @return void
62 */
63 public function tearDown() {
64 unset($this->objectInstance);
65 }
66
67 /**
68 * Prepares a message to be shown when a salted hashing is not supported.
69 *
70 * @return string Empty string if salted hashing method is available, otherwise an according warning
71 */
72 protected function getWarningWhenMethodUnavailable() {
73 $warningMsg = '';
74 if (!CRYPT_MD5) {
75 $warningMsg .= 'MD5 is not supported on your platform. ' . 'Then, some of the md5 tests will fail.';
76 }
77 }
78
79 /**
80 * @test
81 */
82 public function hasCorrectBaseClass() {
83 $hasCorrectBaseClass = 0 === strcmp('TYPO3\\CMS\\Saltedpasswords\\Salt\\Md5Salt', get_class($this->objectInstance)) ? TRUE : FALSE;
84 // XCLASS ?
85 if (!$hasCorrectBaseClass && FALSE != get_parent_class($this->objectInstance)) {
86 $hasCorrectBaseClass = is_subclass_of($this->objectInstance, 'TYPO3\\CMS\\Saltedpasswords\\Salt\\Md5Salt');
87 }
88 $this->assertTrue($hasCorrectBaseClass);
89 }
90
91 /**
92 * @test
93 */
94 public function nonZeroSaltLength() {
95 $this->assertTrue($this->objectInstance->getSaltLength() > 0);
96 }
97
98 /**
99 * @test
100 */
101 public function emptyPasswordResultsInNullSaltedPassword() {
102 $password = '';
103 $this->assertNull($this->objectInstance->getHashedPassword($password));
104 }
105
106 /**
107 * @test
108 */
109 public function nonEmptyPasswordResultsInNonNullSaltedPassword() {
110 $password = 'a';
111 $this->assertNotNull($this->objectInstance->getHashedPassword($password), $this->getWarningWhenMethodUnavailable());
112 }
113
114 /**
115 * @test
116 */
117 public function createdSaltedHashOfProperStructure() {
118 $password = 'password';
119 $saltedHashPassword = $this->objectInstance->getHashedPassword($password);
120 $this->assertTrue($this->objectInstance->isValidSaltedPW($saltedHashPassword), $this->getWarningWhenMethodUnavailable());
121 }
122
123 /**
124 * @test
125 */
126 public function createdSaltedHashOfProperStructureForCustomSaltWithoutSetting() {
127 $password = 'password';
128 // custom salt without setting
129 $randomBytes = \TYPO3\CMS\Core\Utility\GeneralUtility::generateRandomBytes($this->objectInstance->getSaltLength());
130 $salt = $this->objectInstance->base64Encode($randomBytes, $this->objectInstance->getSaltLength());
131 $this->assertTrue($this->objectInstance->isValidSalt($salt), $this->getWarningWhenMethodUnavailable());
132 $saltedHashPassword = $this->objectInstance->getHashedPassword($password, $salt);
133 $this->assertTrue($this->objectInstance->isValidSaltedPW($saltedHashPassword), $this->getWarningWhenMethodUnavailable());
134 }
135
136 /**
137 * Tests authentication procedure with alphabet characters.
138 *
139 * Checks if a "plain-text password" is everytime mapped to the
140 * same "salted password hash" when using the same salt.
141 *
142 * @test
143 */
144 public function authenticationWithValidAlphaCharClassPassword() {
145 $password = 'aEjOtY';
146 $saltedHashPassword = $this->objectInstance->getHashedPassword($password);
147 $this->assertTrue($this->objectInstance->checkPassword($password, $saltedHashPassword), $this->getWarningWhenMethodUnavailable());
148 }
149
150 /**
151 * Tests authentication procedure with numeric characters.
152 *
153 * Checks if a "plain-text password" is everytime mapped to the
154 * same "salted password hash" when using the same salt.
155 *
156 * @test
157 */
158 public function authenticationWithValidNumericCharClassPassword() {
159 $password = '01369';
160 $saltedHashPassword = $this->objectInstance->getHashedPassword($password);
161 $this->assertTrue($this->objectInstance->checkPassword($password, $saltedHashPassword), $this->getWarningWhenMethodUnavailable());
162 }
163
164 /**
165 * Tests authentication procedure with US-ASCII special characters.
166 *
167 * Checks if a "plain-text password" is everytime mapped to the
168 * same "salted password hash" when using the same salt.
169 *
170 * @test
171 */
172 public function authenticationWithValidAsciiSpecialCharClassPassword() {
173 $password = ' !"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~';
174 $saltedHashPassword = $this->objectInstance->getHashedPassword($password);
175 $this->assertTrue($this->objectInstance->checkPassword($password, $saltedHashPassword), $this->getWarningWhenMethodUnavailable());
176 }
177
178 /**
179 * Tests authentication procedure with latin1 special characters.
180 *
181 * Checks if a "plain-text password" is everytime mapped to the
182 * same "salted password hash" when using the same salt.
183 *
184 * @test
185 */
186 public function authenticationWithValidLatin1SpecialCharClassPassword() {
187 $password = '';
188 for ($i = 160; $i <= 191; $i++) {
189 $password .= chr($i);
190 }
191 $password .= chr(215) . chr(247);
192 $saltedHashPassword = $this->objectInstance->getHashedPassword($password);
193 $this->assertTrue($this->objectInstance->checkPassword($password, $saltedHashPassword), $this->getWarningWhenMethodUnavailable());
194 }
195
196 /**
197 * Tests authentication procedure with latin1 umlauts.
198 *
199 * Checks if a "plain-text password" is everytime mapped to the
200 * same "salted password hash" when using the same salt.
201 *
202 * @test
203 */
204 public function authenticationWithValidLatin1UmlautCharClassPassword() {
205 $password = '';
206 for ($i = 192; $i <= 214; $i++) {
207 $password .= chr($i);
208 }
209 for ($i = 216; $i <= 246; $i++) {
210 $password .= chr($i);
211 }
212 for ($i = 248; $i <= 255; $i++) {
213 $password .= chr($i);
214 }
215 $saltedHashPassword = $this->objectInstance->getHashedPassword($password);
216 $this->assertTrue($this->objectInstance->checkPassword($password, $saltedHashPassword), $this->getWarningWhenMethodUnavailable());
217 }
218
219 /**
220 * @test
221 */
222 public function authenticationWithNonValidPassword() {
223 $password = 'password';
224 $password1 = $password . 'INVALID';
225 $saltedHashPassword = $this->objectInstance->getHashedPassword($password);
226 $this->assertFalse($this->objectInstance->checkPassword($password1, $saltedHashPassword), $this->getWarningWhenMethodUnavailable());
227 }
228
229 /**
230 * @test
231 */
232 public function passwordVariationsResultInDifferentHashes() {
233 $pad = 'a';
234 $password = '';
235 $criticalPwLength = 0;
236 // We're using a constant salt.
237 $saltedHashPasswordPrevious = ($saltedHashPasswordCurrent = ($salt = $this->objectInstance->getHashedPassword($pad)));
238 for ($i = 0; $i <= 128; $i += 8) {
239 $password = str_repeat($pad, max($i, 1));
240 $saltedHashPasswordPrevious = $saltedHashPasswordCurrent;
241 $saltedHashPasswordCurrent = $this->objectInstance->getHashedPassword($password, $salt);
242 if ($i > 0 && 0 == strcmp($saltedHashPasswordPrevious, $saltedHashPasswordCurrent)) {
243 $criticalPwLength = $i;
244 break;
245 }
246 }
247 $this->assertTrue($criticalPwLength == 0 || $criticalPwLength > 32, $this->getWarningWhenMethodUnavailable() . 'Duplicates of hashed passwords with plaintext password of length ' . $criticalPwLength . '+.');
248 }
249
250 /**
251 * @test
252 */
253 public function noUpdateNecessityForMd5() {
254 $password = 'password';
255 $saltedHashPassword = $this->objectInstance->getHashedPassword($password);
256 $this->assertFalse($this->objectInstance->isHashUpdateNeeded($saltedHashPassword));
257 }
258
259 }
260
261
262 ?>