ILIAS  release_7 Revision v7.30-3-g800a261c036
All Data Structures Namespaces Files Functions Variables Modules Pages
ilBcryptPasswordEncoderTest.php
Go to the documentation of this file.
1 <?php declare(strict_types=1);
2 /* Copyright (c) 1998-2014 ILIAS open source, Extended GPL, see docs/LICENSE */
3 
4 require_once 'Services/Password/classes/encoders/class.ilBcryptPasswordEncoder.php';
5 require_once 'Services/Password/test/ilPasswordBaseTest.php';
6 
8 
15 {
17  const VALID_COSTS = '08';
18 
20  const PASSWORD = 'password';
21 
23  const WRONG_PASSWORD = 'wrong_password';
24 
26  const CLIENT_SALT = 'homer!12345_/';
27 
29  const PASSWORD_SALT = 'salt';
30 
32  protected $testDirectory;
33 
35  protected $testDirectoryUrl;
36 
40  public function getTestDirectory() : vfs\vfsStreamDirectory
41  {
42  return $this->testDirectory;
43  }
44 
48  public function setTestDirectory(vfs\vfsStreamDirectory $testDirectory) : void
49  {
50  $this->testDirectory = $testDirectory;
51  }
52 
56  public function getTestDirectoryUrl() : string
57  {
59  }
60 
64  public function setTestDirectoryUrl(string $testDirectoryUrl) : void
65  {
66  $this->testDirectoryUrl = $testDirectoryUrl;
67  }
68 
72  private function skipIfPhpVersionIsNotSupported() : void
73  {
74  if (version_compare(phpversion(), '5.3.7', '<')) {
75  $this->markTestSkipped('Requires PHP >= 5.3.7');
76  }
77  }
78 
82  private function isVsfStreamInstalled() : bool
83  {
84  return class_exists('org\bovigo\vfs\vfsStreamWrapper');
85  }
86 
90  private function skipIfvfsStreamNotSupported() : void
91  {
92  if (!$this->isVsfStreamInstalled()) {
93  $this->markTestSkipped('Skipped test, vfsStream (http://vfs.bovigo.org) required');
94  } else {
95  vfs\vfsStream::setup();
96  $this->setTestDirectory(vfs\vfsStream::newDirectory('tests')->at(vfs\vfsStreamWrapper::getRoot()));
97  $this->setTestDirectoryUrl(vfs\vfsStream::url('root/tests'));
98  }
99  }
100 
104  public function costsProvider() : array
105  {
106  $data = [];
107  for ($i = 4; $i <= 31; $i++) {
108  $data[sprintf("Costs: %s", (string) $i)] = [(string) $i];
109  }
110 
111  return $data;
112  }
113 
119  {
120  $encoder = new ilBcryptPasswordEncoder(array(
121  'data_directory' => $this->getTestDirectoryUrl()
122  ));
123 
124  return $encoder;
125  }
126 
132  {
134 
135  $security_flaw_ignoring_encoder = new ilBcryptPasswordEncoder([
136  'ignore_security_flaw' => true,
137  'data_directory' => $this->getTestDirectoryUrl()
138  ]);
139  $this->assertTrue($security_flaw_ignoring_encoder->isSecurityFlawIgnored());
140 
141  $security_flaw_respecting_encoder = new ilBcryptPasswordEncoder([
142  'ignore_security_flaw' => false,
143  'data_directory' => $this->getTestDirectoryUrl()
144  ]);
145  $this->assertFalse($security_flaw_respecting_encoder->isSecurityFlawIgnored());
146 
147  $encoder = new ilBcryptPasswordEncoder([
148  'cost' => self::VALID_COSTS,
149  'data_directory' => $this->getTestDirectoryUrl()
150  ]);
151  $this->assertInstanceOf('ilBcryptPasswordEncoder', $encoder);
152  $this->assertEquals(self::VALID_COSTS, $encoder->getCosts());
153  $this->assertFalse($encoder->isSecurityFlawIgnored());
154  $encoder->setClientSalt(self::CLIENT_SALT);
155 
156  return $encoder;
157  }
158 
165  {
166  $expected = '04';
167 
168  $encoder->setCosts($expected);
169  $this->assertEquals($expected, $encoder->getCosts());
170  }
171 
178  {
179  $this->expectException(ilPasswordException::class);
180  $encoder->setCosts('32');
181  }
182 
189  {
190  $this->expectException(ilPasswordException::class);
191  $encoder->setCosts('3');
192  }
193 
202  public function testCostsCanBeSetInRange(string $costs, ilBcryptPasswordEncoder $encoder) : void
203  {
204  $encoder->setCosts($costs);
205  }
206 
214  ilBcryptPasswordEncoder $encoder
216  $encoder->setCosts(self::VALID_COSTS);
217  $encoded_password = $encoder->encodePassword(self::PASSWORD, self::PASSWORD_SALT);
218  $this->assertTrue($encoder->isPasswordValid($encoded_password, self::PASSWORD, self::PASSWORD_SALT));
219  $this->assertFalse($encoder->isPasswordValid($encoded_password, self::WRONG_PASSWORD, self::PASSWORD_SALT));
220  return $encoder;
221  }
222 
229  ilBcryptPasswordEncoder $encoder
230  ) : void {
231  $this->expectException(ilPasswordException::class);
232  $encoder->setCosts(self::VALID_COSTS);
233  $encoder->encodePassword(str_repeat('a', 5000), self::PASSWORD_SALT);
234  }
235 
242  ilBcryptPasswordEncoder $encoder
243  ) : void {
244  $encoder->setCosts(self::VALID_COSTS);
245  $this->assertFalse($encoder->isPasswordValid('encoded', str_repeat('a', 5000), self::PASSWORD_SALT));
246  }
247 
252  public function testEncoderReliesOnSalts(ilBcryptPasswordEncoder $encoder) : void
253  {
254  $this->assertTrue($encoder->requiresSalt());
255  }
256 
262  {
263  $this->assertFalse($encoder->requiresReencoding('hello'));
264  }
265 
270  public function testNameShouldBeBcrypt(ilBcryptPasswordEncoder $encoder) : void
271  {
272  $this->assertEquals('bcrypt', $encoder->getName());
273  }
274 
279  {
281 
282  $this->expectException(ilPasswordException::class);
283  $encoder = $this->getInstanceWithConfiguredDataDirectory();
284  $encoder->setClientSalt(null);
285  $encoder->setCosts(self::VALID_COSTS);
286  $encoder->encodePassword(self::PASSWORD, self::PASSWORD_SALT);
287  }
288 
293  {
295 
296  $this->expectException(ilPasswordException::class);
297  $encoder = $this->getInstanceWithConfiguredDataDirectory();
298  $encoder->setClientSalt(null);
299  $encoder->setCosts(self::VALID_COSTS);
300  $encoder->isPasswordValid('12121212', self::PASSWORD, self::PASSWORD_SALT);
301  }
302 
307  {
309 
310  $this->getTestDirectory()->chmod(0777);
311  vfs\vfsStream::newFile(ilBcryptPasswordEncoder::SALT_STORAGE_FILENAME)->withContent(self::CLIENT_SALT)->at($this->getTestDirectory());
312 
313  $encoder = $this->getInstanceWithConfiguredDataDirectory();
314  $this->assertEquals(self::CLIENT_SALT, $encoder->getClientSalt());
315  }
316 
321  {
323 
324  $this->getTestDirectory()->chmod(0777);
325 
326  $encoder = $this->getInstanceWithConfiguredDataDirectory();
327  $this->assertNotNull($encoder->getClientSalt());
328  }
329 
334  {
336 
337  $this->expectException(ilPasswordException::class);
338  $this->getTestDirectory()->chmod(0000);
339 
341  }
342 
347  {
349 
350  $encoder = $this->getInstanceWithConfiguredDataDirectory();
351  $encoder->setBackwardCompatibility(true);
352  $this->assertTrue($encoder->isBackwardCompatibilityEnabled());
353  $encoder->setBackwardCompatibility(false);
354  $this->assertFalse($encoder->isBackwardCompatibilityEnabled());
355  }
356 
360  public function testBackwardCompatibility() : void
361  {
364 
365  $encoder = $this->getInstanceWithConfiguredDataDirectory();
366  $encoder->setClientSalt(self::CLIENT_SALT);
367  $encoder->setBackwardCompatibility(true);
368  $encoded_password = $encoder->encodePassword(self::PASSWORD, self::PASSWORD_SALT);
369  $this->assertTrue($encoder->isPasswordValid($encoded_password, self::PASSWORD, self::PASSWORD_SALT));
370  $this->assertEquals('$2a$', substr($encoded_password, 0, 4));
371 
372  $another_encoder = $this->getInstanceWithConfiguredDataDirectory();
373  $another_encoder->setClientSalt(self::CLIENT_SALT);
374  $another_encoder->setBackwardCompatibility(false);
375  $another_encoded_password = $another_encoder->encodePassword(self::PASSWORD, self::PASSWORD_SALT);
376  $this->assertEquals('$2y$', substr($another_encoded_password, 0, 4));
377  $this->assertTrue($another_encoder->isPasswordValid($encoded_password, self::PASSWORD, self::PASSWORD_SALT));
378  }
379 
384  {
386 
387  $this->expectException(ilPasswordException::class);
388  $encoder = $this->getInstanceWithConfiguredDataDirectory();
389  $encoder->setClientSalt(self::CLIENT_SALT);
390  $encoder->setBackwardCompatibility(true);
391  $encoder->encodePassword(self::PASSWORD . chr(195), self::PASSWORD_SALT);
392  }
393 
399  {
401 
402  $encoder = $this->getInstanceWithConfiguredDataDirectory();
403  $encoder->setClientSalt(self::CLIENT_SALT);
404  $encoder->setBackwardCompatibility(true);
405  $encoder->setIsSecurityFlawIgnored(true);
406  $encoder->encodePassword(self::PASSWORD . chr(195), self::PASSWORD_SALT);
407  }
408 }
testCostsCannotBeSetAboveRange(ilBcryptPasswordEncoder $encoder)
testInstanceCanBeCreated
$data
Definition: storeScorm.php:23
testCostsCanBeRetrievedWhenCostsAreSet(ilBcryptPasswordEncoder $encoder)
testInstanceCanBeCreated
encodePassword(string $raw, string $salt)
testEncoderDoesNotSupportReencoding(ilBcryptPasswordEncoder $encoder)
testInstanceCanBeCreated
setTestDirectory(vfs\vfsStreamDirectory $testDirectory)
testPasswordShouldBeCorrectlyEncodedAndVerified(ilBcryptPasswordEncoder $encoder)
testInstanceCanBeCreated
testExceptionIsRaisedIfThePasswordExceedsTheSupportedLengthOnEncoding(ilBcryptPasswordEncoder $encoder)
testInstanceCanBeCreated
testPasswordVerificationShouldFailIfTheRawPasswordExceedsTheSupportedLength(ilBcryptPasswordEncoder $encoder)
testInstanceCanBeCreated
testCostsCanBeSetInRange(string $costs, ilBcryptPasswordEncoder $encoder)
testInstanceCanBeCreated costsProvider
testCostsCannotBeSetBelowRange(ilBcryptPasswordEncoder $encoder)
testInstanceCanBeCreated
testNameShouldBeBcrypt(ilBcryptPasswordEncoder $encoder)
testInstanceCanBeCreated
testEncoderReliesOnSalts(ilBcryptPasswordEncoder $encoder)
testInstanceCanBeCreated
setTestDirectoryUrl(string $testDirectoryUrl)
isPasswordValid(string $encoded, string $raw, string $salt)
$i
Definition: metadata.php:24
testNoExceptionIfPasswordsContainA8BitCharacterAndBackwardCompatibilityIsEnabledWithIgnoredSecurityFlaw()