From c47338e3d5aa10b7baa7107e0111c950f05e5245 Mon Sep 17 00:00:00 2001 From: Rom1-B <8530352+Rom1-B@users.noreply.github.com> Date: Wed, 29 Jul 2026 15:13:25 +0200 Subject: [PATCH] Fix: check host id before forwarding to Centreon API --- .gitignore | 1 + CHANGELOG.md | 6 ++ Makefile | 1 + composer.json | 3 + composer.lock | 138 +++++++++++++++++++++------------------- hook.php | 6 +- rector.php | 88 +++++++------------------ setup.php | 5 +- src/ApiClient.php | 87 ++++++++----------------- src/Config.php | 17 ++--- src/Host.php | 132 ++++++++++++++++++++++++-------------- tests/ApiClientTest.php | 1 + 12 files changed, 234 insertions(+), 251 deletions(-) create mode 100644 Makefile diff --git a/.gitignore b/.gitignore index 4da5e45..8e997d7 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ tests/files/_logs/*.log vendor/ .gh_token .phpunit.result.cache +var/ \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 830eed0..4ec07fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [Unreleased] + +### Fixed + +- Check host id before forwarding requests to the Centreon API + ## [1.1.2] - 2025-12-22 - Fix item match process diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ef1bed5 --- /dev/null +++ b/Makefile @@ -0,0 +1 @@ +include ../../PluginsMakefile.mk diff --git a/composer.json b/composer.json index 17a79a8..dc7fca1 100644 --- a/composer.json +++ b/composer.json @@ -5,6 +5,9 @@ "require-dev": { "glpi-project/tools": "^0.8" }, + "provide": { + "guzzlehttp/guzzle": "*" + }, "config": { "optimize-autoloader": true, "platform": { diff --git a/composer.lock b/composer.lock index 5620753..de4245a 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": "0bb7734a8837cdd118f20d259d3613e7", + "content-hash": "38a12e3e476f18f8c5b9cdabf68dd0a8", "packages": [], "packages-dev": [ { @@ -118,16 +118,16 @@ }, { "name": "symfony/console", - "version": "v6.4.27", + "version": "v6.4.43", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "13d3176cf8ad8ced24202844e9f95af11e2959fc" + "reference": "3b643aa587acbc42f967a429af088a56ed8f046d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/13d3176cf8ad8ced24202844e9f95af11e2959fc", - "reference": "13d3176cf8ad8ced24202844e9f95af11e2959fc", + "url": "https://api.github.com/repos/symfony/console/zipball/3b643aa587acbc42f967a429af088a56ed8f046d", + "reference": "3b643aa587acbc42f967a429af088a56ed8f046d", "shasum": "" }, "require": { @@ -192,7 +192,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.4.27" + "source": "https://github.com/symfony/console/tree/v6.4.43" }, "funding": [ { @@ -212,20 +212,20 @@ "type": "tidelift" } ], - "time": "2025-10-06T10:25:16+00:00" + "time": "2026-07-26T14:44:19+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.6.0", + "version": "v3.7.1", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62" + "reference": "f3202fa1b5097b0af062dc978b32ecf63404e31d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62", - "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/f3202fa1b5097b0af062dc978b32ecf63404e31d", + "reference": "f3202fa1b5097b0af062dc978b32ecf63404e31d", "shasum": "" }, "require": { @@ -238,7 +238,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.6-dev" + "dev-main": "3.7-dev" } }, "autoload": { @@ -263,7 +263,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.7.1" }, "funding": [ { @@ -274,25 +274,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-25T14:21:43+00:00" + "time": "2026-06-05T06:23:12+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.33.0", + "version": "v1.37.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" + "reference": "141046a8f9477948ff284fa65be2095baafb94f2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", - "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/141046a8f9477948ff284fa65be2095baafb94f2", + "reference": "141046a8f9477948ff284fa65be2095baafb94f2", "shasum": "" }, "require": { @@ -342,7 +346,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.37.0" }, "funding": [ { @@ -362,20 +366,20 @@ "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2026-04-10T16:19:22+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.33.0", + "version": "v1.41.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70" + "reference": "bb899c1db0aa8127dc3afe8cda4a67eb24915f8d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70", - "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/bb899c1db0aa8127dc3afe8cda4a67eb24915f8d", + "reference": "bb899c1db0aa8127dc3afe8cda4a67eb24915f8d", "shasum": "" }, "require": { @@ -424,7 +428,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.41.0" }, "funding": [ { @@ -444,20 +448,20 @@ "type": "tidelift" } ], - "time": "2025-06-27T09:58:17+00:00" + "time": "2026-07-28T08:25:59+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.33.0", + "version": "v1.38.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "3833d7255cc303546435cb650316bff708a1c75c" + "reference": "2d446c214bdbe5b71bde5011b060a05fece3ae6b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", - "reference": "3833d7255cc303546435cb650316bff708a1c75c", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/2d446c214bdbe5b71bde5011b060a05fece3ae6b", + "reference": "2d446c214bdbe5b71bde5011b060a05fece3ae6b", "shasum": "" }, "require": { @@ -509,7 +513,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.38.0" }, "funding": [ { @@ -529,20 +533,20 @@ "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2026-05-25T13:48:31+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.33.0", + "version": "v1.38.2", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" + "reference": "d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", - "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6", + "reference": "d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6", "shasum": "" }, "require": { @@ -594,7 +598,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.38.2" }, "funding": [ { @@ -614,20 +618,20 @@ "type": "tidelift" } ], - "time": "2024-12-23T08:48:59+00:00" + "time": "2026-05-27T06:59:30+00:00" }, { "name": "symfony/service-contracts", - "version": "v3.6.0", + "version": "v3.7.1", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4" + "reference": "c0a284bab1ed8aa0417e3d69250ab437739563a0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4", - "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/c0a284bab1ed8aa0417e3d69250ab437739563a0", + "reference": "c0a284bab1ed8aa0417e3d69250ab437739563a0", "shasum": "" }, "require": { @@ -645,7 +649,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.6-dev" + "dev-main": "3.7-dev" } }, "autoload": { @@ -681,7 +685,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.6.0" + "source": "https://github.com/symfony/service-contracts/tree/v3.7.1" }, "funding": [ { @@ -692,31 +696,36 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-04-25T09:37:31+00:00" + "time": "2026-06-16T09:55:08+00:00" }, { "name": "symfony/string", - "version": "v7.3.4", + "version": "v7.4.15", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "f96476035142921000338bad71e5247fbc138872" + "reference": "e394af32256bf9e7bf80849d95e589167c10097b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/f96476035142921000338bad71e5247fbc138872", - "reference": "f96476035142921000338bad71e5247fbc138872", + "url": "https://api.github.com/repos/symfony/string/zipball/e394af32256bf9e7bf80849d95e589167c10097b", + "reference": "e394af32256bf9e7bf80849d95e589167c10097b", "shasum": "" }, "require": { "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3.0", "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-grapheme": "~1.33", "symfony/polyfill-intl-normalizer": "~1.0", "symfony/polyfill-mbstring": "~1.0" }, @@ -724,11 +733,11 @@ "symfony/translation-contracts": "<2.5" }, "require-dev": { - "symfony/emoji": "^7.1", - "symfony/http-client": "^6.4|^7.0", - "symfony/intl": "^6.4|^7.0", + "symfony/emoji": "^7.1|^8.0", + "symfony/http-client": "^6.4|^7.0|^8.0", + "symfony/intl": "^6.4|^7.0|^8.0", "symfony/translation-contracts": "^2.5|^3.0", - "symfony/var-exporter": "^6.4|^7.0" + "symfony/var-exporter": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -767,7 +776,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.3.4" + "source": "https://github.com/symfony/string/tree/v7.4.15" }, "funding": [ { @@ -787,20 +796,20 @@ "type": "tidelift" } ], - "time": "2025-09-11T14:36:48+00:00" + "time": "2026-07-28T07:33:02+00:00" }, { "name": "twig/twig", - "version": "v3.22.0", + "version": "v3.28.0", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "4509984193026de413baf4ba80f68590a7f2c51d" + "reference": "597c12ed286fb9d1701a36684ce6e0cbe28ebc8b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/4509984193026de413baf4ba80f68590a7f2c51d", - "reference": "4509984193026de413baf4ba80f68590a7f2c51d", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/597c12ed286fb9d1701a36684ce6e0cbe28ebc8b", + "reference": "597c12ed286fb9d1701a36684ce6e0cbe28ebc8b", "shasum": "" }, "require": { @@ -810,7 +819,8 @@ "symfony/polyfill-mbstring": "^1.3" }, "require-dev": { - "phpstan/phpstan": "^2.0", + "php-cs-fixer/shim": "^3.0@stable", + "phpstan/phpstan": "^2.0@stable", "psr/container": "^1.0|^2.0", "symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0" }, @@ -854,7 +864,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.22.0" + "source": "https://github.com/twigphp/Twig/tree/v3.28.0" }, "funding": [ { @@ -866,7 +876,7 @@ "type": "tidelift" } ], - "time": "2025-10-29T15:56:47+00:00" + "time": "2026-07-03T20:44:34+00:00" } ], "aliases": [], @@ -881,5 +891,5 @@ "platform-overrides": { "php": "8.2.99" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.9.0" } diff --git a/hook.php b/hook.php index bb7c61a..6fe9d0c 100644 --- a/hook.php +++ b/hook.php @@ -47,7 +47,7 @@ function plugin_centreon_install($version) $table = Host::getTable(); if (!$DB->tableExists($table)) { - $query = "CREATE TABLE `$table` ( + $query = "CREATE TABLE `{$table}` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, `itemtype` VARCHAR(100) NOT NULL, `items_id` INT UNSIGNED NOT NULL DEFAULT '0', @@ -63,6 +63,7 @@ function plugin_centreon_install($version) $migration->changeField($table, 'items_id', 'items_id', "int unsigned NOT NULL DEFAULT '0'"); $migration->changeField($table, 'centreon_id', 'centreon_id', "int unsigned NOT NULL"); } + $centreon_password = Config::getConfigurationValue('plugin:centreon', 'centreon-password'); /**Migration to 1.0.1 */ if ($centreon_password !== null) { @@ -77,6 +78,7 @@ function plugin_centreon_install($version) ]); } } + return true; } @@ -94,7 +96,7 @@ function plugin_centreon_uninstall() foreach ($tables as $table) { $migration = new Migration(PLUGIN_CENTREON_VERSION); - $migration->displayMessage("Uninstalling $table"); + $migration->displayMessage('Uninstalling ' . $table); $migration->dropTable($table); $DB->error(); } diff --git a/rector.php b/rector.php index bb0dd9c..78551e4 100644 --- a/rector.php +++ b/rector.php @@ -28,72 +28,28 @@ * ------------------------------------------------------------------------- */ +use Rector\Configuration\RectorConfigBuilder; + require_once __DIR__ . '/../../src/Plugin.php'; -use Rector\Caching\ValueObject\Storage\FileCacheStorage; -use Rector\CodeQuality\Rector as CodeQuality; -use Rector\Config\RectorConfig; -use Rector\DeadCode\Rector as DeadCode; -use Rector\ValueObject\PhpVersion; +$baseline_file = __DIR__ . '/../../PluginsRector.php'; +if (!file_exists($baseline_file)) { + throw new RuntimeException( + sprintf( + 'Unable to find "%s". Running rector on a plugin requires a GLPI development checkout that ships PluginsRector.php.', + $baseline_file, + ), + ); +} + +$baseline = require $baseline_file; + +/** @var RectorConfigBuilder $config */ +$config = $baseline([ + __DIR__ . '/ajax', + __DIR__ . '/front', + __DIR__ . '/src', + __DIR__ . '/tests', +]); -return RectorConfig::configure() - ->withPaths([ - __DIR__ . '/ajax', - __DIR__ . '/front', - __DIR__ . '/src', - __DIR__ . '/tests', - ]) - ->withPhpVersion(PhpVersion::PHP_82) - ->withCache( - cacheClass: FileCacheStorage::class, - cacheDirectory: sys_get_temp_dir() . '/centreon-rector', - ) - ->withRootFiles() - ->withParallel(timeoutSeconds: 300) - ->withImportNames(removeUnusedImports: true) - ->withRules([ - CodeQuality\Assign\CombinedAssignRector::class, - CodeQuality\BooleanAnd\RemoveUselessIsObjectCheckRector::class, - CodeQuality\BooleanAnd\SimplifyEmptyArrayCheckRector::class, - CodeQuality\BooleanNot\ReplaceMultipleBooleanNotRector::class, - CodeQuality\Catch_\ThrowWithPreviousExceptionRector::class, - CodeQuality\Empty_\SimplifyEmptyCheckOnEmptyArrayRector::class, - CodeQuality\Expression\InlineIfToExplicitIfRector::class, - CodeQuality\Expression\TernaryFalseExpressionToIfRector::class, - CodeQuality\For_\ForRepeatedCountToOwnVariableRector::class, - CodeQuality\Foreach_\ForeachItemsAssignToEmptyArrayToAssignRector::class, - CodeQuality\Foreach_\ForeachToInArrayRector::class, - CodeQuality\Foreach_\SimplifyForeachToCoalescingRector::class, - CodeQuality\Foreach_\UnusedForeachValueToArrayKeysRector::class, - CodeQuality\FuncCall\ChangeArrayPushToArrayAssignRector::class, - CodeQuality\FuncCall\CompactToVariablesRector::class, - CodeQuality\FuncCall\InlineIsAInstanceOfRector::class, - CodeQuality\FuncCall\IsAWithStringWithThirdArgumentRector::class, - CodeQuality\FuncCall\RemoveSoleValueSprintfRector::class, - CodeQuality\FuncCall\SetTypeToCastRector::class, - CodeQuality\FuncCall\SimplifyFuncGetArgsCountRector::class, - CodeQuality\FuncCall\SimplifyInArrayValuesRector::class, - CodeQuality\FuncCall\SimplifyStrposLowerRector::class, - CodeQuality\FuncCall\UnwrapSprintfOneArgumentRector::class, - CodeQuality\Identical\BooleanNotIdenticalToNotIdenticalRector::class, - CodeQuality\Identical\SimplifyArraySearchRector::class, - CodeQuality\Identical\SimplifyConditionsRector::class, - CodeQuality\Identical\StrlenZeroToIdenticalEmptyStringRector::class, - CodeQuality\If_\CombineIfRector::class, - CodeQuality\If_\CompleteMissingIfElseBracketRector::class, - CodeQuality\If_\ConsecutiveNullCompareReturnsToNullCoalesceQueueRector::class, - CodeQuality\If_\ExplicitBoolCompareRector::class, - CodeQuality\If_\ShortenElseIfRector::class, - CodeQuality\If_\SimplifyIfElseToTernaryRector::class, - CodeQuality\If_\SimplifyIfNotNullReturnRector::class, - CodeQuality\If_\SimplifyIfNullableReturnRector::class, - CodeQuality\If_\SimplifyIfReturnBoolRector::class, - CodeQuality\Include_\AbsolutizeRequireAndIncludePathRector::class, - CodeQuality\LogicalAnd\AndAssignsToSeparateLinesRector::class, - CodeQuality\LogicalAnd\LogicalToBooleanRector::class, - CodeQuality\NotEqual\CommonNotEqualRector::class, - CodeQuality\Ternary\UnnecessaryTernaryExpressionRector::class, - DeadCode\Assign\RemoveUnusedVariableAssignRector::class, - ]) - ->withPhpSets(php74: true) // apply PHP sets up to PHP 7.4 -; +return $config; diff --git a/setup.php b/setup.php index 4de3d4a..eb6e9c1 100644 --- a/setup.php +++ b/setup.php @@ -57,10 +57,7 @@ function plugin_init_centreon() $PLUGIN_HOOKS[Hooks::SECURED_CONFIGS]['centreon'] = ['centreon-password']; $PLUGIN_HOOKS[Hooks::PRE_ITEM_UPDATE]['centreon'] = [ - Config::class => [ - GlpiPlugin\Centreon\Config::class, - 'prepareConfigUpdate', - ], + Config::class => GlpiPlugin\Centreon\Config::prepareConfigUpdate(...), ]; diff --git a/src/ApiClient.php b/src/ApiClient.php index de48d90..47e2d2a 100644 --- a/src/ApiClient.php +++ b/src/ApiClient.php @@ -41,7 +41,9 @@ class ApiClient { public ?string $auth_token = null; + public ?int $user_id = null; + public array $api_config = []; /** @@ -53,7 +55,7 @@ public function centreonConfig(): bool { $api_i = new Config(); $this->api_config = $api_i->getConfig(); - return !(!isset($this->api_config['centreon-url']) || trim($this->api_config['centreon-url']) === ''); + return isset($this->api_config['centreon-url']) && trim($this->api_config['centreon-url']) !== ''; } /** @@ -83,13 +85,14 @@ public function connectionRequest(array $params = []): array try { $data = $this->clientRequest('login', $params, 'POST'); - } catch (Exception $e) { + } catch (Exception $exception) { if (isset($params['throw'])) { - throw $e; + throw $exception; } - return ['error' => $e->getMessage()]; + return ['error' => $exception->getMessage()]; } + $this->auth_token = $data['security']['token']; $this->user_id = $data['contact']['id']; @@ -113,10 +116,10 @@ public function diagnostic(): array 'message' => 'You are connected to Centreon API !', ]; } - } catch (Exception $e) { + } catch (Exception $exception) { $result = [ 'result' => false, - 'message' => $e->getMessage(), + 'message' => $exception->getMessage(), ]; } @@ -135,7 +138,6 @@ public function clientRequest(string $endpoint = '', array $params = [], string { $api_client = new Client([ 'base_uri' => $this->api_config['centreon-url'] ?? '', - 'verify' => false, 'connect_timeout' => 3, 'timeout' => 10, ]); @@ -147,14 +149,16 @@ public function clientRequest(string $endpoint = '', array $params = [], string try { $data = $api_client->request($method, $endpoint, $params); - } catch (Exception $e) { + } catch (Exception $exception) { if (isset($params['throw'])) { - throw $e; + throw $exception; } - $err_msg = $e->getMessage(); + + $err_msg = $exception->getMessage(); return ['error' => $err_msg]; } + $data_body = $data->getBody(); $data = json_decode($data_body, true); @@ -165,11 +169,11 @@ public function clientRequest(string $endpoint = '', array $params = [], string return $data; } + /** * Get a list of hosts. * * @param array $params Query parameters. - * @return array */ public function getHostsList(array $params = []): array { @@ -179,9 +183,8 @@ public function getHostsList(array $params = []): array ], ]; $params = array_replace_recursive($defaults, $params); - $data = $this->clientRequest('monitoring/hosts', $params); - return $data; + return $this->clientRequest('monitoring/hosts', $params); } /** @@ -189,14 +192,11 @@ public function getHostsList(array $params = []): array * * @param int $host_id Host ID. * @param array $params Optional parameters. - * @return array */ public function getOneHost(int $host_id, array $params = []): array { - $data = $this->clientRequest('monitoring/hosts/' . $host_id, $params); - - return $data; + return $this->clientRequest('monitoring/hosts/' . $host_id, $params); } /** @@ -204,13 +204,10 @@ public function getOneHost(int $host_id, array $params = []): array * * @param int $host_id Host ID. * @param array $params Optional parameters. - * @return array */ public function getOneHostResources(int $host_id, array $params = []): array { - $data = $this->clientRequest('monitoring/resources/hosts/' . $host_id, $params); - - return $data; + return $this->clientRequest('monitoring/resources/hosts/' . $host_id, $params); } /** @@ -218,26 +215,20 @@ public function getOneHostResources(int $host_id, array $params = []): array * * @param int $host_id Host ID. * @param array $params Optional parameters. - * @return array */ public function getOneHostTimeline(int $host_id, array $params = []): array { - $data = $this->clientRequest('monitoring/hosts/' . $host_id . '/timeline', $params); - - return $data; + return $this->clientRequest('monitoring/hosts/' . $host_id . '/timeline', $params); } /** * Get a list of all services. * * @param array $params Optional parameters. - * @return array */ public function getServicesList(array $params = []): array { - $data = $this->clientRequest('monitoring/services', $params); - - return $data; + return $this->clientRequest('monitoring/services', $params); } /** @@ -245,14 +236,12 @@ public function getServicesList(array $params = []): array * * @param int $host_id Host ID. * @param array $params Optional parameters. - * @return array */ public function getServicesListForOneHost(int $host_id, array $params = []): array { $params['query'] = ['limit' => 30]; - $data = $this->clientRequest('monitoring/hosts/' . $host_id . '/services', $params); - return $data; + return $this->clientRequest('monitoring/hosts/' . $host_id . '/services', $params); } /** @@ -260,14 +249,12 @@ public function getServicesListForOneHost(int $host_id, array $params = []): arr * * @param int $host_id Host ID. * @param array $params Optional parameters. - * @return array */ public function sendCheckToAnHost(int $host_id, array $params = []): array { $params['json']['is_forced'] = true; - $data = $this->clientRequest('monitoring/hosts/' . $host_id . '/check', $params['json'], 'POST'); - return $data; + return $this->clientRequest('monitoring/hosts/' . $host_id . '/check', $params['json'], 'POST'); } /** @@ -275,13 +262,10 @@ public function sendCheckToAnHost(int $host_id, array $params = []): array * * @param int $host_id Host ID. * @param array $params Downtime parameters. - * @return array */ public function setDowntimeOnAHost(int $host_id, array $params): array { - $data = $this->clientRequest('monitoring/hosts/' . $host_id . '/downtimes', $params, 'POST'); - - return $data; + return $this->clientRequest('monitoring/hosts/' . $host_id . '/downtimes', $params, 'POST'); } /** @@ -289,26 +273,20 @@ public function setDowntimeOnAHost(int $host_id, array $params): array * * @param int $host_id Host ID. * @param array $params Optional parameters. - * @return array */ public function listDowntimes(int $host_id, array $params = []): array { - $data = $this->clientRequest('monitoring/hosts/' . $host_id . '/downtimes', $params); - - return $data; + return $this->clientRequest('monitoring/hosts/' . $host_id . '/downtimes', $params); } /** * Get a specific downtime details. * * @param int $downtime_id Downtime ID. - * @return array */ public function displayDowntime(int $downtime_id): array { - $data = $this->clientRequest('monitoring/downtimes/' . $downtime_id); - - return $data; + return $this->clientRequest('monitoring/downtimes/' . $downtime_id); } /** @@ -316,7 +294,6 @@ public function displayDowntime(int $downtime_id): array * * @param int $host_id Host ID. * @param array $params Optional parameters. - * @return array */ public function servicesDowntimesByHost(int $host_id, array $params = []): array { @@ -332,9 +309,7 @@ public function servicesDowntimesByHost(int $host_id, array $params = []): array $queryParams = array_merge($defaultParams, $params); - $data = $this->clientRequest('monitoring/services/downtimes', $queryParams); - - return $data; + return $this->clientRequest('monitoring/services/downtimes', $queryParams); } /** @@ -342,13 +317,10 @@ public function servicesDowntimesByHost(int $host_id, array $params = []): array * * @param int $downtime_id Downtime ID. * @param array $params Optional parameters. - * @return array */ public function cancelDowntime(int $downtime_id, array $params = []): array { - $data = $this->clientRequest('monitoring/downtimes/' . $downtime_id, $params, 'DELETE'); - - return $data; + return $this->clientRequest('monitoring/downtimes/' . $downtime_id, $params, 'DELETE'); } /** @@ -356,12 +328,9 @@ public function cancelDowntime(int $downtime_id, array $params = []): array * * @param int $host_id Host ID. * @param array $request Request payload. - * @return array */ public function acknowledgement(int $host_id, array $request = []): array { - $data = $this->clientRequest('monitoring/hosts/' . $host_id . '/acknowledgements', $request, 'POST'); - - return $data; + return $this->clientRequest('monitoring/hosts/' . $host_id . '/acknowledgements', $request, 'POST'); } } diff --git a/src/Config.php b/src/Config.php index 6263a99..c4d643b 100644 --- a/src/Config.php +++ b/src/Config.php @@ -51,12 +51,10 @@ public static function getConfig() public function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) { - switch ($item->getType()) { - case Glpi_Config::class: - return self::createTabEntry(self::getTypeName(), 0, $item::getType(), self::getIcon()); - } - - return ''; + return match ($item->getType()) { + Glpi_Config::class => self::createTabEntry(self::getTypeName(), 0, $item::getType(), self::getIcon()), + default => '', + }; } public static function displayTabContentForItem( @@ -92,11 +90,12 @@ public static function showForConfig(Glpi_Config $config, $withtemplate = 0) $conf_ok = true; foreach ($current_config as $v) { - if (strlen($v) == 0) { + if ((string) $v === '') { $conf_ok = false; } } - if ($conf_ok == true) { + + if ($conf_ok) { $api = new ApiClient(); $diag = $api->diagnostic(); @@ -106,6 +105,8 @@ public static function showForConfig(Glpi_Config $config, $withtemplate = 0) } else { TemplateRenderer::getInstance()->display('@centreon/checkField.html.twig'); } + + return null; } public static function prepareConfigUpdate(CommonDBTM $item) diff --git a/src/Host.php b/src/Host.php index e312f72..e640749 100644 --- a/src/Host.php +++ b/src/Host.php @@ -45,10 +45,15 @@ class Host extends CommonDBTM { private $api_client; + public $glpi_items = []; + public $centreon_items = []; + public $one_host = []; + public $uid = ''; + public $username = ''; public function __construct(?ApiClient $api_client = null) @@ -63,8 +68,6 @@ public static function getTypeName($nb = 0) /** * Get the list of computers from GLPI - * - * @return array */ public function getComputerList(): array { @@ -82,14 +85,14 @@ public function getComputerList(): array } else { echo __s('The list is empty', 'centreon'); } + $this->glpi_items = $array_computer; return $array_computer; } + /** * Get the list of hosts from Centreon - * - * @return void */ public function hostList(): void { @@ -104,6 +107,7 @@ public function hostList(): void 'centreon_name' => $item_centreon['name'], ]; } + $this->centreon_items = $items_centreon; } } @@ -111,8 +115,6 @@ public function hostList(): void /** * Match Centreon hosts with GLPI computers based on their names. - * - * @return void */ public function matchItems(): void { @@ -130,14 +132,40 @@ public function matchItems(): void } } + /** + * Check that the current user has access to the GLPI item mapped to the given Centreon host. + */ + private function canAccessCentreonHost(int $centreon_id): bool + { + $mapping = new self(); + if (!$mapping->getFromDBByCrit(['centreon_id' => $centreon_id])) { + return false; + } + + $itemtype = $mapping->fields['itemtype']; + $items_id = $mapping->fields['items_id']; + + if (!is_a($itemtype, CommonDBTM::class, true)) { + return false; + } + + $item = new $itemtype(); + + return $item->can($items_id, READ); + } + /** * Get detailed information about a Centreon host. * * @param int $id - * @return array */ public function oneHost($id): array { + $id = (int) $id; + if (!$this->canAccessCentreonHost($id)) { + return []; + } + $res = $this->api_client->connectionRequest(); if ($res['security']['token'] != null) { $this->username = $res['contact']['alias']; @@ -147,7 +175,6 @@ public function oneHost($id): array $getservices = $this->api_client->getServicesListForOneHost($id); $getdowntimes = $this->api_client->listDowntimes($id); if ($gethost != null) { - $i_host = []; $i_host = [ 'status' => $gethost_r['status']['name'], 'name' => $gethost_r['name'], @@ -161,6 +188,7 @@ public function oneHost($id): array if ($gethost_r['in_downtime'] == true) { $i_host['downtimes'] = $gethost_r['downtimes']; } + $i_host['services'] = $getservices['result']; $i_host['nb_services'] = count($i_host['services']); $this->one_host = $i_host; @@ -175,12 +203,14 @@ public function oneHost($id): array /** * Display the timeline of events for a given host. * - * @param int $id * @param string $period 'day', 'week', or 'month' - * @return string */ public function hostTimeline(int $id, string $period): string { + if (!$this->canAccessCentreonHost($id)) { + return __s('Error: unauthorized', 'centreon'); + } + $api = new ApiClient(); $session = $api->connectionRequest(); $timeline = []; @@ -192,6 +222,7 @@ public function hostTimeline(int $id, string $period): string $event['status']['name'] = __s('unset', 'centreon'); $event['tries'] = __s('unset', 'centreon'); } + $timeline[] = [ 'id' => $event['id'], 'date' => $this->transformDate($event['date']), @@ -213,6 +244,7 @@ public function hostTimeline(int $id, string $period): string $period_string = '-1 month'; break; } + $date_end = date('Y-m-d', strtotime(date('Y-m-d') . $period_string)); $filtered_timeline = []; foreach ($timeline as $event => $info) { @@ -221,60 +253,61 @@ public function hostTimeline(int $id, string $period): string $filtered_timeline[$event] = $info; } } + TemplateRenderer::getInstance()->display('@centreon/timeline.html.twig', [ 'timeline' => $filtered_timeline, ]); } + return __s('Error: unable to display timeline', 'centreon'); } public function transformDate($date) { $timestamp = strtotime($date); - $newdate = date('l,F d,Y G:i:s', $timestamp); - return $newdate; + return date('l,F d,Y G:i:s', $timestamp); } public function transformDateForCompare($date) { $timestamp = strtotime($date); - $newdate = date('Y-m-d', $timestamp); - return $newdate; + return date('Y-m-d', $timestamp); } /** * Send a check command to a host. - * - * @param int $id - * @return string */ public function sendCheck(int $id): string { + if (!$this->canAccessCentreonHost($id)) { + return __s('Error: unauthorized', 'centreon'); + } + $res = $this->api_client->connectionRequest(); if (isset($res['security']['token'])) { try { $res = $this->api_client->sendCheckToAnHost($id); - $message = __s('Check sent', 'centreon'); - return $message; + return __s('Check sent', 'centreon'); } catch (Exception $e) { return $e->getMessage(); } } + return __s('Error: unable to send check (unauthenticated)', 'centreon'); } /** * Schedule a downtime on a host. - * - * @param int $id - * @param array $params - * @return array */ public function setDowntime(int $id, array $params): array { + if (!$this->canAccessCentreonHost($id)) { + return ['error' => __s('Error: unauthorized', 'centreon')]; + } + $params['is_fixed'] = filter_var($params['is_fixed'], FILTER_VALIDATE_BOOLEAN); $params['with_services'] = filter_var($params['with_services'], FILTER_VALIDATE_BOOLEAN); $params['start_time'] = $this->convertDateToIso8601($params['start_time']); @@ -283,25 +316,26 @@ public function setDowntime(int $id, array $params): array if ($params['is_fixed'] == true) { $params['duration'] = $this->diffDateInSeconds($params['end_time'], $params['start_time']); } + if ($params['is_fixed'] == false) { $option = $params['time_select']; $params['duration'] = $this->convertToSeconds($option, $params['duration']); $params['duration'] = filter_var($params['duration'], FILTER_VALIDATE_INT); } + unset($params['time_select']); $api = new ApiClient(); $res = $api->connectionRequest(); if (isset($res['security']['token'])) { try { - $res = $api->setDowntimeOnAHost($id, ['json' => $params]); - - return $res; + return $api->setDowntimeOnAHost($id, ['json' => $params]); } catch (Exception $e) { $error_msg = $e->getMessage(); return ['error' => $e->getMessage()]; } } + return [ 'error' => __s('Error: unauthenticated or unable to set downtime', 'centreon'), ]; @@ -311,18 +345,16 @@ public function convertDateToIso8601($date) { $timezone = new DateTimeZone($_SESSION['glpi_tz'] ?? date_default_timezone_get()); $new_date = new DateTime($date, $timezone); - $iso_date = $new_date->format(DATE_ATOM); - return $iso_date; + return $new_date->format(DATE_ATOM); } public function diffDateInSeconds($date1, $date2) { $ts1 = strtotime($date1); $ts2 = strtotime($date2); - $diff = abs($ts2 - $ts1); - return $diff; + return abs($ts2 - $ts1); } public function convertToSeconds($option, $duration) @@ -340,9 +372,6 @@ public function convertToSeconds($option, $duration) /** * Cancel the current host downtime and its related service downtimes. - * - * @param int $downtime_id - * @return array */ public function cancelActualDownTime(int $downtime_id): array { @@ -354,6 +383,13 @@ public function cancelActualDownTime(int $downtime_id): array try { $actualDowntime = $api->displayDowntime($downtime_id); $host_id = $actualDowntime['host_id']; + + if (!$this->canAccessCentreonHost((int) $host_id)) { + return [[ + 'message' => __s('Error: unauthorized', 'centreon'), + ]]; + } + $start_time = $actualDowntime['start_time']; $end_time = $actualDowntime['end_time']; @@ -371,6 +407,7 @@ public function cancelActualDownTime(int $downtime_id): array ]; } } + $api->cancelDowntime($downtime_id); } catch (Exception $e) { $error[] = [ @@ -389,12 +426,14 @@ public function cancelActualDownTime(int $downtime_id): array /** * Acknowledge a Centreon host alert. * - * @param int $host_id - * @param array $request * @return array|string */ public function acknowledgement(int $host_id, array $request = []) { + if (!$this->canAccessCentreonHost($host_id)) { + return __s('Error: unauthorized', 'centreon'); + } + $res = $this->api_client->connectionRequest(); if (isset($res['security']['token'])) { try { @@ -408,6 +447,7 @@ public function acknowledgement(int $host_id, array $request = []) return $e->getMessage(); } } + return __s('Error: unauthenticated or unable to acknowledge', 'centreon'); } @@ -415,9 +455,6 @@ public function acknowledgement(int $host_id, array $request = []) * Sanitize the acknowledgement request payload. * * This ensures the expected types are correctly set before sending to Centreon API. - * - * @param array $request - * @return array */ private function sanitizeAcknowledgementPayload(array $request): array { @@ -448,6 +485,7 @@ public function searchItemMatch(int $id): bool { $item = new Computer(); $item->getFromDB($id); + $computer_name = $item->fields['name']; $api = new ApiClient(); @@ -466,7 +504,7 @@ public function searchItemMatch(int $id): bool //compare results case-insensitively foreach ($match['result'] as $host) { - if (strcasecmp($host['name'], $computer_name) === 0) { + if (strcasecmp($host['name'], (string) $computer_name) === 0) { $centreon_id = $host['id']; $new_id = $this->add([ 'itemtype' => 'Computer', @@ -539,7 +577,7 @@ public static function showForItem(CommonDBTM $item, $withtemplate = 0) $self = new self(); $item_id = $item->getID(); - if ($self->searchForItem($item_id) == true || $self->searchItemMatch($item_id) == true) { + if ($self->searchForItem($item_id) || $self->searchItemMatch($item_id)) { $host_id = $self->fields['centreon_id']; $self->oneHost($host_id); TemplateRenderer::getInstance()->display('@centreon/host.html.twig', [ @@ -556,15 +594,13 @@ public static function showForItem(CommonDBTM $item, $withtemplate = 0) public static function getSpecificValueToDisplay($field, $values, array $options = []) { - switch ($field) { - case 'id': - if (intval($values['centreon_id']) > 0) { - $self = new self(); - $res = $self->oneHost($values['centreon_id']); + if ($field === 'id') { + if (intval($values['centreon_id']) > 0) { + $self = new self(); + $res = $self->oneHost($values['centreon_id']); - return $res['status'] ?? ''; - } - break; + return $res['status'] ?? ''; + } } return parent::getSpecificValueToDisplay($field, $values, $options); diff --git a/tests/ApiClientTest.php b/tests/ApiClientTest.php index e7b0b4f..ecb4998 100644 --- a/tests/ApiClientTest.php +++ b/tests/ApiClientTest.php @@ -44,6 +44,7 @@ class ApiClientTest extends TestCase ], ], ]; + public $returndata = [ 'security' => [ 'token' => 'auth-token',