[pkg-nagios-changes] [Git][nagios-team/icingaweb2][upstream] New upstream version 2.12.1

Bas Couwenberg (@sebastic) gitlab at salsa.debian.org
Thu Nov 16 04:51:24 GMT 2023



Bas Couwenberg pushed to branch upstream at Debian Nagios Maintainer Group / icingaweb2


Commits:
ea7d4a78 by Bas Couwenberg at 2023-11-16T05:44:04+01:00
New upstream version 2.12.1
- - - - -


21 changed files:

- CHANGELOG.md
- VERSION
- application/VERSION
- doc/20-Advanced-Topics.md
- library/Icinga/Application/MigrationManager.php
- library/Icinga/Application/Version.php
- library/Icinga/Protocol/Ldap/LdapConnection.php
- library/Icinga/Web/Controller/ActionController.php
- library/Icinga/Web/Response.php
- modules/doc/module.info
- modules/migrate/application/clicommands/NavigationCommand.php
- modules/migrate/module.info
- modules/monitoring/module.info
- modules/setup/application/forms/AdminAccountPage.php
- modules/setup/application/forms/DbResourcePage.php
- modules/setup/library/Setup/Utils/DbTool.php
- modules/setup/library/Setup/WebWizard.php
- modules/setup/module.info
- modules/translation/module.info
- phpstan-baseline.neon
- public/js/icinga/loader.js


Changes:

=====================================
CHANGELOG.md
=====================================
@@ -4,6 +4,31 @@ Please make sure to always read our [Upgrading](doc/80-Upgrading.md) documentati
 
 ## What's New
 
