Skip to content

Commit

Permalink
Merge pull request #36428 from nextcloud/disable-db-user-create
Browse files Browse the repository at this point in the history
add option to disable db user creation trough environment variable
  • Loading branch information
icewind1991 authored Feb 21, 2023
2 parents c6c512a + b923310 commit 8bc9e23
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 44 deletions.
6 changes: 6 additions & 0 deletions lib/private/Setup/AbstractDatabase.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ abstract class AbstractDatabase {
protected $logger;
/** @var ISecureRandom */
protected $random;
/** @var bool */
protected $tryCreateDbUser;

public function __construct(IL10N $trans, SystemConfig $config, LoggerInterface $logger, ISecureRandom $random) {
$this->trans = $trans;
Expand Down Expand Up @@ -88,6 +90,10 @@ public function initialize($config) {
$dbPort = !empty($config['dbport']) ? $config['dbport'] : '';
$dbTablePrefix = isset($config['dbtableprefix']) ? $config['dbtableprefix'] : 'oc_';

$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->config->setValues([
'dbname' => $dbName,
'dbhost' => $dbHost,
Expand Down
17 changes: 9 additions & 8 deletions lib/private/Setup/MySQL.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,14 @@ public function setupDatabase($username) {
$connection = $this->connect(['dbname' => null]);
}

$this->createSpecificUser($username, new ConnectionAdapter($connection));
if ($this->tryCreateDbUser) {
$this->createSpecificUser($username, new ConnectionAdapter($connection));
}

$this->config->setValues([
'dbuser' => $this->dbUser,
'dbpassword' => $this->dbPassword,
]);

//create the database
$this->createDatabase($connection);
Expand Down Expand Up @@ -147,8 +154,7 @@ private function createSpecificUser($username, $connection): void {
. $this->random->generate(2, ISecureRandom::CHAR_UPPER)
. $this->random->generate(2, ISecureRandom::CHAR_LOWER)
. $this->random->generate(2, ISecureRandom::CHAR_DIGITS)
. $this->random->generate(2, $saveSymbols)
;
. $this->random->generate(2, $saveSymbols);
$this->dbPassword = str_shuffle($password);

try {
Expand Down Expand Up @@ -196,10 +202,5 @@ private function createSpecificUser($username, $connection): void {
$this->dbUser = $rootUser;
$this->dbPassword = $rootPassword;
}

$this->config->setValues([
'dbuser' => $this->dbUser,
'dbpassword' => $this->dbPassword,
]);
}
}
74 changes: 38 additions & 36 deletions lib/private/Setup/PostgreSQL.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,42 +45,44 @@ public function setupDatabase($username) {
$connection = $this->connect([
'dbname' => 'postgres'
]);
//check for roles creation rights in postgresql
$builder = $connection->getQueryBuilder();
$builder->automaticTablePrefix(false);
$query = $builder
->select('rolname')
->from('pg_roles')
->where($builder->expr()->eq('rolcreaterole', new Literal('TRUE')))
->andWhere($builder->expr()->eq('rolname', $builder->createNamedParameter($this->dbUser)));

try {
$result = $query->execute();
$canCreateRoles = $result->rowCount() > 0;
} catch (DatabaseException $e) {
$canCreateRoles = false;
}

if ($canCreateRoles) {
$connectionMainDatabase = $this->connect();
//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);
//create a new password so we don't need to store the admin config in the config file
$this->dbPassword = \OC::$server->getSecureRandom()->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();
if ($this->tryCreateDbUser) {
//check for roles creation rights in postgresql
$builder = $connection->getQueryBuilder();
$builder->automaticTablePrefix(false);
$query = $builder
->select('rolname')
->from('pg_roles')
->where($builder->expr()->eq('rolcreaterole', new Literal('TRUE')))
->andWhere($builder->expr()->eq('rolname', $builder->createNamedParameter($this->dbUser)));

try {
$result = $query->execute();
$canCreateRoles = $result->rowCount() > 0;
} catch (DatabaseException $e) {
$canCreateRoles = false;
}

if ($canCreateRoles) {
$connectionMainDatabase = $this->connect();
//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);
//create a new password so we don't need to store the admin config in the config file
$this->dbPassword = \OC::$server->getSecureRandom()->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();
}
}

$this->config->setValues([
Expand Down

0 comments on commit 8bc9e23

Please sign in to comment.