diff options
Diffstat (limited to 'lib/private/Setup')
-rw-r--r-- | lib/private/Setup/AbstractDatabase.php | 20 | ||||
-rw-r--r-- | lib/private/Setup/MySQL.php | 47 | ||||
-rw-r--r-- | lib/private/Setup/OCI.php | 8 | ||||
-rw-r--r-- | lib/private/Setup/PostgreSQL.php | 39 | ||||
-rw-r--r-- | lib/private/Setup/Sqlite.php | 2 |
5 files changed, 64 insertions, 52 deletions
diff --git a/lib/private/Setup/AbstractDatabase.php b/lib/private/Setup/AbstractDatabase.php index e96ca8a2f3e..8f6294faa66 100644 --- a/lib/private/Setup/AbstractDatabase.php +++ b/lib/private/Setup/AbstractDatabase.php @@ -50,14 +50,14 @@ abstract class AbstractDatabase { public function validate($config) { $errors = []; if (empty($config['dbuser']) && empty($config['dbname'])) { - $errors[] = $this->trans->t("Enter the database Login and name for %s", [$this->dbprettyname]); + $errors[] = $this->trans->t('Enter the database Login and name for %s', [$this->dbprettyname]); } elseif (empty($config['dbuser'])) { - $errors[] = $this->trans->t("Enter the database Login for %s", [$this->dbprettyname]); + $errors[] = $this->trans->t('Enter the database Login for %s', [$this->dbprettyname]); } elseif (empty($config['dbname'])) { - $errors[] = $this->trans->t("Enter the database name for %s", [$this->dbprettyname]); + $errors[] = $this->trans->t('Enter the database name for %s', [$this->dbprettyname]); } if (substr_count($config['dbname'], '.') >= 1) { - $errors[] = $this->trans->t("You cannot use dots in the database name %s", [$this->dbprettyname]); + $errors[] = $this->trans->t('You cannot use dots in the database name %s', [$this->dbprettyname]); } return $errors; } @@ -70,14 +70,13 @@ abstract class AbstractDatabase { $dbPort = !empty($config['dbport']) ? $config['dbport'] : ''; $dbTablePrefix = $config['dbtableprefix'] ?? 'oc_'; - $createUserConfig = $this->config->getValue("setup_create_db_user", true); + $createUserConfig = $this->config->getValue('setup_create_db_user', true); // accept `false` both as bool and string, since setting config values from env will result in a string - $this->tryCreateDbUser = $createUserConfig !== false && $createUserConfig !== "false"; + $this->tryCreateDbUser = $createUserConfig !== false && $createUserConfig !== 'false'; $this->config->setValues([ 'dbname' => $dbName, 'dbhost' => $dbHost, - 'dbport' => $dbPort, 'dbtableprefix' => $dbTablePrefix, ]); @@ -127,13 +126,10 @@ abstract class AbstractDatabase { return $connection; } - /** - * @param string $username - */ - abstract public function setupDatabase($username); + abstract public function setupDatabase(); public function runMigrations(?IOutput $output = null) { - if (!is_dir(\OC::$SERVERROOT."/core/Migrations")) { + if (!is_dir(\OC::$SERVERROOT . '/core/Migrations')) { return; } $ms = new MigrationService('core', \OC::$server->get(Connection::class), $output); diff --git a/lib/private/Setup/MySQL.php b/lib/private/Setup/MySQL.php index 93aee667d18..c4794a86743 100644 --- a/lib/private/Setup/MySQL.php +++ b/lib/private/Setup/MySQL.php @@ -8,6 +8,7 @@ namespace OC\Setup; use Doctrine\DBAL\Platforms\MySQL80Platform; +use Doctrine\DBAL\Platforms\MySQL84Platform; use OC\DB\ConnectionAdapter; use OC\DB\MySqlTools; use OCP\IDBConnection; @@ -16,7 +17,7 @@ use OCP\Security\ISecureRandom; class MySQL extends AbstractDatabase { public $dbprettyname = 'MySQL/MariaDB'; - public function setupDatabase($username) { + public function setupDatabase() { //check if the database user has admin right $connection = $this->connect(['dbname' => null]); @@ -28,7 +29,7 @@ class MySQL extends AbstractDatabase { } if ($this->tryCreateDbUser) { - $this->createSpecificUser($username, new ConnectionAdapter($connection)); + $this->createSpecificUser('oc_admin', new ConnectionAdapter($connection)); } $this->config->setValues([ @@ -41,7 +42,7 @@ class MySQL extends AbstractDatabase { //fill the database if needed $query = 'select count(*) from information_schema.tables where table_schema=? AND table_name = ?'; - $connection->executeQuery($query, [$this->dbName, $this->tablePrefix.'users']); + $connection->executeQuery($query, [$this->dbName, $this->tablePrefix . 'users']); $connection->close(); $connection = $this->connect(); @@ -59,7 +60,7 @@ class MySQL extends AbstractDatabase { /** * @param \OC\DB\Connection $connection */ - private function createDatabase($connection) { + private function createDatabase($connection): void { try { $name = $this->dbName; $user = $this->dbUser; @@ -91,23 +92,30 @@ class MySQL extends AbstractDatabase { * @param IDBConnection $connection * @throws \OC\DatabaseSetupException */ - private function createDBUser($connection) { + private function createDBUser($connection): void { + $name = $this->dbUser; + $password = $this->dbPassword; + try { - $name = $this->dbUser; - $password = $this->dbPassword; // we need to create 2 accounts, one for global use and one for local user. if we don't specify the local one, // the anonymous user would take precedence when there is one. - if ($connection->getDatabasePlatform() instanceof Mysql80Platform) { - $query = "CREATE USER '$name'@'localhost' IDENTIFIED WITH mysql_native_password BY '$password'"; - $connection->executeUpdate($query); - $query = "CREATE USER '$name'@'%' IDENTIFIED WITH mysql_native_password BY '$password'"; - $connection->executeUpdate($query); + if ($connection->getDatabasePlatform() instanceof MySQL84Platform) { + $query = "CREATE USER ?@'localhost' IDENTIFIED WITH caching_sha2_password BY ?"; + $connection->executeStatement($query, [$name,$password]); + $query = "CREATE USER ?@'%' IDENTIFIED WITH caching_sha2_password BY ?"; + $connection->executeStatement($query, [$name,$password]); + } elseif ($connection->getDatabasePlatform() instanceof Mysql80Platform) { + // TODO: Remove this elseif section as soon as MySQL 8.0 is out-of-support (after April 2026) + $query = "CREATE USER ?@'localhost' IDENTIFIED WITH mysql_native_password BY ?"; + $connection->executeStatement($query, [$name,$password]); + $query = "CREATE USER ?@'%' IDENTIFIED WITH mysql_native_password BY ?"; + $connection->executeStatement($query, [$name,$password]); } else { - $query = "CREATE USER '$name'@'localhost' IDENTIFIED BY '$password'"; - $connection->executeUpdate($query); - $query = "CREATE USER '$name'@'%' IDENTIFIED BY '$password'"; - $connection->executeUpdate($query); + $query = "CREATE USER ?@'localhost' IDENTIFIED BY ?"; + $connection->executeStatement($query, [$name,$password]); + $query = "CREATE USER ?@'%' IDENTIFIED BY ?"; + $connection->executeStatement($query, [$name,$password]); } } catch (\Exception $ex) { $this->logger->error('Database user creation failed.', [ @@ -119,7 +127,7 @@ class MySQL extends AbstractDatabase { } /** - * @param $username + * @param string $username * @param IDBConnection $connection */ private function createSpecificUser($username, $connection): void { @@ -158,6 +166,11 @@ class MySQL extends AbstractDatabase { //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 { diff --git a/lib/private/Setup/OCI.php b/lib/private/Setup/OCI.php index 3a0fa34d8d1..61c7f968787 100644 --- a/lib/private/Setup/OCI.php +++ b/lib/private/Setup/OCI.php @@ -31,16 +31,16 @@ class OCI extends AbstractDatabase { public function validate($config) { $errors = []; if (empty($config['dbuser']) && empty($config['dbname'])) { - $errors[] = $this->trans->t("Enter the database Login and name for %s", [$this->dbprettyname]); + $errors[] = $this->trans->t('Enter the database Login and name for %s', [$this->dbprettyname]); } elseif (empty($config['dbuser'])) { - $errors[] = $this->trans->t("Enter the database Login for %s", [$this->dbprettyname]); + $errors[] = $this->trans->t('Enter the database Login for %s', [$this->dbprettyname]); } elseif (empty($config['dbname'])) { - $errors[] = $this->trans->t("Enter the database name for %s", [$this->dbprettyname]); + $errors[] = $this->trans->t('Enter the database name for %s', [$this->dbprettyname]); } return $errors; } - public function setupDatabase($username) { + public function setupDatabase() { try { $this->connect(); } catch (\Exception $e) { diff --git a/lib/private/Setup/PostgreSQL.php b/lib/private/Setup/PostgreSQL.php index 4ece8957ce6..9a686db2e54 100644 --- a/lib/private/Setup/PostgreSQL.php +++ b/lib/private/Setup/PostgreSQL.php @@ -16,10 +16,9 @@ class PostgreSQL extends AbstractDatabase { public $dbprettyname = 'PostgreSQL'; /** - * @param string $username * @throws \OC\DatabaseSetupException */ - public function setupDatabase($username) { + public function setupDatabase() { try { $connection = $this->connect([ 'dbname' => 'postgres' @@ -46,21 +45,11 @@ class PostgreSQL extends AbstractDatabase { //use the admin login data for the new database user //add prefix to the postgresql user name to prevent collisions - $this->dbUser = 'oc_' . strtolower($username); + $this->dbUser = 'oc_admin'; //create a new password so we don't need to store the admin config in the config file $this->dbPassword = \OC::$server->get(ISecureRandom::class)->generate(30, ISecureRandom::CHAR_ALPHANUMERIC); $this->createDBUser($connection); - - // Go to the main database and grant create on the public schema - // The code below is implemented to make installing possible with PostgreSQL version 15: - // https://www.postgresql.org/docs/release/15.0/ - // From the release notes: For new databases having no need to defend against insider threats, granting CREATE permission will yield the behavior of prior releases - // Therefore we assume that the database is only used by one user/service which is Nextcloud - // Additional services should get installed in a separate database in order to stay secure - // Also see https://www.postgresql.org/docs/15/ddl-schemas.html#DDL-SCHEMAS-PATTERNS - $connectionMainDatabase->executeQuery('GRANT CREATE ON SCHEMA public TO "' . addslashes($this->dbUser) . '"'); - $connectionMainDatabase->close(); } } @@ -73,6 +62,20 @@ class PostgreSQL extends AbstractDatabase { $this->createDatabase($connection); // the connection to dbname=postgres is not needed anymore $connection->close(); + + if ($this->tryCreateDbUser) { + if ($canCreateRoles) { + // Go to the main database and grant create on the public schema + // The code below is implemented to make installing possible with PostgreSQL version 15: + // https://www.postgresql.org/docs/release/15.0/ + // From the release notes: For new databases having no need to defend against insider threats, granting CREATE permission will yield the behavior of prior releases + // Therefore we assume that the database is only used by one user/service which is Nextcloud + // Additional services should get installed in a separate database in order to stay secure + // Also see https://www.postgresql.org/docs/15/ddl-schemas.html#DDL-SCHEMAS-PATTERNS + $connectionMainDatabase->executeQuery('GRANT CREATE ON SCHEMA public TO "' . addslashes($this->dbUser) . '"'); + $connectionMainDatabase->close(); + } + } } catch (\Exception $e) { $this->logger->warning('Error trying to connect as "postgres", assuming database is setup and tables need to be created', [ 'exception' => $e, @@ -101,7 +104,7 @@ class PostgreSQL extends AbstractDatabase { private function createDatabase(Connection $connection) { if (!$this->databaseExists($connection)) { //The database does not exists... let's create it - $query = $connection->prepare("CREATE DATABASE " . addslashes($this->dbName) . " OWNER \"" . addslashes($this->dbUser) . '"'); + $query = $connection->prepare('CREATE DATABASE ' . addslashes($this->dbName) . ' OWNER "' . addslashes($this->dbUser) . '"'); try { $query->execute(); } catch (DatabaseException $e) { @@ -110,7 +113,7 @@ class PostgreSQL extends AbstractDatabase { ]); } } else { - $query = $connection->prepare("REVOKE ALL PRIVILEGES ON DATABASE " . addslashes($this->dbName) . " FROM PUBLIC"); + $query = $connection->prepare('REVOKE ALL PRIVILEGES ON DATABASE ' . addslashes($this->dbName) . ' FROM PUBLIC'); try { $query->execute(); } catch (DatabaseException $e) { @@ -127,7 +130,7 @@ class PostgreSQL extends AbstractDatabase { $query = $builder->select('*') ->from('pg_roles') ->where($builder->expr()->eq('rolname', $builder->createNamedParameter($this->dbUser))); - $result = $query->execute(); + $result = $query->executeQuery(); return $result->rowCount() > 0; } @@ -137,7 +140,7 @@ class PostgreSQL extends AbstractDatabase { $query = $builder->select('datname') ->from('pg_database') ->where($builder->expr()->eq('datname', $builder->createNamedParameter($this->dbName))); - $result = $query->execute(); + $result = $query->executeQuery(); return $result->rowCount() > 0; } @@ -151,7 +154,7 @@ class PostgreSQL extends AbstractDatabase { } // create the user - $query = $connection->prepare("CREATE USER \"" . addslashes($this->dbUser) . "\" CREATEDB PASSWORD '" . addslashes($this->dbPassword) . "'"); + $query = $connection->prepare('CREATE USER "' . addslashes($this->dbUser) . "\" CREATEDB PASSWORD '" . addslashes($this->dbPassword) . "'"); $query->execute(); if ($this->databaseExists($connection)) { $query = $connection->prepare('GRANT CONNECT ON DATABASE ' . addslashes($this->dbName) . ' TO "' . addslashes($this->dbUser) . '"'); diff --git a/lib/private/Setup/Sqlite.php b/lib/private/Setup/Sqlite.php index 1b90ebd5a5e..b34b1e32ede 100644 --- a/lib/private/Setup/Sqlite.php +++ b/lib/private/Setup/Sqlite.php @@ -45,7 +45,7 @@ class Sqlite extends AbstractDatabase { } } - public function setupDatabase($username) { + public function setupDatabase() { $datadir = $this->config->getValue( 'datadirectory', \OC::$SERVERROOT . '/data' |