19declare(strict_types=1);
22use PHPUnit\Framework\Attributes\DoesNotPerformAssertions;
23use PHPUnit\Framework\Attributes\DataProvider;
24use PHPUnit\Framework\Attributes\Depends;
59 return class_exists(
'org\bovigo\vfs\vfsStreamWrapper');
65 $this->markTestSkipped(
'Skipped test, vfsStream (https://github.com/bovigo/vfsStream) required');
67 vfs\vfsStream::setup();
68 $this->
setTestDirectory(vfs\vfsStream::newDirectory(
'test')->at(vfs\vfsStreamWrapper::getRoot()));
79 for ($i = 4; $i <= 31; ++$i) {
80 $data[sprintf(
'Costs: %s', $i)] = [(string) $i];
89 'data_directory' => $this->testDirectoryUrl
98 'ignore_security_flaw' =>
true,
99 'data_directory' => $this->testDirectoryUrl
101 $this->assertTrue($security_flaw_ignoring_encoder->isSecurityFlawIgnored());
104 'ignore_security_flaw' =>
false,
105 'data_directory' => $this->testDirectoryUrl
107 $this->assertFalse($security_flaw_respecting_encoder->isSecurityFlawIgnored());
110 'cost' => self::VALID_COSTS,
111 'data_directory' => $this->testDirectoryUrl
113 $this->assertInstanceOf(ilBcryptPasswordEncoder::class, $encoder);
114 $this->assertSame(self::VALID_COSTS, $encoder->getCosts());
115 $this->assertFalse($encoder->isSecurityFlawIgnored());
116 $encoder->setClientSalt(self::CLIENT_SALT);
121 #[Depends('testInstanceCanBeCreated')]
127 $this->assertSame($expected, $encoder->
getCosts());
130 #[Depends('testInstanceCanBeCreated')]
133 $this->expectException(ilPasswordException::class);
137 #[Depends('testInstanceCanBeCreated')]
140 $this->expectException(ilPasswordException::class);
144 #[DoesNotPerformAssertions]
145 #[Depends('testInstanceCanBeCreated')]
146 #[DataProvider('costsProvider')]
152 #[Depends('testInstanceCanBeCreated')]
157 $encoded_password = $encoder->
encodePassword(self::PASSWORD, self::PASSWORD_SALT);
158 $this->assertTrue($encoder->
isPasswordValid($encoded_password, self::PASSWORD, self::PASSWORD_SALT));
159 $this->assertFalse($encoder->
isPasswordValid($encoded_password, self::WRONG_PASSWORD, self::PASSWORD_SALT));
164 #[Depends('testInstanceCanBeCreated')]
169 $encoder->
setCosts(self::VALID_COSTS);
170 $encoder->
encodePassword(str_repeat(
'a', 5000), self::PASSWORD_SALT);
173 #[Depends('testInstanceCanBeCreated')]
177 $encoder->setCosts(self::VALID_COSTS);
178 $this->assertFalse($encoder->
isPasswordValid(
'encoded', str_repeat(
'a', 5000), self::PASSWORD_SALT));
181 #[Depends('testInstanceCanBeCreated')]
187 #[Depends('testInstanceCanBeCreated')]
193 #[Depends('testInstanceCanBeCreated')]
196 $this->assertSame(
'bcrypt', $encoder->
getName());
201 $this->skipIfvfsStreamNotSupported();
203 $this->expectException(ilPasswordException::class);
204 $encoder = $this->getInstanceWithConfiguredDataDirectory();
206 $encoder->
setCosts(self::VALID_COSTS);
212 $this->skipIfvfsStreamNotSupported();
214 $this->expectException(ilPasswordException::class);
215 $encoder = $this->getInstanceWithConfiguredDataDirectory();
217 $encoder->
setCosts(self::VALID_COSTS);
218 $encoder->
isPasswordValid(
'12121212', self::PASSWORD, self::PASSWORD_SALT);
223 $this->skipIfvfsStreamNotSupported();
225 $this->testDirectory->chmod(0777);
228 $encoder = $this->getInstanceWithConfiguredDataDirectory();
229 $this->assertSame(self::CLIENT_SALT, $encoder->
getClientSalt());
234 $this->skipIfvfsStreamNotSupported();
236 $this->testDirectory->chmod(0777);
238 $encoder = $this->getInstanceWithConfiguredDataDirectory();
244 $this->skipIfvfsStreamNotSupported();
246 $this->expectException(ilPasswordException::class);
247 $this->testDirectory->chmod(0000);
249 $this->getInstanceWithConfiguredDataDirectory();
254 $this->skipIfvfsStreamNotSupported();
256 $encoder = $this->getInstanceWithConfiguredDataDirectory();
265 $this->skipIfvfsStreamNotSupported();
267 $encoder = $this->getInstanceWithConfiguredDataDirectory();
271 $encoded_password = $encoder->
encodePassword(self::PASSWORD, self::PASSWORD_SALT);
272 $this->assertTrue($encoder->
isPasswordValid($encoded_password, self::PASSWORD, self::PASSWORD_SALT));
273 $this->assertSame(
'$2a$', substr($encoded_password, 0, 4));
275 $another_encoder = $this->getInstanceWithConfiguredDataDirectory();
276 $another_encoder->setClientSalt(self::CLIENT_SALT);
278 $another_encoder->setBackwardCompatibility(
false);
279 $another_encoded_password = $another_encoder->encodePassword(self::PASSWORD, self::PASSWORD_SALT);
280 $this->assertSame(
'$2y$', substr($another_encoded_password, 0, 4));
281 $this->assertTrue($another_encoder->isPasswordValid($encoded_password, self::PASSWORD, self::PASSWORD_SALT));
286 $this->skipIfvfsStreamNotSupported();
288 $this->expectException(ilPasswordException::class);
289 $encoder = $this->getInstanceWithConfiguredDataDirectory();
292 $encoder->
encodePassword(self::PASSWORD . chr(195), self::PASSWORD_SALT);
295 #[DoesNotPerformAssertions]
298 $this->skipIfvfsStreamNotSupported();
300 $encoder = $this->getInstanceWithConfiguredDataDirectory();
304 $encoder->
encodePassword(self::PASSWORD . chr(195), self::PASSWORD_SALT);
testClientSaltIsGeneratedWhenNoClientSaltExistsYet()
testCostsCanBeSetInRange(string $costs, ilBcryptPasswordEncoder $encoder)
testInstanceCanBeCreatedAndInitializedWithClientSalt()
const string WRONG_PASSWORD
testPasswordVerificationShouldFailIfTheRawPasswordExceedsTheSupportedLength(ilBcryptPasswordEncoder $encoder)
setTestDirectory(vfs\vfsStreamDirectory $testDirectory)
getInstanceWithConfiguredDataDirectory()
testPasswordShouldBeCorrectlyEncodedAndVerified(ilBcryptPasswordEncoder $encoder)
testCostsCanBeRetrievedWhenCostsAreSet(ilBcryptPasswordEncoder $encoder)
testBackwardCompatibilityCanBeRetrievedWhenBackwardCompatibilityIsSet()
const string PASSWORD_SALT
testCostsCannotBeSetBelowRange(ilBcryptPasswordEncoder $encoder)
testExceptionIfPasswordsContainA8BitCharacterAndBackwardCompatibilityIsEnabled()
testNoExceptionIfPasswordsContainA8BitCharacterAndBackwardCompatibilityIsEnabledWithIgnoredSecurityFlaw()
vfs vfsStreamDirectory $testDirectory
setTestDirectoryUrl(string $testDirectoryUrl)
testExceptionIsRaisedIfSaltIsMissingIsOnEncoding()
testInstanceCanBeCreated()
testExceptionIsRaisedIfSaltIsMissingIsOnVerification()
testEncoderReliesOnSalts(ilBcryptPasswordEncoder $encoder)
testExceptionIsRaisedIfThePasswordExceedsTheSupportedLengthOnEncoding(ilBcryptPasswordEncoder $encoder)
testBackwardCompatibility()
testEncoderDoesNotSupportReencoding(ilBcryptPasswordEncoder $encoder)
testCostsCannotBeSetAboveRange(ilBcryptPasswordEncoder $encoder)
skipIfvfsStreamNotSupported()
testNameShouldBeBcrypt(ilBcryptPasswordEncoder $encoder)
testExceptionIsRaisedWhenClientSaltCouldNotBeGeneratedInCaseNoClientSaltExistsYet()
encodePassword(string $raw, string $salt)
Encodes the raw password.
getName()
Returns a unique name/id of the concrete password encoder.
setBackwardCompatibility(bool $backward_compatibility)
Set the backward compatibility $2a$ instead of $2y$ for PHP 5.3.7+.
const string SALT_STORAGE_FILENAME
isBackwardCompatibilityEnabled()
requiresSalt()
Returns whether the encoder requires a salt.
isPasswordValid(string $encoded, string $raw, string $salt)
Checks a raw password against an encoded password.
setClientSalt(?string $client_salt)
requiresReencoding(string $encoded)
Returns whether the encoded password needs to be re-encoded.
setIsSecurityFlawIgnored(bool $is_security_flaw_ignored)
Class for user password exception handling in ILIAS.