aboutsummaryrefslogtreecommitdiffstats
path: root/lib/private/Setup
diff options
context:
space:
mode:
Diffstat (limited to 'lib/private/Setup')
-rw-r--r--lib/private/Setup/AbstractDatabase.php20
-rw-r--r--lib/private/Setup/MySQL.php47
-rw-r--r--lib/private/Setup/OCI.php8
-rw-r--r--lib/private/Setup/PostgreSQL.php39
-rw-r--r--lib/private/Setup/Sqlite.php2
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'