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 
4 require_once 'Services/Password/classes/encoders/class.ilBcryptPasswordEncoder.php';
5 require_once 'Services/Password/test/ilPasswordBaseTest.php';
6 
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  {
56  return $this->test_directory;
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 
98  private function skipIfPhpVersionIsNotSupported()
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 
325  public function testBackwardCompatibility()
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 }
testCostsCannotBeSetAboveRange(ilBcryptPasswordEncoder $encoder)
testInstanceCanBeCreated ilPasswordException
encodePassword($raw, $salt)
{Encodes the raw password.The password to encode The salt string The encoded password} ...
requiresSalt()
{Returns whether or not the encoder requires a salt.boolean}
testCostsCanBeRetrievedWhenCostsAreSet(ilBcryptPasswordEncoder $encoder)
testInstanceCanBeCreated
testEncoderDoesNotSupportReencoding(ilBcryptPasswordEncoder $encoder)
testInstanceCanBeCreated
testCostsCanBeSetInRange($costs, ilBcryptPasswordEncoder $encoder)
testInstanceCanBeCreated costsProvider
requiresReencoding($encoded)
{Returns whether or not the a encoded password needs to be re-encoded.string boolean} ...
testExceptionIsNotRaisedIfTheRawPasswordContainsA8BitCharacterAndBackwardCompatibilityIsEnabledWithIgnoredSecurityFlaw()
testPasswordShouldBeCorrectlyEncodedAndVerified(ilBcryptPasswordEncoder $encoder)
testInstanceCanBeCreated
testExceptionIsRaisedIfSaltIsMissingIsOnEncoding()
ilPasswordException
testExceptionIsRaisedIfThePasswordExceedsTheSupportedLengthOnEncoding(ilBcryptPasswordEncoder $encoder)
testInstanceCanBeCreated ilPasswordException
testExceptionIsRaisedIfSaltIsMissingIsOnVerification()
ilPasswordException
testPasswordVerificationShouldFailIfTheRawPasswordExceedsTheSupportedLength(ilBcryptPasswordEncoder $encoder)
testInstanceCanBeCreated
getName()
{Returns a unique name/id of the concrete password encoder.string}
testExceptionIsRaisedIfTheRawPasswordContainsA8BitCharacterAndBackwardCompatibilityIsEnabled()
ilPasswordException
testExceptionIsRaisedWhenClientSaltCouldNotBeGeneratedInCaseNoClientSaltExistsYet()
ilPasswordException
testCostsCannotBeSetBelowRange(ilBcryptPasswordEncoder $encoder)
testInstanceCanBeCreated ilPasswordException
testNameShouldBeBcrypt(ilBcryptPasswordEncoder $encoder)
testInstanceCanBeCreated
$i
Definition: disco.tpl.php:19
testEncoderReliesOnSalts(ilBcryptPasswordEncoder $encoder)
testInstanceCanBeCreated
isPasswordValid($encoded, $raw, $salt)
{Checks a raw password against an encoded password.The raw password has to be injected into the encod...
assertException($exception_class)
$data
Definition: bench.php:6