From d038a2795dc30c49ec36abaf6a170e92adeb29b8 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Mon, 13 Apr 2015 14:10:24 +0200 Subject: [PATCH 1/3] Wizard: Differentiate between privileges required to create and setup a db Fixes the bug that if a database and a login are already existing and only the schema needs to be set up, which is possible using the resource's login, the user is required to provide another login with the seemingly missing privileges. refs #8707 --- modules/setup/library/Setup/Utils/DbTool.php | 17 ++++++----- modules/setup/library/Setup/WebWizard.php | 32 ++++++++++++++------ 2 files changed, 32 insertions(+), 17 deletions(-) diff --git a/modules/setup/library/Setup/Utils/DbTool.php b/modules/setup/library/Setup/Utils/DbTool.php index b08f42bf8..3073778c8 100644 --- a/modules/setup/library/Setup/Utils/DbTool.php +++ b/modules/setup/library/Setup/Utils/DbTool.php @@ -721,7 +721,8 @@ EOD; foreach (array_intersect($privileges, array_keys($this->pgsqlGrantContexts)) as $privilege) { if (false === empty($context) && $this->pgsqlGrantContexts[$privilege] & static::TABLE_LEVEL) { $tablePrivileges[] = $privilege; - } elseif ($this->pgsqlGrantContexts[$privilege] & static::DATABASE_LEVEL) { + } + if ($this->pgsqlGrantContexts[$privilege] & static::DATABASE_LEVEL) { $dbPrivileges[] = $privilege; } } @@ -760,14 +761,14 @@ EOD; // connected to the database defined in the resource configuration it is safe to just ignore them // as the chances are very high that the database is created later causing the current user being // the owner with ALL privileges. (Which in turn can be granted to others.) - } - if (array_search('CREATE', $privileges) !== false) { - $query = $this->query( - 'select rolcreatedb from pg_roles where rolname = :user', - array(':user' => $username !== null ? $username : $this->config['username']) - ); - $privilegesGranted &= $query->fetchColumn() !== false; + if (array_search('CREATE', $privileges) !== false) { + $query = $this->query( + 'select rolcreatedb from pg_roles where rolname = :user', + array(':user' => $username !== null ? $username : $this->config['username']) + ); + $privilegesGranted &= $query->fetchColumn() !== false; + } } if (array_search('CREATEROLE', $privileges) !== false) { diff --git a/modules/setup/library/Setup/WebWizard.php b/modules/setup/library/Setup/WebWizard.php index afe791732..1180379bb 100644 --- a/modules/setup/library/Setup/WebWizard.php +++ b/modules/setup/library/Setup/WebWizard.php @@ -17,7 +17,7 @@ use Icinga\Module\Setup\Forms\PreferencesPage; use Icinga\Module\Setup\Forms\AuthBackendPage; use Icinga\Module\Setup\Forms\AdminAccountPage; use Icinga\Module\Setup\Forms\LdapDiscoveryPage; -use Icinga\Module\Setup\Forms\LdapDiscoveryConfirmPage; +//use Icinga\Module\Setup\Forms\LdapDiscoveryConfirmPage; use Icinga\Module\Setup\Forms\LdapResourcePage; use Icinga\Module\Setup\Forms\RequirementsPage; use Icinga\Module\Setup\Forms\GeneralConfigPage; @@ -41,6 +41,17 @@ use Icinga\Module\Setup\Requirement\ConfigDirectoryRequirement; */ class WebWizard extends Wizard implements SetupWizard { + /** + * The privileges required by Icinga Web 2 to create the database and a login + * + * @var array + */ + protected $databaseCreationPrivileges = array( + 'CREATE', + 'CREATE USER', // MySQL + 'CREATEROLE' // PostgreSQL + ); + /** * The privileges required by Icinga Web 2 to setup the database * @@ -48,10 +59,8 @@ class WebWizard extends Wizard implements SetupWizard */ protected $databaseSetupPrivileges = array( 'CREATE', - 'ALTER', - 'REFERENCES', - 'CREATE USER', // MySQL - 'CREATEROLE' // PostgreSQL + 'ALTER', // MySQL only + 'REFERENCES' ); /** @@ -148,7 +157,9 @@ class WebWizard extends Wizard implements SetupWizard $page->setResourceConfig($this->getPageData('setup_ldap_resource')); } } elseif ($page->getName() === 'setup_database_creation') { - $page->setDatabaseSetupPrivileges($this->databaseSetupPrivileges); + $page->setDatabaseSetupPrivileges( + array_merge($this->databaseCreationPrivileges, $this->databaseSetupPrivileges) + ); $page->setDatabaseUsagePrivileges($this->databaseUsagePrivileges); $page->setResourceConfig($this->getPageData('setup_db_resource')); } elseif ($page->getName() === 'setup_summary') { @@ -211,8 +222,8 @@ class WebWizard extends Wizard implements SetupWizard try { $db->connectToDb(); // Are we able to login on the database? if (array_search(key($this->databaseTables), $db->listTables()) === false) { - // In case the database schema does not yet exist the user - // needs the privileges to create and setup the database + // In case the database schema does not yet exist the + // user needs the privileges to setup the database $skip = $db->checkPrivileges($this->databaseSetupPrivileges, $this->databaseTables); } else { // In case the database schema exists the user needs the required privileges @@ -224,7 +235,10 @@ class WebWizard extends Wizard implements SetupWizard $db->connectToHost(); // Are we able to login on the server? // It is not possible to reliably determine whether a database exists or not if a user can't // log in to the database, so we just require the user to be able to create the database - $skip = $db->checkPrivileges($this->databaseSetupPrivileges, $this->databaseTables); + $skip = $db->checkPrivileges( + array_merge($this->databaseCreationPrivileges, $this->databaseSetupPrivileges), + $this->databaseTables + ); } catch (PDOException $_) { // We are NOT able to login on the server.. } From e0891aedca366a9ba15b0ac8822a119ba30d7d28 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Mon, 13 Apr 2015 14:13:02 +0200 Subject: [PATCH 2/3] DbTool: Add mysql context identifiers for the REFERENCES privilege Though this privilege is not in use until mysql version 5.7.6 it is registered as privilege in the privilege tables in earlier versions. refs #8707 --- modules/setup/library/Setup/Utils/DbTool.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/setup/library/Setup/Utils/DbTool.php b/modules/setup/library/Setup/Utils/DbTool.php index 3073778c8..3e5fb479c 100644 --- a/modules/setup/library/Setup/Utils/DbTool.php +++ b/modules/setup/library/Setup/Utils/DbTool.php @@ -78,7 +78,7 @@ class DbTool 'INSERT' => 29, 'LOCK TABLES' => 5, 'PROCESS' => 1, - 'REFERENCES' => 0, + 'REFERENCES' => 12, 'RELOAD' => 1, 'REPLICATION CLIENT' => 1, 'REPLICATION SLAVE' => 1, From a21d54460db20e924415d85467cb81bfa41cdc02 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Mon, 13 Apr 2015 14:17:18 +0200 Subject: [PATCH 3/3] DbTool: Fix that all mysql privileges were checked regardless of their context refs #8707 --- modules/setup/library/Setup/Utils/DbTool.php | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/modules/setup/library/Setup/Utils/DbTool.php b/modules/setup/library/Setup/Utils/DbTool.php index 3e5fb479c..ae2fcc38f 100644 --- a/modules/setup/library/Setup/Utils/DbTool.php +++ b/modules/setup/library/Setup/Utils/DbTool.php @@ -629,10 +629,6 @@ EOD; $mysqlPrivileges = array_intersect($privileges, array_keys($this->mysqlGrantContexts)); list($_, $host) = explode('@', $this->query('select current_user()')->fetchColumn()); $grantee = "'" . ($username === null ? $this->config['username'] : $username) . "'@'" . $host . "'"; - $privilegeCondition = sprintf( - 'privilege_type IN (%s)', - join(',', array_map(array($this, 'quote'), $mysqlPrivileges)) - ); if (isset($this->config['dbname'])) { $dbPrivileges = array(); @@ -653,7 +649,7 @@ EOD; . ' FROM information_schema.schema_privileges' . ' WHERE grantee = :grantee' . ' AND table_schema = :dbname' - . ' AND ' . $privilegeCondition + . ' AND privilege_type IN (' . join(',', array_map(array($this, 'quote'), $dbPrivileges)) . ')' . ($requireGrants ? " AND is_grantable = 'YES'" : ''), array(':grantee' => $grantee, ':dbname' => $this->config['dbname']) ); @@ -666,14 +662,13 @@ EOD; !$dbPrivilegesGranted || array_intersect($dbPrivileges, $tablePrivileges) != $tablePrivileges ) ) { - $tableCondition = 'table_name IN (' . join(',', array_map(array($this, 'quote'), $context)) . ')'; $query = $this->query( 'SELECT COUNT(*) as matches' . ' FROM information_schema.table_privileges' . ' WHERE grantee = :grantee' . ' AND table_schema = :dbname' - . ' AND ' . $tableCondition - . ' AND ' . $privilegeCondition + . ' AND table_name IN (' . join(',', array_map(array($this, 'quote'), $context)) . ')' + . ' AND privilege_type IN (' . join(',', array_map(array($this, 'quote'), $tablePrivileges)) . ')' . ($requireGrants ? " AND is_grantable = 'YES'" : ''), array(':grantee' => $grantee, ':dbname' => $this->config['dbname']) ); @@ -688,7 +683,8 @@ EOD; $query = $this->query( 'SELECT COUNT(*) as matches FROM information_schema.user_privileges WHERE grantee = :grantee' - . ' AND ' . $privilegeCondition . ($requireGrants ? " AND is_grantable = 'YES'" : ''), + . ' AND privilege_type IN (' . join(',', array_map(array($this, 'quote'), $mysqlPrivileges)) . ')' + . ($requireGrants ? " AND is_grantable = 'YES'" : ''), array(':grantee' => $grantee) ); return (int) $query->fetchObject()->matches === count($mysqlPrivileges);