Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 23 additions & 10 deletions src/Definition/PasswordDefinition.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,49 +55,62 @@ public function getRule($rule): string|bool|int
return $this->rules[$rule];
}

public function matchPassword(string $password): bool
const SUCCESS = 0;
const FAIL_MINIMUM_CHARS = 1;
const FAIL_UPPERCASE = 2;
const FAIL_LOWERCASE = 4;
const FAIL_SYMBOLS = 8;
const FAIL_NUMBERS = 16;
const FAIL_WHITESPACE = 32;
const FAIL_SEQUENTIAL = 64;
const FAIL_REPEATED = 128;

public function matchPassword(string $password): int
{
$result = 0;

// match password against the rules
if (strlen($password) < $this->rules[self::MINIMUM_CHARS]) {
return false;
$result |= PasswordDefinition::FAIL_MINIMUM_CHARS;
}
if ($this->rules[self::REQUIRE_UPPERCASE] > 0) {
if (preg_match_all('/[A-Z]/', $password, $matches) < $this->rules[self::REQUIRE_UPPERCASE]) {
return false;
$result |= PasswordDefinition::FAIL_UPPERCASE;
}
}
if ($this->rules[self::REQUIRE_LOWERCASE] > 0) {
if (preg_match_all('/[a-z]/', $password, $matches) < $this->rules[self::REQUIRE_LOWERCASE]) {
return false;
$result |= PasswordDefinition::FAIL_LOWERCASE;
}
}
if ($this->rules[self::REQUIRE_SYMBOLS] > 0) {
if (preg_match_all('/[!@#$%^&*()\-_=+{};:,<.>]/', $password, $matches) < $this->rules[self::REQUIRE_SYMBOLS]) {
return false;
$result |= PasswordDefinition::FAIL_SYMBOLS;
}
}
if ($this->rules[self::REQUIRE_NUMBERS] > 0) {
if (preg_match_all('/[0-9]/', $password, $matches) < $this->rules[self::REQUIRE_NUMBERS]) {
return false;
$result |= PasswordDefinition::FAIL_NUMBERS;
}
}
if ($this->rules[self::ALLOW_WHITESPACE] == 0) {
if (preg_match_all('/\s/', $password, $matches) > 0) {
return false;
$result |= PasswordDefinition::FAIL_WHITESPACE;
}
}
if ($this->rules[self::ALLOW_SEQUENTIAL] == 0) {
if (preg_match_all('/([aA][bB][cC]|[bB][cC][dD]|[cC][dD][eE]|[dD][eE][fF]|[eE][fF][gG]|[fF][gG][hH]|[gG][hH][iI]|[hH][iI][jJ]|[iI][jJ][kK]|[jJ][kK][lL]|[kK][lL][mM]|[lL][mM][nN]|[mM][nN][oO]|[nN][oO][pP]|[oO][pP][qQ]|[pP][qQ][rR]|[qQ][rR][sS]|[rR][sS][tT]|[sS][tT][uU]|[tT][uU][vV]|[uU][vV][wW]|[vV][wW][xX]|[wW][xX][yY]|[xX][yY][zZ]|012|123|234|345|456|567|678|789|890|987|876|765|654|543|432|321)/', $password, $matches) > 0) {
return false;
$result |= PasswordDefinition::FAIL_SEQUENTIAL;
}

}
if ($this->rules[self::ALLOW_REPEATED] == 0) {
if (preg_match_all('/(..?)\1{2,}/', $password, $matches) > 0) {
return false;
$result |= PasswordDefinition::FAIL_REPEATED;
}
}
return true;

return $result;
}


