ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
ilBcryptPasswordEncoderTest.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 1998-2014 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4require_once 'Services/Password/classes/encoders/class.ilBcryptPasswordEncoder.php';
5require_once 'Services/Password/test/ilPasswordBaseTest.php';
6
7use org\bovigo\vfs;
8
15{
19 const VALID_COSTS = '08';
20
24 const PASSWORD = 'password';
25
29 const WRONG_PASSWORD = 'wrong_password';
30
34 const CLIENT_SALT = 'homer!12345_/';
35
39 const PASSWORD_SALT = 'salt';
40
44 protected $test_directory;
45
50
54 public function getTestDirectory()
55 {
57 }
58
63 {
64 $this->test_directory = $test_directory;
65 }
66
70 public function getTestDirectoryUrl()
71 {
73 }
74
79 {
80 $this->test_directory_url = $test_directory_url;
81 }
82
86 protected function setUp()
87 {
88 vfs\vfsStream::setup();
89 $this->setTestDirectory(vfs\vfsStream::newDirectory('tests')->at(vfs\vfsStreamWrapper::getRoot()));
90 $this->setTestDirectoryUrl(vfs\vfsStream::url('root/tests'));
91
92 parent::setUp();
93 }
94
99 {
100 if (version_compare(phpversion(), '5.3.7', '<')) {
101 $this->markTestSkipped('Requires PHP >= 5.3.7');
102 }
103 }
104
108 public function costsProvider()
109 {
110 $data = array();
111 for ($i = 4; $i <= 31; $i++) {
112 $data[] = array($i);
113 }
114 return $data;
115 }
116
121 {
122 $encoder = new ilBcryptPasswordEncoder(array(
123 'data_directory' => $this->getTestDirectoryUrl()
124 ));
125
126 return $encoder;
127 }
128
132 public function testInstanceCanBeCreated()
133 {
134 $security_flaw_ignoring_encoder = new ilBcryptPasswordEncoder(array(
135 'ignore_security_flaw' => true,
136 'data_directory' => $this->getTestDirectoryUrl()
137 ));
138 $this->assertTrue($security_flaw_ignoring_encoder->isSecurityFlawIgnored());
139
140 $security_flaw_respecting_encoder = new ilBcryptPasswordEncoder(array(
141 'ignore_security_flaw' => false,
142 'data_directory' => $this->getTestDirectoryUrl()
143 ));
144 $this->assertFalse($security_flaw_respecting_encoder->isSecurityFlawIgnored());
145
146 $encoder = new ilBcryptPasswordEncoder(array(
147 'cost' => self::VALID_COSTS,
148 'data_directory' => $this->getTestDirectoryUrl()
149 ));
150 $this->assertInstanceOf('ilBcryptPasswordEncoder', $encoder);
151 $this->assertEquals(self::VALID_COSTS, $encoder->getCosts());
152 $this->assertFalse($encoder->isSecurityFlawIgnored());
153 $encoder->setClientSalt(self::CLIENT_SALT);
154
155 return $encoder;
156 }
157
162 {
163 $encoder->setCosts(4);
164 $this->assertEquals(4, $encoder->getCosts());
165 }
166
172 {
173 $this->assertException(ilPasswordException::class);
174 $encoder->setCosts(32);
175 }
176
182 {
183 $this->assertException(ilPasswordException::class);
184 $encoder->setCosts(3);
185 }
186
191 public function testCostsCanBeSetInRange($costs, ilBcryptPasswordEncoder $encoder)
192 {
193 $encoder->setCosts($costs);
194 }
195
200 {
201 $encoder->setCosts(self::VALID_COSTS);
202 $encoded_password = $encoder->encodePassword(self::PASSWORD, self::PASSWORD_SALT);
203 $this->assertTrue($encoder->isPasswordValid($encoded_password, self::PASSWORD, self::PASSWORD_SALT));
204 $this->assertFalse($encoder->isPasswordValid($encoded_password, self::WRONG_PASSWORD, self::PASSWORD_SALT));
205 return $encoder;
206 }
207
213 {
214 $this->assertException(ilPasswordException::class);
215 $encoder->setCosts(self::VALID_COSTS);
216 $encoder->encodePassword(str_repeat('a', 5000), self::PASSWORD_SALT);
217 }
218
223 {
224 $encoder->setCosts(self::VALID_COSTS);
225 $this->assertFalse($encoder->isPasswordValid('encoded', str_repeat('a', 5000), self::PASSWORD_SALT));
226 }
227
232 {
233 $this->assertTrue($encoder->requiresSalt());
234 }
235
240 {
241 $this->assertFalse($encoder->requiresReencoding('hello'));
242 }
243
248 {
249 $this->assertEquals('bcrypt', $encoder->getName());
250 }
251
256 {
257 $this->assertException(ilPasswordException::class);
258 $encoder = $this->getInstanceWithConfiguredDataDirectory();
259 $encoder->setClientSalt(null);
260 $encoder->setCosts(self::VALID_COSTS);
261 $encoder->encodePassword(self::PASSWORD, self::PASSWORD_SALT);
262 }
263
268 {
269 $this->assertException(ilPasswordException::class);
270 $encoder = $this->getInstanceWithConfiguredDataDirectory();
271 $encoder->setClientSalt(null);
272 $encoder->setCosts(self::VALID_COSTS);
273 $encoder->isPasswordValid('12121212', self::PASSWORD, self::PASSWORD_SALT);
274 }
275
280 {
281 $this->getTestDirectory()->chmod(0777);
282 vfs\vfsStream::newFile(ilBcryptPasswordEncoder::SALT_STORAGE_FILENAME)->withContent(self::CLIENT_SALT)->at($this->getTestDirectory());
283
284 $encoder = $this->getInstanceWithConfiguredDataDirectory();
285 $this->assertEquals(self::CLIENT_SALT, $encoder->getClientSalt());
286 }
287
292 {
293 $this->getTestDirectory()->chmod(0777);
294
295 $encoder = $this->getInstanceWithConfiguredDataDirectory();
296 $this->assertNotNull($encoder->getClientSalt());
297 }
298
303 {
304 $this->assertException(ilPasswordException::class);
305 $this->getTestDirectory()->chmod(0000);
306
307 $encoder = $this->getInstanceWithConfiguredDataDirectory();
308 }
309
314 {
315 $encoder = $this->getInstanceWithConfiguredDataDirectory();
316 $encoder->setBackwardCompatibility(true);
317 $this->assertTrue($encoder->isBackwardCompatibilityEnabled());
318 $encoder->setBackwardCompatibility(false);
319 $this->assertFalse($encoder->isBackwardCompatibilityEnabled());
320 }
321
326 {
328
329 $encoder = $this->getInstanceWithConfiguredDataDirectory();
330 $encoder->setClientSalt(self::CLIENT_SALT);
331 $encoder->setBackwardCompatibility(true);
332 $encoded_password = $encoder->encodePassword(self::PASSWORD, self::PASSWORD_SALT);
333 $this->assertTrue($encoder->isPasswordValid($encoded_password, self::PASSWORD, self::PASSWORD_SALT));
334 $this->assertEquals('$2a$', substr($encoded_password, 0, 4));
335
336 $another_encoder = $this->getInstanceWithConfiguredDataDirectory();
337 $another_encoder->setClientSalt(self::CLIENT_SALT);
338 $another_encoder->setBackwardCompatibility(false);
339 $another_encoded_password = $another_encoder->encodePassword(self::PASSWORD, self::PASSWORD_SALT);
340 $this->assertEquals('$2y$', substr($another_encoded_password, 0, 4));
341 $this->assertTrue($another_encoder->isPasswordValid($encoded_password, self::PASSWORD, self::PASSWORD_SALT));
342 }
343
348 {
349 $this->assertException(ilPasswordException::class);
350 $encoder = $this->getInstanceWithConfiguredDataDirectory();
351 $encoder->setClientSalt(self::CLIENT_SALT);
352 $encoder->setBackwardCompatibility(true);
353 $encoder->encodePassword(self::PASSWORD . chr(195), self::PASSWORD_SALT);
354 }
355
360 {
361 $encoder = $this->getInstanceWithConfiguredDataDirectory();
362 $encoder->setClientSalt(self::CLIENT_SALT);
363 $encoder->setBackwardCompatibility(true);
364 $encoder->setIsSecurityFlawIgnored(true);
365 $encoder->encodePassword(self::PASSWORD . chr(195), self::PASSWORD_SALT);
366 }
367}
An exception for terminatinating execution or to throw for unit testing.
testPasswordVerificationShouldFailIfTheRawPasswordExceedsTheSupportedLength(ilBcryptPasswordEncoder $encoder)
@depends testInstanceCanBeCreated
testPasswordShouldBeCorrectlyEncodedAndVerified(ilBcryptPasswordEncoder $encoder)
@depends testInstanceCanBeCreated
testCostsCanBeRetrievedWhenCostsAreSet(ilBcryptPasswordEncoder $encoder)
@depends testInstanceCanBeCreated
testCostsCannotBeSetBelowRange(ilBcryptPasswordEncoder $encoder)
@depends testInstanceCanBeCreated @expectedException ilPasswordException
testCostsCanBeSetInRange($costs, ilBcryptPasswordEncoder $encoder)
@depends testInstanceCanBeCreated @dataProvider costsProvider
testExceptionIsRaisedIfSaltIsMissingIsOnEncoding()
@expectedException ilPasswordException
testExceptionIsRaisedIfTheRawPasswordContainsA8BitCharacterAndBackwardCompatibilityIsEnabled()
@expectedException ilPasswordException
testExceptionIsRaisedIfSaltIsMissingIsOnVerification()
@expectedException ilPasswordException
testExceptionIsNotRaisedIfTheRawPasswordContainsA8BitCharacterAndBackwardCompatibilityIsEnabledWithIgnoredSecurityFlaw()
testEncoderReliesOnSalts(ilBcryptPasswordEncoder $encoder)
@depends testInstanceCanBeCreated
testExceptionIsRaisedIfThePasswordExceedsTheSupportedLengthOnEncoding(ilBcryptPasswordEncoder $encoder)
@depends testInstanceCanBeCreated @expectedException ilPasswordException
testEncoderDoesNotSupportReencoding(ilBcryptPasswordEncoder $encoder)
@depends testInstanceCanBeCreated
testCostsCannotBeSetAboveRange(ilBcryptPasswordEncoder $encoder)
@depends testInstanceCanBeCreated @expectedException ilPasswordException
testNameShouldBeBcrypt(ilBcryptPasswordEncoder $encoder)
@depends testInstanceCanBeCreated
testExceptionIsRaisedWhenClientSaltCouldNotBeGeneratedInCaseNoClientSaltExistsYet()
@expectedException ilPasswordException
encodePassword($raw, $salt)
{{Encodes the raw password.string The encoded password}}
requiresReencoding($encoded)
{{{Returns whether or not the a encoded password needs to be re-encoded.boolean}}}
isPasswordValid($encoded, $raw, $salt)
{{Checks a raw password against an encoded password.The raw password has to be injected into the enco...
requiresSalt()
{{Returns whether or not the encoder requires a salt.boolean}}
assertException($exception_class)
$i
Definition: disco.tpl.php:19
$data
Definition: bench.php:6