use pdo for postgres setup

This commit is contained in:
Robin Appelman 2016-07-12 13:50:54 +02:00
parent 8a79d314cf
commit 7ffda5d10f
2 changed files with 86 additions and 106 deletions

View File

@ -101,10 +101,10 @@ abstract class AbstractDatabase {
} }
/** /**
* @param array $configOverwrite
* @return \OC\DB\Connection * @return \OC\DB\Connection
* @throws \OC\DatabaseSetupException
*/ */
protected function connect() { protected function connect(array $configOverwrite = []) {
$systemConfig = $this->config->getSystemConfig(); $systemConfig = $this->config->getSystemConfig();
$cf = new ConnectionFactory(); $cf = new ConnectionFactory();
$connectionParams = $cf->createConnectionParams($systemConfig); $connectionParams = $cf->createConnectionParams($systemConfig);
@ -115,6 +115,7 @@ abstract class AbstractDatabase {
if (!$connectionParams['password']) { if (!$connectionParams['password']) {
$connectionParams['password'] = $this->dbPassword; $connectionParams['password'] = $this->dbPassword;
} }
$connectionParams = array_merge($connectionParams, $configOverwrite);
return $cf->getConnection($systemConfig->getValue('dbtype', 'sqlite'), $connectionParams); return $cf->getConnection($systemConfig->getValue('dbtype', 'sqlite'), $connectionParams);
} }

View File

@ -26,42 +26,34 @@
*/ */
namespace OC\Setup; namespace OC\Setup;
use OC\DatabaseException;
use OC\DB\QueryBuilder\Literal;
use OCP\IDBConnection;
class PostgreSQL extends AbstractDatabase { class PostgreSQL extends AbstractDatabase {
public $dbprettyname = 'PostgreSQL'; public $dbprettyname = 'PostgreSQL';
public function setupDatabase($username) { public function setupDatabase($username) {
$e_host = addslashes($this->dbHost); $connection = $this->connect([
$e_user = addslashes($this->dbUser); 'dbname' => 'postgres'
$e_password = addslashes($this->dbPassword); ]);
// adding port support through installer
if(!empty($this->dbPort)) {
// casting to int to avoid malicious input
$port = (int)$this->dbPort;
} else if(strpos($e_host, ':')) {
list($e_host, $port)=explode(':', $e_host, 2);
} else {
$port=false;
}
//check if the database user has admin rights
$connection_string = "host='$e_host' dbname=postgres user='$e_user' port='$port' password='$e_password'";
$connection = @pg_connect($connection_string);
if(!$connection) {
// Try if we can connect to the DB with the specified name
$e_dbname = addslashes($this->dbName);
$connection_string = "host='$e_host' dbname='$e_dbname' user='$e_user' port='$port' password='$e_password'";
$connection = @pg_connect($connection_string);
if(!$connection)
throw new \OC\DatabaseSetupException($this->trans->t('PostgreSQL connection failed'),
$this->trans->t('Please check your connection details.'));
}
$e_user = pg_escape_string($this->dbUser);
//check for roles creation rights in postgresql //check for roles creation rights in postgresql
$query="SELECT 1 FROM pg_roles WHERE rolcreaterole=TRUE AND rolname='$e_user'"; $builder = $connection->getQueryBuilder();
$result = pg_query($connection, $query); $builder->automaticTablePrefix(false);
if($result and pg_num_rows($result) > 0) { $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) {
//use the admin login data for the new database user //use the admin login data for the new database user
//add prefix to the postgresql user name to prevent collisions //add prefix to the postgresql user name to prevent collisions
@ -72,7 +64,7 @@ class PostgreSQL extends AbstractDatabase {
$this->createDBUser($connection); $this->createDBUser($connection);
} }
$systemConfig = \OC::$server->getSystemConfig(); $systemConfig = $this->config->getSystemConfig();
$systemConfig->setValues([ $systemConfig->setValues([
'dbuser' => $this->dbUser, 'dbuser' => $this->dbUser,
'dbpassword' => $this->dbPassword, 'dbpassword' => $this->dbPassword,
@ -80,98 +72,85 @@ class PostgreSQL extends AbstractDatabase {
//create the database //create the database
$this->createDatabase($connection); $this->createDatabase($connection);
$query = $connection->prepare("select count(*) FROM pg_class WHERE relname=? limit 1");
$query->execute([$this->tablePrefix . "users"]);
$tablesSetup = $query->fetchColumn() > 0;
// the connection to dbname=postgres is not needed anymore // the connection to dbname=postgres is not needed anymore
pg_close($connection); $connection->close();
// connect to the ownCloud database (dbname=$this->dbname) and check if it needs to be filled // connect to the ownCloud database (dbname=$this->dbname) and check if it needs to be filled
$this->dbUser = $systemConfig->getValue('dbuser'); $this->dbUser = $systemConfig->getValue('dbuser');
$this->dbPassword = $systemConfig->getValue('dbpassword'); $this->dbPassword = $systemConfig->getValue('dbpassword');
$connection = $this->connect();
$e_host = addslashes($this->dbHost); try {
$e_dbname = addslashes($this->dbName); $connection->connect();
$e_user = addslashes($this->dbUser); } catch (\Exception $e) {
$e_password = addslashes($this->dbPassword); $this->logger->logException($e);
// Fix database with port connection
if(strpos($e_host, ':')) {
list($e_host, $port)=explode(':', $e_host, 2);
} else {
$port=false;
}
$connection_string = "host='$e_host' dbname='$e_dbname' user='$e_user' port='$port' password='$e_password'";
$connection = @pg_connect($connection_string);
if(!$connection) {
throw new \OC\DatabaseSetupException($this->trans->t('PostgreSQL username and/or password not valid'), throw new \OC\DatabaseSetupException($this->trans->t('PostgreSQL username and/or password not valid'),
$this->trans->t('You need to enter either an existing account or the administrator.')); $this->trans->t('You need to enter either an existing account or the administrator.'));
} }
$query = "select count(*) FROM pg_class WHERE relname='".$this->tablePrefix."users' limit 1";
$result = pg_query($connection, $query);
if($result) { if(!$tablesSetup) {
$row = pg_fetch_row($result);
}
if(!$result or $row[0]==0) {
\OC_DB::createDbFromStructure($this->dbDefinitionFile); \OC_DB::createDbFromStructure($this->dbDefinitionFile);
} }
} }
private function createDatabase($connection) { private function createDatabase(IDBConnection $connection) {
//we can't use OC_BD functions here because we need to connect as the administrative user. if(!$this->databaseExists($connection)) {
$e_name = pg_escape_string($this->dbName);
$e_user = pg_escape_string($this->dbUser);
$query = "select datname from pg_database where datname = '$e_name'";
$result = pg_query($connection, $query);
if(!$result) {
$entry = $this->trans->t('DB Error: "%s"', array(pg_last_error($connection))) . '<br />';
$entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '<br />';
\OCP\Util::writeLog('setup.pg', $entry, \OCP\Util::WARN);
}
if(! pg_fetch_row($result)) {
//The database does not exists... let's create it //The database does not exists... let's create it
$query = "CREATE DATABASE \"$e_name\" OWNER \"$e_user\""; $query = $connection->prepare("CREATE DATABASE " . addslashes($this->dbName) . " OWNER " . addslashes($this->dbUser));
$result = pg_query($connection, $query); try {
if(!$result) { $query->execute();
$entry = $this->trans->t('DB Error: "%s"', array(pg_last_error($connection))) . '<br />'; } catch (DatabaseException $e) {
$entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '<br />'; $this->logger->error('Error while trying to create database');
\OCP\Util::writeLog('setup.pg', $entry, \OCP\Util::WARN); $this->logger->logException($e);
} }
else { } else {
$query = "REVOKE ALL PRIVILEGES ON DATABASE \"$e_name\" FROM PUBLIC"; $query = $connection->prepare("REVOKE ALL PRIVILEGES ON DATABASE " . addslashes($this->dbName) . " FROM PUBLIC");
pg_query($connection, $query); try {
$query->execute();
} catch (DatabaseException $e) {
$this->logger->error('Error while trying to restrict database permissions');
$this->logger->logException($e);
} }
} }
} }
private function createDBUser($connection) { private function userExists(IDBConnection $connection) {
$e_name = pg_escape_string($this->dbUser); $builder = $connection->getQueryBuilder();
$e_password = pg_escape_string($this->dbPassword); $builder->automaticTablePrefix(false);
$query = "select * from pg_roles where rolname='$e_name';"; $query = $builder->select('*')
$result = pg_query($connection, $query); ->from('pg_roles')
if(!$result) { ->where($builder->expr()->eq('rolname', $builder->createNamedParameter($this->dbUser)));
$entry = $this->trans->t('DB Error: "%s"', array(pg_last_error($connection))) . '<br />'; $result = $query->execute();
$entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '<br />'; return $result->rowCount() > 0;
\OCP\Util::writeLog('setup.pg', $entry, \OCP\Util::WARN); }
}
if(! pg_fetch_row($result)) { private function databaseExists(IDBConnection $connection) {
//user does not exists let's create it :) $builder = $connection->getQueryBuilder();
$query = "CREATE USER \"$e_name\" CREATEDB PASSWORD '$e_password';"; $builder->automaticTablePrefix(false);
$result = pg_query($connection, $query); $query = $builder->select('datname')
if(!$result) { ->from('pg_database')
$entry = $this->trans->t('DB Error: "%s"', array(pg_last_error($connection))) . '<br />'; ->where($builder->expr()->eq('datname', $builder->createNamedParameter($this->dbName)));
$entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '<br />'; $result = $query->execute();
\OCP\Util::writeLog('setup.pg', $entry, \OCP\Util::WARN); return $result->rowCount() > 0;
} }
}
else { // change password of the existing role private function createDBUser(IDBConnection $connection) {
$query = "ALTER ROLE \"$e_name\" WITH PASSWORD '$e_password';"; try {
$result = pg_query($connection, $query); if ($this->userExists($connection, $this->dbUser)) {
if(!$result) { // change the password
$entry = $this->trans->t('DB Error: "%s"', array(pg_last_error($connection))) . '<br />'; $query = $connection->prepare("ALTER ROLE " . addslashes($this->dbUser) . " CREATEDB WITH PASSWORD " . addslashes($this->dbPassword));
$entry .= $this->trans->t('Offending command was: "%s"', array($query)) . '<br />'; } else {
\OCP\Util::writeLog('setup.pg', $entry, \OCP\Util::WARN); // create the user
$query = $connection->prepare("CREATE USER " . addslashes($this->dbUser) . " CREATEDB PASSWORD " . addslashes($this->dbPassword));
} }
$query->execute();
} catch (DatabaseException $e) {
$this->logger->error('Error while trying to create database user');
$this->logger->logException($e);
} }
} }
} }