Expand Down
8 changes: 6 additions & 2 deletions src/Model/UserModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,13 @@ public function getPassword(): ?string
public function setPassword(?string $password): void
{
// Password len equals to 40 means that the password is already encrypted with sha1
if (!empty($password) && strlen($password) != 40 && !empty($this->passwordDefinition) && !$this->passwordDefinition->matchPassword($password)) {
throw new InvalidArgumentException("Password does not match the password definition");
if (!empty($this->passwordDefinition) && !empty($password) && strlen($password) != 40) {
$match = $this->passwordDefinition->matchPassword($password);
if ($match != PasswordDefinition::SUCCESS) {
throw new InvalidArgumentException("Password does not match the password definition [{$match}]");
}
}

$this->password = $password;
}

Expand Down
3 changes: 2 additions & 1 deletion src/UsersDBDataset.php
Original file line number Diff line number Diff line change
Expand Up @@ -411,10 +411,11 @@ public function getProperty(string|HexUuidLiteral|int $userId, string $propertyN
* Return all property's fields from this user
*
* @param UserModel $userRow
* @throws RepositoryReadOnlyException
*/
protected function setPropertiesInUser(UserModel $userRow): void
{
$value = $this->propertiesRepository->getMapper()->getFieldMap(UserDefinition::FIELD_USERID)->getUpdateFunctionValue($userRow->getUserid(), $userRow);
$value = $this->propertiesRepository->getMapper()->getFieldMap(UserDefinition::FIELD_USERID)->getUpdateFunctionValue($userRow->getUserid(), $userRow, $this->propertiesRepository->getDbDriverWrite()->getDbHelper());
$query = Query::getInstance()
->table($this->getUserPropertiesDefinition()->table())
->where("{$this->getUserPropertiesDefinition()->getUserid()} = :id", ['id' => $value]);
Expand Down
48 changes: 24 additions & 24 deletions tests/PasswordDefinitionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ public function testMatchPasswordMinimumChars()
PasswordDefinition::ALLOW_SEQUENTIAL => 1, // Allow sequential characters
PasswordDefinition::ALLOW_REPEATED => 1 // Allow repeated characters
]);
$this->assertFalse($passwordDefinition->matchPassword('1234567'));
$this->assertTrue($passwordDefinition->matchPassword('12345678'));
$this->assertEquals(PasswordDefinition::FAIL_MINIMUM_CHARS, $passwordDefinition->matchPassword('1234567'));
$this->assertEquals(PasswordDefinition::SUCCESS, $passwordDefinition->matchPassword('12345678'));
}

public function testMatchPasswordUppercase()
Expand All @@ -80,9 +80,9 @@ public function testMatchPasswordUppercase()
PasswordDefinition::ALLOW_SEQUENTIAL => 1, // Allow sequential characters
PasswordDefinition::ALLOW_REPEATED => 1 // Allow repeated characters
]);
$this->assertFalse($passwordDefinition->matchPassword('12345678'));
$this->assertFalse($passwordDefinition->matchPassword('12345678A'));
$this->assertTrue($passwordDefinition->matchPassword('1234567BA'));
$this->assertEquals(PasswordDefinition::FAIL_UPPERCASE, $passwordDefinition->matchPassword('12345678'));
$this->assertEquals(PasswordDefinition::FAIL_UPPERCASE, $passwordDefinition->matchPassword('12345678A'));
$this->assertEquals(PasswordDefinition::SUCCESS, $passwordDefinition->matchPassword('1234567BA'));
}

public function testMatchPasswordLowercase()
Expand All @@ -97,9 +97,9 @@ public function testMatchPasswordLowercase()
PasswordDefinition::ALLOW_SEQUENTIAL => 1, // Allow sequential characters
PasswordDefinition::ALLOW_REPEATED => 1 // Allow repeated characters
]);
$this->assertFalse($passwordDefinition->matchPassword('12345678'));
$this->assertFalse($passwordDefinition->matchPassword('12345678a'));
$this->assertTrue($passwordDefinition->matchPassword('1234567ba'));
$this->assertEquals(PasswordDefinition::FAIL_LOWERCASE, $passwordDefinition->matchPassword('12345678'));
$this->assertEquals(PasswordDefinition::FAIL_LOWERCASE, $passwordDefinition->matchPassword('12345678a'));
$this->assertEquals(PasswordDefinition::SUCCESS, $passwordDefinition->matchPassword('1234567ba'));
}

public function testMatchPasswordSymbols()
Expand All @@ -114,9 +114,9 @@ public function testMatchPasswordSymbols()
PasswordDefinition::ALLOW_SEQUENTIAL => 1, // Allow sequential characters
PasswordDefinition::ALLOW_REPEATED => 1 // Allow repeated characters
]);
$this->assertFalse($passwordDefinition->matchPassword('12345678'));
$this->assertFalse($passwordDefinition->matchPassword('12345678!'));
$this->assertTrue($passwordDefinition->matchPassword('1234567!!'));
$this->assertEquals(PasswordDefinition::FAIL_SYMBOLS, $passwordDefinition->matchPassword('12345678'));
$this->assertEquals(PasswordDefinition::FAIL_SYMBOLS, $passwordDefinition->matchPassword('12345678!'));
$this->assertEquals(PasswordDefinition::SUCCESS, $passwordDefinition->matchPassword('1234567!!'));
}

