1
0
Fork 0
mirror of https://github.com/archtechx/tenancy.git synced 2026-05-06 15:24:03 +00:00

Validate user passwords in DB managers

Also, make the validateParameter method ignore null parameters, e.g. for cases when tenants are created using Tenant::make() without tenancy_db_username set -- $databaseConfig->getUsername() allows null, same should go for the validate method whose only concern is checking strings for invalid characters.
This commit is contained in:
lukinovec 2026-04-29 17:22:24 +02:00
parent db03997339
commit 0fdb8b2041
4 changed files with 43 additions and 7 deletions

View file

@ -28,8 +28,8 @@ trait ManagesPostgresUsers
$username = $databaseConfig->getUsername(); $username = $databaseConfig->getUsername();
$password = $databaseConfig->getPassword(); $password = $databaseConfig->getPassword();
// todo@validation password
$this->validateParameter($username); $this->validateParameter($username);
$this->validatePassword($password);
$createUser = ! $this->userExists($username); $createUser = ! $this->userExists($username);

View file

@ -18,22 +18,58 @@ trait ValidatesSqlParameters
return 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-'; return 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-';
} }
/**
* Characters allowed in database user passwords.
*
* Passwords are always quoted in the SQL statements, so it's safe
* to allow a wider range of characters, as long as it doesn't include
* characters that can break out of the quoted SQL strings (so e.g.
* ', ", \, and ` aren't allowed).
*/
protected static function passwordAllowlist(): string
{
return ' !#$%&()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_abcdefghijklmnopqrstuvwxyz{|}~';
}
/** /**
* Validate that parameters (database names, usernames, etc.) * Validate that parameters (database names, usernames, etc.)
* contain only allowed characters before used in SQL statements. * only contain allowed characters before used in SQL statements.
*
* By default, only the characters in static::parameterAllowlist() are allowed.
* *
* @throws InvalidArgumentException * @throws InvalidArgumentException
*/ */
protected function validateParameter(string|array $parameters): string|array protected function validateParameter(string|array|null $parameters, string|null $allowlist = null): string|array|null
{ {
if (is_null($parameters)) {
// Return null if there's nothing to validate
// (e.g. when $databaseConfig->getUsername() of an
// improperly created tenant is passed).
return null;
}
$allowlist = $allowlist ?? static::parameterAllowlist();
foreach ((array) $parameters as $parameter) { foreach ((array) $parameters as $parameter) {
foreach (str_split($parameter) as $char) { foreach (str_split($parameter) as $char) {
if (! str_contains(static::parameterAllowlist(), $char)) { if (! str_contains($allowlist, $char)) {
throw new InvalidArgumentException("Invalid character '{$char}' in SQL parameter: {$parameter}"); throw new InvalidArgumentException("Invalid character '{$char}' in parameter: {$parameter}");
} }
} }
} }
return $parameters; return $parameters;
} }
/**
* Validate that a password only contains allowed characters before used in SQL statements.
*
* Used as a shorthand for validateParameter() with the less strict allowlist.
*
* @throws InvalidArgumentException
*/
protected function validatePassword(string|null $password): string|null
{
return $this->validateParameter($password, static::passwordAllowlist());
}
} }

View file

@ -24,8 +24,8 @@ class PermissionControlledMicrosoftSQLServerDatabaseManager extends MicrosoftSQL
$username = $databaseConfig->getUsername(); $username = $databaseConfig->getUsername();
$password = $databaseConfig->getPassword(); $password = $databaseConfig->getPassword();
// todo@validation password
$this->validateParameter([$database, $username]); $this->validateParameter([$database, $username]);
$this->validatePassword($password);
// Create login // Create login
$this->connection()->statement("CREATE LOGIN [$username] WITH PASSWORD = '$password'"); $this->connection()->statement("CREATE LOGIN [$username] WITH PASSWORD = '$password'");

View file

@ -25,8 +25,8 @@ class PermissionControlledMySQLDatabaseManager extends MySQLDatabaseManager impl
$username = $databaseConfig->getUsername(); $username = $databaseConfig->getUsername();
$password = $databaseConfig->getPassword(); $password = $databaseConfig->getPassword();
//todo@validation password
$this->validateParameter([$database, $username]); $this->validateParameter([$database, $username]);
$this->validatePassword($password);
$this->connection()->statement("CREATE USER `{$username}`@`%` IDENTIFIED BY '{$password}'"); $this->connection()->statement("CREATE USER `{$username}`@`%` IDENTIFIED BY '{$password}'");