+### What's New in Version 2.12.1
+
+You can find all issues related to this release on our Roadmap.
+
+#### PHP 8.3 Support
+
+This time we're a little ahead for once. PHP 8.3 is due in a week, and we are compatible with it now!
+There's not much else to say about it, so let's continue with the fixes.
+
+* Support for PHP 8.3 [#5136](https://github.com/Icinga/icingaweb2/issues/5136)
+
+#### Fixes
+
+You may have noticed a dashboard endlessly loading in the morning after you got to work again.
+The web server may also have stopped that with a complaint about a too long URL. This is now
+fixed and the dashboard should appear as usual. Then there was an issue with our support for
+PostgreSQL. We learned it the hard way to avoid such already in the past again and again.
+Though, this one slipped through our thorough testing and prevented some from successfully
+migrating the database schema. It's fixed now. Another fixed issue, is that the UI looks
+somewhat skewed if you have CSP enabled and logged out and in again.
+
+* Login Redirect Loop [#5133](https://github.com/Icinga/icingaweb2/issues/5133)
+* UI database migration not fully compatible with PostgreSQL [#5129](https://github.com/Icinga/icingaweb2/issues/5129)
+* Missing styles when logging out and in while CSP is enabled [#5126](https://github.com/Icinga/icingaweb2/issues/5126)
+
 ### What's New in Version 2.12.0
 
 You can find all issues related to this release on our [Roadmap](https://github.com/Icinga/icingaweb2/milestone/79?closed=1).


=====================================
VERSION
=====================================
@@ -1 +1 @@
-v2.12.0
+v2.12.1


=====================================
application/VERSION
=====================================
@@ -1 +1 @@
-7cd79a5c7ff66a6a67ecd55875c214ba4b2c7db4 2023-09-21 16:40:28 +0200
+cd2daeb2cb8537c633d343a29eb76c54cd2ebbf2 2023-11-15 12:50:13 +0100


=====================================
doc/20-Advanced-Topics.md
=====================================
@@ -142,7 +142,7 @@ Here is a list of all Icinga Web components that are capable of strict CSP.
 | Icinga Certificate Monitoring     | [v1.3.0](https://github.com/Icinga/icingaweb2-module-x509/releases/tag/v1.3.0)            |
 | Icinga PDF Export                 | [v0.10.2](https://github.com/Icinga/icingaweb2-module-pdfexport/releases/tag/v0.10.2)     |
 | Icinga Web Jira Integration       | [v1.3.2](https://github.com/Icinga/icingaweb2-module-jira/releases/tag/v1.3.2)            |
-| Icinga Web Graphite Integration   | [v1.3.0](https://github.com/Icinga/icingaweb2-module-graphite/releases/tag/v1.3.0)        |
+| Icinga Web Graphite Integration   | [v1.3.0](https://github.com/Icinga/icingaweb2-module-graphite/releases/tag/v1.2.4)        |
 | Icinga Web GenericTTS Integration | [v2.1.0](https://github.com/Icinga/icingaweb2-module-generictts/releases/tag/v2.1.0)      |
 | Icinga Web Nagvis Integration     | [v1.2.0](https://github.com/Icinga/icingaweb2-module-nagvis/releases/tag/v1.2.0)          |
 | Icinga Web AWS Integration        | [v1.1.0](https://github.com/Icinga/icingaweb2-module-aws/releases/tag/v1.1.0)             |


=====================================
library/Icinga/Application/MigrationManager.php
=====================================
@@ -207,7 +207,7 @@ final class MigrationManager implements Countable
      */
     public function getRequiredDatabasePrivileges(): array
     {
-        return ['CREATE','SELECT','INSERT','UPDATE','DELETE','DROP','ALTER','CREATE VIEW','INDEX','EXECUTE'];
+        return ['CREATE','SELECT','INSERT','UPDATE','DELETE','DROP','ALTER','CREATE VIEW','INDEX','EXECUTE','USAGE'];
     }
 
     /**
@@ -258,7 +258,11 @@ final class MigrationManager implements Countable
         $tool = $this->createDbTool($db);
         $tool->connectToDb();
 
-        if ($tool->checkPrivileges(['SELECT'], [], $actualUsername)) {
+        $isPgsql = $db->getAdapter() instanceof Sql\Adapter\Pgsql;
+        // PgSQL doesn't have SELECT privilege on a database level and granting the CREATE,CONNECT, and TEMPORARY
+        // privileges on a database doesn't permit a user to read data from a table. Hence, we have to grant the
+        // required database,schema and table privileges simultaneously.
+        if (! $isPgsql && $tool->checkPrivileges(['SELECT'], [], $actualUsername)) {
             // Checks only database level grants. If this succeeds, the grants were issued manually.
             if (! $tool->checkPrivileges($privileges, [], $actualUsername) && $tool->isGrantable($privileges)) {
                 // Any missing grant is now granted on database level as well, not to mix things up
@@ -334,13 +338,20 @@ final class MigrationManager implements Countable
 
         $dbTool = $this->createDbTool($conn);
         $dbTool->connectToDb();
-        if (! $dbTool->checkPrivileges($this->getRequiredDatabasePrivileges())
-            && ! $dbTool->checkPrivileges($this->getRequiredDatabasePrivileges(), $tables)
-        ) {
+
+        $isPgsql = $conn->getAdapter() instanceof Sql\Adapter\Pgsql;
+        $privileges = $this->getRequiredDatabasePrivileges();
+        $dbPrivilegesGranted = $dbTool->checkPrivileges($privileges);
+        $tablePrivilegesGranted = $dbTool->checkPrivileges($privileges, $tables);
+        if (! $dbPrivilegesGranted && ($isPgsql || ! $tablePrivilegesGranted)) {
+            return false;
+        }
+
+        if ($isPgsql && ! $tablePrivilegesGranted) {
             return false;
         }
 
-        if ($canIssueGrants && ! $dbTool->isGrantable($this->getRequiredDatabasePrivileges())) {
+        if ($canIssueGrants && ! $dbTool->isGrantable($privileges)) {
             return false;
         }
 


=====================================
library/Icinga/Application/Version.php
=====================================
@@ -8,7 +8,7 @@ namespace Icinga\Application;
  */
 class Version
 {
-    const VERSION = '2.12.0';
+    const VERSION = '2.12.1';
 
     /**
      * Get the version of this instance of Icinga Web 2


=====================================
library/Icinga/Protocol/Ldap/LdapConnection.php
=====================================
@@ -1198,7 +1198,7 @@ class LdapConnection implements Selectable, Inspectable
 
         $hostname = $this->normalizeHostname($this->hostname);
 
-        $ds = ldap_connect($hostname, $this->port);
+        $ds = ldap_connect($hostname);
 
         // Set a proper timeout for each connection
         ldap_set_option($ds, LDAP_OPT_NETWORK_TIMEOUT, $this->timeout);


=====================================
library/Icinga/Web/Controller/ActionController.php
=====================================
@@ -399,7 +399,8 @@ class ActionController extends Zend_Controller_Action
             }
         }
 
-        $this->rerenderLayout()->redirectNow($login);
+        $this->getResponse()->setReloadWindow(true);
+        $this->redirectNow($login);
     }
 
     protected function rerenderLayout()


=====================================
library/Icinga/Web/Response.php
=====================================
@@ -322,7 +322,9 @@ class Response extends Zend_Controller_Response_Http
         if ($request->isXmlHttpRequest()) {
             if ($redirectUrl !== null) {
                 if ($request->isGet() && Icinga::app()->getViewRenderer()->view->compact) {
-                    $redirectUrl->getParams()->set('showCompact', true);
+                    if ($redirectUrl->getParam('redirect') !== '__SELF__') {
+                        $redirectUrl->getParams()->set('showCompact', true);
+                    }
                 }
 
                 $encodedRedirectUrl = rawurlencode($redirectUrl->getAbsoluteUrl());


=====================================
modules/doc/module.info
=====================================
@@ -1,4 +1,4 @@
 Module: doc
-Version: 2.12.0
+Version: 2.12.1
 Description: Documentation module
  Extracts, shows and exports documentation for Icinga Web 2 and its modules.


=====================================
modules/migrate/application/clicommands/NavigationCommand.php
=====================================
@@ -4,192 +4,17 @@
 
 namespace Icinga\Module\Migrate\Clicommands;
 
-use Icinga\Application\Config;
-use Icinga\Application\Icinga;
 use Icinga\Application\Logger;
 use Icinga\Cli\Command;
-use Icinga\Data\ConfigObject;
-use Icinga\Exception\NotReadableError;
-use Icinga\Exception\NotWritableError;
-use Icinga\Module\Icingadb\Compat\UrlMigrator;
-use Icinga\Util\DirectoryIterator;
-use Icinga\Web\Request;
-use ipl\Web\Filter\QueryString;
-use ipl\Web\Url;
 
 class NavigationCommand extends Command
 {
     /**
-     * Migrate local user monitoring navigation items to the Icinga DB Web actions
-     *
-     * USAGE
-     *
-     *  icingacli migrate navigation [options]
-     *
-     * OPTIONS:
-     *
-     *  --user=<username>  Migrate monitoring navigation items only for
-     *                     the given user. (Default *)
-     *
-     *  --delete           Remove the legacy files after successfully
-     *                     migrated the navigation items.
+     * Deprecated. Use `icingacli icingadb migrate navigation` instead.
      */
-    public function indexAction()
+    public function indexAction(): void
     {
-        $moduleManager = Icinga::app()->getModuleManager();
-        if (! $moduleManager->hasEnabled('icingadb')) {
-            Logger::error('Icinga DB module is not enabled. Please verify that the module is installed and enabled.');
-            return;
-        }
-
-        $preferencesPath = Config::resolvePath('preferences');
-        $sharedNavigation = Config::resolvePath('navigation');
-        if (! file_exists($preferencesPath) && ! file_exists($sharedNavigation)) {
-            Logger::info('There are no local user navigation items to migrate');
-            return;
-        }
-
-        $rc = 0;
-        $user = $this->params->get('user');
-        $directories = new DirectoryIterator($preferencesPath);
-
-        foreach ($directories as $directory) {
-            $username = $user;
-            if ($username !== null && $directories->key() !== $username) {
-                continue;
-            }
-
-            if ($username === null) {
-                $username = $directories->key();
-            }
-
-            $hostActions = $this->readFromIni($directory . '/host-actions.ini', $rc);
-            $serviceActions = $this->readFromIni($directory . '/service-actions.ini', $rc);
-
-            Logger::info('Migrating monitoring navigation items for user "%s" to the Icinga DB Web actions', $username);
-
-            if (! $hostActions->isEmpty()) {
-                $this->migrateNavigationItems($hostActions, $directory . '/icingadb-host-actions.ini', $rc);
-            }
-
-            if (! $serviceActions->isEmpty()) {
-                $this->migrateNavigationItems($serviceActions, $directory . '/icingadb-service-actions.ini', $rc);
-            }
-        }
-
-        // Start migrating shared navigation items
-        $hostActions = $this->readFromIni($sharedNavigation . '/host-actions.ini', $rc);
-        $serviceActions = $this->readFromIni($sharedNavigation . '/service-actions.ini', $rc);
-
-        Logger::info('Migrating shared monitoring navigation items to the Icinga DB Web actions');
-
-        if (! $hostActions->isEmpty()) {
-            $this->migrateNavigationItems($hostActions, $sharedNavigation . '/icingadb-host-actions.ini', $rc);
-        }
-
-        if (! $serviceActions->isEmpty()) {
-            $this->migrateNavigationItems($serviceActions, $sharedNavigation . '/icingadb-service-actions.ini', $rc);
-        }
-
-        if ($rc > 0) {
-            Logger::error('Failed to migrate some monitoring navigation items');
-            exit($rc);
-        }
-
-        Logger::info('Successfully migrated all local user monitoring navigation items');
-    }
-
-    /**
-     * Migrate the given config to the given new config path
-     *
-     * @param Config $config
-     * @param string $path
-     * @param int    $rc
-     */
-    private function migrateNavigationItems($config, $path, &$rc)
-    {
-        $deleteLegacyFiles = $this->params->get('delete');
-        $newConfig = $this->readFromIni($path, $rc);
-        $counter = 1;
-
-        /** @var ConfigObject $configObject */
-        foreach ($config->getConfigObject() as $configObject) {
-            // Change the config type from "host-action" to icingadb's new action
-            if (strpos($path, 'icingadb-host-actions') !== false) {
-                $configObject->type = 'icingadb-host-action';
-            } else {
-                $configObject->type = 'icingadb-service-action';
-            }
-
-            $urlString = $configObject->get('url');
-            if ($urlString !== null) {
-                $url = Url::fromPath($urlString, [], new Request());
-
-                try {
-                    $urlString = UrlMigrator::transformUrl($url)->getAbsoluteUrl();
-                    $configObject->url = rawurldecode($urlString);
-                } catch (\InvalidArgumentException $err) {
-                    // Do nothing
-                }
-            }
-
-            $legacyFilter = $configObject->get('filter');
-            if ($legacyFilter !== null) {
-                $filter = QueryString::parse($legacyFilter);
-                $filter = UrlMigrator::transformFilter($filter);
-                if ($filter !== false) {
-                    $configObject->filter = rawurldecode(QueryString::render($filter));
-                } else {
-                    unset($configObject->filter);
-                }
-            }
-
-            $section = $config->key();
-            while ($newConfig->hasSection($section)) {
-                $section = $config->key() . $counter++;
-            }
-
-            $newConfig->setSection($section, $configObject);
-        }
-
-        try {
-            if (! $newConfig->isEmpty()) {
-                $newConfig->saveIni();
-
-                // Remove the legacy file only if explicitly requested
-                if ($deleteLegacyFiles) {
-                    unlink($config->getConfigFile());
-                }
-            }
-        } catch (NotWritableError $error) {
-            Logger::error('%s: %s', $error->getMessage(), $error->getPrevious()->getMessage());
-            $rc = 256;
-        }
-    }
-
-    /**
-     * Get the navigation items config from the given ini path
-     *
-     * @param string $path Absolute path of the ini file
-     * @param int $rc      The return code used to exit the action
-     *
-     * @return Config
-     */
-    private function readFromIni($path, &$rc)
-    {
-        try {
-            $config = Config::fromIni($path);
-        } catch (NotReadableError $error) {
-            if ($error->getPrevious() !== null) {
-                Logger::error('%s: %s', $error->getMessage(), $error->getPrevious()->getMessage());
-            } else {
-                Logger::error($error->getMessage());
-            }
-
-            $config = new Config();
-            $rc = 128;
-        }
-
-        return $config;
+        Logger::error('Deprecated. Use `icingacli icingadb migrate navigation` instead.');
+        exit(1);
     }
 }


=====================================
modules/migrate/module.info
=====================================
@@ -1,5 +1,5 @@
 Module: migrate
-Version: 2.12.0
+Version: 2.12.1
 Description: Migrate module
  This module was introduced with the domain-aware authentication feature in version 2.5.0.
  It helps you migrating users and user configurations according to a given domain.


=====================================
modules/monitoring/module.info
=====================================
@@ -1,5 +1,5 @@
 Module: monitoring
-Version: 2.12.0
+Version: 2.12.1
 Description: Icinga monitoring module
  IDO accessor and UI for your monitoring. This is the initial instalment for a
  graphical presentation of Icinga environments. The predecessor of Icinga DB.


=====================================
modules/setup/application/forms/AdminAccountPage.php
=====================================
@@ -301,8 +301,9 @@ class AdminAccountPage extends Form
                 ->select(array('user_name'))
                 ->order('user_name', 'asc', true);
             if (in_array($this->backendConfig['backend'], array('ldap', 'msldap'))) {
-                /** @var LdapQuery $query */
-                $query->setUsePagedResults();
+                /** @var LdapQuery $ldapQuery */
+                $ldapQuery = $query->getQuery();
+                $ldapQuery->setUsePagedResults();
             }
 
             return $query->fetchColumn();
@@ -360,8 +361,9 @@ class AdminAccountPage extends Form
                 ->createUserGroupBackend()
                 ->select(array('group_name'));
             if (in_array($this->backendConfig['backend'], array('ldap', 'msldap'))) {
-                /** @var LdapQuery $query */
-                $query->setUsePagedResults();
+                /** @var LdapQuery $ldapQuery */
+                $ldapQuery = $query->getQuery();
+                $ldapQuery->setUsePagedResults();
             }
 
             return $query->fetchColumn();


=====================================
modules/setup/application/forms/DbResourcePage.php
=====================================
@@ -141,14 +141,14 @@ class DbResourcePage extends Form
 
         if ($this->getValue('db') === 'pgsql') {
             if ($connectionError !== null) {
-                $this->warning(sprintf(
-                    $this->translate('Unable to check the server\'s version. This is usually not a critical error'
-                    . ' as there is probably only access to the database permitted which does not exist yet. If you are'
-                    . ' absolutely sure you are running PostgreSQL in a version equal to or newer than 9.1,'
-                    . ' you can skip the validation and safely proceed to the next step. The error was: %s'),
-                    $connectionError->getMessage()
-                ));
-                $state = false;
+//              $this->warning(sprintf(
+//                  $this->translate('Unable to check the server\'s version. This is usually not a critical error'
+//                  . ' as there is probably only access to the database permitted which does not exist yet. If you are'
+//                  . ' absolutely sure you are running PostgreSQL in a version equal to or newer than 9.1,'
+//                  . ' you can skip the validation and safely proceed to the next step. The error was: %s'),
+//                  $connectionError->getMessage()
+//              ));
+//              $state = false;
             } else {
                 $version = $db->getServerVersion();
                 if (version_compare($version, '9.1', '<')) {


=====================================
modules/setup/library/Setup/Utils/DbTool.php
=====================================
@@ -99,14 +99,7 @@ class DbTool
     protected $pgsqlGrantContexts = array(
         'ALL'               => 63,
         'ALL PRIVILEGES'    => 63,
-        'SELECT'            => 24,
-        'INSERT'            => 24,
-        'UPDATE'            => 24,
-        'DELETE'            => 8,
-        'TRUNCATE'          => 8,
-        'REFERENCES'        => 24,
-        'TRIGGER'           => 8,
-        'CREATE'            => 12,
+        'CREATE'            => 13,
         'CONNECT'           => 4,
         'TEMPORARY'         => 4,
         'TEMP'              => 4,
@@ -633,13 +626,21 @@ class DbTool
             }
         } elseif ($this->config['db'] === 'pgsql') {
             $dbPrivileges = array();
-            $tablePrivileges = array();
+            $schemaPrivileges = [];
             foreach (array_intersect($privileges, array_keys($this->pgsqlGrantContexts)) as $privilege) {
-                if (! 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;
                 }
+
+                if ($this->pgsqlGrantContexts[$privilege] & static::GLOBAL_LEVEL) {
+                    $schemaPrivileges[] = $privilege;
+                }
+            }
+
+            if (! empty($schemaPrivileges)) {
+                // Allow the user to create,alter and use all attribute types in schema public
+                // such as creating and dropping custom data types (boolenum)
+                $this->exec(sprintf('GRANT %s ON SCHEMA public TO %s', implode(',', $schemaPrivileges), $username));
             }
 
             if (! empty($dbPrivileges)) {
@@ -651,15 +652,10 @@ class DbTool
                 ));
             }
 
-            if (! empty($tablePrivileges)) {
-                foreach ($context as $table) {
-                    $this->exec(sprintf(
-                        'GRANT %s ON TABLE %s TO %s',
-                        join(',', $tablePrivileges),
-                        $table,
-                        $username
-                    ));
-                }
+            foreach ($context as $table) {
+                // PostgreSQL documentation says "You must own the table to use ALTER TABLE.", hence it isn't
+                // sufficient to just issue grants, as the user is still not allowed to alter that table.
+                $this->exec(sprintf('ALTER TABLE %s OWNER TO %s', $table, $username));
             }
         }
     }
@@ -854,57 +850,71 @@ EOD;
         $username = null
     ) {
         $privilegesGranted = true;
+        $owner = $username ?: $this->config['username'];
+        $isSuperUser = $this->query('select rolsuper from pg_roles where rolname = :user', [':user' => $owner])
+            ->fetchColumn();
+
         if ($this->dbFromConfig) {
+            $schemaPrivileges = [];
             $dbPrivileges = array();
-            $tablePrivileges = array();
-            foreach (array_intersect($privileges, array_keys($this->pgsqlGrantContexts)) as $privilege) {
-                if (! empty($context) && $this->pgsqlGrantContexts[$privilege] & static::TABLE_LEVEL) {
-                    $tablePrivileges[] = $privilege;
-                }
-                if ($this->pgsqlGrantContexts[$privilege] & static::DATABASE_LEVEL) {
-                    $dbPrivileges[] = $privilege;
+            if (! $isSuperUser) {
+                foreach (array_intersect($privileges, array_keys($this->pgsqlGrantContexts)) as $privilege) {
+                    if ($this->pgsqlGrantContexts[$privilege] & static::DATABASE_LEVEL) {
+                        $dbPrivileges[] = $privilege;
+                    }
+                    if ($this->pgsqlGrantContexts[$privilege] & static::GLOBAL_LEVEL) {
+                        $schemaPrivileges[] = $privilege;
+                    }
                 }
-            }
 
-            if (! empty($dbPrivileges)) {
-                $dbExclusivesGranted = true;
-                foreach ($dbPrivileges as $dbPrivilege) {
-                    $query = $this->query(
-                        'SELECT has_database_privilege(:user, :dbname, :privilege) AS db_privilege_granted',
-                        array(
-                            ':user'         => $username !== null ? $username : $this->config['username'],
-                            ':dbname'       => $this->config['dbname'],
-                            ':privilege'    => $dbPrivilege . ($requireGrants ? ' WITH GRANT OPTION' : '')
-                        )
-                    );
-                    if (! $query->fetchObject()->db_privilege_granted) {
-                        $privilegesGranted = false;
-                        if (! in_array($dbPrivilege, $tablePrivileges)) {
-                            $dbExclusivesGranted = false;
+                if (! empty($schemaPrivileges)) {
+                    foreach ($schemaPrivileges as $schemaPrivilege) {
+                        $query = $this->query(
+                            'SELECT has_schema_privilege(:user, :schema, :privilege) AS db_privilege_granted',
+                            [
+                                ':user'      => $owner,
+                                ':schema'    => 'public',
+                                ':privilege' => $schemaPrivilege . ($requireGrants ? ' WITH GRANT OPTION' : '')
+                            ]
+                        );
+
+                        if (! $query->fetchObject()->db_privilege_granted) {
+                            // The user doesn't fully have the provided privileges.
+                            $privilegesGranted = false;
+                            break;
                         }
                     }
                 }
 
-                if ($privilegesGranted) {
-                    // Do not check privileges twice if they are already granted at database level
-                    $tablePrivileges = array_diff($tablePrivileges, $dbPrivileges);
-                } elseif ($dbExclusivesGranted) {
-                    $privilegesGranted = true;
-                }
-            }
-
-            if ($privilegesGranted && !empty($tablePrivileges)) {
-                foreach (array_intersect($context, $this->listTables()) as $table) {
-                    foreach ($tablePrivileges as $tablePrivilege) {
+                if ($privilegesGranted && ! empty($dbPrivileges)) {
+                    foreach ($dbPrivileges as $dbPrivilege) {
                         $query = $this->query(
-                            'SELECT has_table_privilege(:user, :table, :privilege) AS table_privilege_granted',
+                            'SELECT has_database_privilege(:user, :dbname, :privilege) AS db_privilege_granted',
                             array(
-                                ':user'         => $username !== null ? $username : $this->config['username'],
-                                ':table'        => $table,
-                                ':privilege'    => $tablePrivilege . ($requireGrants ? ' WITH GRANT OPTION' : '')
+                                ':user'         => $owner,
+                                ':dbname'       => $this->config['dbname'],
+                                ':privilege'    => $dbPrivilege . ($requireGrants ? ' WITH GRANT OPTION' : '')
                             )
                         );
-                        $privilegesGranted &= $query->fetchObject()->table_privilege_granted;
+                        if (! $query->fetchObject()->db_privilege_granted) {
+                            // The user doesn't fully have the provided privileges.
+                            $privilegesGranted = false;
+                            break;
+                        }
+                    }
+                }
+
+                if ($privilegesGranted && ! empty($context)) {
+                    foreach (array_intersect($context, $this->listTables()) as $table) {
+                        $query = $this->query(
+                            'SELECT tableowner FROM pg_catalog.pg_tables WHERE tablename = :tablename',
+                            [':tablename' => $table]
+                        );
+
+                        if ($query->fetchColumn() !== $owner) {
+                            $privilegesGranted = false;
+                            break;
+                        }
                     }
                 }
             }
@@ -914,31 +924,27 @@ EOD;
             // 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, true) !== false) {
+            if (in_array('CREATE', $privileges, true)) {
                 $query = $this->query(
                     'select rolcreatedb from pg_roles where rolname = :user',
                     array(':user' => $username !== null ? $username : $this->config['username'])
                 );
-                $privilegesGranted &= $query->fetchColumn() !== false;
+                $privilegesGranted = $query->fetchColumn() !== false;
             }
         }
 
-        if (array_search('CREATEROLE', $privileges, true) !== false) {
+        if ($privilegesGranted && in_array('CREATEROLE', $privileges, true)) {
             $query = $this->query(
                 'select rolcreaterole from pg_roles where rolname = :user',
                 array(':user' => $username !== null ? $username : $this->config['username'])
             );
-            $privilegesGranted &= $query->fetchColumn() !== false;
+            $privilegesGranted = $query->fetchColumn() !== false;
         }
 
-        if (array_search('SUPER', $privileges, true) !== false) {
-            $query = $this->query(
-                'select rolsuper from pg_roles where rolname = :user',
-                array(':user' => $username !== null ? $username : $this->config['username'])
-            );
-            $privilegesGranted &= $query->fetchColumn() !== false;
+        if ($privilegesGranted && in_array('SUPER', $privileges, true)) {
+            $privilegesGranted = $isSuperUser === true;
         }
 
-        return (bool) $privilegesGranted;
+        return $privilegesGranted;
     }
 }


=====================================
modules/setup/library/Setup/WebWizard.php
=====================================
@@ -83,6 +83,7 @@ class WebWizard extends Wizard implements SetupWizard
         'ALTER',
         'DROP',
         'INDEX',
+        'USAGE', // PostgreSQL
         'TEMPORARY', // PostgreSql
         'CREATE TEMPORARY TABLES' // MySQL
     );


=====================================
modules/setup/module.info
=====================================
@@ -1,5 +1,5 @@
 Module: setup
-Version: 2.12.0
+Version: 2.12.1
 Description: Setup module
  Web based wizard for setting up Icinga Web 2 and its modules.
  This includes the data backends (e.g. relational database, LDAP),


=====================================
modules/translation/module.info
=====================================
@@ -1,5 +1,5 @@
 Module: translation
-Version: 2.12.0
+Version: 2.12.1
 Description: Translation module
  This module allows developers and translators to translate modules for multiple
  languages. You do not need this module to run an internationalized web frontend.


=====================================
phpstan-baseline.neon
=====================================
@@ -7467,7 +7467,7 @@ parameters:
 
 		-
 			message: "#^Cannot access offset string on mixed\\.$#"
-			count: 3
+			count: 2
 			path: library/Icinga/Data/Db/DbQuery.php
 
 		-
@@ -9137,7 +9137,7 @@ parameters:
 
 		-
 			message: "#^Cannot access offset int\\<0, max\\> on array\\<int\\|string, mixed\\>\\|false\\.$#"
-			count: 3
+			count: 2
 			path: library/Icinga/File/Storage/LocalFileStorage.php
 
 		-
@@ -11620,11 +11620,6 @@ parameters:
 			count: 1
 			path: library/Icinga/Util/Format.php
 
-		-
-			message: "#^Parameter \\#1 \\$timestamp of method DateTime\\:\\:setTimestamp\\(\\) expects int, DateTime\\|int given\\.$#"
-			count: 2
-			path: library/Icinga/Util/Format.php
-
 		-
 			message: "#^Property Icinga\\\\Util\\\\Format\\:\\:\\$bitBase has no type specified\\.$#"
 			count: 1
@@ -11797,17 +11792,17 @@ parameters:
 
 		-
 			message: "#^Cannot access offset 'acknowledged' on mixed\\.$#"
-			count: 2
+			count: 1
 			path: library/Icinga/Web/Announcement/AnnouncementCookie.php
 
 		-
 			message: "#^Cannot access offset 'etag' on mixed\\.$#"
-			count: 2
+			count: 1
 			path: library/Icinga/Web/Announcement/AnnouncementCookie.php
 
 		-
 			message: "#^Cannot access offset 'next' on mixed\\.$#"
-			count: 2
+			count: 1
 			path: library/Icinga/Web/Announcement/AnnouncementCookie.php
 
 		-
@@ -11872,7 +11867,7 @@ parameters:
 
 		-
 			message: "#^Cannot access offset 'acknowledged…' on mixed\\.$#"
-			count: 2
+			count: 1
 			path: library/Icinga/Web/ApplicationStateCookie.php
 
 		-
@@ -12407,12 +12402,12 @@ parameters:
 
 		-
 			message: "#^Cannot access offset 'decorators' on mixed\\.$#"
-			count: 4
+			count: 2
 			path: library/Icinga/Web/Form.php
 
 		-
 			message: "#^Cannot access offset 'type' on mixed\\.$#"
-			count: 2
+			count: 1
 			path: library/Icinga/Web/Form.php
 
 		-
@@ -16865,31 +16860,6 @@ parameters:
 			count: 1
 			path: modules/migrate/application/clicommands/ConfigCommand.php
 
-		-
-			message: "#^Cannot call method getMessage\\(\\) on Throwable\\|null\\.$#"
-			count: 1
-			path: modules/migrate/application/clicommands/NavigationCommand.php
-
-		-
-			message: "#^Method Icinga\\\\Module\\\\Migrate\\\\Clicommands\\\\NavigationCommand\\:\\:indexAction\\(\\) has no return type specified\\.$#"
-			count: 1
-			path: modules/migrate/application/clicommands/NavigationCommand.php
-
-		-
-			message: "#^Method Icinga\\\\Module\\\\Migrate\\\\Clicommands\\\\NavigationCommand\\:\\:migrateNavigationItems\\(\\) has no return type specified\\.$#"
-			count: 1
-			path: modules/migrate/application/clicommands/NavigationCommand.php
-
-		-
-			message: "#^Parameter \\#1 \\$string of static method ipl\\\\Web\\\\Filter\\\\QueryString\\:\\:parse\\(\\) expects string, mixed given\\.$#"
-			count: 1
-			path: modules/migrate/application/clicommands/NavigationCommand.php
-
-		-
-			message: "#^Parameter \\#1 \\$url of static method Icinga\\\\Web\\\\Url\\:\\:fromPath\\(\\) expects string, mixed given\\.$#"
-			count: 1
-			path: modules/migrate/application/clicommands/NavigationCommand.php
-
 		-
 			message: "#^Cannot call method getMessage\\(\\) on Throwable\\|null\\.$#"
 			count: 1
@@ -20552,7 +20522,7 @@ parameters:
 
 		-
 			message: "#^Cannot access offset 'joinCondition' on mixed\\.$#"
-			count: 5
+			count: 3
 			path: modules/monitoring/library/Monitoring/Backend/Ido/Query/IdoQuery.php
 
 		-
@@ -22287,12 +22257,12 @@ parameters:
 
 		-
 			message: "#^Cannot access offset 'code' on mixed\\.$#"
-			count: 3
+			count: 1
 			path: modules/monitoring/library/Monitoring/Command/Transport/ApiCommandTransport.php
 
 		-
 			message: "#^Cannot access offset 'error' on mixed\\.$#"
-			count: 4
+			count: 2
 			path: modules/monitoring/library/Monitoring/Command/Transport/ApiCommandTransport.php
 
 		-
@@ -23315,11 +23285,6 @@ parameters:
 			count: 1
 			path: modules/monitoring/library/Monitoring/Object/MonitoredObject.php
 
-		-
-			message: "#^Cannot access offset string on array\\|stdClass\\.$#"
-			count: 2
-			path: modules/monitoring/library/Monitoring/Object/MonitoredObject.php
-
 		-
 			message: "#^Cannot access property \\$is_json on mixed\\.$#"
 			count: 2
@@ -25532,7 +25497,7 @@ parameters:
 
 		-
 			message: "#^Cannot call method fetchColumn\\(\\) on mixed\\.$#"
-			count: 8
+			count: 9
 			path: modules/setup/library/Setup/Utils/DbTool.php
 
 		-
@@ -25665,11 +25630,6 @@ parameters:
 			count: 1
 			path: modules/setup/library/Setup/Utils/DbTool.php
 
-		-
-			message: "#^Parameter \\#1 \\$array of function array_intersect expects array, array\\|null given\\.$#"
-			count: 1
-			path: modules/setup/library/Setup/Utils/DbTool.php
-
 		-
 			message: "#^Parameter \\#1 \\$dbname of method Icinga\\\\Module\\\\Setup\\\\Utils\\\\DbTool\\:\\:pdoConnect\\(\\) expects string, string\\|null given\\.$#"
 			count: 1
@@ -26042,7 +26002,7 @@ parameters:
 
 		-
 			message: "#^Cannot access offset mixed on int\\.$#"
-			count: 7
+			count: 5
 			path: modules/translation/library/Translation/Cli/ArrayToTextTableHelper.php
 
 		-


=====================================
public/js/icinga/loader.js
=====================================
@@ -524,11 +524,11 @@
                 var originUrl = req.$target.data('icingaUrl');
 
                 $(window).on('popstate.__back__', { self: this }, function (event) {
-                    var _this = event.data.self;
-                    var $refreshTarget = $('#col2');
-                    var refreshUrl;
+                    const _this = event.data.self;
+                    let $refreshTarget = $('#col2');
+                    let refreshUrl;
 
-                    var hash = icinga.history.getCol2State();
+                    const hash = icinga.history.getCol2State();
                     if (hash && hash.match(/^#!/)) {
                         // TODO: These three lines are copied from history.js, I don't like this
                         var parts = hash.split(/#!/);
@@ -546,22 +546,10 @@
                         $refreshTarget = $('#col1');
                     }
 
-                    // loadUrl won't run this request, as due to the history handling it's already running.
-                    // The important bit though is that it returns this (already running) request. This way
-                    // it's possible to set `scripted = true` on the request. (`addToHistory = true` should
-                    // already be the case, though it's added again just in case it's not already `true`..)
-                    var req = _this.loadUrl(refreshUrl, $refreshTarget);
-                    req.addToHistory = false;
-                    req.scripted = true;
-
-                    setTimeout(function () {
-                        // TODO: Find a better solution than a hardcoded one
-                        // This is still the *cheat* to get live results
-                        // (in case there's a delay and a change is not instantly effective)
-                        var req = _this.loadUrl(refreshUrl, $refreshTarget);
-                        req.addToHistory = false;
-                        req.scripted = true;
-                    }, 1000);
+                    const refreshReq = _this.loadUrl(refreshUrl, $refreshTarget);
+                    refreshReq.autoRefreshInterval = req.getResponseHeader('X-Icinga-Refresh');
+                    refreshReq.autorefresh = true;
+                    refreshReq.scripted = true;
 
                     $(window).off('popstate.__back__');
                 });
@@ -649,6 +637,7 @@
                 var redirectionUrl = icinga.utils.addUrlFlag(url, 'renderLayout');
                 var r = this.loadUrl(redirectionUrl, $('#layout'));
                 r.historyUrl = url;
+                r.referrer = referrer;
                 if (parts.length) {
                     r.loadNext = parts;
                 } else if (!! document.location.hash) {
@@ -801,14 +790,9 @@
                 this.icinga.ui.setWindowId(windowId);
             }
 
-            var referrer = req.referrer;
-            if (typeof referrer === 'undefined') {
-                referrer = req;
-            }
-
             var autoSubmit = false;
             var currentUrl = this.icinga.utils.parseUrl(req.$target.data('icingaUrl'));
-            if (referrer.method === 'POST') {
+            if (req.method === 'POST') {
                 var newUrl = this.icinga.utils.parseUrl(req.url);
                 if (newUrl.path === currentUrl.path && this.icinga.utils.arraysEqual(newUrl.params, currentUrl.params)) {
                     autoSubmit = true;
@@ -828,7 +812,7 @@
                     let url = currentUrl.path + (locationQuery ? '?' + locationQuery : '');
                     if (req.autosubmit || autoSubmit) {
                         // Also update a form's action if it doesn't differ from the container's url
-                        var $form = $(referrer.forceFocus).closest('form');
+                        var $form = $(req.forceFocus).closest('form');
                         var formAction = $form.attr('action');
                         if (!! formAction) {
                             formAction = this.icinga.utils.parseUrl(formAction);
@@ -973,7 +957,7 @@
                 });
             }
 
-            if (this.processRedirectHeader(req)) {
+            if ((textStatus === 'abort' && typeof req.referrer !== 'undefined') || this.processRedirectHeader(req)) {
                 return;
             }
 



View it on GitLab: https://salsa.debian.org/nagios-team/icingaweb2/-/commit/ea7d4a781d4addfb4ead662f12cc7c98ee4a19e4

-- 
View it on GitLab: https://salsa.debian.org/nagios-team/icingaweb2/-/commit/ea7d4a781d4addfb4ead662f12cc7c98ee4a19e4
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-nagios-changes/attachments/20231116/54c3cbd8/attachment-0001.htm>


More information about the pkg-nagios-changes mailing list