diff --git a/Jenkinsfile b/Jenkinsfile
index dbc405468e8..4a12d0562f6 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -308,7 +308,7 @@ try {
checkout scm
}
sh 'rm -rf *.deb'
- sh 'docker run -i --entrypoint /src/centreon/ci/scripts/centreon-deb-package.sh -w "/src" -v "$PWD:/src" -e DISTRIB="bullseye" -e VERSION=$VERSION -e RELEASE=$RELEASE registry.centreon.com/centreon-debian11-dependencies:22.04'
+ sh 'docker run -i --entrypoint /src/centreon/ci/scripts/centreon-deb-package.sh -w "/src" -v "$PWD:/src" -e DISTRIB="bullseye" -e VERSION=$VERSION -e RELEASE=$RELEASE registry.centreon.com/mon-build-dependencies-22.04:debian11'
stash name: 'Debian11', includes: '*.deb'
archiveArtifacts artifacts: "*"
sh 'rm -rf *.deb'
diff --git a/SECURITY_ACK.md b/SECURITY_ACK.md
index e0ab076587b..ebe04dfb8f7 100644
--- a/SECURITY_ACK.md
+++ b/SECURITY_ACK.md
@@ -14,6 +14,7 @@ Centreon reserves the right to make final decisions regarding publishing acknowl
2022
+* 2022/05/23 - Lucas Carmo and Daniel França Lima from [Hakaï Security](https://www.hakaioffensivesecurity.com/)
* 2022/02/16 - Anonymous working with Trend Micro Zero Day Initiative
2021
diff --git a/ci/debian/rules b/ci/debian/rules
index 0e8ee8a1a3c..287f52a3658 100644
--- a/ci/debian/rules
+++ b/ci/debian/rules
@@ -13,7 +13,7 @@ override_dh_clean:
override_dh_auto_build:
composer install --no-dev --optimize-autoloader -n
- npm ci
+ npm ci --legacy-peer-deps
npm run build
find . -type f | \
grep -v debian/extra/centreon-web/centreon-macroreplacement.txt | \
diff --git a/ci/scripts/centreon-deb-package.sh b/ci/scripts/centreon-deb-package.sh
index d7a1cdcca36..be700cfccb0 100755
--- a/ci/scripts/centreon-deb-package.sh
+++ b/ci/scripts/centreon-deb-package.sh
@@ -39,9 +39,8 @@ done
rm -rf lang
# Generate API documentation.
-apt install -y npm && sleep 30
-npm install -g redoc-cli
-/usr/local/bin/redoc-cli bundle --options.hideDownloadButton=true doc/API/centreon-api-v${MAJOR_VERSION}.yaml -o ../centreon-api-v${MAJOR_VERSION}.html
+npm i -g redoc-cli
+redoc-cli build --options.hideDownloadButton=true doc/API/centreon-api-v${MAJOR_VERSION}.yaml -o ../centreon-api-v${MAJOR_VERSION}.html
# Make tar with original content
cd ..
diff --git a/composer.json b/composer.json
index c7c1a574bcd..aade76f0c59 100644
--- a/composer.json
+++ b/composer.json
@@ -65,6 +65,7 @@
"symfony/framework-bundle": "5.4.*",
"symfony/http-client": "5.4.*",
"symfony/http-kernel": "5.4.*",
+ "symfony/lock": "5.4.*",
"symfony/maker-bundle": "^1.11",
"symfony/monolog-bundle": "^3.7",
"symfony/options-resolver": "5.4.*",
@@ -85,7 +86,7 @@
"Tests\\": "tests/php/",
"Centreon\\Test\\Api\\": "tests/api/"
},
- "classmap": ["www/class/"],
+ "classmap": ["www/class/", "lib/Centreon"],
"files" : [
"GPL_LIB/smarty-plugins/function.eval.php",
"www/api/exceptions.php",
diff --git a/composer.lock b/composer.lock
index 23c9b05bd79..366ec06e77c 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "94134d5a5dc2cb311e57863a9f0dafd8",
+ "content-hash": "668e34fd2ddb66b073d8e525d65c166a",
"packages": [
{
"name": "beberlei/assert",
@@ -3623,6 +3623,85 @@
],
"time": "2022-05-27T07:09:08+00:00"
},
+ {
+ "name": "symfony/lock",
+ "version": "v5.4.10",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/lock.git",
+ "reference": "41a308008d92d30cae5615d903c4d46d95932eea"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/lock/zipball/41a308008d92d30cae5615d903c4d46d95932eea",
+ "reference": "41a308008d92d30cae5615d903c4d46d95932eea",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2.5",
+ "psr/log": "^1|^2|^3",
+ "symfony/deprecation-contracts": "^2.1|^3",
+ "symfony/polyfill-php80": "^1.16"
+ },
+ "conflict": {
+ "doctrine/dbal": "<2.13"
+ },
+ "require-dev": {
+ "doctrine/dbal": "^2.13|^3.0",
+ "predis/predis": "~1.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Lock\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jérémy Derussé",
+ "email": "jeremy@derusse.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Creates and manages locks, a mechanism to provide exclusive access to a shared resource",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "cas",
+ "flock",
+ "locking",
+ "mutex",
+ "redlock",
+ "semaphore"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/lock/tree/v5.4.10"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2022-06-09T13:29:56+00:00"
+ },
{
"name": "symfony/maker-bundle",
"version": "v1.43.0",
@@ -6549,12 +6628,12 @@
"source": {
"type": "git",
"url": "https://github.com/centreon/centreon-test-lib.git",
- "reference": "2aed30ebf46d7b76478166fdf122112a1c3722c6"
+ "reference": "6333b03d4d26974d1595e2b00960b86e9a338f74"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/centreon/centreon-test-lib/zipball/2aed30ebf46d7b76478166fdf122112a1c3722c6",
- "reference": "2aed30ebf46d7b76478166fdf122112a1c3722c6",
+ "url": "https://api.github.com/repos/centreon/centreon-test-lib/zipball/6333b03d4d26974d1595e2b00960b86e9a338f74",
+ "reference": "6333b03d4d26974d1595e2b00960b86e9a338f74",
"shasum": ""
},
"require": {
@@ -6599,7 +6678,7 @@
"issues": "https://github.com/centreon/centreon-test-lib/issues",
"source": "https://github.com/centreon/centreon-test-lib/tree/master"
},
- "time": "2022-04-27T09:10:57+00:00"
+ "time": "2022-08-05T09:52:42+00:00"
},
{
"name": "facade/ignition-contracts",
@@ -10885,5 +10964,5 @@
"platform-overrides": {
"php": "8.0"
},
- "plugin-api-version": "2.1.0"
+ "plugin-api-version": "2.3.0"
}
diff --git a/config/packages/Centreon.yaml b/config/packages/Centreon.yaml
index f0d99f90221..f8efbb150f4 100644
--- a/config/packages/Centreon.yaml
+++ b/config/packages/Centreon.yaml
@@ -223,6 +223,42 @@ services:
class: Core\Infrastructure\Platform\Repository\FileReadPlatformRepository
arguments: ['%centreon_etc_path%', '%centreon_install_path%']
+ Core\Platform\Application\Validator\RequirementValidatorsInterface:
+ class: Core\Platform\Infrastructure\Validator\RequirementValidators
+ arguments:
+ $requirementValidators: !tagged_iterator 'platform.requirement.validators'
+
+ Core\Platform\Infrastructure\Validator\RequirementValidators\DatabaseRequirementValidator:
+ arguments:
+ $dbRequirementValidators: !tagged_iterator 'platform.requirement.database.validators'
+
+ Core\Platform\Infrastructure\Validator\RequirementValidators\PhpRequirementValidator:
+ arguments:
+ $requiredPhpVersion: '%required_php_version%'
+
+ Core\Platform\Infrastructure\Validator\RequirementValidators\DatabaseRequirementValidators\MariaDbRequirementValidator:
+ arguments:
+ $requiredMariaDbMinVersion: '%required_mariadb_min_version%'
+
+ Core\Platform\Application\Repository\ReadVersionRepositoryInterface:
+ class: Core\Platform\Infrastructure\Repository\DbReadVersionRepository
+ public: true
+
+ Core\Platform\Application\Repository\ReadUpdateRepositoryInterface:
+ class: Core\Platform\Infrastructure\Repository\FsReadUpdateRepository
+ arguments:
+ $installDir: '%centreon_install_path%'
+ public: true
+
+ Core\Platform\Application\Repository\UpdateLockerRepositoryInterface:
+ class: Core\Platform\Infrastructure\Repository\SymfonyUpdateLockerRepository
+ public: true
+
+ Core\Platform\Application\Repository\WriteUpdateRepositoryInterface:
+ class: Core\Platform\Infrastructure\Repository\DbWriteUpdateRepository
+ arguments: ['%centreon_var_lib%', '%centreon_install_path%']
+ public: true
+
# Monitoring resources
_instanceof:
Centreon\Infrastructure\Monitoring\Resource\Provider\ProviderInterface:
@@ -238,6 +274,10 @@ services:
tags: ['authentication.provider.responses']
Core\Security\Infrastructure\Api\FindProviderConfigurations\ProviderPresenter\ProviderPresenterInterface:
tags: ['authentication.provider.presenters']
+ Core\Platform\Application\Validator\RequirementValidatorInterface:
+ tags: ['platform.requirement.validators']
+ Core\Platform\Infrastructure\Validator\RequirementValidators\DatabaseRequirementValidatorInterface:
+ tags: ['platform.requirement.database.validators']
Centreon\Domain\Monitoring\Interfaces\ResourceRepositoryInterface:
factory: ['@Centreon\Infrastructure\Monitoring\Resource\ResourceRepositoryFactory', 'createResourceRepository']
diff --git a/config/routes/Centreon/platform.yaml b/config/routes/Centreon/platform.yaml
index a521348ecbf..d77666e43f6 100644
--- a/config/routes/Centreon/platform.yaml
+++ b/config/routes/Centreon/platform.yaml
@@ -4,6 +4,12 @@ centreon_application_platform_getversion:
controller: 'Centreon\Application\Controller\PlatformController::getVersions'
condition: "request.attributes.get('version') >= 21.10"
+centreon_application_platform_updateversions:
+ methods: PATCH
+ path: /platform/updates
+ controller: 'Core\Platform\Infrastructure\Api\UpdateVersions\UpdateVersionsController'
+ condition: "request.attributes.get('version') >= 22.04"
+
centreon_application_platformtopology_addplatformtotopology:
methods: POST
path: /platform/topology
diff --git a/config/services.yaml b/config/services.yaml
index 41975cd9de1..566596ebc51 100644
--- a/config/services.yaml
+++ b/config/services.yaml
@@ -22,6 +22,8 @@ parameters:
media_path: "img/media"
redirect_default_page: "/monitoring/resources"
session_expiration_delay: 120
+ required_php_version: "%env(_CENTREON_PHP_VERSION_)%"
+ required_mariadb_min_version: "%env(_CENTREON_MARIA_DB_MIN_VERSION_)%"
services:
# Default configuration for services in *this* file
@@ -66,6 +68,9 @@ services:
decorates: router
arguments: ['@.inner']
+ Symfony\Component\Finder\Finder:
+ shared: false
+
# Security
Security\Domain\Authentication\Interfaces\AuthenticationRepositoryInterface:
diff --git a/cron/centAcl.php b/cron/centAcl.php
index be8e3dc0c61..320231a2d43 100644
--- a/cron/centAcl.php
+++ b/cron/centAcl.php
@@ -172,15 +172,15 @@
* Remove data from old groups (deleted groups)
*/
$aclGroupToDelete = "SELECT DISTINCT acl_group_id
- FROM " . $centreonDbName . ".acl_groups WHERE acl_group_activate = '1'";
- $aclGroupToDelete2 = "SELECT DISTINCT acl_group_id FROM " . $centreonDbName . ".acl_res_group_relations";
- $pearDB->beginTransaction();
+ FROM `" . $centreonDbName . "`.acl_groups WHERE acl_group_activate = '1'";
+ $aclGroupToDelete2 = "SELECT DISTINCT acl_group_id FROM `" . $centreonDbName . "`.acl_res_group_relations";
+ $pearDBO->beginTransaction();
try {
$pearDBO->query("DELETE FROM centreon_acl WHERE group_id NOT IN (" . $aclGroupToDelete . ")");
$pearDBO->query("DELETE FROM centreon_acl WHERE group_id NOT IN (" . $aclGroupToDelete2 . ")");
- $pearDB->commit();
+ $pearDBO->commit();
} catch (\PDOException $e) {
- $pearDB->rollBack();
+ $pearDBO->rollBack();
$centreonLog->insertLog(
2,
"CentACL CRON: failed to delete old groups relations"
diff --git a/doc/API/centreon-api-v22.04.yaml b/doc/API/centreon-api-v22.04.yaml
index a75b7a57821..34f82120597 100644
--- a/doc/API/centreon-api-v22.04.yaml
+++ b/doc/API/centreon-api-v22.04.yaml
@@ -3528,6 +3528,8 @@ paths:
moduleName:
type: object
$ref: '#/components/schemas/Platform.Versions'
+ /platform/updates:
+ $ref: "./v22.04/Administration/updates.yaml"
/platform/installation/status:
get:
tags:
@@ -3541,7 +3543,7 @@ paths:
application/json:
schema:
type: object
- required: ["installed_version", "has_upgrade_available"]
+ required: ["is_installed", "has_upgrade_available"]
properties:
is_installed:
type: boolean
diff --git a/doc/API/v22.04/Administration/updates.yaml b/doc/API/v22.04/Administration/updates.yaml
new file mode 100644
index 00000000000..58e895903c1
--- /dev/null
+++ b/doc/API/v22.04/Administration/updates.yaml
@@ -0,0 +1,30 @@
+---
+patch:
+ tags:
+ - Platform
+ summary: "Update Centreon web"
+ description: |
+ Update Centreon web component
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ components:
+ type: array
+ items:
+ type: object
+ properties:
+ name:
+ type: string
+ enum: [ centreon-web ]
+ responses:
+ 204:
+ description: "Platform updated"
+ 404:
+ description: "Updates not found"
+ 500:
+ $ref: "../../centreon-api-v22.04.yaml#/components/responses/InternalServerError"
+...
\ No newline at end of file
diff --git a/features/VirtualMetricHandle.feature b/features/VirtualMetricHandle.feature
index d6fc325ee21..9e128d34b64 100644
--- a/features/VirtualMetricHandle.feature
+++ b/features/VirtualMetricHandle.feature
@@ -5,16 +5,16 @@ Feature: Virtual Metric Handle
Background:
Given I am logged in a Centreon server with configured metrics
-
+
Scenario: Create a virtual metric
When I add a virtual metric
Then all properties are saved
-
+
Scenario: Duplicate a virtual metric
Given an existing virtual metric
When I duplicate a virtual metric
Then all properties are copied except the name
-
+
Scenario: Delete a virtual metric
Given an existing virtual metric
When I delete a virtual metric
diff --git a/features/bootstrap/VirtualMetricHandleContext.php b/features/bootstrap/VirtualMetricHandleContext.php
index 47c44733822..16130030d81 100644
--- a/features/bootstrap/VirtualMetricHandleContext.php
+++ b/features/bootstrap/VirtualMetricHandleContext.php
@@ -24,7 +24,8 @@ public function iAddAVirtualMetric()
$this->page = new MetricsConfigurationPage($this);
$this->page->setProperties(array(
'name' => $this->vmName,
- 'linked-host_services' => $this->host . ' - ' . $this->hostService
+ 'linked-host_services' => $this->host . ' - ' . $this->hostService,
+ 'known_metrics' => $this->functionRPN,
));
$this->page->setProperties(array('function' => $this->functionRPN));
$this->page->save();
diff --git a/lang/es_ES.UTF-8/LC_MESSAGES/messages.po b/lang/es_ES.UTF-8/LC_MESSAGES/messages.po
index 3ef62236f25..c2938b35436 100644
--- a/lang/es_ES.UTF-8/LC_MESSAGES/messages.po
+++ b/lang/es_ES.UTF-8/LC_MESSAGES/messages.po
@@ -9079,10 +9079,6 @@ msgstr "Compruebe si el servicio está parado"
msgid "Preexec definition"
msgstr "Definiendo el comando PREEXEC"
-#: centreon-web/www/include/configuration/configObject/traps/formTraps.php:360
-msgid "The same OID element already exists"
-msgstr "El mismo OID ya existe."
-
#: centreon-web/www/include/configuration/configObject/traps/formTraps.php:368
msgid "Advanced matching rules"
msgstr "Reglas de correspondencia avanzadas"
diff --git a/lang/fr_FR.UTF-8/LC_MESSAGES/messages.po b/lang/fr_FR.UTF-8/LC_MESSAGES/messages.po
index 1c1b0bbed83..ae774523348 100644
--- a/lang/fr_FR.UTF-8/LC_MESSAGES/messages.po
+++ b/lang/fr_FR.UTF-8/LC_MESSAGES/messages.po
@@ -9554,10 +9554,6 @@ msgstr "Contrôle si le service est en plage de maintenance"
msgid "Preexec definition"
msgstr "Définition de la commande PREEXEC"
-#: centreon-web/www/include/configuration/configObject/traps/formTraps.php:360
-msgid "The same OID element already exists"
-msgstr "Le même OID existe déjà"
-
#: centreon-web/www/include/configuration/configObject/traps/formTraps.php:368
msgid "Advanced matching rules"
msgstr "Règles de correspondance avancées"
@@ -16914,3 +16910,69 @@ msgstr "Les attributs liés suivants sont manquants : %s"
msgid "Warning, maximum size exceeded for input '%s' (max: %d), it will be truncated upon saving"
msgstr "Attention, taille maximale dépassée pour le champ '%s' (max: %d), il sera tronqué à l'enregistrement"
+
+msgid "Update already in progress"
+msgstr "Une mise à jour est déjà en cours"
+
+msgid "An error occurred when retrieving the current version"
+msgstr "Une erreur s'est produite lors de la récupération de la version actuelle"
+
+msgid "Cannot retrieve the current version"
+msgstr "La version actuelle n'a pas pu être récupérée"
+
+msgid "An error occurred when retrieving available updates"
+msgstr "Une erreur s'est produite lors de la récupération des mises à jour disponibles"
+
+msgid "An error occurred when applying the update %s (%s)"
+msgstr "Une erreur s'est produite lors de l'application de la mise à jour %s (%s)"
+
+msgid "Error while locking the update process"
+msgstr "Erreur lors du verrouillage du processus de mise à jour"
+
+msgid "Error while unlocking the update process"
+msgstr "Erreur lors du déverrouillage du processus de mise à jour"
+
+msgid "An error occurred when applying post update actions"
+msgstr "Une erreur s'est produite lors de l'application des actions postérieures à la mise à jour"
+
+msgid "Updates not found"
+msgstr "Les mises à jour n'ont pas été trouvées"
+
+msgid "PHP version %s required (%s installed)"
+msgstr "La version %s de PHP est requise (%s installée)"
+
+msgid "PHP extension %s not loaded"
+msgstr "L'extension %s de PHP n'est pas chargée"
+
+msgid "Error when retrieving the database version"
+msgstr "Erreur lors de la récupération de la version de la base de données"
+
+msgid "Cannot retrieve the database version information"
+msgstr "Les informations de version de la base de données n'ont pas pu être récupérées"
+
+msgid "MariaDB version %s required (%s installed)"
+msgstr "La version %s de MariaDB est requise (%s installée)"
+
+msgid "Service severity"
+msgstr "Criticité du service"
+
+msgid "Service severity level"
+msgstr "Niveau de criticité du service"
+
+msgid "Host severity"
+msgstr "Criticité d'hôte"
+
+msgid "Host severity level"
+msgstr "Niveau de criticité d'hôte"
+
+msgid "Centreon database schema does not seem to be installed."
+msgstr "Le schema de base de données de Centreon ne semble pas installé."
+
+msgid "Centreon database schema version is \"%s\" (\"%s\" required)."
+msgstr "La version du schema de base de données de Centreon est \"%s\" (\"%s\" requise)."
+
+msgid "Please use Web UI to install Centreon."
+msgstr "Veuillez utiliser l'interface Web pour installer Centreon."
+
+msgid "Please use Web UI to update Centreon."
+msgstr "Veuillez utiliser l'interface Web pour mettre à jour Centreon."
diff --git a/lang/pt_BR.UTF-8/LC_MESSAGES/messages.po b/lang/pt_BR.UTF-8/LC_MESSAGES/messages.po
index fe81994ea1f..9e76be908f9 100644
--- a/lang/pt_BR.UTF-8/LC_MESSAGES/messages.po
+++ b/lang/pt_BR.UTF-8/LC_MESSAGES/messages.po
@@ -10237,10 +10237,6 @@ msgstr "Checagem de Manutenção"
msgid "Preexec definition"
msgstr "Definição de pré-execução"
-#: centreon-web/www/include/configuration/configObject/traps/formTraps.php:376
-msgid "The same OID element already exists"
-msgstr "O mesmo OID já existe"
-
#: centreon-web/www/include/configuration/configObject/traps/formTraps.php:384
msgid "Advanced matching rules"
msgstr "Regras de correspondencia avançada"
diff --git a/lang/pt_PT.UTF-8/LC_MESSAGES/messages.po b/lang/pt_PT.UTF-8/LC_MESSAGES/messages.po
index f72a46f3aee..664500c9dc4 100644
--- a/lang/pt_PT.UTF-8/LC_MESSAGES/messages.po
+++ b/lang/pt_PT.UTF-8/LC_MESSAGES/messages.po
@@ -10238,10 +10238,6 @@ msgstr "Checagem de Manutenção"
msgid "Preexec definition"
msgstr "Definição de pré-execução"
-#: centreon-web/www/include/configuration/configObject/traps/formTraps.php:376
-msgid "The same OID element already exists"
-msgstr "O mesmo OID já existe"
-
#: centreon-web/www/include/configuration/configObject/traps/formTraps.php:384
msgid "Advanced matching rules"
msgstr "Regras de correspondencia avançada"
diff --git a/src/Centreon/Infrastructure/DatabaseConnection.php b/src/Centreon/Infrastructure/DatabaseConnection.php
index 404ada96717..39263cc0cff 100644
--- a/src/Centreon/Infrastructure/DatabaseConnection.php
+++ b/src/Centreon/Infrastructure/DatabaseConnection.php
@@ -91,4 +91,14 @@ public function setStorageDbName(string $storageDbName)
{
$this->storageDbName = $storageDbName;
}
+
+ /**
+ * switch connection to another database
+ *
+ * @param string $dbName
+ */
+ public function switchToDb(string $dbName): void
+ {
+ $this->query('use ' . $dbName);
+ }
}
diff --git a/src/Centreon/Infrastructure/Repository/AbstractRepositoryDRB.php b/src/Centreon/Infrastructure/Repository/AbstractRepositoryDRB.php
index c8ccf79ea23..27e68c256fd 100644
--- a/src/Centreon/Infrastructure/Repository/AbstractRepositoryDRB.php
+++ b/src/Centreon/Infrastructure/Repository/AbstractRepositoryDRB.php
@@ -48,8 +48,8 @@ class AbstractRepositoryDRB
protected function translateDbName(string $request): string
{
return str_replace(
- array(':dbstg', ':db'),
- array($this->db->getStorageDbName(), $this->db->getCentreonDbName()),
+ [':dbstg', ':db'],
+ [$this->db->getStorageDbName(), $this->db->getCentreonDbName()],
$request
);
}
diff --git a/src/CentreonRemote/Application/Webservice/CentreonConfigurationRemote.php b/src/CentreonRemote/Application/Webservice/CentreonConfigurationRemote.php
index f9bb7e1eabc..1ff417403b2 100755
--- a/src/CentreonRemote/Application/Webservice/CentreonConfigurationRemote.php
+++ b/src/CentreonRemote/Application/Webservice/CentreonConfigurationRemote.php
@@ -564,7 +564,6 @@ private function addServerToListOfRemotes(
} else {
$data = [
'ip' => $serverIP,
- 'app_key' => '',
'version' => '',
'is_connected' => '1',
'created_at' => $date,
diff --git a/src/CentreonRemote/Application/Webservice/CentreonRemoteServer.php b/src/CentreonRemote/Application/Webservice/CentreonRemoteServer.php
index 40768c67cfe..8bfd90de78f 100644
--- a/src/CentreonRemote/Application/Webservice/CentreonRemoteServer.php
+++ b/src/CentreonRemote/Application/Webservice/CentreonRemoteServer.php
@@ -109,14 +109,6 @@ public function postAddToWaitList(): string
throw new \RestBadRequestException('Can not access your address.');
}
- if (
- !isset($_POST['app_key'])
- || !$_POST['app_key']
- || empty($appKey = filter_var($_POST['app_key'], FILTER_SANITIZE_STRING))
- ) {
- throw new \RestBadRequestException('Please send \'app_key\' in the request.');
- }
-
if (
!isset($_POST['version'])
|| !$_POST['version']
@@ -147,15 +139,14 @@ public function postAddToWaitList(): string
}
$createdAt = date('Y-m-d H:i:s');
- $insertQuery = "INSERT INTO `remote_servers` (`ip`, `app_key`, `version`, `is_connected`,
+ $insertQuery = "INSERT INTO `remote_servers` (`ip`, `version`, `is_connected`,
`created_at`, `http_method`, `http_port`, `no_check_certificate`)
- VALUES (:ip, :app_key, :version, 0, '{$createdAt}',
+ VALUES (:ip, :version, 0, '{$createdAt}',
:http_method, :http_port, :no_check_certificate
)";
$insert = $this->pearDB->prepare($insertQuery);
$insert->bindValue(':ip', $ip, \PDO::PARAM_STR);
- $insert->bindValue(':app_key', $appKey, \PDO::PARAM_STR);
$insert->bindValue(':version', $version, \PDO::PARAM_STR);
$insert->bindValue(':http_method', $httpScheme, \PDO::PARAM_STR);
$insert->bindValue(':http_port', $httpPort, \PDO::PARAM_INT);
diff --git a/src/CentreonRemote/Domain/Service/NotifyMasterService.php b/src/CentreonRemote/Domain/Service/NotifyMasterService.php
index d5b0295f933..9af5d665ddb 100644
--- a/src/CentreonRemote/Domain/Service/NotifyMasterService.php
+++ b/src/CentreonRemote/Domain/Service/NotifyMasterService.php
@@ -93,19 +93,10 @@ public function pingMaster($ip, $data, $noCheckCertificate = false, $noProxy = f
$url = "{$ip}/centreon/api/external.php?object=centreon_remote_server&action=addToWaitList";
$repository = $this->dbManager->getRepository(InformationsRepository::class);
- $applicationKey = $repository->getOneByKey('appKey');
$version = $repository->getOneByKey('version');
- if (empty($applicationKey)) {
- return [
- 'status' => self::FAIL,
- 'details' => self::NO_APP_KEY
- ];
- }
-
try {
$curlData = [
- 'app_key' => $applicationKey->getValue(),
'version' => $version->getValue(),
'http_method' => $data['remoteHttpMethod'] ?? 'http',
'http_port' => $data['remoteHttpPort'] ?? '',
diff --git a/src/Core/Platform/Application/Repository/ReadUpdateRepositoryInterface.php b/src/Core/Platform/Application/Repository/ReadUpdateRepositoryInterface.php
new file mode 100644
index 00000000000..db999e5fa71
--- /dev/null
+++ b/src/Core/Platform/Application/Repository/ReadUpdateRepositoryInterface.php
@@ -0,0 +1,34 @@
+info('Updating versions');
+
+ try {
+ $this->validateRequirementsOrFail();
+
+ $this->lockUpdate();
+
+ $currentVersion = $this->getCurrentVersionOrFail();
+
+ $availableUpdates = $this->getAvailableUpdatesOrFail($currentVersion);
+
+ $this->runUpdates($availableUpdates);
+
+ $this->unlockUpdate();
+
+ $this->runPostUpdate($this->getCurrentVersionOrFail());
+ } catch (UpdateNotFoundException $e) {
+ $this->error(
+ $e->getMessage(),
+ ['trace' => $e->getTraceAsString()],
+ );
+
+ $presenter->setResponseStatus(new NotFoundResponse('Updates'));
+
+ return;
+ } catch (\Throwable $e) {
+ $this->error(
+ $e->getMessage(),
+ ['trace' => $e->getTraceAsString()],
+ );
+
+ $presenter->setResponseStatus(new ErrorResponse($e->getMessage()));
+
+ return;
+ }
+
+ $presenter->setResponseStatus(new NoContentResponse());
+ }
+
+ /**
+ * Validate platform requirements or fail
+ *
+ * @throws \Exception
+ */
+ private function validateRequirementsOrFail(): void
+ {
+ $this->info('Validating platform requirements');
+
+ $this->requirementValidators->validateRequirementsOrFail();
+ }
+
+ /**
+ * Lock update process
+ */
+ private function lockUpdate(): void
+ {
+ $this->info('Locking centreon update process...');
+
+ if (!$this->updateLocker->lock()) {
+ throw UpdateVersionsException::updateAlreadyInProgress();
+ }
+ }
+
+ /**
+ * Unlock update process
+ */
+ private function unlockUpdate(): void
+ {
+ $this->info('Unlocking centreon update process...');
+
+ $this->updateLocker->unlock();
+ }
+
+ /**
+ * Get current version or fail
+ *
+ * @return string
+ *
+ * @throws \Exception
+ */
+ private function getCurrentVersionOrFail(): string
+ {
+ $this->info('Getting current version');
+
+ try {
+ $currentVersion = $this->readVersionRepository->findCurrentVersion();
+ } catch (\Exception $e) {
+ throw UpdateVersionsException::errorWhenRetrievingCurrentVersion($e);
+ }
+
+ if ($currentVersion === null) {
+ throw UpdateVersionsException::cannotRetrieveCurrentVersion();
+ }
+
+ return $currentVersion;
+ }
+
+ /**
+ * Get available updates
+ *
+ * @param string $currentVersion
+ * @return string[]
+ */
+ private function getAvailableUpdatesOrFail(string $currentVersion): array
+ {
+ try {
+ $this->info(
+ 'Getting available updates',
+ [
+ 'current_version' => $currentVersion,
+ ],
+ );
+
+ return $this->readUpdateRepository->findOrderedAvailableUpdates($currentVersion);
+ } catch (UpdateNotFoundException $e) {
+ throw $e;
+ } catch (\Throwable $e) {
+ throw UpdateVersionsException::errorWhenRetrievingAvailableUpdates($e);
+ }
+ }
+
+ /**
+ * Run given version updates
+ *
+ * @param string[] $versions
+ *
+ * @throws \Throwable
+ */
+ private function runUpdates(array $versions): void
+ {
+ foreach ($versions as $version) {
+ try {
+ $this->info("Running update $version");
+ $this->writeUpdateRepository->runUpdate($version);
+ } catch (\Throwable $e) {
+ throw UpdateVersionsException::errorWhenApplyingUpdate($version, $e->getMessage(), $e);
+ }
+ }
+ }
+
+ /**
+ * Run post update actions
+ *
+ * @param string $currentVersion
+ *
+ * @throws UpdateVersionsException
+ */
+ private function runPostUpdate(string $currentVersion): void
+ {
+ $this->info("Running post update actions");
+
+ try {
+ $this->writeUpdateRepository->runPostUpdate($currentVersion);
+ } catch (\Throwable $e) {
+ throw UpdateVersionsException::errorWhenApplyingPostUpdate($e);
+ }
+ }
+}
diff --git a/src/Core/Platform/Application/UseCase/UpdateVersions/UpdateVersionsException.php b/src/Core/Platform/Application/UseCase/UpdateVersions/UpdateVersionsException.php
new file mode 100644
index 00000000000..dbfaec97ba3
--- /dev/null
+++ b/src/Core/Platform/Application/UseCase/UpdateVersions/UpdateVersionsException.php
@@ -0,0 +1,87 @@
+denyAccessUnlessGrantedForApiConfiguration();
+
+ /**
+ * @var Contact $contact
+ */
+ $contact = $this->getUser();
+ if (! $contact->isAdmin()) {
+ $presenter->setResponseStatus(new UnauthorizedResponse('Only admin user can perform upgrade'));
+
+ return $presenter->show();
+ }
+
+ $this->info('Validating request body...');
+ $this->validateDataSent($request, __DIR__ . '/UpdateVersionsSchema.json');
+
+ $useCase($presenter);
+
+ return $presenter->show();
+ }
+}
diff --git a/src/Core/Platform/Infrastructure/Api/UpdateVersions/UpdateVersionsPresenter.php b/src/Core/Platform/Infrastructure/Api/UpdateVersions/UpdateVersionsPresenter.php
new file mode 100644
index 00000000000..a27dcfad745
--- /dev/null
+++ b/src/Core/Platform/Infrastructure/Api/UpdateVersions/UpdateVersionsPresenter.php
@@ -0,0 +1,31 @@
+db = $db;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function findCurrentVersion(): ?string
+ {
+ $currentVersion = null;
+
+ $statement = $this->db->query(
+ "SELECT `value` FROM `informations` WHERE `key` = 'version'"
+ );
+ if ($statement !== false && is_array($result = $statement->fetch(\PDO::FETCH_ASSOC))) {
+ $currentVersion = $result['value'];
+ }
+
+ return $currentVersion;
+ }
+}
diff --git a/src/Core/Platform/Infrastructure/Repository/DbWriteUpdateRepository.php b/src/Core/Platform/Infrastructure/Repository/DbWriteUpdateRepository.php
new file mode 100644
index 00000000000..1255ee9ecc8
--- /dev/null
+++ b/src/Core/Platform/Infrastructure/Repository/DbWriteUpdateRepository.php
@@ -0,0 +1,319 @@
+db = $db;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function runUpdate(string $version): void
+ {
+ $this->runMonitoringSql($version);
+ $this->runScript($version);
+ $this->runConfigurationSql($version);
+ $this->runPostScript($version);
+ $this->updateVersionInformation($version);
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function runPostUpdate(string $currentVersion): void
+ {
+ if (! $this->filesystem->exists($this->installDir)) {
+ return;
+ }
+
+ $this->backupInstallDirectory($currentVersion);
+ $this->removeInstallDirectory();
+ }
+
+ /**
+ * Backup installation directory
+ *
+ * @param string $currentVersion
+ */
+ private function backupInstallDirectory(string $currentVersion): void
+ {
+ $backupDirectory = $this->libDir . '/installs/install-' . $currentVersion . '-' . date('Ymd_His');
+
+ $this->info(
+ "Backing up installation directory",
+ [
+ 'source' => $this->installDir,
+ 'destination' => $backupDirectory,
+ ],
+ );
+
+ $this->filesystem->mirror(
+ $this->installDir,
+ $backupDirectory,
+ );
+ }
+
+ /**
+ * Remove installation directory
+ */
+ private function removeInstallDirectory(): void
+ {
+ $this->info(
+ "Removing installation directory",
+ [
+ 'installation_directory' => $this->installDir,
+ ],
+ );
+
+ $this->filesystem->remove($this->installDir);
+ }
+
+ /**
+ * Run sql queries on monitoring database
+ *
+ * @param string $version
+ */
+ private function runMonitoringSql(string $version): void
+ {
+ $upgradeFilePath = $this->installDir . '/sql/centstorage/Update-CSTG-' . $version . '.sql';
+ if (is_readable($upgradeFilePath)) {
+ $this->db->switchToDb($this->db->getStorageDbName());
+ $this->runSqlFile($upgradeFilePath);
+ }
+ }
+
+ /**
+ * Run php upgrade script
+ *
+ * @param string $version
+ */
+ private function runScript(string $version): void
+ {
+ $pearDB = $this->dependencyInjector['configuration_db'];
+ $pearDBO = $this->dependencyInjector['realtime_db'];
+
+ $upgradeFilePath = $this->installDir . '/php/Update-' . $version . '.php';
+ if (is_readable($upgradeFilePath)) {
+ include_once $upgradeFilePath;
+ }
+ }
+
+ /**
+ * Run sql queries on configuration database
+ *
+ * @param string $version
+ */
+ private function runConfigurationSql(string $version): void
+ {
+ $upgradeFilePath = $this->installDir . '/sql/centreon/Update-DB-' . $version . '.sql';
+ if (is_readable($upgradeFilePath)) {
+ $this->db->switchToDb($this->db->getCentreonDbName());
+ $this->runSqlFile($upgradeFilePath);
+ }
+ }
+
+ /**
+ * Run php post upgrade script
+ *
+ * @param string $version
+ */
+ private function runPostScript(string $version): void
+ {
+ $pearDB = $this->dependencyInjector['configuration_db'];
+ $pearDBO = $this->dependencyInjector['realtime_db'];
+
+ $upgradeFilePath = $this->installDir . '/php/Update-' . $version . '.post.php';
+ if (is_readable($upgradeFilePath)) {
+ include_once $upgradeFilePath;
+ }
+ }
+
+ /**
+ * Update version information
+ *
+ * @param string $version
+ */
+ private function updateVersionInformation(string $version): void
+ {
+ $statement = $this->db->prepare(
+ $this->translateDbName(
+ "UPDATE `:db`.`informations` SET `value` = :version WHERE `key` = 'version'"
+ )
+ );
+ $statement->bindValue(':version', $version, \PDO::PARAM_STR);
+ $statement->execute();
+ }
+
+ /**
+ * Run sql file and use temporary file to store last executed line
+ *
+ * @param string $filePath
+ * @return void
+ */
+ private function runSqlFile(string $filePath): void
+ {
+ set_time_limit(0);
+
+ $fileName = basename($filePath);
+ $tmpFile = $this->installDir . '/tmp/' . $fileName;
+
+ $alreadyExecutedQueriesCount = $this->getAlreadyExecutedQueriesCount($tmpFile);
+
+ if (is_readable($filePath)) {
+ $fileStream = fopen($filePath, 'r');
+ if (is_resource($fileStream)) {
+ $query = '';
+ $currentLineNumber = 0;
+ $executedQueriesCount = 0;
+ try {
+ while (! feof($fileStream)) {
+ $currentLineNumber++;
+ $currentLine = fgets($fileStream);
+ if ($currentLine && ! $this->isSqlComment($currentLine)) {
+ $query .= ' ' . trim($currentLine);
+ }
+
+ if ($this->isSqlCompleteQuery($query)) {
+ $executedQueriesCount++;
+ if ($executedQueriesCount > $alreadyExecutedQueriesCount) {
+ try {
+ $this->executeQuery($query);
+ } catch (RepositoryException $e) {
+ throw $e;
+ }
+
+ $this->writeExecutedQueriesCountInTemporaryFile($tmpFile, $executedQueriesCount);
+ }
+ $query = '';
+ }
+ }
+ } catch (\Throwable $e) {
+ $this->error($e->getMessage(), ['trace' => $e->getTraceAsString()]);
+ throw $e;
+ } finally {
+ fclose($fileStream);
+ }
+ }
+ }
+ }
+
+ /**
+ * Get stored executed queries count in temporary file to retrieve next query to run in case of an error occurred
+ *
+ * @param string $tmpFile
+ * @return int
+ */
+ private function getAlreadyExecutedQueriesCount(string $tmpFile): int
+ {
+ $startLineNumber = 0;
+ if (is_readable($tmpFile)) {
+ $lineNumber = file_get_contents($tmpFile);
+ if (is_numeric($lineNumber)) {
+ $startLineNumber = (int) $lineNumber;
+ }
+ }
+
+ return $startLineNumber;
+ }
+
+ /**
+ * Write executed queries count in temporary file to retrieve upgrade when an error occurred
+ *
+ * @param string $tmpFile
+ * @param int $count
+ */
+ private function writeExecutedQueriesCountInTemporaryFile(string $tmpFile, int $count): void
+ {
+ if (! file_exists($tmpFile) || is_writable($tmpFile)) {
+ $this->info('Writing in temporary file : ' . $tmpFile);
+ file_put_contents($tmpFile, $count);
+ } else {
+ $this->warning('Cannot write in temporary file : ' . $tmpFile);
+ }
+ }
+
+ /**
+ * Check if a line a sql comment
+ *
+ * @param string $line
+ * @return bool
+ */
+ private function isSqlComment(string $line): bool
+ {
+ return str_starts_with('--', trim($line));
+ }
+
+ /**
+ * Check if a query is complete (trailing semicolon)
+ *
+ * @param string $query
+ * @return bool
+ */
+ private function isSqlCompleteQuery(string $query): bool
+ {
+ return ! empty(trim($query)) && preg_match('/;\s*$/', $query);
+ }
+
+ /**
+ * Execute sql query
+ *
+ * @param string $query
+ *
+ * @throws \Exception
+ */
+ private function executeQuery(string $query): void
+ {
+ try {
+ $this->db->query($query);
+ } catch (\Exception $e) {
+ throw new RepositoryException('Cannot execute query: ' . $query, 0, $e);
+ }
+ }
+}
diff --git a/src/Core/Platform/Infrastructure/Repository/FsReadUpdateRepository.php b/src/Core/Platform/Infrastructure/Repository/FsReadUpdateRepository.php
new file mode 100644
index 00000000000..8c0a7916698
--- /dev/null
+++ b/src/Core/Platform/Infrastructure/Repository/FsReadUpdateRepository.php
@@ -0,0 +1,105 @@
+findAvailableUpdates($currentVersion);
+
+ return $this->orderUpdates($availableUpdates);
+ }
+
+ /**
+ * Get available updates
+ *
+ * @param string $currentVersion
+ * @return string[]
+ */
+ private function findAvailableUpdates(string $currentVersion): array
+ {
+ if (! $this->filesystem->exists($this->installDir)) {
+ $this->error('Install directory not found on filesystem: ' . $this->installDir);
+ throw UpdateNotFoundException::updatesNotFound();
+ }
+
+ $fileNameVersionRegex = '/Update-(?[a-zA-Z0-9\-\.]+)\.php/';
+ $availableUpdates = [];
+
+ $updateFiles = $this->finder->files()
+ ->in($this->installDir)
+ ->name($fileNameVersionRegex);
+
+ foreach ($updateFiles as $updateFile) {
+ if (preg_match($fileNameVersionRegex, $updateFile->getFilename(), $matches)) {
+ if (version_compare($matches['version'], $currentVersion, '>')) {
+ $this->info('Update version found: ' . $matches['version']);
+ $availableUpdates[] = $matches['version'];
+ }
+ }
+ }
+
+ return $availableUpdates;
+ }
+
+ /**
+ * Order updates
+ *
+ * @param string[] $updates
+ * @return string[]
+ */
+ private function orderUpdates(array $updates): array
+ {
+ usort(
+ $updates,
+ fn (string $versionA, string $versionB) => version_compare($versionA, $versionB),
+ );
+
+ return $updates;
+ }
+}
diff --git a/src/Core/Platform/Infrastructure/Repository/SymfonyUpdateLockerRepository.php b/src/Core/Platform/Infrastructure/Repository/SymfonyUpdateLockerRepository.php
new file mode 100644
index 00000000000..2442b6c0e0b
--- /dev/null
+++ b/src/Core/Platform/Infrastructure/Repository/SymfonyUpdateLockerRepository.php
@@ -0,0 +1,79 @@
+lock = $lockFactory->createLock(self::LOCK_NAME);
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function lock(): bool
+ {
+ $this->info('Locking centreon update process on filesystem...');
+
+ try {
+ return $this->lock->acquire();
+ } catch (\Throwable $e) {
+ throw UpdateLockerException::errorWhileLockingUpdate($e);
+ }
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function unlock(): void
+ {
+ $this->info('Unlocking centreon update process from filesystem...');
+
+ try {
+ $this->lock->release();
+ } catch (\Throwable $e) {
+ throw UpdateLockerException::errorWhileUnlockingUpdate($e);
+ }
+ }
+}
diff --git a/src/Core/Platform/Infrastructure/Validator/RequirementValidators.php b/src/Core/Platform/Infrastructure/Validator/RequirementValidators.php
new file mode 100644
index 00000000000..b573a47a62d
--- /dev/null
+++ b/src/Core/Platform/Infrastructure/Validator/RequirementValidators.php
@@ -0,0 +1,63 @@
+ $requirementValidators
+ *
+ * @throws \Exception
+ */
+ public function __construct(
+ \Traversable $requirementValidators,
+ ) {
+ if (iterator_count($requirementValidators) === 0) {
+ throw new \Exception('Requirement validators not found');
+ }
+ $this->requirementValidators = iterator_to_array($requirementValidators);
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function validateRequirementsOrFail(): void
+ {
+ foreach ($this->requirementValidators as $requirementValidator) {
+ $this->info('Validating platform requirement with ' . $requirementValidator::class);
+ $requirementValidator->validateRequirementOrFail();
+ }
+ }
+}
diff --git a/src/Core/Platform/Infrastructure/Validator/RequirementValidators/DatabaseRequirementException.php b/src/Core/Platform/Infrastructure/Validator/RequirementValidators/DatabaseRequirementException.php
new file mode 100644
index 00000000000..f9517d8216a
--- /dev/null
+++ b/src/Core/Platform/Infrastructure/Validator/RequirementValidators/DatabaseRequirementException.php
@@ -0,0 +1,49 @@
+ $dbRequirementValidators
+ *
+ * @throws \Exception
+ */
+ public function __construct(
+ DatabaseConnection $db,
+ \Traversable $dbRequirementValidators,
+ ) {
+ $this->db = $db;
+
+ if (iterator_count($dbRequirementValidators) === 0) {
+ throw new \Exception('Database requirement validators not found');
+ }
+ $this->dbRequirementValidators = iterator_to_array($dbRequirementValidators);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @throws DatabaseRequirementException
+ */
+ public function validateRequirementOrFail(): void
+ {
+ $this->initDatabaseVersionInformation();
+
+ foreach ($this->dbRequirementValidators as $dbRequirementValidator) {
+ if ($dbRequirementValidator->isValidFor($this->versionComment)) {
+ $this->info(
+ 'Validating requirement by ' . $dbRequirementValidator::class,
+ [
+ 'current_version' => $this->version,
+ ],
+ );
+ $dbRequirementValidator->validateRequirementOrFail($this->version);
+ $this->info('Requirement validated by ' . $dbRequirementValidator::class);
+ }
+ }
+ }
+
+ /**
+ * Get database version information
+ *
+ * @throws DatabaseRequirementException
+ */
+ private function initDatabaseVersionInformation(): void
+ {
+ $this->info('Getting database version information');
+
+ try {
+ $statement = $this->db->query("SHOW VARIABLES WHERE Variable_name IN ('version', 'version_comment')");
+ while ($statement !== false && is_array($row = $statement->fetch(\PDO::FETCH_ASSOC))) {
+ if ($row['Variable_name'] === "version") {
+ $this->info('Retrieved DBMS version: ' . $row['Value']);
+ $this->version = $row['Value'];
+ } elseif ($row['Variable_name'] === "version_comment") {
+ $this->info('Retrieved DBMS version comment: ' . $row['Value']);
+ $this->versionComment = $row['Value'];
+ }
+ }
+ } catch (\Throwable $e) {
+ $this->error(
+ 'Error when getting DBMS version from database',
+ [
+ 'message' => $e->getMessage(),
+ 'trace' => $e->getTraceAsString(),
+ ],
+ );
+ throw DatabaseRequirementException::errorWhenGettingDatabaseVersion($e);
+ }
+
+ if (empty($this->version) || empty($this->versionComment)) {
+ $this->info('Cannot retrieve the database version information');
+ throw DatabaseRequirementException::cannotRetrieveVersionInformation();
+ }
+ }
+}
diff --git a/src/Core/Platform/Infrastructure/Validator/RequirementValidators/DatabaseRequirementValidatorInterface.php b/src/Core/Platform/Infrastructure/Validator/RequirementValidators/DatabaseRequirementValidatorInterface.php
new file mode 100644
index 00000000000..ba44860931b
--- /dev/null
+++ b/src/Core/Platform/Infrastructure/Validator/RequirementValidators/DatabaseRequirementValidatorInterface.php
@@ -0,0 +1,43 @@
+info(
+ 'Checking if version comment contains MariaDB string',
+ [
+ 'version_comment' => $versionComment,
+ ],
+ );
+
+ return strpos($versionComment, "MariaDB") !== false;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @throws MariaDbRequirementException
+ */
+ public function validateRequirementOrFail(string $version): void
+ {
+ $currentMariaDBMajorVersion = VersionHelper::regularizeDepthVersion($version, 1);
+
+ $this->info(
+ 'Comparing current MariaDB version ' . $currentMariaDBMajorVersion
+ . ' to minimal required version ' . $this->requiredMariaDbMinVersion
+ );
+
+ if (
+ VersionHelper::compare($currentMariaDBMajorVersion, $this->requiredMariaDbMinVersion, VersionHelper::LT)
+ ) {
+ $this->error('MariaDB requirement is not validated');
+
+ throw MariaDbRequirementException::badMariaDbVersion(
+ $this->requiredMariaDbMinVersion,
+ $currentMariaDBMajorVersion,
+ );
+ }
+ }
+}
diff --git a/src/Core/Platform/Infrastructure/Validator/RequirementValidators/PhpRequirementException.php b/src/Core/Platform/Infrastructure/Validator/RequirementValidators/PhpRequirementException.php
new file mode 100644
index 00000000000..8086d3d86bc
--- /dev/null
+++ b/src/Core/Platform/Infrastructure/Validator/RequirementValidators/PhpRequirementException.php
@@ -0,0 +1,56 @@
+validatePhpVersionOrFail();
+ $this->validatePhpExtensionsOrFail();
+ }
+
+ /**
+ * Check installed php version
+ *
+ * @throws PhpRequirementException
+ */
+ private function validatePhpVersionOrFail(): void
+ {
+ $currentPhpMajorVersion = VersionHelper::regularizeDepthVersion(PHP_VERSION, 1);
+
+ $this->info(
+ 'Comparing current PHP version ' . $currentPhpMajorVersion
+ . ' to required version ' . $this->requiredPhpVersion
+ );
+ if (! VersionHelper::compare($currentPhpMajorVersion, $this->requiredPhpVersion, VersionHelper::EQUAL)) {
+ throw PhpRequirementException::badPhpVersion($this->requiredPhpVersion, $currentPhpMajorVersion);
+ }
+ }
+
+ /**
+ * Check if required php extensions are loaded
+ *
+ * @throws PhpRequirementException
+ */
+ private function validatePhpExtensionsOrFail(): void
+ {
+ $this->info('Checking PHP extensions');
+ foreach (self::EXTENSION_REQUIREMENTS as $extensionName) {
+ $this->validatePhpExtensionOrFail($extensionName);
+ }
+ }
+
+ /**
+ * check if given php extension is loaded
+ *
+ * @param string $extensionName
+ *
+ * @throws PhpRequirementException
+ */
+ private function validatePhpExtensionOrFail(string $extensionName): void
+ {
+ $this->info('Checking PHP extension ' . $extensionName);
+ if (! extension_loaded($extensionName)) {
+ $this->error('PHP extension ' . $extensionName . ' is not loaded');
+ throw PhpRequirementException::phpExtensionNotLoaded($extensionName);
+ }
+ }
+}
diff --git a/src/EventSubscriber/UpdateEventSubscriber.php b/src/EventSubscriber/UpdateEventSubscriber.php
new file mode 100644
index 00000000000..9c629695103
--- /dev/null
+++ b/src/EventSubscriber/UpdateEventSubscriber.php
@@ -0,0 +1,109 @@
+ [
+ ['validateCentreonWebVersionOrFail', 35],
+ ],
+ ];
+ }
+
+ /**
+ * validate centreon web installed version when update endpoint is called
+ *
+ * @param RequestEvent $event
+ * @throws \Exception
+ */
+ public function validateCentreonWebVersionOrFail(RequestEvent $event): void
+ {
+ $this->debug('Checking if route matches updates endpoint');
+ if (
+ $event->getRequest()->getMethod() === Request::METHOD_PATCH
+ && preg_match(
+ '#^.*/api/(?:latest|beta|v[0-9]+|v[0-9]+\.[0-9]+)/platform/updates$#',
+ $event->getRequest()->getPathInfo(),
+ )
+ ) {
+ $this->debug('Getting Centreon web current version');
+ $currentVersion = $this->readVersionRepository->findCurrentVersion();
+
+ if ($currentVersion === null) {
+ $errorMessage =
+ _('Centreon database schema does not seem to be installed.')
+ . ' '
+ . _('Please use Web UI to install Centreon.');
+ $this->error($errorMessage);
+ throw new \Exception(_($errorMessage));
+ }
+
+ $this->debug(
+ sprintf(
+ 'Comparing installed version %s to required version %s',
+ $currentVersion,
+ self::MINIMAL_INSTALLED_VERSION,
+ ),
+ );
+ if (version_compare($currentVersion, self::MINIMAL_INSTALLED_VERSION, '<')) {
+ $errorMessage = sprintf(
+ _('Centreon database schema version is "%s" ("%s" required).')
+ . ' '
+ . _('Please use Web UI to update Centreon.'),
+ $currentVersion,
+ self::MINIMAL_INSTALLED_VERSION,
+ );
+ $this->debug($errorMessage);
+ throw new \Exception(_($errorMessage));
+ }
+ }
+ }
+}
diff --git a/tests/api/Context/PlatformInstallationStatusContext.php b/tests/api/Context/PlatformInstallationStatusContext.php
new file mode 100644
index 00000000000..e1bf8b4e561
--- /dev/null
+++ b/tests/api/Context/PlatformInstallationStatusContext.php
@@ -0,0 +1,52 @@
+getContainer()->execute(
+ 'mysql -e "DROP DATABASE centreon_storage"',
+ 'web'
+ );
+ $this->getContainer()->execute(
+ 'mysql -e "DROP DATABASE centreon"',
+ 'web'
+ );
+ $this->getContainer()->execute(
+ 'rm -f /etc/centreon/centreon.conf.php',
+ 'web'
+ );
+ $this->getContainer()->execute(
+ 'rm -rf /var/cache/centreon/symfony',
+ 'web'
+ );
+ }
+}
diff --git a/tests/api/Context/PlatformUpdateContext.php b/tests/api/Context/PlatformUpdateContext.php
new file mode 100644
index 00000000000..842bd5c0379
--- /dev/null
+++ b/tests/api/Context/PlatformUpdateContext.php
@@ -0,0 +1,48 @@
+getContainer()->execute(
+ 'mkdir -p /usr/share/centreon/www/install/php',
+ 'web'
+ );
+ $this->getContainer()->execute(
+ "sh -c 'echo \" /usr/share/centreon/www/install/php/Update-99.99.99.php'",
+ 'web'
+ );
+ $this->getContainer()->execute(
+ 'chown -R apache. /usr/share/centreon/www/install',
+ 'web'
+ );
+ }
+}
diff --git a/tests/api/behat.yml b/tests/api/behat.yml
index be4954bf1ae..8e8ece2e02a 100644
--- a/tests/api/behat.yml
+++ b/tests/api/behat.yml
@@ -72,6 +72,14 @@ default:
paths: [ "%paths.base%/features/PlatformInformation.feature" ]
contexts:
- Centreon\Test\Api\Context\PlatformInformationContext
+ platform_fresh_install:
+ paths: [ "%paths.base%/features/PlatformInstallationStatus.feature" ]
+ contexts:
+ - Centreon\Test\Api\Context\PlatformInstallationStatusContext
+ platform_update:
+ paths: [ "%paths.base%/features/PlatformUpdate.feature" ]
+ contexts:
+ - Centreon\Test\Api\Context\PlatformUpdateContext
host_groups:
paths: [ "%paths.base%/features/HostGroup.feature" ]
contexts:
diff --git a/tests/api/features/PlatformInstallationStatus.feature b/tests/api/features/PlatformInstallationStatus.feature
new file mode 100644
index 00000000000..5df7be8f915
--- /dev/null
+++ b/tests/api/features/PlatformInstallationStatus.feature
@@ -0,0 +1,18 @@
+Feature:
+ In order to maintain centreon platform
+ As an administrator
+ I want to known the platform installation status
+
+ Background:
+ Given a running instance of Centreon Web API
+ And the endpoints are described in Centreon Web API documentation
+
+ Scenario: Update platform information
+ When I send a GET request to '/api/latest/platform/installation/status'
+ Then the response code should be "200"
+ And the JSON node "is_installed" should be equal to true
+
+ Given Centreon Web is not installed
+ When I send a GET request to '/api/latest/platform/installation/status'
+ Then the response code should be "200"
+ And the JSON node "is_installed" should be equal to false
diff --git a/tests/api/features/PlatformUpdate.feature b/tests/api/features/PlatformUpdate.feature
new file mode 100644
index 00000000000..624d875699d
--- /dev/null
+++ b/tests/api/features/PlatformUpdate.feature
@@ -0,0 +1,41 @@
+Feature:
+ In order to maintain easily centreon platform
+ As a user
+ I want to update centreon web using api
+
+ Background:
+ Given a running instance of Centreon Web API
+ And the endpoints are described in Centreon Web API documentation
+
+ Scenario: Update platform information
+ Given I am logged in
+
+ When an update is available
+ And I send a PATCH request to '/api/latest/platform/updates' with body:
+ """
+ {
+ "components": [
+ {
+ "name": "centreon-web"
+ }
+ ]
+ }
+ """
+ Then the response code should be "204"
+
+ When I send a GET request to '/api/latest/platform/versions'
+ Then the response code should be "200"
+ And the JSON node "web.version" should be equal to the string "99.99.99"
+
+ When I send a PATCH request to '/api/latest/platform/updates' with body:
+ """
+ {
+ "components": [
+ {
+ "name": "centreon-web"
+ }
+ ]
+ }
+ """
+ Then the response code should be "404"
+ And the JSON node "message" should be equal to the string "Updates not found"
\ No newline at end of file
diff --git a/tests/php/Core/Platform/Application/UseCase/UpdateVersions/UpdateVersionsTest.php b/tests/php/Core/Platform/Application/UseCase/UpdateVersions/UpdateVersionsTest.php
new file mode 100644
index 00000000000..6f96a95531a
--- /dev/null
+++ b/tests/php/Core/Platform/Application/UseCase/UpdateVersions/UpdateVersionsTest.php
@@ -0,0 +1,157 @@
+requirementValidators = $this->createMock(RequirementValidatorsInterface::class);
+ $this->updateLockerRepository = $this->createMock(UpdateLockerRepositoryInterface::class);
+ $this->readVersionRepository = $this->createMock(ReadVersionRepositoryInterface::class);
+ $this->readUpdateRepository = $this->createMock(ReadUpdateRepositoryInterface::class);
+ $this->writeUpdateRepository = $this->createMock(WriteUpdateRepositoryInterface::class);
+ $this->presenter = $this->createMock(UpdateVersionsPresenterInterface::class);
+});
+
+it('should stop update process when an other update is already started', function () {
+ $updateVersions = new UpdateVersions(
+ $this->requirementValidators,
+ $this->updateLockerRepository,
+ $this->readVersionRepository,
+ $this->readUpdateRepository,
+ $this->writeUpdateRepository,
+ );
+
+ $this->updateLockerRepository
+ ->expects($this->once())
+ ->method('lock')
+ ->willReturn(false);
+
+ $this->presenter
+ ->expects($this->once())
+ ->method('setResponseStatus')
+ ->with(new ErrorResponse('Update already in progress'));
+
+ $updateVersions($this->presenter);
+});
+
+it('should present an error response if a requirement is not validated', function () {
+ $updateVersions = new UpdateVersions(
+ $this->requirementValidators,
+ $this->updateLockerRepository,
+ $this->readVersionRepository,
+ $this->readUpdateRepository,
+ $this->writeUpdateRepository,
+ );
+
+ $this->requirementValidators
+ ->expects($this->once())
+ ->method('validateRequirementsOrFail')
+ ->willThrowException(new RequirementException('Requirement is not validated'));
+
+ $this->presenter
+ ->expects($this->once())
+ ->method('setResponseStatus')
+ ->with(new ErrorResponse('Requirement is not validated'));
+
+ $updateVersions($this->presenter);
+});
+
+it('should present an error response if current centreon version is not found', function () {
+ $updateVersions = new UpdateVersions(
+ $this->requirementValidators,
+ $this->updateLockerRepository,
+ $this->readVersionRepository,
+ $this->readUpdateRepository,
+ $this->writeUpdateRepository,
+ );
+
+ $this->updateLockerRepository
+ ->expects($this->once())
+ ->method('lock')
+ ->willReturn(true);
+
+ $this->readVersionRepository
+ ->expects($this->once())
+ ->method('findCurrentVersion')
+ ->willReturn(null);
+
+ $this->presenter
+ ->expects($this->once())
+ ->method('setResponseStatus')
+ ->with(new ErrorResponse('Cannot retrieve the current version'));
+
+ $updateVersions($this->presenter);
+});
+
+it('should run found updates', function () {
+ $updateVersions = new UpdateVersions(
+ $this->requirementValidators,
+ $this->updateLockerRepository,
+ $this->readVersionRepository,
+ $this->readUpdateRepository,
+ $this->writeUpdateRepository,
+ );
+
+ $this->updateLockerRepository
+ ->expects($this->once())
+ ->method('lock')
+ ->willReturn(true);
+
+ $this->readVersionRepository
+ ->expects($this->exactly(2))
+ ->method('findCurrentVersion')
+ ->will($this->onConsecutiveCalls('22.04.0', '22.10.1'));
+
+ $this->readUpdateRepository
+ ->expects($this->once())
+ ->method('findOrderedAvailableUpdates')
+ ->with('22.04.0')
+ ->willReturn(['22.10.0-beta.1', '22.10.0', '22.10.1']);
+
+ $this->writeUpdateRepository
+ ->expects($this->exactly(3))
+ ->method('runUpdate')
+ ->withConsecutive(
+ [$this->equalTo('22.10.0-beta.1')],
+ [$this->equalTo('22.10.0')],
+ [$this->equalTo('22.10.1')],
+ );
+
+ $this->presenter
+ ->expects($this->once())
+ ->method('setResponseStatus')
+ ->with(new NoContentResponse());
+
+ $updateVersions($this->presenter);
+});
diff --git a/tests/php/Core/Platform/Infrastructure/Repository/FsReadUpdateRepositoryTest.php b/tests/php/Core/Platform/Infrastructure/Repository/FsReadUpdateRepositoryTest.php
new file mode 100644
index 00000000000..16682e3ea3c
--- /dev/null
+++ b/tests/php/Core/Platform/Infrastructure/Repository/FsReadUpdateRepositoryTest.php
@@ -0,0 +1,89 @@
+filesystem = $this->createMock(Filesystem::class);
+ $this->finder = $this->createMock(Finder::class);
+});
+
+it('should return an error when install directory does not exist', function () {
+ $repository = new FsReadUpdateRepository(sys_get_temp_dir(), $this->filesystem, $this->finder);
+
+ $this->filesystem
+ ->expects($this->once())
+ ->method('exists')
+ ->willReturn(false);
+
+ $availableUpdates = $repository->findOrderedAvailableUpdates('22.04.0');
+})->throws(
+ UpdateNotFoundException::class,
+ UpdateNotFoundException::updatesNotFound()->getMessage(),
+);
+
+it('should order found updates', function () {
+ $repository = new FsReadUpdateRepository(sys_get_temp_dir(), $this->filesystem, $this->finder);
+
+ $this->filesystem
+ ->expects($this->once())
+ ->method('exists')
+ ->willReturn(true);
+
+ $this->finder
+ ->expects($this->once())
+ ->method('files')
+ ->willReturn($this->finder);
+
+ $this->finder
+ ->expects($this->once())
+ ->method('in')
+ ->willReturn($this->finder);
+
+ $this->finder
+ ->expects($this->once())
+ ->method('name')
+ ->willReturn(
+ [
+ new \SplFileInfo('Update-21.10.0.php'),
+ new \SplFileInfo('Update-22.04.0.php'),
+ new \SplFileInfo('Update-22.10.11.php'),
+ new \SplFileInfo('Update-22.10.1.php'),
+ new \SplFileInfo('Update-22.10.0-beta.3.php'),
+ new \SplFileInfo('Update-22.10.0-alpha.1.php'),
+ ]
+ );
+
+ $availableUpdates = $repository->findOrderedAvailableUpdates('22.04.0');
+ expect($availableUpdates)->toEqual([
+ '22.10.0-alpha.1',
+ '22.10.0-beta.3',
+ '22.10.1',
+ '22.10.11'
+ ]);
+});
diff --git a/tests/php/bootstrap.php b/tests/php/bootstrap.php
index 2ca3e800b03..d1d41179b9f 100644
--- a/tests/php/bootstrap.php
+++ b/tests/php/bootstrap.php
@@ -24,8 +24,7 @@
}
$mockedPreRequisiteConstants = [
- '_CENTREON_PHP_MIN_VERSION_' => '8.0',
- '_CENTREON_PHP_MAX_VERSION_' => '8.0',
+ '_CENTREON_PHP_VERSION_' => '8.0',
'_CENTREON_MARIA_DB_MIN_VERSION_' => '10.5',
];
foreach ($mockedPreRequisiteConstants as $mockedPreRequisiteConstant => $value) {
diff --git a/tests/rest_api/realtime_rest_api.postman_collection.json b/tests/rest_api/realtime_rest_api.postman_collection.json
index bcaea1bfb75..3f7f0535134 100644
--- a/tests/rest_api/realtime_rest_api.postman_collection.json
+++ b/tests/rest_api/realtime_rest_api.postman_collection.json
@@ -6730,7 +6730,7 @@
" while(curDate-date < millis);",
"}",
"",
- "wait(5000);"
+ "wait(8000);"
]
}
},
diff --git a/www/api/class/centreon_ceip.class.php b/www/api/class/centreon_ceip.class.php
index 396cdc213cc..2fc08f64262 100644
--- a/www/api/class/centreon_ceip.class.php
+++ b/www/api/class/centreon_ceip.class.php
@@ -120,9 +120,7 @@ private function getServerType(): array
*/
private function getVisitorInformation(): array
{
- $locale = $this->user->lang === 'browser'
- ? null
- : $this->user->lang;
+ $locale = $this->user->get_lang();
$role = $this->user->admin
? "admin"
diff --git a/www/class/centreon-clapi/centreonAPI.class.php b/www/class/centreon-clapi/centreonAPI.class.php
index 89844631e99..dd4cbadda48 100644
--- a/www/class/centreon-clapi/centreonAPI.class.php
+++ b/www/class/centreon-clapi/centreonAPI.class.php
@@ -594,7 +594,7 @@ public function checkUser($useSha1 = false, $isWorker = false)
$row,
$row['ar_id']
);
- if ($centreonAuth->checkPassword() == 1) {
+ if ($centreonAuth->checkPassword() == \CentreonAuth::PASSWORD_VALID) {
\CentreonClapi\CentreonUtils::setUserId($row['contact_id']);
return 1;
}
diff --git a/www/class/centreonACL.class.php b/www/class/centreonACL.class.php
index e1e244c7ca3..699419dd29a 100644
--- a/www/class/centreonACL.class.php
+++ b/www/class/centreonACL.class.php
@@ -400,15 +400,17 @@ private function setTopology()
if ($DBRESULT->rowCount()) {
$topology = array();
$tmp_topo_page = array();
- while ($topo_group = $DBRESULT->fetchRow()) {
- $query2 = "SELECT topology_topology_id, acl_topology_relations.access_right "
+ $statement = $centreonDb
+ ->prepare("SELECT topology_topology_id, acl_topology_relations.access_right "
. "FROM acl_topology_relations, acl_topology "
. "WHERE acl_topology.acl_topo_activate = '1' "
. "AND acl_topology.acl_topo_id = acl_topology_relations.acl_topo_id "
- . "AND acl_topology_relations.acl_topo_id = '" . $topo_group["acl_topology_id"] . "' "
- . "AND acl_topology_relations.access_right != 0"; // do not get "access none"
- $DBRESULT2 = $centreonDb->query($query2);
- while ($topo_page = $DBRESULT2->fetchRow()) {
+ . "AND acl_topology_relations.acl_topo_id = :acl_topology_id "
+ . "AND acl_topology_relations.access_right != 0");
+ while ($topo_group = $DBRESULT->fetchRow()) {
+ $statement->bindValue(':acl_topology_id', (int) $topo_group["acl_topology_id"], \PDO::PARAM_INT);
+ $statement->execute();
+ while ($topo_page = $statement->fetchRow()) {
$topology[] = (int) $topo_page["topology_topology_id"];
if (!isset($tmp_topo_page[$topo_page['topology_topology_id']])) {
$tmp_topo_page[$topo_page["topology_topology_id"]] = $topo_page["access_right"];
@@ -423,7 +425,7 @@ private function setTopology()
}
}
}
- $DBRESULT2->closeCursor();
+ $statement->closeCursor();
}
$DBRESULT->closeCursor();
@@ -1691,22 +1693,28 @@ public function updateACL($data = null)
$request = "SELECT group_id FROM centreon_acl " .
"WHERE host_id = " . $data['duplicate_host'] . " AND service_id IS NULL";
$DBRESULT = \CentreonDBInstance::getMonInstance()->query($request);
+ $hostAclStatement = \CentreonDBInstance::getMonInstance()
+ ->prepare("INSERT INTO centreon_acl (host_id, service_id, group_id) "
+ . "VALUES (:data_id, NULL, :group_id)");
+ $serviceAclStatement = \CentreonDBInstance::getMonInstance()
+ ->prepare("INSERT INTO centreon_acl (host_id, service_id, group_id) "
+ . "VALUES (:data_id, :service_id, :group_id) "
+ . "ON DUPLICATE KEY UPDATE group_id = :group_id");
while ($row = $DBRESULT->fetchRow()) {
// Insert New Host
- $request1 = "INSERT INTO centreon_acl (host_id, service_id, group_id) "
- . "VALUES ('" . $data["id"] . "', NULL, " . $row['group_id'] . ")";
- \CentreonDBInstance::getMonInstance()->query($request1);
-
+ $hostAclStatement->bindValue(':data_id', (int) $data["id"], \PDO::PARAM_INT);
+ $hostAclStatement->bindValue(':group_id', (int) $row['group_id'], \PDO::PARAM_INT);
+ $hostAclStatement->execute();
// Insert services
$request = "SELECT service_id, group_id FROM centreon_acl "
. "WHERE host_id = " . $data['duplicate_host'] . " AND service_id IS NOT NULL";
$DBRESULT2 = \CentreonDBInstance::getMonInstance()->query($request);
while ($row2 = $DBRESULT2->fetch()) {
- $request2 = "INSERT INTO centreon_acl (host_id, service_id, group_id) "
- . "VALUES ('" . $data["id"] . "', "
- . "'" . $row2["service_id"] . "', " . $row2['group_id'] . ") "
- . "ON DUPLICATE KEY UPDATE group_id = " . $row2['group_id'];
- \CentreonDBInstance::getMonInstance()->query($request2);
+ $serviceAclStatement->bindValue(':data_id', (int) $data["id"], \PDO::PARAM_INT);
+ $serviceAclStatement
+ ->bindValue(':service_id', (int) $row2["service_id"], \PDO::PARAM_INT);
+ $serviceAclStatement->bindValue(':group_id', (int) $row2['group_id'], \PDO::PARAM_INT);
+ $serviceAclStatement->execute();
}
}
}
@@ -1730,10 +1738,14 @@ public function updateACL($data = null)
$request = "SELECT group_id FROM centreon_acl "
. "WHERE host_id = $host_id AND service_id = " . $data['duplicate_service'];
$DBRESULT = \CentreonDBInstance::getMonInstance()->query($request);
+ $statement = \CentreonDBInstance::getMonInstance()
+ ->prepare("INSERT INTO centreon_acl (host_id, service_id, group_id) "
+ . "VALUES (:host_id, :data_id, :group_id)");
while ($row = $DBRESULT->fetchRow()) {
- $request2 = "INSERT INTO centreon_acl (host_id, service_id, group_id) "
- . "VALUES ('" . $host_id . "', '" . $data["id"] . "', " . $row['group_id'] . ")";
- \CentreonDBInstance::getMonInstance()->query($request2);
+ $statement->bindValue(':host_id', (int) $host_id, \PDO::PARAM_INT);
+ $statement->bindValue(':data_id', (int) $data["id"], \PDO::PARAM_INT);
+ $statement->bindValue(':group_id', (int) $row['group_id'], \PDO::PARAM_INT);
+ $statement->execute();
}
}
}
diff --git a/www/class/centreonAuth.LDAP.class.php b/www/class/centreonAuth.LDAP.class.php
index a51cbe8c260..3006d15eff9 100644
--- a/www/class/centreonAuth.LDAP.class.php
+++ b/www/class/centreonAuth.LDAP.class.php
@@ -33,7 +33,8 @@
*
*/
-require_once _CENTREON_PATH_ . 'www/class/centreonLDAP.class.php';
+require_once __DIR__ . '/centreonAuth.class.php';
+require_once __DIR__ . '/centreonLDAP.class.php';
/**
* Class for Ldap authentication
@@ -91,8 +92,6 @@ public function __construct($pearDB, $CentreonLog, $login, $password, $contactIn
*/
private function getLogFlag()
{
- global $pearDB;
-
$res = $this->pearDB->query("SELECT value FROM options WHERE `key` = 'debug_ldap_import'");
$data = $res->fetch();
if (isset($data["value"])) {
@@ -107,34 +106,39 @@ private function getLogFlag()
*/
public function checkPassword()
{
- if (!isset($this->contactInfos['contact_ldap_dn']) || $this->contactInfos['contact_ldap_dn'] == '') {
+ if (empty(trim($this->contactInfos['contact_ldap_dn']))) {
$this->contactInfos['contact_ldap_dn'] = $this->ldap->findUserDn($this->contactInfos['contact_alias']);
-
- /* Validate if user exists in this resource */
} elseif (
- isset($this->contactInfos['contact_ldap_dn'])
- && $this->contactInfos['contact_ldap_dn'] != ''
- && $this->ldap->findUserDn($this->contactInfos['contact_alias']) !== $this->contactInfos['contact_ldap_dn']
- ) {
- if ($this->ldap->connect()) {
+ ($userDn = $this->ldap->findUserDn($this->contactInfos['contact_alias']))
+ && $userDn !== $this->contactInfos['contact_ldap_dn']
+ ) { // validate if user exists in this resource
+ if (! $userDn) {
//User resource error
- return 0;
+ return CentreonAuth::PASSWORD_INVALID;
} else {
//LDAP fallback
- return 2;
+ return CentreonAuth::PASSWORD_CANNOT_BE_VERIFIED;
}
}
- /*
- * LDAP BIND
- */
- if (!isset($this->contactInfos['contact_ldap_dn']) || trim($this->contactInfos['contact_ldap_dn']) == '') {
- return 2;
+ if (empty(trim($this->contactInfos['contact_ldap_dn']))) {
+ return CentreonAuth::PASSWORD_CANNOT_BE_VERIFIED;
}
- @ldap_bind($this->ds, $this->contactInfos['contact_ldap_dn'], $this->typePassword);
+
if ($this->debug) {
- $this->CentreonLog->insertLog(3, "Connexion = " . $this->contactInfos['contact_ldap_dn'] . " :: " .
- ldap_error($this->ds));
+ $this->CentreonLog->insertLog(
+ 3,
+ 'LDAP AUTH : ' . $this->contactInfos['contact_ldap_dn'] . ' :: Authentication in progress'
+ );
+ }
+
+ @ldap_bind($this->ds, $this->contactInfos['contact_ldap_dn'], $this->typePassword);
+
+ if (empty($this->ds)) {
+ if ($this->debug) {
+ $this->CentreonLog->insertLog(3, "DS empty");
+ }
+ return CentreonAuth::PASSWORD_CANNOT_BE_VERIFIED;
}
/*
@@ -146,54 +150,29 @@ public function checkPassword()
* 52 : Server is unavailable => Fallback
* 81 : Can't contact LDAP server (php5) => Fallback
*/
- if (isset($this->ds) && $this->ds) {
- switch (ldap_errno($this->ds)) {
- case 0:
- if ($this->debug) {
- $this->CentreonLog->insertLog(3, "LDAP AUTH : OK, let's go ! ");
- }
- if (false == $this->updateUserDn()) {
- return 0;
- }
- return 1;
- break;
- case 2:
- if ($this->debug) {
- $this->CentreonLog->insertLog(3, "LDAP AUTH : Protocol Error ");
- }
- return 2;
- break;
- case -1:
- case 51:
- if ($this->debug) {
- $this->CentreonLog->insertLog(3, "LDAP AUTH : Error, Server Busy. Try later");
- }
- return -1;
- break;
- case 52:
- if ($this->debug) {
- $this->CentreonLog->insertLog(3, "LDAP AUTH : Error, Server unavailable. Try later");
- }
- return -1;
- break;
- case 81:
- if ($this->debug) {
- $this->CentreonLog->insertLog(3, "LDAP AUTH : Error, Fallback to Local AUTH");
- }
- return 2;
- break;
- default:
- if ($this->debug) {
- $this->CentreonLog->insertLog(3, "LDAP AUTH : LDAP don't like you, sorry");
- }
- return 0;
- break;
- }
- } else {
- if ($this->debug) {
- $this->CentreonLog->insertLog(3, "DS empty");
- }
- return 0; /* 2 ?? */
+ switch (ldap_errno($this->ds)) {
+ case 0:
+ if ($this->debug) {
+ $this->CentreonLog->insertLog(3, "LDAP AUTH : Success");
+ }
+ if (false == $this->updateUserDn()) {
+ return CentreonAuth::PASSWORD_INVALID;
+ }
+ return CentreonAuth::PASSWORD_VALID;
+ case -1:
+ case 2: // protocol error
+ case 51: // busy
+ case 52: // unavailable
+ case 81: // server down
+ if ($this->debug) {
+ $this->CentreonLog->insertLog(3, "LDAP AUTH : " . ldap_error($this->ds));
+ }
+ return CentreonAuth::PASSWORD_CANNOT_BE_VERIFIED;
+ default:
+ if ($this->debug) {
+ $this->CentreonLog->insertLog(3, "LDAP AUTH : " . ldap_error($this->ds));
+ }
+ return CentreonAuth::PASSWORD_INVALID;
}
}
@@ -260,24 +239,26 @@ public function updateUserDn()
* Searching if the user already exist in the DB and updating OR adding him
*/
if (isset($this->contactInfos['contact_id'])) {
- $stmt = $this->pearDB->prepare(
- 'UPDATE contact SET
- contact_ldap_dn = :userDn,
- contact_name = :userDisplay,
- contact_email = :userEmail,
- contact_pager = :userPager,
- ar_id = :arId
- WHERE contact_id = :contactId'
- );
try {
// checking if the LDAP synchronization on login is enabled or needed
- if (
- !$this->ldap->isSyncNeededAtLogin($this->arId, $this->contactInfos['contact_id'])
- ) {
+ if (!$this->ldap->isSyncNeededAtLogin($this->arId, $this->contactInfos['contact_id'])) {
// skipping the update
return true;
}
- // Updating the user DN and extended information
+
+ $this->CentreonLog->insertLog(
+ 3,
+ 'LDAP AUTH : Updating user DN of ' . $userDisplay
+ );
+ $stmt = $this->pearDB->prepare(
+ 'UPDATE contact SET
+ contact_ldap_dn = :userDn,
+ contact_name = :userDisplay,
+ contact_email = :userEmail,
+ contact_pager = :userPager,
+ ar_id = :arId
+ WHERE contact_id = :contactId'
+ );
$stmt->bindValue(':userDn', $userDn, \PDO::PARAM_STR);
$stmt->bindValue(':userDisplay', $userDisplay, \PDO::PARAM_STR);
$stmt->bindValue(':userEmail', $userEmail, \PDO::PARAM_STR);
diff --git a/www/class/centreonAuth.class.php b/www/class/centreonAuth.class.php
index a2ea42427bb..f4927c283af 100644
--- a/www/class/centreonAuth.class.php
+++ b/www/class/centreonAuth.class.php
@@ -35,6 +35,7 @@
*/
require_once __DIR__ . '/centreonContact.class.php';
+require_once __DIR__ . '/centreonAuth.LDAP.class.php';
class CentreonAuth
{
@@ -49,10 +50,15 @@ class CentreonAuth
public const PASSWORD_HASH_ALGORITHM = PASSWORD_BCRYPT;
+ public const PASSWORD_VALID = 1;
+ public const PASSWORD_INVALID = 0;
+ public const PASSWORD_CANNOT_BE_VERIFIED = -1;
+
public const ENCRYPT_MD5 = 1;
public const ENCRYPT_SHA1 = 2;
public const AUTH_TYPE_LOCAL = 'local';
+ public const AUTH_TYPE_LDAP = 'ldap';
// Declare Values
public $userInfos;
@@ -63,7 +69,12 @@ class CentreonAuth
protected $cryptEngine;
protected $autologin;
protected $cryptPossibilities;
+
+ /**
+ * @var CentreonDB
+ */
protected $pearDB;
+
protected $debug;
protected $dependencyInjector;
@@ -157,158 +168,170 @@ protected function getLogFlag()
*/
protected function checkPassword($password, $token = "", $autoImport = false)
{
- if ((strlen($password) == 0 || $password === "") && $token === "") {
- $this->passwdOk = 0;
+ if (empty($password) && empty($token)) {
+ $this->passwdOk = self::PASSWORD_INVALID;
return;
}
- if ($this->userInfos["contact_auth_type"] == "ldap" && $this->autologin == 0) {
- /*
- * Insert LDAP Class
- */
- include_once(_CENTREON_PATH_ . "/www/class/centreonAuth.LDAP.class.php");
-
- $query = "SELECT ar_id FROM auth_ressource WHERE ar_enable = '1'";
- $res = $this->pearDB->query($query);
- $authResources = array();
- while ($row = $res->fetch()) {
- $index = $row['ar_id'];
- if (isset($this->userInfos['ar_id']) && $this->userInfos['ar_id'] == $row['ar_id']) {
- $index = 0;
- }
- $authResources[$index] = $row['ar_id'];
+
+ if ($this->autologin) {
+ $this->checkAutologinKey($password, $token);
+ return;
+ }
+
+ if ($this->userInfos["contact_auth_type"] === self::AUTH_TYPE_LDAP) {
+ $this->checkLdapPassword($password, $autoImport);
+ return;
+ }
+
+ if (
+ empty($this->userInfos["contact_auth_type"])
+ || $this->userInfos["contact_auth_type"] === self::AUTH_TYPE_LOCAL
+ ) {
+ $this->checkLocalPassword($password);
+ return;
+ }
+
+ $this->passwdOk = self::PASSWORD_INVALID;
+ }
+
+ /**
+ * Check autologin key
+ *
+ * @param string $password
+ * @param string $token
+ */
+ private function checkAutologinKey($password, $token): void
+ {
+ if (
+ !empty($this->userInfos["contact_autologin_key"])
+ && $this->userInfos["contact_autologin_key"] === $token
+ ) {
+ $this->passwdOk = self::PASSWORD_VALID;
+ } elseif (
+ !empty($password)
+ && $this->userInfos["contact_passwd"] === $password
+ ) {
+ $this->passwdOk = self::PASSWORD_VALID;
+ } else {
+ $this->passwdOk = self::PASSWORD_INVALID;
+ }
+ }
+
+ /**
+ * Check ldap user password
+ *
+ * @param string $password
+ * @param bool $autoImport
+ */
+ private function checkLdapPassword($password, $autoImport): void
+ {
+ $res = $this->pearDB->query("SELECT ar_id FROM auth_ressource WHERE ar_enable = '1'");
+ $authResources = [];
+ while ($row = $res->fetch()) {
+ $index = $row['ar_id'];
+ if (isset($this->userInfos['ar_id']) && $this->userInfos['ar_id'] == $row['ar_id']) {
+ $index = 0;
}
+ $authResources[$index] = $row['ar_id'];
+ }
- foreach ($authResources as $arId) {
- if ($autoImport && !isset($this->ldap_auto_import[$arId])) {
- break;
- }
- if ($this->passwdOk == 1) {
- break;
- }
- $authLDAP = new CentreonAuthLDAP(
- $this->pearDB,
- $this->CentreonLog,
- $this->login,
- $this->password,
- $this->userInfos,
- $arId
- );
- $this->passwdOk = $authLDAP->checkPassword();
- if ($this->passwdOk == -1) {
- $this->passwdOk = 0;
- if (
- isset($this->userInfos["contact_passwd"])
- && password_verify($this->password, $this->userInfos["contact_passwd"])
- ) {
- $this->passwdOk = 1;
- if (isset($this->ldap_store_password[$arId]) && $this->ldap_store_password[$arId]) {
- $hashedPassword = password_hash($this->password, self::PASSWORD_HASH_ALGORITHM);
- $contact = new \CentreonContact($this->pearDB);
- $contact->addPasswordByContactId(
- (int) $this->userInfos['contact_id'],
+ foreach ($authResources as $arId) {
+ if ($autoImport && !isset($this->ldap_auto_import[$arId])) {
+ break;
+ }
+ if ($this->passwdOk == self::PASSWORD_VALID) {
+ break;
+ }
+ $authLDAP = new CentreonAuthLDAP(
+ $this->pearDB,
+ $this->CentreonLog,
+ $this->login,
+ $this->password,
+ $this->userInfos,
+ $arId
+ );
+ $this->passwdOk = $authLDAP->checkPassword();
+
+ if ($this->passwdOk == self::PASSWORD_VALID) {
+ if (isset($this->ldap_store_password[$arId]) && $this->ldap_store_password[$arId]) {
+ if (!isset($this->userInfos["contact_passwd"])) {
+ $hashedPassword = password_hash($this->password, self::PASSWORD_HASH_ALGORITHM);
+ $contact = new \CentreonContact($this->pearDB);
+ $contactId = $contact->findContactIdByAlias($this->login);
+ if ($contactId !== null) {
+ $contact->addPasswordByContactId($contactId, $hashedPassword);
+ }
+ // Update password if LDAP authentication is valid but password not up to date in Centreon.
+ } elseif (!password_verify($this->password, $this->userInfos["contact_passwd"])) {
+ $hashedPassword = password_hash($this->password, self::PASSWORD_HASH_ALGORITHM);
+ $contact = new \CentreonContact($this->pearDB);
+ $contactId = $contact->findContactIdByAlias($this->login);
+ if ($contactId !== null) {
+ $contact->replacePasswordByContactId(
+ $contactId,
+ $this->userInfos["contact_passwd"],
$hashedPassword
);
}
}
- } elseif ($this->passwdOk == 1) {
- if (isset($this->ldap_store_password[$arId]) && $this->ldap_store_password[$arId]) {
- if (!isset($this->userInfos["contact_passwd"])) {
- $hashedPassword = password_hash($this->password, self::PASSWORD_HASH_ALGORITHM);
- $contact = new \CentreonContact($this->pearDB);
- $contactId = $contact->findContactIdByAlias($this->login);
- if ($contactId !== null) {
- $contact->addPasswordByContactId($contactId, $hashedPassword);
- }
- // Update password if LDAP authentication is valid but password not up to date in Centreon.
- } elseif (!password_verify($this->password, $this->userInfos["contact_passwd"])) {
- $hashedPassword = password_hash($this->password, self::PASSWORD_HASH_ALGORITHM);
- $contact = new \CentreonContact($this->pearDB);
- $contactId = $contact->findContactIdByAlias($this->login);
- if ($contactId !== null) {
- $contact->replacePasswordByContactId(
- $contactId,
- $this->userInfos["contact_passwd"],
- $hashedPassword
- );
- }
- }
- }
}
- }
- } elseif (
- $this->userInfos["contact_auth_type"] == ""
- || $this->userInfos["contact_auth_type"] === self::AUTH_TYPE_LOCAL
- || $this->autologin
- ) {
- if (
- $this->autologin
- && $this->userInfos["contact_autologin_key"]
- && $this->userInfos["contact_autologin_key"] === $token
- ) {
- $this->passwdOk = 1;
- } elseif (
- !empty($password)
- && $this->userInfos["contact_passwd"] === $password
- && $this->autologin
- ) {
- $this->passwdOk = 1;
-
- // Update password from md5 to bcrypt if old md5 password is valid.
- } elseif (
- !empty($password)
- && (str_starts_with($this->userInfos["contact_passwd"], 'md5__')
- && $this->userInfos["contact_passwd"] === $this->myCrypt($password)
- || 'md5__' . $this->userInfos["contact_passwd"] === $this->myCrypt($password))
- ) {
- $newPassword = password_hash($password, self::PASSWORD_HASH_ALGORITHM);
- $statement = $this->pearDB->prepare(
- "UPDATE `contact_password` SET password = :newPassword
- WHERE password = :oldPassword AND contact_id = :contactId"
- );
- $statement->bindValue(':newPassword', $newPassword, \PDO::PARAM_STR);
- $statement->bindValue(':oldPassword', $this->userInfos["contact_passwd"], \PDO::PARAM_STR);
- $statement->bindValue(':contactId', $this->userInfos["contact_id"], \PDO::PARAM_INT);
- $statement->execute();
- $this->passwdOk = 1;
- } elseif (
- !empty($password)
- && password_verify($password, $this->userInfos["contact_passwd"])
- && $this->autologin == 0
- ) {
- $this->passwdOk = 1;
- } else {
- $this->passwdOk = 0;
+ break;
}
}
- /**
- * LDAP - fallback
- */
- if ($this->passwdOk == 2) {
+ if ($this->passwdOk == self::PASSWORD_CANNOT_BE_VERIFIED) {
if (
- $this->autologin && $this->userInfos["contact_autologin_key"]
- && $this->userInfos["contact_autologin_key"] === $token
- ) {
- $this->passwdOk = 1;
- } elseif (
- !empty($password)
- && isset($this->userInfos["contact_passwd"])
- && $this->userInfos["contact_passwd"] === $password && $this->autologin
- ) {
- $this->passwdOk = 1;
- } elseif (
!empty($password)
- && isset($this->userInfos["contact_passwd"])
+ && !empty($this->userInfos["contact_passwd"])
&& password_verify($password, $this->userInfos["contact_passwd"])
- && $this->autologin == 0
) {
- $this->passwdOk = 1;
+ $this->passwdOk = self::PASSWORD_VALID;
} else {
- $this->passwdOk = 0;
+ $this->passwdOk = self::PASSWORD_INVALID;
}
}
}
+ /**
+ * Check local user password
+ *
+ * @param string $password
+ */
+ private function checkLocalPassword($password)
+ {
+ if (empty($password)) {
+ $this->passwdOk = self::PASSWORD_INVALID;
+ return;
+ }
+
+ if (password_verify($password, $this->userInfos["contact_passwd"])) {
+ $this->passwdOk = self::PASSWORD_VALID;
+ return;
+ }
+
+ if (
+ (
+ str_starts_with($this->userInfos["contact_passwd"], 'md5__')
+ && $this->userInfos["contact_passwd"] === $this->myCrypt($password)
+ )
+ || 'md5__' . $this->userInfos["contact_passwd"] === $this->myCrypt($password)
+ ) {
+ $newPassword = password_hash($password, self::PASSWORD_HASH_ALGORITHM);
+ $statement = $this->pearDB->prepare(
+ "UPDATE `contact_password` SET password = :newPassword
+ WHERE password = :oldPassword AND contact_id = :contactId"
+ );
+ $statement->bindValue(':newPassword', $newPassword, \PDO::PARAM_STR);
+ $statement->bindValue(':oldPassword', $this->userInfos["contact_passwd"], \PDO::PARAM_STR);
+ $statement->bindValue(':contactId', $this->userInfos["contact_id"], \PDO::PARAM_INT);
+ $statement->execute();
+ $this->passwdOk = self::PASSWORD_VALID;
+ return;
+ }
+
+ $this->passwdOk = self::PASSWORD_INVALID;
+ }
+
/**
* Check user password
*
@@ -339,12 +362,13 @@ protected function checkUser($username, $password, $token)
if ($dbResult->rowCount()) {
$this->userInfos = $dbResult->fetch();
if ($this->userInfos["default_page"]) {
- $dbResult2 = $this->pearDB->query(
- "SELECT topology_url_opt FROM topology WHERE topology_page = "
- . $this->userInfos["default_page"]
+ $statement = $this->pearDB->prepare(
+ "SELECT topology_url_opt FROM topology WHERE topology_page = :topology_page"
);
- if ($dbResult2->numRows()) {
- $data = $dbResult2->fetch();
+ $statement->bindValue(':topology_page', (int) $this->userInfos["default_page"], \PDO::PARAM_INT);
+ $statement->execute();
+ if ($statement->rowCount()) {
+ $data = $statement->fetch(\PDO::FETCH_ASSOC);
$this->userInfos["default_page"] .= $data["topology_url_opt"];
}
}
@@ -354,7 +378,7 @@ protected function checkUser($username, $password, $token)
*/
$this->getCryptFunction();
$this->checkPassword($password, $token);
- if ($this->passwdOk == 1) {
+ if ($this->passwdOk == self::PASSWORD_VALID) {
$this->CentreonLog->setUID($this->userInfos["contact_id"]);
$this->CentreonLog->insertLog(
CentreonUserLog::TYPE_LOGIN,
@@ -362,54 +386,49 @@ protected function checkUser($username, $password, $token)
. "Authentication succeeded for '" . $username . "'"
);
} else {
- // Take care before modifying this message pattern as it may break tools such as fail2ban
- $this->CentreonLog->insertLog(
- CentreonUserLog::TYPE_LOGIN,
- "[" . self::AUTH_TYPE_LOCAL . "] [" . $_SERVER["REMOTE_ADDR"] . "] "
- . "Authentication failed for '" . $username . "'"
+ $this->setAuthenticationError(
+ $this->userInfos['contact_auth_type'],
+ $username,
+ 'invalid credentials'
);
- $this->error = _('Your credentials are incorrect.');
}
} elseif (count($this->ldap_auto_import)) {
/*
* Add temporary userinfo auth_type
*/
$this->userInfos['contact_alias'] = $username;
- $this->userInfos['contact_auth_type'] = "ldap";
+ $this->userInfos['contact_auth_type'] = self::AUTH_TYPE_LDAP;
$this->userInfos['contact_email'] = '';
$this->userInfos['contact_pager'] = '';
$this->checkPassword($password, "", true);
/*
* Reset userInfos with imported information
*/
- $dbResult = $this->pearDB->query(
+ $statement = $this->pearDB->prepare(
"SELECT * FROM `contact` " .
- "WHERE `contact_alias` = '" . $this->pearDB->escape($username, true) . "'" .
+ "WHERE `contact_alias` = :contact_alias " .
"AND `contact_activate` = '1' AND `contact_register` = '1' LIMIT 1"
);
- if ($dbResult->rowCount()) {
- $this->userInfos = $dbResult->fetch();
+ $statement->bindValue(':contact_alias', $this->pearDB->escape($username, true), \PDO::PARAM_STR);
+ $statement->execute();
+ if ($statement->rowCount()) {
+ $this->userInfos = $statement->fetch(\PDO::FETCH_ASSOC);
if ($this->userInfos["default_page"]) {
- $dbResult2 = $this->pearDB->query(
- "SELECT topology_url_opt FROM topology WHERE topology_page = "
- . $this->userInfos["default_page"]
+ $statement = $this->pearDB->prepare(
+ "SELECT topology_url_opt FROM topology WHERE topology_page = :topology_page"
);
- if ($dbResult2->numRows()) {
- $data = $dbResult2->fetch();
+ $statement->bindValue(':topology_page', (int) $this->userInfos["default_page"], \PDO::PARAM_INT);
+ $statement->execute();
+ if ($statement->rowCount()) {
+ $data = $statement->fetch(\PDO::FETCH_ASSOC);
$this->userInfos["default_page"] .= $data["topology_url_opt"];
}
}
+ } else {
+ $this->setAuthenticationError(self::AUTH_TYPE_LDAP, $username, 'not found');
}
} else {
- if (strlen($username) > 0) {
- // Take care before modifying this message pattern as it may break tools such as fail2ban
- $this->CentreonLog->insertLog(
- CentreonUserLog::TYPE_LOGIN,
- "[" . self::AUTH_TYPE_LOCAL . "] [" . $_SERVER["REMOTE_ADDR"] . "] "
- . "Authentication failed for '" . $username . "' : not found"
- );
- }
- $this->error = _('Your credentials are incorrect.');
+ $this->setAuthenticationError(self::AUTH_TYPE_LOCAL, $username, 'not found');
}
}
@@ -482,4 +501,25 @@ protected function getAuthType()
{
return $this->authType;
}
+
+ /**
+ * Set authentication error and log it
+ *
+ * @param string $authenticationType
+ * @param string|bool $username
+ * @param string $reason
+ */
+ private function setAuthenticationError(string $authenticationType, $username, string $reason): void
+ {
+ if (is_string($username) && strlen($username) > 0) {
+ // Take care before modifying this message pattern as it may break tools such as fail2ban
+ $this->CentreonLog->insertLog(
+ CentreonUserLog::TYPE_LOGIN,
+ "[" . $authenticationType . "] [" . $_SERVER["REMOTE_ADDR"] . "] "
+ . "Authentication failed for '" . $username . "' : " . $reason
+ );
+ }
+
+ $this->error = _('Your credentials are incorrect.');
+ }
}
diff --git a/www/class/centreonContactgroup.class.php b/www/class/centreonContactgroup.class.php
index 4eab2bd3d4e..9c297811ed3 100644
--- a/www/class/centreonContactgroup.class.php
+++ b/www/class/centreonContactgroup.class.php
@@ -279,20 +279,27 @@ public function syncWithLdapConfigGen()
$msg = array();
$ldapServerConnError = array();
- $cgRes = $this->db->query("SELECT cg.cg_id, cg.cg_name, cg.cg_ldap_dn, cg.ar_id " .
- "FROM contactgroup as cg, auth_ressource as ar " .
- "WHERE cg.cg_type = 'ldap' AND cg.ar_id = ar.ar_id AND ar.ar_enable = '1' AND (" .
- "EXISTS(SELECT 1 FROM contactgroup_host_relation chr WHERE chr.contactgroup_cg_id = cg.cg_id LIMIT 1) "
- . " OR " .
- "EXISTS(SELECT 1 FROM contactgroup_service_relation csr WHERE csr.contactgroup_cg_id = cg.cg_id LIMIT 1)"
- . " OR " .
- "EXISTS(SELECT 1 FROM contactgroup_hostgroup_relation chr WHERE chr.contactgroup_cg_id = cg.cg_id LIMIT 1)"
- . " OR " .
- "EXISTS(SELECT 1 FROM contactgroup_servicegroup_relation csr " .
- "WHERE csr.contactgroup_cg_id = cg.cg_id LIMIT 1)"
- . " OR " .
- "EXISTS(SELECT 1 FROM escalation_contactgroup_relation ecr WHERE ecr.contactgroup_cg_id = cg.cg_id LIMIT 1)"
- . ") ORDER BY cg.ar_id");
+ $cgRes = $this->db->query(
+ "SELECT cg.cg_id, cg.cg_name, cg.cg_ldap_dn, cg.ar_id, ar.ar_name
+ FROM contactgroup as cg, auth_ressource as ar
+ WHERE cg.cg_type = 'ldap'
+ AND cg.ar_id = ar.ar_id
+ AND ar.ar_enable = '1'
+ AND (
+ EXISTS (
+ SELECT 1 FROM contactgroup_host_relation chr WHERE chr.contactgroup_cg_id = cg.cg_id LIMIT 1
+ ) OR EXISTS (
+ SELECT 1 FROM contactgroup_service_relation csr WHERE csr.contactgroup_cg_id = cg.cg_id LIMIT 1
+ ) OR EXISTS (
+ SELECT 1 FROM contactgroup_hostgroup_relation chr WHERE chr.contactgroup_cg_id = cg.cg_id LIMIT 1
+ ) OR EXISTS (
+ SELECT 1 FROM contactgroup_servicegroup_relation csr WHERE csr.contactgroup_cg_id = cg.cg_id LIMIT 1
+ ) OR EXISTS (
+ SELECT 1 FROM escalation_contactgroup_relation ecr WHERE ecr.contactgroup_cg_id = cg.cg_id LIMIT 1
+ )
+ )
+ ORDER BY cg.ar_id"
+ );
$currentLdapId = 0; // the chosen LDAP configuration which should never stay to 0 if the LDAP is found
$ldapConn = null;
@@ -310,10 +317,7 @@ public function syncWithLdapConfigGen()
$connectionResult = $ldapConn->connect();
if ($connectionResult == false) {
$ldapServerConnError[$cgRow['ar_id']] = 1;
- $stmt = $this->db->query("SELECT ar_name FROM auth_ressource " .
- "WHERE ar_id = " . (int)$cgRow['ar_id']);
- $res = $stmt->fetch();
- $msg[] = "Unable to connect to LDAP server : " . $res['ar_name'] . ".";
+ $msg[] = "Unable to connect to LDAP server : " . $cgRow['ar_name'] . ".";
continue;
}
}
@@ -331,9 +335,7 @@ public function syncWithLdapConfigGen()
if (!$contact) {
// no need to continue. If there's no contact, there's no relation to insert.
- $stmt = $this->db->query("SELECT ar_name FROM auth_ressource WHERE ar_id = " . (int)$cgRow['ar_id']);
- $res = $stmt->fetch();
- $msg[] = "Error : there's no contact to update for LDAP : " . $res['ar_name'] . ".";
+ $msg[] = "Error : there's no contact to update for LDAP : " . $cgRow['ar_name'] . ".";
return $msg;
}
try {
@@ -436,18 +438,19 @@ public function syncWithLdap()
throw $e;
}
continue;
- } else {
- // Update the ldap group in contactgroup
- $queryUpdateDn = "UPDATE contactgroup SET cg_ldap_dn = '" . $dn .
- "' WHERE cg_id = " . $row['cg_id'];
+ } else { // Update the ldap group dn in contactgroup
try {
- $this->db->query($queryUpdateDn);
+ $updateDnStatement = $this->db->prepare(
+ "UPDATE contactgroup SET cg_ldap_dn = :cg_dn WHERE cg_id = :cg_id"
+ );
+ $updateDnStatement->bindValue(':cg_dn', $dn, \PDO::PARAM_STR);
+ $updateDnStatement->bindValue(':cg_id', $row['cg_id'], \PDO::PARAM_INT);
+ $updateDnStatement->execute();
$row['cg_ldap_dn'] = $dn;
} catch (\PDOException $e) {
$msg[] = "Error processing update contactgroup request of ldap group : " .
$row['cg_name'];
throw $e;
- continue;
}
}
}
@@ -460,16 +463,16 @@ public function syncWithLdap()
);
$deleteStmt->bindValue(':cgId', $row['cg_id'], \PDO::PARAM_INT);
$deleteStmt->execute();
- $contact = '';
+ $contactDns = '';
foreach ($members as $member) {
- $contact .= $this->db->quote($member) . ',';
+ $contactDns .= $this->db->quote($member) . ',';
}
- $contact = rtrim($contact, ",");
+ $contactDns = rtrim($contactDns, ",");
- if ($contact !== '') {
+ if ($contactDns !== '') {
try {
$resContact = $this->db->query(
- "SELECT contact_id FROM contact WHERE contact_ldap_dn IN (" . $contact . ")"
+ "SELECT contact_id FROM contact WHERE contact_ldap_dn IN (" . $contactDns . ")"
);
} catch (\PDOException $e) {
$msg[] = "Error in getting contact id from members.";
diff --git a/www/class/centreonGraph.class.php b/www/class/centreonGraph.class.php
index fd55822883a..4ae3ef297d8 100644
--- a/www/class/centreonGraph.class.php
+++ b/www/class/centreonGraph.class.php
@@ -1076,16 +1076,18 @@ private function getDefaultGraphTemplate()
return;
} else {
$command_id = getMyServiceField($this->indexData["service_id"], "command_command_id");
- $DBRESULT = $this->DB->query("SELECT graph_id FROM command WHERE `command_id` = '" . $command_id . "'");
- if ($DBRESULT->rowCount()) {
- $data = $DBRESULT->fetch();
+ $statement = $this->DB->prepare("SELECT graph_id FROM command WHERE `command_id` = :command_id");
+ $statement->bindValue(':command_id', (int) $command_id, \PDO::PARAM_INT);
+ $statement->execute();
+ if ($statement->rowCount()) {
+ $data = $statement->fetch();
if ($data["graph_id"] != 0) {
$this->templateId = $data["graph_id"];
unset($data);
return;
}
}
- $DBRESULT->closeCursor();
+ $statement->closeCursor();
unset($command_id);
}
$DBRESULT = $this->DB->query("SELECT graph_id FROM giv_graphs_template WHERE default_tpl1 = '1' LIMIT 1");
@@ -1119,12 +1121,12 @@ public function setTemplate($template_id = null)
/*
* Graph is based on a module check point
*/
- $DBRESULT_meta = $this->DB->query(
- "SELECT graph_id
+ $statement = $this->DB->prepare("SELECT graph_id
FROM meta_service
- WHERE `meta_name` = '" . $this->indexData["service_description"] . "'"
- );
- $meta = $DBRESULT_meta->fetch();
+ WHERE `meta_name` = :service_desc");
+ $statement->bindValue(':service_desc', $this->indexData["service_description"], PDO::PARAM_STR);
+ $statement->execute();
+ $meta = $statement->fetch();
$this->templateId = $meta["graph_id"];
unset($meta);
}
@@ -1149,14 +1151,14 @@ private function getServiceGraphID()
$service_id = $this->indexData["service_id"];
$tab = array();
- while (1) {
- $DBRESULT = $this->DB->query(
- "SELECT esi.graph_id, service_template_model_stm_id
+ $statement = $this->DB->prepare("SELECT esi.graph_id, service_template_model_stm_id
FROM service
LEFT JOIN extended_service_information esi ON esi.service_service_id = service_id
- WHERE service_id = '" . $service_id . "' LIMIT 1"
- );
- $row = $DBRESULT->fetch();
+ WHERE service_id = :service_id LIMIT 1");
+ while (1) {
+ $statement->bindValue(':service_id', (int) $service_id, \PDO::PARAM_INT);
+ $statement->execute();
+ $row = $statement->fetch();
if ($row["graph_id"]) {
$this->graphID = $row["graph_id"];
return $this->graphID;
diff --git a/www/class/centreonHostgroups.class.php b/www/class/centreonHostgroups.class.php
index c8c5b1225a2..34dd68d6947 100644
--- a/www/class/centreonHostgroups.class.php
+++ b/www/class/centreonHostgroups.class.php
@@ -334,6 +334,12 @@ public function getObjectForSelect2($values = array(), $options = array())
return $items;
}
+ $hostgroups = [];
+ // $values structure: ['1,2,3,4'], keeping the foreach in case it could have more than one index
+ foreach ($values as $value) {
+ $hostgroups = array_merge($hostgroups, explode(',', $value));
+ }
+
// get list of authorized hostgroups
if (!$centreon->user->access->admin) {
$hgAcl = $centreon->user->access->getHostGroupAclConf(
@@ -347,7 +353,7 @@ public function getObjectForSelect2($values = array(), $options = array())
'conditions' => array(
'hostgroup.hg_id' => array(
'IN',
- $values
+ $hostgroups
)
)
),
@@ -359,15 +365,13 @@ public function getObjectForSelect2($values = array(), $options = array())
$listValues = '';
$queryValues = array();
- foreach ($values as $k => $v) {
- //As it happens that $v could be like "X,Y" when two hostgroups are selected, we added a second foreach
- $multiValues = explode(',', $v);
- foreach ($multiValues as $item) {
- $ids = explode('-', $item);
- $listValues .= ':hgId_' . $ids[0] . ', ';
- $queryValues['hgId_' . $ids[0]] = (int)$ids[0];
- }
+ foreach ($hostgroups as $item) {
+ // the below explode may not be useful
+ $ids = explode('-', $item);
+ $listValues .= ':hgId_' . $ids[0] . ', ';
+ $queryValues['hgId_' . $ids[0]] = (int)$ids[0];
}
+
$listValues = rtrim($listValues, ', ');
$query = 'SELECT hg_id, hg_name FROM hostgroup WHERE hg_id IN (' . $listValues . ') ORDER BY hg_name ';
$stmt = $this->DB->prepare($query);
diff --git a/www/class/centreonLDAP.class.php b/www/class/centreonLDAP.class.php
index ec88cec5d00..d8dd7d18c93 100644
--- a/www/class/centreonLDAP.class.php
+++ b/www/class/centreonLDAP.class.php
@@ -65,8 +65,8 @@ public function __construct($pearDB, $centreonLog = null, $arId = null)
/* Check if use service form DNS */
$use_dns_srv = 0;
$dbResult = $this->db->query(
- "SELECT `ari_value`
- FROM `auth_ressource_info`
+ "SELECT `ari_value`
+ FROM `auth_ressource_info`
WHERE `ari_name` = 'ldap_srv_dns' AND ar_id = " . (int) $arId
);
$row = $dbResult->fetch();
@@ -76,9 +76,9 @@ public function __construct($pearDB, $centreonLog = null, $arId = null)
}
$dbResult = $this->db->query(
- "SELECT `key`, `value`
- FROM `options`
- WHERE `key`
+ "SELECT `key`, `value`
+ FROM `options`
+ WHERE `key`
IN ('debug_ldap_import', 'debug_path')"
);
while ($row = $dbResult->fetch()) {
@@ -97,22 +97,17 @@ public function __construct($pearDB, $centreonLog = null, $arId = null)
$searchTimeout = 5;
$tempSearchTimeout = $this->getLdapHostParameters($arId, 'ldap_search_timeout');
- if (count($tempSearchTimeout) > 0) {
- if (
- isset($tempSearchTimeout['ari_value'])
- && !empty($tempSearchTimeout['ari_value'])
- ) {
- $searchTimeout = $tempSearchTimeout['ari_value'];
- }
+ if (!empty($tempSearchTimeout['ari_value'])) {
+ $searchTimeout = $tempSearchTimeout['ari_value'];
}
/* Get the list of server ldap */
if ($use_dns_srv != "0") {
$dns_query = '_ldap._tcp';
$dbResult = $this->db->query(
- "SELECT `ari_value`
- FROM auth_ressource_info
- WHERE `ari_name` = 'ldap_dns_use_domain'
+ "SELECT `ari_value`
+ FROM auth_ressource_info
+ WHERE `ari_name` = 'ldap_dns_use_domain'
AND ar_id = " . (int) $arId
);
$row = $dbResult->fetch();
@@ -122,11 +117,12 @@ public function __construct($pearDB, $centreonLog = null, $arId = null)
}
$list = dns_get_record($dns_query, DNS_SRV);
foreach ($list as $entry) {
- $ldap = array();
- $ldap['host'] = $entry['target'];
- $ldap['id'] = $arId;
- $ldap['search_timeout'] = $searchTimeout;
- $ldap['info'] = $this->getInfoUseDnsConnect();
+ $ldap = [
+ 'host' => $entry['target'],
+ 'id' => $arId,
+ 'search_timeout' => $searchTimeout,
+ 'info' => $this->getInfoUseDnsConnect(),
+ ];
$ldap['info']['port'] = $entry['port'];
$ldap['info'] = array_merge($ldap['info'], $this->getBindInfo((int) $arId));
$this->ldapHosts[] = $ldap;
@@ -138,10 +134,12 @@ public function __construct($pearDB, $centreonLog = null, $arId = null)
WHERE auth_ressource_id = ' . (int) $arId . ' ORDER BY host_order'
);
while ($row = $dbResult->fetch()) {
- $ldap = array();
- $ldap['host'] = $row['host_address'];
- $ldap['id'] = $arId;
- $ldap['search_timeout'] = $searchTimeout;
+ $ldap = [
+ 'host' => $row['host_address'],
+ 'id' => $arId,
+ 'search_timeout' => $searchTimeout,
+ 'info' => $this->getInfoUseDnsConnect(),
+ ];
$ldap['info'] = $this->getInfoConnect($row['ldap_host_id']);
$ldap['info'] = array_merge($ldap['info'], $this->getBindInfo((int) $arId));
$this->ldapHosts[] = $ldap;
@@ -1003,11 +1001,6 @@ public function isSyncNeededAtLogin(int $arId, int $contactId): bool
'Error while getting automatic synchronization value for LDAP Id : ' . $arId
);
// assuming it needs to be synchronized
- $this->centreonLog->insertLog(
- 3,
- 'LDAP AUTH : Updating user DN of ' .
- (!empty($contactData['contact_name']) ? $contactData['contact_name'] : "contact id $contactId")
- );
return true;
}
$this->centreonLog->insertLog(
diff --git a/www/class/centreonTraps.class.php b/www/class/centreonTraps.class.php
index e10b7bbbd15..0e05dd4ad6a 100644
--- a/www/class/centreonTraps.class.php
+++ b/www/class/centreonTraps.class.php
@@ -170,37 +170,6 @@ public function testOidFormat($oid = null)
}
}
- /**
- *
- * tests if trap already exists
- * @param $oid
- */
- public function testTrapExistence($oid = null)
- {
- if ($oid !== null && $this->testOidFormat($oid) === true) {
- $id = null;
- if (isset($this->form)) {
- $id = $this->form->getSubmitValue('traps_id');
- }
- $query = "SELECT traps_oid, traps_id FROM traps WHERE traps_oid = :oid ";
-
- $statement = $this->db->prepare($query);
- $statement->bindValue(':oid', $oid, \PDO::PARAM_STR);
- $statement->execute();
-
- $trap = $statement->fetch(\PDO::FETCH_ASSOC);
-
- /**
- * If the trap already existing return false to trigger an error with the form validation rule
- */
- if ($statement->rowCount() >= 1 && $trap["traps_id"] != $id) {
- return false;
- } else {
- return true;
- }
- }
- }
-
/**
*
* Delete Traps
diff --git a/www/class/centreonUser.class.php b/www/class/centreonUser.class.php
index 2c61e80a732..398ed4733f2 100644
--- a/www/class/centreonUser.class.php
+++ b/www/class/centreonUser.class.php
@@ -56,7 +56,6 @@ class CentreonUser
public $groupListStr;
public $access;
public $log;
- public $userCrypted;
protected $token;
public $default_page;
private $showDeprecatedPages;
@@ -109,7 +108,6 @@ public function __construct($user = array())
* Initiate Log Class
*/
$this->log = new CentreonUserLog($this->user_id, $pearDB);
- $this->userCrypted = md5($this->alias);
/**
* Init rest api auth
diff --git a/www/class/centreonXMLBGRequest.class.php b/www/class/centreonXMLBGRequest.class.php
index 695afe56a02..49e25bbf15a 100644
--- a/www/class/centreonXMLBGRequest.class.php
+++ b/www/class/centreonXMLBGRequest.class.php
@@ -221,11 +221,12 @@ public function __construct(
private function isUserAdmin()
{
- $query = "SELECT contact_admin, contact_id FROM contact " .
- "WHERE contact.contact_id = '" . CentreonDB::escape($this->user_id) . "' LIMIT 1";
- $dbResult = $this->DB->query($query);
- $admin = $dbResult->fetchRow();
- $dbResult->closeCursor();
+ $statement = $this->DB->prepare("SELECT contact_admin, contact_id FROM contact " .
+ "WHERE contact.contact_id = :userId LIMIT 1");
+ $statement->bindValue(":userId", (int) $this->user_id, \PDO::PARAM_INT);
+ $statement->execute();
+ $admin = $statement->fetchRow();
+ $statement->closeCursor();
if ($admin !== false && $admin["contact_admin"]) {
$this->is_admin = 1;
} else {
diff --git a/www/front_src/src/Authentication/FormInputs/FieldsTable/Row.tsx b/www/front_src/src/Authentication/FormInputs/FieldsTable/Row.tsx
index b43d27bcc96..d44ab8453fc 100644
--- a/www/front_src/src/Authentication/FormInputs/FieldsTable/Row.tsx
+++ b/www/front_src/src/Authentication/FormInputs/FieldsTable/Row.tsx
@@ -19,6 +19,7 @@ const useStyles = makeStyles((theme) => ({
columnGap: theme.spacing(2),
display: 'grid',
gridTemplateColumns: `repeat(${columns}, 1fr) ${theme.spacing(6)}`,
+ gridTemplateRows: 'min-content',
}),
}));
diff --git a/www/front_src/src/Authentication/Openid/Form/inputs.ts b/www/front_src/src/Authentication/Openid/Form/inputs.ts
index 01c07962a97..55b3b1fa125 100644
--- a/www/front_src/src/Authentication/Openid/Form/inputs.ts
+++ b/www/front_src/src/Authentication/Openid/Form/inputs.ts
@@ -1,4 +1,4 @@
-import { equals, isEmpty, isNil, not, path, prop } from 'ramda';
+import { equals, isEmpty, not, prop } from 'ramda';
import { FormikValues } from 'formik';
import {
@@ -32,7 +32,7 @@ import {
labelDeleteRelation,
labelAuthorizationKey,
} from '../translatedLabels';
-import { AuthenticationType, AuthorizationRule } from '../models';
+import { AuthenticationType } from '../models';
import { InputProps, InputType } from '../../FormInputs/models';
import {
labelActivation,
@@ -249,20 +249,6 @@ export const inputs: Array = [
claimValue: '',
},
deleteLabel: labelDeleteRelation,
- getRequired: ({ values, index }): boolean => {
- const tableValues = prop('authorizationRules', values);
-
- const rowValues = path(
- ['authorizationRules', index],
- values,
- );
-
- return isNil(prop('contactGroup', values))
- ? not(isNil(rowValues))
- : isNil(tableValues) ||
- isEmpty(rowValues?.claimValue) ||
- isNil(rowValues?.accessGroup);
- },
},
label: labelDefineRelationAuthorizationValueAndAccessGroup,
type: InputType.FieldsTable,
diff --git a/www/front_src/src/Authentication/Openid/index.test.tsx b/www/front_src/src/Authentication/Openid/index.test.tsx
index d7fffde1689..ab9b4efb751 100644
--- a/www/front_src/src/Authentication/Openid/index.test.tsx
+++ b/www/front_src/src/Authentication/Openid/index.test.tsx
@@ -445,11 +445,10 @@ describe('Openid configuration form', () => {
accessGroupsEndpoint,
labelAccessGroup,
'Access Group 2',
- 1,
],
])(
'updates the %p field when an option is selected from the retrieved options',
- async (_, retrievedOptions, endpoint, label, value, index = 0) => {
+ async (_, retrievedOptions, endpoint, label, value) => {
mockGetRequestsWithNoAuthorizationConfiguration();
renderOpenidConfigurationForm();
@@ -484,7 +483,7 @@ describe('Openid configuration form', () => {
userEvent.click(screen.getByText(value));
await waitFor(() => {
- expect(screen.getAllByLabelText(label)[index]).toHaveValue(value);
+ expect(screen.getAllByLabelText(label)[0]).toHaveValue(value);
});
},
);
@@ -508,40 +507,4 @@ describe('Openid configuration form', () => {
);
});
});
-
- it('displays the "Authorization value" and "Access group" fields as required when the "Contact group" field is filled', async () => {
- mockGetRequestsWithNoAuthorizationConfiguration();
- mockedAxios.get.mockResolvedValueOnce({
- data: retrievedContactGroups,
- });
-
- renderOpenidConfigurationForm();
-
- await waitFor(() => {
- expect(screen.getByLabelText(labelContactGroup)).toBeInTheDocument();
- });
-
- userEvent.click(screen.getByLabelText(labelContactGroup));
-
- await waitFor(() => {
- expect(mockedAxios.get).toHaveBeenCalledWith(
- `${contactGroupsEndpoint}?page=1&sort_by=${encodeURIComponent(
- '{"name":"ASC"}',
- )}`,
- cancelTokenRequestParam,
- );
- });
-
- await waitFor(() => {
- expect(screen.getByText('Contact Group 1')).toBeInTheDocument();
- });
-
- userEvent.click(screen.getByText('Contact Group 1'));
-
- await waitFor(() => {
- expect(screen.getByLabelText(labelAuthorizationValue)).toHaveAttribute(
- 'required',
- );
- });
- });
});
diff --git a/www/front_src/src/Authentication/Openid/useValidationSchema.ts b/www/front_src/src/Authentication/Openid/useValidationSchema.ts
index 4f703165f68..038812dadee 100644
--- a/www/front_src/src/Authentication/Openid/useValidationSchema.ts
+++ b/www/front_src/src/Authentication/Openid/useValidationSchema.ts
@@ -6,7 +6,6 @@ import {
labelRequired,
labelInvalidURL,
labelInvalidIPAddress,
- labelAtLeastOneAuthorizationIsRequired,
} from './translatedLabels';
const IPAddressRegexp = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(\/\d{1,3})?$/;
@@ -29,15 +28,7 @@ const useValidationSchema = (): Yup.SchemaOf => {
return Yup.object({
authenticationType: Yup.string().required(t(labelRequired)),
authorizationEndpoint: Yup.string().nullable().required(t(labelRequired)),
- authorizationRules: Yup.array()
- .of(authorizationSchema)
- .when('contactGroup', (contactGroup, schema) => {
- return contactGroup
- ? schema
- .min(1, t(labelAtLeastOneAuthorizationIsRequired))
- .required(t(labelRequired))
- : schema.nullable();
- }),
+ authorizationRules: Yup.array().of(authorizationSchema),
autoImport: Yup.boolean().required(t(labelRequired)),
baseUrl: Yup.string()
.matches(urlRegexp, t(labelInvalidURL))
diff --git a/www/front_src/src/Authentication/index.tsx b/www/front_src/src/Authentication/index.tsx
index bf12422f160..71668d687f8 100644
--- a/www/front_src/src/Authentication/index.tsx
+++ b/www/front_src/src/Authentication/index.tsx
@@ -1,9 +1,8 @@
-import { useMemo } from 'react';
+import { useEffect, useMemo, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useAtomValue } from 'jotai';
import { useUpdateAtom } from 'jotai/utils';
-import { Responsive } from '@visx/visx';
import { Box, Container, Paper, Tab } from '@mui/material';
import { TabContext, TabList, TabPanel } from '@mui/lab';
@@ -90,35 +89,39 @@ const useStyles = makeStyles((theme) => ({
formContainer: {
display: 'grid',
gridTemplateColumns: '1.2fr 0.6fr',
- height: '100%',
- overflowY: 'auto',
+ justifyItems: 'center',
padding: theme.spacing(3),
},
image: {
+ height: '200px',
opacity: 0.5,
padding: theme.spacing(0, 5),
position: 'sticky',
top: 0,
+ width: '200px',
},
panel: {
- height: '80%',
padding: 0,
},
paper: {
boxShadow: theme.shadows[3],
- height: '100%',
},
tabList: {
boxShadow: theme.shadows[2],
},
}));
-const marginBottomHeight = 88;
+const scrollMargin = 8;
const Authentication = (): JSX.Element => {
const classes = useStyles();
const { t } = useTranslation();
+ const formContainerRef = useRef(null);
+
+ const [windowHeight, setWindowHeight] = useState(window.innerHeight);
+ const [clientRect, setClientRect] = useState(null);
+
const appliedTab = useAtomValue(appliedTabAtom);
const { themeMode } = useAtomValue(userAtom);
const setTab = useUpdateAtom(tabAtom);
@@ -127,6 +130,23 @@ const Authentication = (): JSX.Element => {
setTab(newTab);
};
+ const resize = (): void => {
+ setWindowHeight(window.innerHeight);
+ };
+
+ useEffect(() => {
+ window.addEventListener('resize', resize);
+
+ setClientRect(formContainerRef.current?.getBoundingClientRect() ?? null);
+
+ return () => {
+ window.removeEventListener('resize', resize);
+ };
+ }, []);
+
+ const formContainerHeight =
+ windowHeight - (clientRect?.top || 0) - scrollMargin;
+
const tabs = useMemo(
() =>
panels.map(({ title, value }) => (
@@ -136,33 +156,31 @@ const Authentication = (): JSX.Element => {
);
const tabPanels = useMemo(
- () => (
-
- {({ height }): Array =>
- panels.map(({ Component, value, image }) => (
-
-
{/if}
diff --git a/www/include/views/componentTemplates/formComponentTemplate.php b/www/include/views/componentTemplates/formComponentTemplate.php
index faaec375c5b..4b27228c4e3 100644
--- a/www/include/views/componentTemplates/formComponentTemplate.php
+++ b/www/include/views/componentTemplates/formComponentTemplate.php
@@ -359,7 +359,7 @@ function insertValueQuery() {
var e_input = document.Form.ds_name;
var e_select = document.getElementById('sl_list_metrics');
var sd_o = e_select.selectedIndex;
- if (sd_o != 0) {
+ if (sd_o != -1) {
var chaineAj = '';
chaineAj = e_select.options[sd_o].text;
chaineAj = chaineAj.replace(/\s(\[[CV]DEF\]|)\s*$/, "");
@@ -431,7 +431,6 @@ function popup_color_picker(t,name)
}
$vdef = 0; /* don't list VDEF in metrics list */
-include_once('./include/views/graphs/common/makeJS_formMetricsList.php');
if ($o === MODIFY_COMPONENT_TEMPLATE || $o === WATCH_COMPONENT_TEMPLATE) {
$host_service_id = filter_var(
$_POST['host_service_id'] ?? ($compo["host_id"] . '-' . $compo['service_id']),
@@ -446,9 +445,20 @@ function popup_color_picker(t,name)
?>
diff --git a/www/include/views/graphs/common/makeJS_formMetricsList.php b/www/include/views/graphs/common/makeJS_formMetricsList.php
deleted file mode 100644
index b817ce94a11..00000000000
--- a/www/include/views/graphs/common/makeJS_formMetricsList.php
+++ /dev/null
@@ -1,177 +0,0 @@
-.
- *
- * Linking this program statically or dynamically with other modules is making a
- * combined work based on this program. Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this program give Centreon
- * permission to link this program with independent modules to produce an executable,
- * regardless of the license terms of these independent modules, and to copy and
- * distribute the resulting executable under terms of Centreon choice, provided that
- * Centreon also meet, for each linked independent module, the terms and conditions
- * of the license of that module. An independent module is a module which is not
- * derived from this program. If you modify this program, you may extend this
- * exception to your version of the program, but you are not obliged to do so. If you
- * do not wish to do so, delete this exception statement from your version.
- *
- * For more information : contact@centreon.com
- *
- * SVN : $URL$
- * SVN : $Id$
- *
- */
-
- /*
- * Lang file
- */
- $locale = $oreon->user->get_lang();
- putenv("LANG=$locale");
- setlocale(LC_ALL, $locale);
- bindtextdomain("messages", _CENTREON_PATH_ . "www/locale/");
- bind_textdomain_codeset("messages", "UTF-8");
- textdomain("messages");
-?>
diff --git a/www/include/views/graphs/common/makeXML_ListMetrics.php b/www/include/views/graphs/common/makeXML_ListMetrics.php
deleted file mode 100644
index 5d7afe858b1..00000000000
--- a/www/include/views/graphs/common/makeXML_ListMetrics.php
+++ /dev/null
@@ -1,173 +0,0 @@
-.
- *
- * Linking this program statically or dynamically with other modules is making a
- * combined work based on this program. Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this program give Centreon
- * permission to link this program with independent modules to produce an executable,
- * regardless of the license terms of these independent modules, and to copy and
- * distribute the resulting executable under terms of Centreon choice, provided that
- * Centreon also meet, for each linked independent module, the terms and conditions
- * of the license of that module. An independent module is a module which is not
- * derived from this program. If you modify this program, you may extend this
- * exception to your version of the program, but you are not obliged to do so. If you
- * do not wish to do so, delete this exception statement from your version.
- *
- * For more information : contact@centreon.com
- *
- * SVN : $URL$
- * SVN : $Id$
- *
- */
-
- header('Content-Type: text/xml');
- header('Cache-Control: no-cache');
-
- require_once realpath(dirname(__FILE__) . "/../../../../../config/centreon.config.php");
- require_once _CENTREON_PATH_."/www/class/centreonDB.class.php";
- require_once _CENTREON_PATH_."/www/class/centreonXML.class.php";
-
-function compare($a, $b)
-{
- if ($a["metric_name"] == $b["metric_name"]) {
- return 0;
- }
- return ( $a["metric_name"] < $b["metric_name"] ) ? -1 : 1;
-}
-
- $pearDB = new CentreonDB();
- $pearDBO = new CentreonDB("centstorage");
-
- /*
- * Get session
- */
- require_once(_CENTREON_PATH_ . "www/class/centreonSession.class.php");
- require_once(_CENTREON_PATH_ . "www/class/centreon.class.php");
-if (!isset($_SESSION['centreon'])) {
- CentreonSession::start();
-}
-
-if (isset($_SESSION['centreon'])) {
- $oreon = $_SESSION['centreon'];
-} else {
- exit;
-}
-
- /*
- * Get language
- */
- $locale = $oreon->user->get_lang();
- putenv("LANG=$locale");
- setlocale(LC_ALL, $locale);
- bindtextdomain("messages", _CENTREON_PATH_ . "www/locale/");
-;
- bind_textdomain_codeset("messages", "UTF-8");
- textdomain("messages");
-
- #
- # Existing Real Metric List comes from DBO -> Store in $rmetrics Array
- #
- $s_datas = array();
- $o_datas = array(""=> utf8_decode(_("List of known metrics")));
- $mx_l = strlen($o_datas[""]);
- $where = "";
- $def_type = array(0=>"CDEF",1=>"VDEF");
-
-if (isset($_GET['vdef']) && is_numeric($_GET['vdef']) && $_GET['vdef'] == 0) {
- $where = " AND def_type='".$_GET["vdef"]."'";
-}
-
-if (isset($_GET["host_id"]) && $_GET["service_id"]) {
- if (!is_numeric($_GET['host_id']) || !is_numeric($_GET['service_id'])) {
- $buffer = new CentreonXML();
- $buffer->writeElement('error', 'Bad id format');
- $buffer->output();
- exit;
- }
- $host_id = $_GET["host_id"];
- $service_id = $_GET["service_id"];
-
- $query = "SELECT id "
- . "FROM index_data "
- . "WHERE host_id = " . $pearDB->escape($host_id) . " "
- . "AND service_id = " . $pearDB->escape($service_id) . " ";
-
- $index_id = 0;
- $pq_sql = $pearDBO->query($query);
- if ($row = $pq_sql->fetchRow()) {
- $index_id = $row['id'];
- }
-
- $query = "SELECT metric_id, metric_name "
- . "FROM metrics "
- . "WHERE index_id = " . $index_id . " ";
- $pq_sql = $pearDBO->query($query);
- while ($fw_sql = $pq_sql->fetchRow()) {
- $sd_l = strlen($fw_sql["metric_name"]);
- $fw_sql["metric_name"] = $fw_sql["metric_name"] . " ";
- $s_datas[] = $fw_sql;
- if ($sd_l > $mx_l) {
- $mx_l = $sd_l;
- }
- }
- $pq_sql->closeCursor();
- $query = "SELECT vmetric_id, vmetric_name, def_type "
- . "FROM virtual_metrics "
- . "WHERE index_id = " . $index_id . " "
- . $where . " ";
- $pq_sql = $pearDB->query($query);
-
- while ($fw_sql = $pq_sql->fetchRow()) {
- $sd_l = strlen($fw_sql["vmetric_name"]." [CDEF]");
- $fw_sql["metric_name"] = $fw_sql["vmetric_name"]." [".$def_type[$fw_sql["def_type"]]."] ";
- $fw_sql["metric_id"] = "v".$fw_sql["vmetric_id"];
- $s_datas[] = $fw_sql;
- if ($sd_l > $mx_l) {
- $mx_l = $sd_l;
- }
- $pq_sql->closeCursor();
- }
-}
-
- usort($s_datas, "compare");
-
-foreach ($s_datas as $key => $om) {
- $o_datas[$om["metric_id"]] = $om["metric_name"];
-}
-
-for ($i = strlen($o_datas[""]); $i != $mx_l; $i++) {
- $o_datas[""] .= " ";
-}
-
- # The first element of the select is empty
- $buffer = new CentreonXML();
- $buffer->startElement("options_data");
- $buffer->writeElement("td_id", "td_list_metrics");
- $buffer->writeElement("select_id", "sl_list_metrics");
-
- # Now we fill out the select with templates id and names
-foreach ($o_datas as $o_id => $o_alias) {
- $buffer->startElement("option");
- $buffer->writeElement("o_id", $o_id);
- $buffer->writeElement("o_alias", $o_alias);
- $buffer->endElement();
-}
-
- $buffer->endElement();
- $buffer->output();
diff --git a/www/include/views/graphs/generateGraphs/generateImage.php b/www/include/views/graphs/generateGraphs/generateImage.php
index 54632504a17..2d43aa60992 100644
--- a/www/include/views/graphs/generateGraphs/generateImage.php
+++ b/www/include/views/graphs/generateGraphs/generateImage.php
@@ -95,6 +95,8 @@
} else {
die('Invalid token');
}
+} else {
+ throw new \Exception('Username and token query strings must be set.');
}
$index = filter_var(
@@ -182,19 +184,37 @@
$dbstorage = new CentreonDB('centstorage');
$aclGroups = $acl->getAccessGroupsString();
- $sql = "SELECT host_id, service_id FROM index_data WHERE id = " .$pearDB->escape($index);
- $res = $dbstorage->query($sql);
- if (!$res->rowCount()) {
+ $sql = "SELECT host_id, service_id FROM index_data WHERE id = :index_data_id";
+ $statement = $dbstorage->prepare($sql);
+ $statement->bindValue(':index_data_id', (int) $index, \PDO::PARAM_INT);
+ $statement->execute();
+ if (!$statement->rowCount()) {
die('Graph not found');
}
- $row = $res->fetch();
- unset($res);
+ $row = $statement->fetch(\PDO::FETCH_ASSOC);
+ unset($statement);
$hostId = $row['host_id'];
$serviceId = $row['service_id'];
- $sql = "SELECT service_id FROM centreon_acl WHERE host_id = $hostId AND service_id = $serviceId
- AND group_id IN ($aclGroups)";
- $res = $pearDBO->query($sql);
- if (!$res->rowCount()) {
+ $aclGroupsExploded = explode(',', $aclGroups);
+ if (empty($aclGroupsExploded)) {
+ throw new \Exception('Access denied');
+ }
+
+ $aclGroupsQueryBinds = [];
+ foreach ($aclGroupsExploded as $key => $value) {
+ $aclGroupsQueryBinds[':acl_group_' . $key] = $value;
+ }
+ $aclGroupBinds = implode(',', array_keys($aclGroupsQueryBinds));
+ $sql = "SELECT service_id FROM centreon_acl WHERE host_id = :host_id AND service_id = :service_id
+ AND group_id IN ($aclGroupBinds)";
+ $statement = $pearDBO->prepare($sql);
+ $statement->bindValue(':host_id', (int) $hostId, \PDO::PARAM_INT);
+ $statement->bindValue(':service_id', (int) $serviceId, \PDO::PARAM_INT);
+ foreach ($aclGroupsQueryBinds as $key => $value) {
+ $statement->bindValue($key, (int) $value, \PDO::PARAM_INT);
+ }
+ $statement->execute();
+ if (!$statement->rowCount()) {
die('Access denied');
}
}
diff --git a/www/include/views/virtualMetrics/formVirtualMetrics.ihtml b/www/include/views/virtualMetrics/formVirtualMetrics.ihtml
index 86c044fee1a..98ea810739a 100644
--- a/www/include/views/virtualMetrics/formVirtualMetrics.ihtml
+++ b/www/include/views/virtualMetrics/formVirtualMetrics.ihtml
@@ -48,7 +48,10 @@
{$form.rpn_function.html}
{if $o == "a" || $o == "c"}
-
+
+
+
+
{/if}
diff --git a/www/include/views/virtualMetrics/formVirtualMetrics.php b/www/include/views/virtualMetrics/formVirtualMetrics.php
index a90eb4cf6d6..4cf98e972b9 100644
--- a/www/include/views/virtualMetrics/formVirtualMetrics.php
+++ b/www/include/views/virtualMetrics/formVirtualMetrics.php
@@ -236,7 +236,7 @@ function insertValueQuery() {
var e_txtarea = document.Form.rpn_function;
var e_select = document.getElementById('sl_list_metrics');
var sd_o = e_select.selectedIndex;
- if (sd_o != 0) {
+ if (sd_o != -1) {
var chaineAj = '';
chaineAj = e_select.options[sd_o].text;
//chaineAj = chaineAj.substring(0, chaineAj.length - 3);
@@ -329,7 +329,7 @@ function manageVDEF() {
$tpl->display("formVirtualMetrics.ihtml");
}
$vdef = 1; /* Display VDEF too */
-include_once("./include/views/graphs/common/makeJS_formMetricsList.php");
+
if ($o == METRIC_MODIFY || $o == METRIC_WATCH) {
isset($_POST["host_id"]) && $_POST["host_id"] != null
? $host_service_id = $_POST["host_id"]
@@ -340,11 +340,21 @@ function manageVDEF() {
: $host_service_id = 0;
}
?>
-
diff --git a/www/install/createTables.sql b/www/install/createTables.sql
index aa1a86c661d..c72f2449beb 100644
--- a/www/install/createTables.sql
+++ b/www/install/createTables.sql
@@ -2321,7 +2321,6 @@ CREATE TABLE IF NOT EXISTS contact_feature (
CREATE TABLE IF NOT EXISTS `remote_servers` (
`id` INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`ip` VARCHAR(255) NOT NULL,
- `app_key` VARCHAR(40) NOT NULL,
`version` VARCHAR(16) NOT NULL,
`is_connected` TINYINT(1) NOT NULL DEFAULT 0,
`created_at` TIMESTAMP NOT NULL,
diff --git a/www/install/insertBaseConf.sql b/www/install/insertBaseConf.sql
index ccc87787142..06481bb738f 100644
--- a/www/install/insertBaseConf.sql
+++ b/www/install/insertBaseConf.sql
@@ -2,7 +2,7 @@
-- Insert version
--
-INSERT INTO `informations` (`key` ,`value`) VALUES ('version', '22.04.2');
+INSERT INTO `informations` (`key` ,`value`) VALUES ('version', '22.04.3');
--
-- Contenu de la table `contact`
diff --git a/www/install/php/Update-22.04.2.php b/www/install/php/Update-22.04.2.php
index 8572f2a05df..18f7e537d45 100644
--- a/www/install/php/Update-22.04.2.php
+++ b/www/install/php/Update-22.04.2.php
@@ -18,3 +18,34 @@
* For more information : contact@centreon.com
*
*/
+
+require_once __DIR__ . '/../../class/centreonLog.class.php';
+
+$centreonLog = new CentreonLog();
+
+//error specific content
+$versionOfTheUpgrade = 'UPGRADE - 22.04.2: ';
+$errorMessage = '';
+
+try {
+ $pearDB->beginTransaction();
+
+ $errorMessage = "Unable to delete 'appKey' information from database";
+ $pearDB->query("DELETE FROM `informations` WHERE `key` = 'appKey'");
+
+ $pearDB->commit();
+} catch (\Exception $e) {
+ if ($pearDB->inTransaction()) {
+ $pearDB->rollBack();
+ }
+
+ $centreonLog->insertLog(
+ 4,
+ $versionOfTheUpgrade . $errorMessage .
+ " - Code : " . (int)$e->getCode() .
+ " - Error : " . $e->getMessage() .
+ " - Trace : " . $e->getTraceAsString()
+ );
+
+ throw new \Exception($versionOfTheUpgrade . $errorMessage, (int) $e->getCode(), $e);
+}
diff --git a/www/install/php/Update-22.04.3.php b/www/install/php/Update-22.04.3.php
new file mode 100644
index 00000000000..8572f2a05df
--- /dev/null
+++ b/www/install/php/Update-22.04.3.php
@@ -0,0 +1,20 @@
+.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * Linking this program statically or dynamically with other modules is making a
- * combined work based on this program. Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this program give Centreon
- * permission to link this program with independent modules to produce an executable,
- * regardless of the license terms of these independent modules, and to copy and
- * distribute the resulting executable under terms of Centreon choice, provided that
- * Centreon also meet, for each linked independent module, the terms and conditions
- * of the license of that module. An independent module is a module which is not
- * derived from this program. If you modify this program, you may extend this
- * exception to your version of the program, but you are not obliged to do so. If you
- * do not wish to do so, delete this exception statement from your version.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*
* For more information : contact@centreon.com
*
*/
session_start();
-require_once realpath(dirname(__FILE__) . "/../../../../config/centreon.config.php");
-require_once _CENTREON_PATH_ . '/www/class/centreonDB.class.php';
-require_once '../../steps/functions.php';
+require_once __DIR__ . '/../../../../bootstrap.php';
+require_once __DIR__ . '/../../../class/centreonDB.class.php';
+require_once __DIR__ . '/../../steps/functions.php';
+
+use Core\Platform\Application\Repository\UpdateLockerRepositoryInterface;
+use Core\Platform\Application\Repository\ReadUpdateRepositoryInterface;
+use Core\Platform\Application\Repository\WriteUpdateRepositoryInterface;
+use Core\Platform\Application\UseCase\UpdateVersions\UpdateVersionsException;
$current = $_POST['current'];
$next = $_POST['next'];
$status = 0;
-/**
- * Variables for upgrade scripts
- */
-try {
- $pearDB = new CentreonDB('centreon', 3);
- $pearDBO = new CentreonDB('centstorage', 3);
-} catch (Exception $e) {
- exitUpgradeProcess(1, $current, $next, $e->getMessage());
-}
+$kernel = \App\Kernel::createForWeb();
-/**
- * Upgrade storage sql
- */
-$storageSql = '../../sql/centstorage/Update-CSTG-' . $next . '.sql';
-if (is_file($storageSql)) {
- $result = splitQueries($storageSql, ';', $pearDBO, '../../tmp/Update-CSTG-' . $next);
- if ("0" != $result) {
- exitUpgradeProcess(1, $current, $next, $result);
- }
-}
+$updateLockerRepository = $kernel->getContainer()->get(UpdateLockerRepositoryInterface::class);
+$updateWriteRepository = $kernel->getContainer()->get(WriteUpdateRepositoryInterface::class);
-/**
- * Pre upgrade PHP
- */
-$prePhp = '../../php/Update-' . $next . '.php';
-if (is_file($prePhp)) {
- try {
- include_once $prePhp;
- } catch (Exception $e) {
- exitUpgradeProcess(1, $current, $next, $e->getMessage());
+try {
+ if (! $updateLockerRepository->lock()) {
+ throw UpdateVersionsException::updateAlreadyInProgress();
}
-}
-/**
- * Upgrade configuration sql
- */
-$confSql = '../../sql/centreon/Update-DB-' . $next . '.sql';
-if (is_file($confSql)) {
- $result = splitQueries($confSql, ';', $pearDB, '../../tmp/Update-DB-' . $next);
- if ("0" != $result) {
- exitUpgradeProcess(1, $current, $next, $result);
- }
-}
+ $updateWriteRepository->runUpdate($next);
-/**
- * Post upgrade PHP
- */
-$postPhp = '../../php/Update-' . $next . '.post.php';
-if (is_file($postPhp)) {
- try {
- include_once $postPhp;
- } catch (Exception $e) {
- exitUpgradeProcess(1, $current, $next, $e->getMessage());
- }
+ $updateLockerRepository->unlock();
+} catch (\Throwable $e) {
+ exitUpgradeProcess(1, $current, $next, $e->getMessage());
}
-/**
- * Update version in database.
- */
-$res = $pearDB->prepare("UPDATE `informations` SET `value` = ? WHERE `key` = 'version'");
-$res->execute(array($next));
$current = $next;
-/*
-** To find the next version that we should update to, we will look in
-** the www/install/php directory where all PHP update scripts are
-** stored. We will extract the target version from the filename and find
-** the closest version to the current version.
-*/
-$next = '';
-if ($handle = opendir('../../php')) {
- while (false !== ($file = readdir($handle))) {
- if (preg_match('/Update-([a-zA-Z0-9\-\.]+)\.php/', $file, $matches)) {
- if ((version_compare($current, $matches[1]) < 0) &&
- (empty($next) || (version_compare($matches[1], $next) < 0))) {
- $next = $matches[1];
- }
- }
- }
- closedir($handle);
-}
+$updateReadRepository = $kernel->getContainer()->get(ReadUpdateRepositoryInterface::class);
+$availableUpdates = $updateReadRepository->findOrderedAvailableUpdates($current);
+$next = empty($availableUpdates) ? '' : array_shift($availableUpdates);
+
$_SESSION['CURRENT_VERSION'] = $current;
$okMsg = "OK";
+
exitUpgradeProcess($status, $current, $next, $okMsg);
diff --git a/www/install/step_upgrade/process/process_step5.php b/www/install/step_upgrade/process/process_step5.php
index df5d79e2174..c4a723a14f2 100644
--- a/www/install/step_upgrade/process/process_step5.php
+++ b/www/install/step_upgrade/process/process_step5.php
@@ -37,44 +37,15 @@
require_once __DIR__ . '/../../../../bootstrap.php';
require_once '../../steps/functions.php';
-function recurseRmdir($dir)
-{
- $files = array_diff(scandir($dir), array('.', '..'));
- foreach ($files as $file) {
- (is_dir("$dir/$file")) ? recurseRmdir("$dir/$file") : unlink("$dir/$file");
- }
- return rmdir($dir);
-}
-
-function recurseCopy($source, $dest)
-{
- if (is_link($source)) {
- return symlink(readlink($source), $dest);
- }
+use Core\Platform\Application\Repository\WriteUpdateRepositoryInterface;
+use Core\Platform\Application\UseCase\UpdateVersions\UpdateVersionsException;
- if (is_file($source)) {
- return copy($source, $dest);
- }
-
- if (!is_dir($dest)) {
- mkdir($dest);
- }
+$kernel = \App\Kernel::createForWeb();
- $dir = dir($source);
- while (false !== $entry = $dir->read()) {
- if ($entry == '.' || $entry == '..') {
- continue;
- }
-
- recurseCopy("$source/$entry", "$dest/$entry");
- }
-
- $dir->close();
- return true;
-}
+$updateWriteRepository = $kernel->getContainer()->get(WriteUpdateRepositoryInterface::class);
$parameters = filter_input_array(INPUT_POST);
-$current = filter_var($_POST['current'] ?? "step 5", FILTER_SANITIZE_STRING);
+$current = filter_var($_POST['current'] ?? "step 5", FILTER_SANITIZE_FULL_SPECIAL_CHARS);
if ($parameters) {
if ((int)$parameters["send_statistics"] === 1) {
@@ -88,16 +59,19 @@ function recurseCopy($source, $dest)
$db->query($query);
}
-$name = 'install-' . $_SESSION['CURRENT_VERSION'] . '-' . date('Ymd_His');
-$completeName = _CENTREON_VARLIB_ . '/installs/' . $name;
-$sourceInstallDir = str_replace('step_upgrade', '', realpath(dirname(__FILE__) . '/../'));
-
try {
- if (recurseCopy($sourceInstallDir, $completeName)) {
- recurseRmdir($sourceInstallDir);
+ if (!isset($_SESSION['CURRENT_VERSION']) || ! preg_match('/^\d+\.\d+\.\d+/', $_SESSION['CURRENT_VERSION'])) {
+ throw new \Exception('Cannot get current version');
}
-} catch (Exception $e) {
- exitUpgradeProcess(1, $current, '', $e->getMessage());
+
+ $updateWriteRepository->runPostUpdate($_SESSION['CURRENT_VERSION']);
+} catch (\Throwable $e) {
+ exitUpgradeProcess(
+ 1,
+ $current,
+ '',
+ UpdateVersionsException::errorWhenApplyingPostUpdate($e)->getMessage()
+ );
}
session_destroy();
diff --git a/www/install/steps/process/insertBaseConf.php b/www/install/steps/process/insertBaseConf.php
index 5a2fe96e73a..95f3e2bab70 100644
--- a/www/install/steps/process/insertBaseConf.php
+++ b/www/install/steps/process/insertBaseConf.php
@@ -138,9 +138,7 @@
$link->exec("INSERT INTO `options` (`key`, `value`) VALUES ('gmt','" . $timezoneId . "')");
# Generate random key for this instance and set it to be not central and not remote
-$uniqueKey = md5(uniqid(rand(), true));
$informationsTableInsert = "INSERT INTO `informations` (`key`,`value`) VALUES
- ('appKey', '{$uniqueKey}'),
('isRemote', 'no'),
('isCentral', 'yes')";