Compare commits

...

2 Commits

2 changed files with 61 additions and 39 deletions
+39 -29
View File
@@ -18,6 +18,9 @@ use OCP\Security\ISecureRandom;
class MySQL extends AbstractDatabase {
public string $dbprettyname = 'MySQL/MariaDB';
/** @var int MySQL username length limit */
private const MAX_USERNAME_LENGTH = 16;
public function setupDatabase(): void {
//check if the database user has admin right
$connection = $this->connect(['dbname' => null]);
@@ -58,6 +61,36 @@ class MySQL extends AbstractDatabase {
}
}
/**
* Check whether a MySQL user account already exists.
*/
private function userExists(IDBConnection $connection, string $username): bool {
$result = $connection->executeQuery(
'SELECT user FROM mysql.user WHERE user=?',
[$username]
);
$exists = count($result->fetchAll()) > 0;
$result->closeCursor();
return $exists;
}
/**
* Find a username starting from $base that doesn't already exist,
* respecting MySQL's 16-character username limit.
*/
private function findAvailableUsername(IDBConnection $connection, string $base): string {
$candidate = substr($base, 0, self::MAX_USERNAME_LENGTH);
$i = 1;
while ($this->userExists($connection, $candidate)) {
$suffix = (string)$i;
$candidate = substr($base, 0, self::MAX_USERNAME_LENGTH - strlen($suffix)) . $suffix;
$i++;
}
return $candidate;
}
private function createDatabase(\OC\DB\Connection $connection): void {
try {
$name = $this->dbName;
@@ -143,35 +176,12 @@ class MySQL extends AbstractDatabase {
//we don't have a dbuser specified in config
if ($this->dbUser !== $oldUser) {
//add prefix to the admin username to prevent collisions
$adminUser = substr('oc_' . $username, 0, 16);
$i = 1;
while (true) {
//this should be enough to check for admin rights in mysql
$query = 'SELECT user FROM mysql.user WHERE user=?';
$result = $connection->executeQuery($query, [$adminUser]);
//current dbuser has admin rights
$data = $result->fetchAll();
$result->closeCursor();
//new dbuser does not exist
if (count($data) === 0) {
//use the admin login data for the new database user
$this->dbUser = $adminUser;
$this->createDBUser($connection);
// if sharding is used we need to manually call this for every shard as those also need the user setup!
/** @var ConnectionAdapter $connection */
foreach ($connection->getInner()->getShardConnections() as $shard) {
$this->createDBUser($shard);
}
break;
} else {
//repeat with different username
$length = strlen((string)$i);
$adminUser = substr('oc_' . $username, 0, 16 - $length) . $i;
$i++;
}
$this->dbUser = $this->findAvailableUsername($connection, 'oc_' . $username);
$this->createDBUser($connection);
// if sharding is used we need to manually call this for every shard as those also need the user setup!
/** @var ConnectionAdapter $connection */
foreach ($connection->getInner()->getShardConnections() as $shard) {
$this->createDBUser($shard);
}
} else {
// Reuse existing password if a database config is already present
+22 -10
View File
@@ -103,6 +103,21 @@ class PostgreSQL extends AbstractDatabase {
}
}
/**
* Find a role name starting from $base that doesn't already exist.
*/
private function findAvailableUsername(Connection $connection, string $base): string {
$candidate = $base;
$i = 1;
while ($this->userExists($connection, $candidate)) {
$i++;
$candidate = $base . $i;
}
return $candidate;
}
private function createDatabase(Connection $connection): void {
if (!$this->databaseExists($connection)) {
//The database does not exists... let's create it
@@ -126,12 +141,15 @@ class PostgreSQL extends AbstractDatabase {
}
}
private function userExists(Connection $connection): bool {
/**
* Check whether a PostgreSQL role already exists.
*/
private function userExists(Connection $connection, string $username): bool {
$builder = $connection->getQueryBuilder();
$builder->automaticTablePrefix(false);
$query = $builder->select('*')
$query = $builder->select('rolname')
->from('pg_roles')
->where($builder->expr()->eq('rolname', $builder->createNamedParameter($this->dbUser)));
->where($builder->expr()->eq('rolname', $builder->createNamedParameter($username)));
$result = $query->executeQuery();
return $result->rowCount() > 0;
}
@@ -147,14 +165,8 @@ class PostgreSQL extends AbstractDatabase {
}
private function createDBUser(Connection $connection): void {
$dbUser = $this->dbUser;
$this->dbUser = $this->findAvailableUsername($connection, $this->dbUser);
try {
$i = 1;
while ($this->userExists($connection)) {
$i++;
$this->dbUser = $dbUser . $i;
}
// create the user
$query = $connection->prepare('CREATE USER "' . addslashes($this->dbUser) . "\" CREATEDB PASSWORD '" . addslashes($this->dbPassword) . "'");
$query->executeStatement();