public function testMatchPasswordNumbers()
Expand All @@ -131,9 +131,9 @@ public function testMatchPasswordNumbers()
PasswordDefinition::ALLOW_SEQUENTIAL => 1, // Allow sequential characters
PasswordDefinition::ALLOW_REPEATED => 1 // Allow repeated characters
]);
$this->assertFalse($passwordDefinition->matchPassword('abcdefgh'));
$this->assertFalse($passwordDefinition->matchPassword('abcdefg1'));
$this->assertTrue($passwordDefinition->matchPassword('abcdef11'));
$this->assertEquals(PasswordDefinition::FAIL_NUMBERS, $passwordDefinition->matchPassword('abcdefgh'));
$this->assertEquals(PasswordDefinition::FAIL_NUMBERS, $passwordDefinition->matchPassword('abcdefg1'));
$this->assertEquals(PasswordDefinition::SUCCESS, $passwordDefinition->matchPassword('abcdef11'));
}

public function testMatchPasswordWhitespace()
Expand All @@ -148,7 +148,7 @@ public function testMatchPasswordWhitespace()
PasswordDefinition::ALLOW_SEQUENTIAL => 1, // Allow sequential characters
PasswordDefinition::ALLOW_REPEATED => 1 // Allow repeated characters
]);
$this->assertFalse($passwordDefinition->matchPassword('1234 678'));
$this->assertEquals(PasswordDefinition::FAIL_WHITESPACE, $passwordDefinition->matchPassword('1234 678'));
}

public function testMatchPasswordSequential()
Expand All @@ -163,11 +163,11 @@ public function testMatchPasswordSequential()
PasswordDefinition::ALLOW_SEQUENTIAL => 0, // Allow sequential characters
PasswordDefinition::ALLOW_REPEATED => 1 // Allow repeated characters
]);
$this->assertFalse($passwordDefinition->matchPassword('123asdkls')); // 123 is sequential
$this->assertFalse($passwordDefinition->matchPassword('sds456sks')); // 456 is sequential
$this->assertFalse($passwordDefinition->matchPassword('aju654sks')); // 654 is sequential
$this->assertFalse($passwordDefinition->matchPassword('791fghkalal')); // fgh is sequential
$this->assertTrue($passwordDefinition->matchPassword('diykdsn132'));
$this->assertEquals(PasswordDefinition::FAIL_SEQUENTIAL, $passwordDefinition->matchPassword('123asdkls')); // 123 is sequential
$this->assertEquals(PasswordDefinition::FAIL_SEQUENTIAL, $passwordDefinition->matchPassword('sds456sks')); // 456 is sequential
$this->assertEquals(PasswordDefinition::FAIL_SEQUENTIAL, $passwordDefinition->matchPassword('aju654sks')); // 654 is sequential
$this->assertEquals(PasswordDefinition::FAIL_SEQUENTIAL, $passwordDefinition->matchPassword('791fghkalal')); // fgh is sequential
$this->assertEquals(PasswordDefinition::SUCCESS, $passwordDefinition->matchPassword('diykdsn132'));
}

public function testMatchCharsRepeated()
Expand All @@ -183,9 +183,9 @@ public function testMatchCharsRepeated()
PasswordDefinition::ALLOW_REPEATED => 0 // Allow repeated characters
]);

$this->assertFalse($passwordDefinition->matchPassword('hay111oihsc')); // 111 is repeated
$this->assertFalse($passwordDefinition->matchPassword('haycccoihsc')); // ccc is repeated
$this->assertFalse($passwordDefinition->matchPassword('oilalalapo')); // lalala is repeated
$this->assertTrue($passwordDefinition->matchPassword('hay1d11oihsc'));
$this->assertEquals(PasswordDefinition::FAIL_REPEATED, $passwordDefinition->matchPassword('hay111oihsc')); // 111 is repeated
$this->assertEquals(PasswordDefinition::FAIL_REPEATED, $passwordDefinition->matchPassword('haycccoihsc')); // ccc is repeated
$this->assertEquals(PasswordDefinition::FAIL_REPEATED, $passwordDefinition->matchPassword('oilalalapo')); // lalala is repeated
$this->assertEquals(PasswordDefinition::SUCCESS, $passwordDefinition->matchPassword('hay1d11oihsc'));
}
}
Loading