d72c23e8eb5b2589d258deeb0891b12c78c75587
[Packages/TYPO3.CMS.git] / typo3 / sysext / saltedpasswords / Tests / Unit / Salt / SaltFactoryTest.php
1 <?php
2 namespace TYPO3\CMS\Saltedpasswords\Tests\Unit\Salt;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Core\Crypto\Random;
18
19 /**
20 * Testcase for SaltFactory
21 */
22 class SaltFactoryTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
23 {
24 /**
25 * Keeps instance of object to test.
26 *
27 * @var \TYPO3\CMS\Saltedpasswords\Salt\AbstractSalt
28 */
29 protected $objectInstance = null;
30
31 /**
32 * Sets up the fixtures for this testcase.
33 */
34 protected function setUp()
35 {
36 $GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['saltedpasswords'] = [
37 'BE' => [
38 'saltedPWHashingMethod' => \TYPO3\CMS\Saltedpasswords\Salt\Pbkdf2Salt::class,
39 'forceSalted' => 0,
40 'onlyAuthService' => 0,
41 'updatePasswd' => 1,
42 ],
43 'FE' => [
44 'enabled' => 1,
45 'saltedPWHashingMethod' => \TYPO3\CMS\Saltedpasswords\Salt\Pbkdf2Salt::class,
46 'forceSalted' => 0,
47 'onlyAuthService' => 0,
48 'updatePasswd' => 1,
49 ],
50 ];
51 $this->objectInstance = \TYPO3\CMS\Saltedpasswords\Salt\SaltFactory::getSaltingInstance();
52 }
53
54 /**
55 * @test
56 */
57 public function objectInstanceNotNull()
58 {
59 $this->assertNotNull($this->objectInstance);
60 }
61
62 /**
63 * @test
64 */
65 public function objectInstanceExtendsAbstractClass()
66 {
67 $this->assertTrue(is_subclass_of($this->objectInstance, \TYPO3\CMS\Saltedpasswords\Salt\AbstractSalt::class));
68 }
69
70 /**
71 * @test
72 */
73 public function objectInstanceImplementsInterface()
74 {
75 $this->assertTrue(method_exists($this->objectInstance, 'checkPassword'), 'Missing method checkPassword() from interface ' . \TYPO3\CMS\Saltedpasswords\Salt\SaltInterface::class . '.');
76 $this->assertTrue(method_exists($this->objectInstance, 'isHashUpdateNeeded'), 'Missing method isHashUpdateNeeded() from interface ' . \TYPO3\CMS\Saltedpasswords\Salt\SaltInterface::class . '.');
77 $this->assertTrue(method_exists($this->objectInstance, 'isValidSalt'), 'Missing method isValidSalt() from interface ' . \TYPO3\CMS\Saltedpasswords\Salt\SaltInterface::class . '.');
78 $this->assertTrue(method_exists($this->objectInstance, 'isValidSaltedPW'), 'Missing method isValidSaltedPW() from interface ' . \TYPO3\CMS\Saltedpasswords\Salt\SaltInterface::class . '.');
79 $this->assertTrue(method_exists($this->objectInstance, 'getHashedPassword'), 'Missing method getHashedPassword() from interface ' . \TYPO3\CMS\Saltedpasswords\Salt\SaltInterface::class . '.');
80 $this->assertTrue(method_exists($this->objectInstance, 'getSaltLength'), 'Missing method getSaltLength() from interface ' . \TYPO3\CMS\Saltedpasswords\Salt\SaltInterface::class . '.');
81 }
82
83 /**
84 * @test
85 */
86 public function base64EncodeReturnsProperLength()
87 {
88 // 3 Bytes should result in a 6 char length base64 encoded string
89 // used for MD5 and PHPass salted hashing
90 $byteLength = 3;
91 $reqLengthBase64 = (int)ceil($byteLength * 8 / 6);
92 $randomBytes = (new Random())->generateRandomBytes($byteLength);
93 $this->assertTrue(strlen($this->objectInstance->base64Encode($randomBytes, $byteLength)) == $reqLengthBase64);
94 // 16 Bytes should result in a 22 char length base64 encoded string
95 // used for Blowfish salted hashing
96 $byteLength = 16;
97 $reqLengthBase64 = (int)ceil($byteLength * 8 / 6);
98 $randomBytes = (new Random())->generateRandomBytes($byteLength);
99 $this->assertTrue(strlen($this->objectInstance->base64Encode($randomBytes, $byteLength)) == $reqLengthBase64);
100 }
101
102 /**
103 * @test
104 */
105 public function objectInstanceForMD5Salts()
106 {
107 $saltMD5 = '$1$rasmusle$rISCgZzpwk3UhDidwXvin0';
108 $this->objectInstance = \TYPO3\CMS\Saltedpasswords\Salt\SaltFactory::getSaltingInstance($saltMD5);
109 $this->assertTrue(get_class($this->objectInstance) == \TYPO3\CMS\Saltedpasswords\Salt\Md5Salt::class || is_subclass_of($this->objectInstance, \TYPO3\CMS\Saltedpasswords\Salt\Md5Salt::class));
110 }
111
112 /**
113 * @test
114 */
115 public function objectInstanceForBlowfishSalts()
116 {
117 $saltBlowfish = '$2a$07$abcdefghijklmnopqrstuuIdQV69PAxWYTgmnoGpe0Sk47GNS/9ZW';
118 $this->objectInstance = \TYPO3\CMS\Saltedpasswords\Salt\SaltFactory::getSaltingInstance($saltBlowfish);
119 $this->assertTrue(get_class($this->objectInstance) == \TYPO3\CMS\Saltedpasswords\Salt\BlowfishSalt::class || is_subclass_of($this->objectInstance, \TYPO3\CMS\Saltedpasswords\Salt\BlowfishSalt::class));
120 }
121
122 /**
123 * @test
124 */
125 public function objectInstanceForPhpassSalts()
126 {
127 $saltPhpass = '$P$CWF13LlG/0UcAQFUjnnS4LOqyRW43c.';
128 $this->objectInstance = \TYPO3\CMS\Saltedpasswords\Salt\SaltFactory::getSaltingInstance($saltPhpass);
129 $this->assertTrue(get_class($this->objectInstance) == \TYPO3\CMS\Saltedpasswords\Salt\PhpassSalt::class || is_subclass_of($this->objectInstance, \TYPO3\CMS\Saltedpasswords\Salt\PhpassSalt::class));
130 }
131
132 /**
133 * @test
134 */
135 public function objectInstanceForPbkdf2Salts()
136 {
137 $saltPbkdf2 = '$pbkdf2-sha256$6400$0ZrzXitFSGltTQnBWOsdAw$Y11AchqV4b0sUisdZd0Xr97KWoymNE0LNNrnEgY4H9M';
138 $this->objectInstance = \TYPO3\CMS\Saltedpasswords\Salt\SaltFactory::getSaltingInstance($saltPbkdf2);
139 $this->assertTrue(get_class($this->objectInstance) == \TYPO3\CMS\Saltedpasswords\Salt\Pbkdf2Salt::class || is_subclass_of($this->objectInstance, \TYPO3\CMS\Saltedpasswords\Salt\Pbkdf2Salt::class));
140 }
141
142 /**
143 * @test
144 */
145 public function resettingFactoryInstanceSucceeds()
146 {
147 $defaultClassNameToUse = \TYPO3\CMS\Saltedpasswords\Utility\SaltedPasswordsUtility::getDefaultSaltingHashingMethod();
148 if ($defaultClassNameToUse == \TYPO3\CMS\Saltedpasswords\Salt\Md5Salt::class) {
149 $saltedPW = '$P$CWF13LlG/0UcAQFUjnnS4LOqyRW43c.';
150 } else {
151 $saltedPW = '$1$rasmusle$rISCgZzpwk3UhDidwXvin0';
152 }
153 $this->objectInstance = \TYPO3\CMS\Saltedpasswords\Salt\SaltFactory::getSaltingInstance($saltedPW);
154 // resetting
155 $this->objectInstance = \TYPO3\CMS\Saltedpasswords\Salt\SaltFactory::getSaltingInstance(null);
156 $this->assertTrue(get_class($this->objectInstance) == $defaultClassNameToUse || is_subclass_of($this->objectInstance, $defaultClassNameToUse));
157 }
158 }