first sync

This commit is contained in:
2025-08-27 21:17:28 +02:00
parent 0ce51dbe03
commit 247efa5d8f
35 changed files with 7725 additions and 2 deletions

352
README.md
View File

@@ -1,3 +1,351 @@
# SIEM---Wazuh # Plugin GLPI SIEM-Wazuh
Plugin GLPI pour intéger Wazuh dans GLPI [![Version](https://img.shields.io/badge/version-1.0.0-blue.svg)](https://github.com/siem-wazuh/glpi-plugin)
[![GLPI](https://img.shields.io/badge/GLPI-10.0.x-green.svg)](https://glpi-project.org/)
[![License](https://img.shields.io/badge/license-GPL%20v2%2B-orange.svg)](LICENSE)
## Description
Le plugin SIEM-Wazuh permet l'intégration complète entre Wazuh (solution SIEM open source) et GLPI (système de gestion des services IT). Il permet de :
- **Surveiller** automatiquement les serveurs Wazuh configurés
- **Récupérer** les alertes de sécurité en temps réel
- **Associer** automatiquement les alertes aux assets de l'inventaire GLPI
- **Créer** automatiquement des tickets pour les incidents critiques
- **Gérer** centralement la configuration depuis l'interface GLPI
## Fonctionnalités
### 🛡️ Surveillance Proactive
- Synchronisation automatique des alertes Wazuh
- Configuration de multiples serveurs Wazuh
- Filtrage par niveau de règle et sévérité
- Intervalle de synchronisation configurable
### 🔗 Intégration Assets
- Association automatique alertes ↔ ordinateurs
- Association automatique alertes ↔ équipements réseau
- Correspondance par nom d'hôte et adresse IP
- Onglets dédiés sur chaque asset
### 🎫 Gestion des Tickets
- Création automatique de tickets GLPI
- Configuration des types et catégories
- Priorité automatique basée sur la sévérité
- Assignation automatique configurables
### 🌍 Interface Multilingue
Support complet pour :
- 🇫🇷 Français
- 🇬🇧 Anglais
- 🇩🇪 Allemand
- 🇪🇸 Espagnol
- 🇮🇹 Italien
- 🇵🇹 Portugais
- 🇵🇱 Polonais
### ⚙️ Configuration Avancée
- Interface de configuration intuitive
- Gestion granulaire des droits utilisateur
- Logs de débogage détaillés
- Statistiques et tableaux de bord
## Prérequis
### Système
- **GLPI** : Version 10.0.0 minimum
- **PHP** : Version 7.4 minimum
- **Extensions PHP** : curl, json, mbstring, openssl
- **Base de données** : MySQL 5.7+ ou MariaDB 10.2+
### Wazuh
- **Wazuh Manager** : Version 4.0+ recommandée
- **API Wazuh** : Accès avec authentification
- **Wazuh Indexer** : Optionnel (pour requêtes avancées)
## Installation
### 1. Téléchargement
```bash
cd /path/to/glpi/plugins/
wget https://github.com/siem-wazuh/glpi-plugin/releases/download/1.0.0/siem-wazuh-1.0.0.tar.gz
tar -xzf siem-wazuh-1.0.0.tar.gz
```
### 2. Installation via Interface GLPI
1. Se connecter en tant qu'administrateur GLPI
2. Aller dans **Configuration > Plugins**
3. Localiser le plugin "SIEM - Wazuh"
4. Cliquer sur **Installer**
5. Cliquer sur **Activer**
### 3. Configuration Initiale
#### Configuration des Droits
1. **Administration > Profils**
2. Sélectionner le profil à configurer
3. Onglet **SIEM Wazuh Rights**
4. Attribuer les droits appropriés :
- **Configuration** : Accès à la configuration
- **Servers** : Gestion des serveurs Wazuh
- **Alerts** : Consultation des alertes
#### Ajout d'un Serveur Wazuh
1. **Administration > Serveurs Wazuh**
2. Cliquer sur **+** (Ajouter)
3. Remplir les informations :
```
Nom connexion: Serveur Wazuh Production
URL Serveur Wazuh: https://wazuh-manager.domain.com
Port API: 55000
Login API: wazuh
Mot de passe API: [mot_de_passe_sécurisé]
Intervalle de synchronisation: 300 (secondes)
```
4. **Tester la connexion**
5. **Enregistrer**
#### Configuration Générale
1. **Outils > Configuration SIEM Wazuh**
2. Configurer les paramètres selon vos besoins :
- **Synchronisation automatique** : Activé
- **Création automatique de tickets** : Activé
- **Niveau de règle minimum** : 5
- **Rétention des alertes** : 90 jours
## Configuration
### Paramètres de Synchronisation
| Paramètre | Description | Valeur par défaut |
|-----------|-------------|-------------------|
| `sync_enabled` | Active la synchronisation | `1` (Oui) |
| `max_alerts_per_sync` | Maximum d'alertes par sync | `100` |
| `min_rule_level` | Niveau minimum des règles | `5` |
| `sync_interval` | Intervalle en secondes | `300` |
### Mapping des Assets
Le plugin associe automatiquement les alertes aux assets GLPI :
1. **Par nom d'hôte** : `agent.name` → `computers.name`
2. **Par adresse IP** : `agent.ip` → `networkports.ip`
3. **Sensible à la casse** : Configurable
4. **Patterns à ignorer** : `localhost`, `127.0.0.1`, etc.
### Création de Tickets
Les tickets sont créés automatiquement selon ces règles :
| Niveau Règle | Sévérité | Priorité Ticket |
|--------------|----------|-----------------|
| 1-4 | Low | Très faible |
| 5-6 | Low | Faible |
| 7-9 | Medium | Moyenne |
| 10-11 | High | Élevée |
| 12+ | Critical | Très élevée |
## Utilisation
### Consultation des Alertes
#### Sur les Assets
- Aller sur un ordinateur ou équipement réseau
- Cliquer sur l'onglet **"Alertes Wazuh"**
- Consulter le résumé et la liste des alertes
#### Vue Globale
- **Outils > Configuration SIEM Wazuh**
- Consulter les **statistiques générales**
- Filtrer par serveur, sévérité, statut
### Actions Disponibles
#### Sur les Alertes
- ✅ **Marquer comme traitée**
- ❌ **Ignorer l'alerte**
- 🎫 **Créer un ticket manuellement**
- 📊 **Exporter en CSV**
#### Sur les Serveurs
- 🔧 **Tester la connexion**
- 🔄 **Synchroniser manuellement**
- ⏯️ **Activer/Désactiver**
- 📈 **Consulter les statistiques**
## Tâches Automatisées
### Cron Jobs
Le plugin configure automatiquement deux tâches :
```bash
# Synchronisation des alertes (toutes les 5 minutes)
*/5 * * * * php /path/to/glpi/front/cron.php --force=PluginSiemWazuhAlert-sync_alerts
# Nettoyage des anciennes alertes (quotidien)
0 2 * * * php /path/to/glpi/front/cron.php --force=PluginSiemWazuhAlert-cleanup_old_alerts
```
### Activation des Tâches
1. **Administration > Tâches automatiques**
2. Rechercher "Wazuh"
3. Activer les tâches
4. Configurer la fréquence si nécessaire
## Dépannage
### Problèmes Courants
#### Connexion Échouée
```
Erreur: Connection failed: cURL error 7: Failed to connect
```
**Solutions :**
- Vérifier l'URL et le port du serveur
- Contrôler les règles de firewall
- Tester depuis le serveur GLPI : `curl -k https://wazuh-server:55000`
#### Authentification Échouée
```
Erreur: Authentication failed: 401 Unauthorized
```
**Solutions :**
- Vérifier les identifiants API
- Contrôler les permissions utilisateur Wazuh
- Vérifier que l'utilisateur existe : `GET /security/users`
#### Pas d'Alertes Synchronisées
**Vérifications :**
1. Niveau de règle minimum trop élevé
2. Serveur inactif
3. Pas d'alertes récentes dans Wazuh
4. Erreurs dans les logs : **Debug & Logs**
### Logs de Débogage
Activer le mode debug :
1. **Outils > Configuration SIEM Wazuh**
2. Onglet **Debug & Logs**
3. **Mode debug** : Activé
4. **Niveau de log** : Debug
5. Consulter la section **Logs récents**
### Support et Logs Système
```bash
# Logs Apache/Nginx
tail -f /var/log/apache2/error.log | grep -i wazuh
# Logs PHP
tail -f /var/log/php/error.log | grep -i wazuh
# Logs GLPI
tail -f /var/log/glpi/glpi.log | grep -i wazuh
```
## API et Intégration
### Endpoints Disponibles
Le plugin expose quelques endpoints pour intégration :
```
GET /plugins/siem-wazuh/ajax/sync_alerts.php?action=status
POST /plugins/siem-wazuh/ajax/sync_alerts.php (sync)
POST /plugins/siem-wazuh/ajax/test_connection.php
```
### Webhooks Wazuh
Pour recevoir les alertes en temps réel, configurez un webhook :
```xml
<!-- /var/ossec/etc/ossec.conf -->
<integration>
<name>webhook</name>
<hook_url>https://glpi.domain.com/plugins/siem-wazuh/webhook.php</hook_url>
<level>7</level>
<rule_id>100001,100002</rule_id>
<alert_format>json</alert_format>
</integration>
```
## Développement
### Structure du Plugin
```
plugins/siem-wazuh/
├── README.md # Documentation
├── CHANGELOG.md # Historique des versions
├── LICENSE # Licence GPL v2+
├── SIEM-Wazuh.xml # Descripteur plugin
├── setup.php # Configuration principale
├── hook.php # Installation/désinstallation
├── inc/ # Classes PHP
│ ├── wazuhserver.class.php
│ ├── wazuhalert.class.php
│ ├── wazuhconfig.class.php
│ ├── wazuhtab.class.php
│ └── wazuhapi.class.php
├── front/ # Interface web
│ ├── wazuhserver.php
│ ├── wazuhserver.form.php
│ └── wazuhconfig.php
├── ajax/ # Requêtes AJAX
│ ├── test_connection.php
│ └── sync_alerts.php
├── locales/ # Traductions
│ ├── fr_FR.po
│ ├── en_GB.po
│ └── ...
├── css/ # Feuilles de style
│ └── style.css
├── js/ # JavaScript
│ └── wazuh.js
├── pics/ # Images
│ └── wazuh-logo.png
└── sql/ # Scripts SQL
├── install.sql
└── uninstall.sql
```
### Contribution
1. Fork le projet
2. Créer une branche feature (`git checkout -b feature/nouvelle-fonctionnalite`)
3. Commiter les modifications (`git commit -m 'Ajout nouvelle fonctionnalité'`)
4. Pousser sur la branche (`git push origin feature/nouvelle-fonctionnalite`)
5. Créer une Pull Request
## Licence
Ce plugin est distribué sous licence **GPL v2+**. Voir le fichier [LICENSE](LICENSE) pour plus de détails.
## Support
- 🐛 **Issues** : [GitHub Issues](https://github.com/siem-wazuh/glpi-plugin/issues)
- 💬 **Discussions** : [GitHub Discussions](https://github.com/siem-wazuh/glpi-plugin/discussions)
- 📧 **Email** : support@siem-wazuh.org
- 📖 **Documentation** : [Wiki](https://github.com/siem-wazuh/glpi-plugin/wiki)
## Changelog
### Version 1.0.0 (2024-01-01)
- 🎉 Version initiale
- ✅ Support multiples serveurs Wazuh
- ✅ Synchronisation automatique des alertes
- ✅ Association avec assets GLPI
- ✅ Création automatique de tickets
- ✅ Interface multilingue (7 langues)
- ✅ Gestion des droits utilisateur
- ✅ API REST pour intégration
- ✅ Logs de débogage complets
---
**Made with ❤️ by the SIEM-Wazuh Team**

106
SIEM-Wazuh.xml Normal file
View File

@@ -0,0 +1,106 @@
<?xml version="1.0" encoding="UTF-8"?>
<root>
<name>SIEM - Wazuh</name>
<key>siem-wazuh</key>
<state>stable</state>
<logo>https://raw.githubusercontent.com/siem-wazuh/glpi-plugin/main/pics/wazuh-logo.png</logo>
<description>
<short>
<fr><![CDATA[Intégration SIEM Wazuh avec GLPI pour la gestion centralisée des alertes de sécurité]]></fr>
<en><![CDATA[Wazuh SIEM integration with GLPI for centralized security alert management]]></en>
<de><![CDATA[Wazuh SIEM Integration mit GLPI für zentrale Sicherheitswarnungen]]></de>
<es><![CDATA[Integración SIEM Wazuh con GLPI para gestión centralizada de alertas de seguridad]]></es>
<it><![CDATA[Integrazione SIEM Wazuh con GLPI per la gestione centralizzata degli avvisi di sicurezza]]></it>
<pt><![CDATA[Integração SIEM Wazuh com GLPI para gestão centralizada de alertas de segurança]]></pt>
<pl><![CDATA[Integracja SIEM Wazuh z GLPI do scentralizowanego zarządzania alertami bezpieczeństwa]]></pl>
</short>
<long>
<fr><![CDATA[Ce plugin permet l'intégration complète de Wazuh SIEM avec GLPI. Il offre les fonctionnalités suivantes :
• Configuration de multiples serveurs Wazuh
• Synchronisation automatique des alertes de sécurité
• Association automatique des alertes aux assets de l'inventaire
• Création automatique de tickets pour les incidents de sécurité
• Interface multilingue (FR, EN, DE, ES, IT, PT, PL)
• Tableau de bord avec statistiques des alertes
• Gestion granulaire des droits utilisateur
• Onglets dédiés sur les équipements informatiques
Le plugin surveille en continu les serveurs Wazuh configurés et crée automatiquement des tickets GLPI lorsque des alertes critiques sont détectées, permettant une réponse rapide aux incidents de sécurité.]]></fr>
<en><![CDATA[This plugin enables complete integration of Wazuh SIEM with GLPI. It provides the following features:
• Configuration of multiple Wazuh servers
• Automatic synchronization of security alerts
• Automatic association of alerts with inventory assets
• Automatic ticket creation for security incidents
• Multilingual interface (FR, EN, DE, ES, IT, PT, PL)
• Dashboard with alert statistics
• Granular user rights management
• Dedicated tabs on IT equipment
The plugin continuously monitors configured Wazuh servers and automatically creates GLPI tickets when critical alerts are detected, enabling rapid response to security incidents.]]></en>
</long>
</description>
<homepage>https://github.com/siem-wazuh/glpi-plugin</homepage>
<download>https://github.com/siem-wazuh/glpi-plugin/releases</download>
<issues>https://github.com/siem-wazuh/glpi-plugin/issues</issues>
<readme>https://github.com/siem-wazuh/glpi-plugin/blob/main/README.md</readme>
<authors>
<author>SIEM-Wazuh Team</author>
</authors>
<versions>
<version>
<num>1.0.0</num>
<compatibility>~10.0.0</compatibility>
<download_url>https://github.com/siem-wazuh/glpi-plugin/releases/download/1.0.0/glpi-siem-wazuh-1.0.0.tar.gz</download_url>
<changelog><![CDATA[
Version initiale 1.0.0 :
- Configuration de serveurs Wazuh multiples
- Synchronisation automatique des alertes
- Association avec les assets GLPI
- Création automatique de tickets
- Interface multilingue
- Gestion des droits utilisateur
- Onglets sur les équipements
- Tâches automatisées (cron)
- API REST pour intégration externe
]]></changelog>
<php_min>7.4</php_min>
<glpi_min>10.0.0</glpi_min>
<glpi_max>10.0.99</glpi_max>
</version>
</versions>
<langs>
<lang>fr_FR</lang>
<lang>en_GB</lang>
<lang>de_DE</lang>
<lang>es_ES</lang>
<lang>it_IT</lang>
<lang>pt_BR</lang>
<lang>pl_PL</lang>
</langs>
<license>GPL v2+</license>
<tags>
<fr>
<tag>SIEM</tag>
<tag>Sécurité</tag>
<tag>Wazuh</tag>
<tag>Alertes</tag>
<tag>Monitoring</tag>
<tag>Intégration</tag>
</fr>
<en>
<tag>SIEM</tag>
<tag>Security</tag>
<tag>Wazuh</tag>
<tag>Alerts</tag>
<tag>Monitoring</tag>
<tag>Integration</tag>
</en>
</tags>
<screenshots>
<screenshot>https://raw.githubusercontent.com/siem-wazuh/glpi-plugin/main/pics/screenshot-1.png</screenshot>
<screenshot>https://raw.githubusercontent.com/siem-wazuh/glpi-plugin/main/pics/screenshot-2.png</screenshot>
<screenshot>https://raw.githubusercontent.com/siem-wazuh/glpi-plugin/main/pics/screenshot-3.png</screenshot>
</screenshots>
</root>

342
ajax/sync_alerts.php Normal file
View File

@@ -0,0 +1,342 @@
<?php
/*
* Plugin SIEM-Wazuh pour GLPI
* AJAX - Synchronisation des alertes Wazuh
*/
include ('../../../inc/includes.php');
header('Content-Type: application/json');
// Vérification des droits et du plugin
if (!Session::haveRight("plugin_siem_wazuh_server", UPDATE) || !Plugin::isPluginActive('siem-wazuh')) {
echo json_encode(['success' => false, 'message' => __('Access denied', 'siem-wazuh')]);
exit;
}
// Vérification CSRF pour les requêtes POST
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !Session::validateCSRF($_POST)) {
echo json_encode(['success' => false, 'message' => __('Invalid CSRF token', 'siem-wazuh')]);
exit;
}
$response = ['success' => false, 'message' => '', 'stats' => []];
try {
$action = $_POST['action'] ?? $_GET['action'] ?? 'sync';
switch ($action) {
case 'sync':
$server_id = intval($_POST['server_id'] ?? $_GET['server_id'] ?? 0);
if ($server_id > 0) {
// Synchronisation d'un serveur spécifique
$result = syncSingleServer($server_id);
} else {
// Synchronisation de tous les serveurs actifs
$result = syncAllServers();
}
$response = $result;
break;
case 'sync_for_item':
// Synchronisation pour un élément spécifique
$item_id = intval($_POST['item_id'] ?? 0);
$item_type = $_POST['item_type'] ?? '';
if ($item_id > 0 && !empty($item_type)) {
$result = syncForItem($item_id, $item_type);
$response = $result;
} else {
throw new Exception(__('Invalid item parameters', 'siem-wazuh'));
}
break;
case 'status':
// Statut de la synchronisation
$response = getSyncStatus();
break;
default:
throw new Exception(__('Unknown action', 'siem-wazuh'));
}
} catch (Exception $e) {
$response = [
'success' => false,
'message' => $e->getMessage(),
'error_type' => 'exception'
];
}
echo json_encode($response, JSON_UNESCAPED_UNICODE);
/**
* Synchroniser un serveur spécifique
*/
function syncSingleServer($server_id) {
$server = new PluginSiemWazuhServer();
if (!$server->getFromDB($server_id)) {
throw new Exception(__('Server not found', 'siem-wazuh'));
}
$start_time = microtime(true);
$result = $server->syncAlerts();
$sync_time = round((microtime(true) - $start_time) * 1000, 2);
if ($result['success']) {
// Extraire le nombre d'alertes du message
$processed = 0;
if (preg_match('/(\d+)/', $result['message'], $matches)) {
$processed = intval($matches[1]);
}
Event::log(
$server_id,
"PluginSiemWazuhServer",
5,
"sync",
sprintf(__('Manual sync completed for server %s: %s'), $server->fields['name'], $result['message'])
);
return [
'success' => true,
'message' => $result['message'],
'stats' => [
'processed' => $processed,
'sync_time' => $sync_time,
'server_name' => $server->fields['name']
]
];
} else {
Event::log(
$server_id,
"PluginSiemWazuhServer",
2,
"sync",
sprintf(__('Manual sync failed for server %s: %s'), $server->fields['name'], $result['message'])
);
return [
'success' => false,
'message' => $result['message'],
'server_name' => $server->fields['name']
];
}
}
/**
* Synchroniser tous les serveurs actifs
*/
function syncAllServers() {
global $DB;
$iterator = $DB->request([
'FROM' => 'glpi_plugin_siem_wazuh_servers',
'WHERE' => ['is_active' => 1]
]);
$total_processed = 0;
$successful_servers = 0;
$failed_servers = 0;
$sync_results = [];
$start_time = microtime(true);
foreach ($iterator as $server_data) {
try {
$result = syncSingleServer($server_data['id']);
if ($result['success']) {
$successful_servers++;
$total_processed += $result['stats']['processed'] ?? 0;
$sync_results[] = [
'server' => $server_data['name'],
'status' => 'success',
'processed' => $result['stats']['processed'] ?? 0
];
} else {
$failed_servers++;
$sync_results[] = [
'server' => $server_data['name'],
'status' => 'failed',
'error' => $result['message']
];
}
} catch (Exception $e) {
$failed_servers++;
$sync_results[] = [
'server' => $server_data['name'],
'status' => 'error',
'error' => $e->getMessage()
];
}
}
$total_time = round((microtime(true) - $start_time) * 1000, 2);
$message = sprintf(
__('Sync completed: %d servers processed, %d successful, %d failed, %d total alerts processed'),
count($sync_results),
$successful_servers,
$failed_servers,
$total_processed
);
return [
'success' => $failed_servers == 0,
'message' => $message,
'stats' => [
'total_servers' => count($sync_results),
'successful_servers' => $successful_servers,
'failed_servers' => $failed_servers,
'total_processed' => $total_processed,
'sync_time' => $total_time
],
'details' => $sync_results
];
}
/**
* Synchroniser pour un élément spécifique
*/
function syncForItem($item_id, $item_type) {
// Cette fonction recherche et synchronise les alertes
// pour un élément spécifique (ordinateur, équipement réseau, etc.)
$valid_types = ['Computer', 'NetworkEquipment', 'Peripheral', 'Phone', 'Printer'];
if (!in_array($item_type, $valid_types)) {
throw new Exception(__('Invalid item type', 'siem-wazuh'));
}
$item = new $item_type();
if (!$item->getFromDB($item_id)) {
throw new Exception(__('Item not found', 'siem-wazuh'));
}
// Récupérer les informations de l'élément pour le matching
$search_criteria = [];
// Recherche par nom
if (!empty($item->fields['name'])) {
$search_criteria['hostname'] = $item->fields['name'];
}
// Recherche par IP (si disponible)
$ip_addresses = [];
if (method_exists($item, 'getNetworkInterfaces')) {
// Logique pour récupérer les adresses IP de l'élément
// Cette partie nécessiterait une implémentation plus détaillée
}
// Synchroniser avec tous les serveurs actifs en filtrant par critères
global $DB;
$iterator = $DB->request([
'FROM' => 'glpi_plugin_siem_wazuh_servers',
'WHERE' => ['is_active' => 1]
]);
$total_found = 0;
foreach ($iterator as $server_data) {
$server = new PluginSiemWazuhServer();
$server->fields = $server_data;
$api = new PluginSiemWazuhAPI($server);
// Construire les paramètres de recherche pour l'API
$search_params = [];
if (!empty($search_criteria['hostname'])) {
$search_params['agent.name'] = $search_criteria['hostname'];
}
try {
$result = $api->getAlerts($search_params);
if ($result['success'] && isset($result['data']['data'])) {
$alert = new PluginSiemWazuhAlert();
$processed = $alert->processAlerts($server_data['id'], $result['data']['data']);
$total_found += $processed;
}
} catch (Exception $e) {
// Log l'erreur mais continue avec les autres serveurs
error_log("SIEM-Wazuh: Error syncing for item $item_type:$item_id on server {$server_data['name']}: " . $e->getMessage());
}
}
return [
'success' => true,
'message' => sprintf(__('%d alerts found and processed for %s'), $total_found, $item->getName()),
'stats' => [
'processed' => $total_found,
'item_name' => $item->getName(),
'item_type' => $item_type
]
];
}
/**
* Obtenir le statut de synchronisation
*/
function getSyncStatus() {
global $DB;
// Statistiques générales
$stats = [];
// Nombre total de serveurs
$stats['total_servers'] = countElementsInTable('glpi_plugin_siem_wazuh_servers');
$stats['active_servers'] = countElementsInTable('glpi_plugin_siem_wazuh_servers', ['is_active' => 1]);
// Dernière synchronisation
$last_sync = $DB->request([
'SELECT' => ['MAX' => 'last_sync AS last_sync'],
'FROM' => 'glpi_plugin_siem_wazuh_servers',
'WHERE' => ['is_active' => 1]
])->current();
$stats['last_sync'] = $last_sync['last_sync'];
// Alertes par statut
$alert_stats = [];
$statuses = ['new', 'processed', 'ignored', 'ticket_created'];
foreach ($statuses as $status) {
$alert_stats[$status] = countElementsInTable('glpi_plugin_siem_wazuh_alerts', ['status' => $status]);
}
$stats['alerts'] = $alert_stats;
// Alertes par sévérité
$severity_stats = [];
$severities = ['low', 'medium', 'high', 'critical'];
foreach ($severities as $severity) {
$severity_stats[$severity] = countElementsInTable('glpi_plugin_siem_wazuh_alerts', ['severity' => $severity]);
}
$stats['severity'] = $severity_stats;
// Alertes des dernières 24h
$stats['alerts_24h'] = countElementsInTable(
'glpi_plugin_siem_wazuh_alerts',
['date_creation' => ['>=', date('Y-m-d H:i:s', strtotime('-24 hours'))]]
);
// Tickets créés aujourd'hui
$stats['tickets_today'] = countElementsInTable(
'glpi_plugin_siem_wazuh_alerts',
[
'status' => 'ticket_created',
'date_mod' => ['>=', date('Y-m-d 00:00:00')]
]
);
// Vérifier s'il y a une synchronisation en cours
$config = new PluginSiemWazuhConfig();
$sync_in_progress = $config->getConfiguration('sync_in_progress', 0);
return [
'success' => true,
'message' => __('Status retrieved successfully', 'siem-wazuh'),
'stats' => $stats,
'sync_in_progress' => (bool)$sync_in_progress,
'timestamp' => date('Y-m-d H:i:s')
];
}

81
ajax/test_connection.php Normal file
View File

@@ -0,0 +1,81 @@
<?php
/*
* Plugin SIEM-Wazuh pour GLPI
* AJAX - Test de connexion aux serveurs Wazuh
*/
include ('../../../inc/includes.php');
header('Content-Type: application/json');
// Vérification des droits et du plugin
if (!Session::haveRight("plugin_siem_wazuh_server", READ) || !Plugin::isPluginActive('siem-wazuh')) {
echo json_encode(['success' => false, 'message' => __('Access denied', 'siem-wazuh')]);
exit;
}
// Vérification CSRF
if (!Session::validateCSRF($_POST)) {
echo json_encode(['success' => false, 'message' => __('Invalid CSRF token', 'siem-wazuh')]);
exit;
}
$response = ['success' => false, 'message' => ''];
try {
$server_id = intval($_POST['server_id'] ?? 0);
if ($server_id <= 0) {
throw new Exception(__('Invalid server ID', 'siem-wazuh'));
}
$server = new PluginSiemWazuhServer();
if (!$server->getFromDB($server_id)) {
throw new Exception(__('Server not found', 'siem-wazuh'));
}
// Test de connexion
$result = $server->testConnection();
if ($result['success']) {
$response = [
'success' => true,
'message' => $result['message'],
'server_info' => $result['data'] ?? null,
'timestamp' => date('Y-m-d H:i:s')
];
// Log du test réussi
Event::log(
$server_id,
"PluginSiemWazuhServer",
5,
"connection",
sprintf(__('Connection test successful for server %s'), $server->fields['name'])
);
} else {
$response = [
'success' => false,
'message' => $result['message'],
'error_type' => 'connection_failed'
];
// Log du test échoué
Event::log(
$server_id,
"PluginSiemWazuhServer",
2,
"connection",
sprintf(__('Connection test failed for server %s: %s'), $server->fields['name'], $result['message'])
);
}
} catch (Exception $e) {
$response = [
'success' => false,
'message' => $e->getMessage(),
'error_type' => 'exception'
];
}
echo json_encode($response, JSON_UNESCAPED_UNICODE);

487
css/style.css Normal file
View File

@@ -0,0 +1,487 @@
/**
* SIEM-Wazuh Plugin for GLPI - Stylesheet
* Styles for the SIEM-Wazuh plugin interface
*/
/* General plugin styles */
.siem-wazuh-container {
padding: 15px;
}
.siem-wazuh-header {
display: flex;
align-items: center;
margin-bottom: 20px;
padding: 10px;
background: #f8f9fa;
border-radius: 5px;
}
.siem-wazuh-logo {
width: 32px;
height: 32px;
margin-right: 10px;
}
/* Server status indicators */
.server-status {
display: inline-block;
padding: 3px 8px;
border-radius: 3px;
font-size: 11px;
font-weight: bold;
text-transform: uppercase;
}
.server-status.active {
background-color: #28a745;
color: white;
}
.server-status.inactive {
background-color: #dc3545;
color: white;
}
.server-status.testing {
background-color: #ffc107;
color: #212529;
}
/* Alert severity badges */
.severity-badge {
display: inline-block;
padding: 2px 6px;
border-radius: 3px;
font-size: 10px;
font-weight: bold;
text-transform: uppercase;
}
.severity-low {
background-color: #28a745;
color: white;
}
.severity-medium {
background-color: #ffc107;
color: #212529;
}
.severity-high {
background-color: #fd7e14;
color: white;
}
.severity-critical {
background-color: #dc3545;
color: white;
}
/* Status badges */
.status-badge {
display: inline-block;
padding: 2px 6px;
border-radius: 3px;
font-size: 10px;
font-weight: bold;
}
.status-new {
background-color: #17a2b8;
color: white;
}
.status-processed {
background-color: #28a745;
color: white;
}
.status-ignored {
background-color: #6c757d;
color: white;
}
.status-ticket {
background-color: #007bff;
color: white;
}
.status-ticket_created {
background-color: #007bff;
color: white;
}
/* Rule level indicators */
.rule-level-1,
.rule-level-2,
.rule-level-3,
.rule-level-4 {
background-color: #28a745;
color: white;
}
.rule-level-5,
.rule-level-6,
.rule-level-7 {
background-color: #ffc107;
color: #212529;
}
.rule-level-8,
.rule-level-9,
.rule-level-10,
.rule-level-11 {
background-color: #fd7e14;
color: white;
}
.rule-level-12,
.rule-level-13,
.rule-level-14,
.rule-level-15 {
background-color: #dc3545;
color: white;
}
/* Alert summary styles */
.alert-summary {
margin-bottom: 20px;
}
.alert-summary .tab_cadre_fixe {
border: 1px solid #dee2e6;
}
.alert-summary td {
text-align: center;
padding: 10px;
border-right: 1px solid #dee2e6;
}
.alert-summary td:last-child {
border-right: none;
}
.alert-summary strong {
font-size: 18px;
display: block;
margin-bottom: 5px;
}
/* Filters section */
.alert-filters {
background-color: #f8f9fa;
padding: 15px;
border-radius: 5px;
margin-bottom: 20px;
}
/* Action buttons */
.action-buttons {
white-space: nowrap;
}
.action-buttons .btn {
margin: 0 2px;
padding: 4px 8px;
font-size: 11px;
border-radius: 3px;
}
.btn-primary {
background-color: #007bff;
border-color: #007bff;
color: white;
}
.btn-success {
background-color: #28a745;
border-color: #28a745;
color: white;
}
.btn-warning {
background-color: #ffc107;
border-color: #ffc107;
color: #212529;
}
.btn-danger {
background-color: #dc3545;
border-color: #dc3545;
color: white;
}
.btn-secondary {
background-color: #6c757d;
border-color: #6c757d;
color: white;
}
/* JSON data display */
.json-data {
background-color: #f8f9fa;
border: 1px solid #dee2e6;
border-radius: 4px;
padding: 10px;
font-family: Monaco, Menlo, "Ubuntu Mono", monospace;
font-size: 12px;
max-height: 300px;
overflow-y: auto;
white-space: pre-wrap;
}
/* Configuration tabs */
.config-tabs {
margin-bottom: 20px;
}
.config-tabs .nav-tabs {
border-bottom: 1px solid #dee2e6;
margin-bottom: 0;
}
.config-tabs .nav-item {
display: inline-block;
margin-bottom: -1px;
}
.config-tabs .nav-link {
display: block;
padding: 10px 15px;
text-decoration: none;
color: #495057;
border: 1px solid transparent;
border-top-left-radius: 0.25rem;
border-top-right-radius: 0.25rem;
margin-right: 2px;
}
.config-tabs .nav-link:hover {
border-color: #e9ecef #e9ecef #dee2e6;
text-decoration: none;
}
.config-tabs .nav-link.active {
color: #495057;
background-color: #fff;
border-color: #dee2e6 #dee2e6 #fff;
}
/* Log level badges */
.log-debug {
background-color: #d1ecf1;
color: #0c5460;
padding: 2px 6px;
border-radius: 3px;
font-size: 10px;
font-weight: bold;
}
.log-info {
background-color: #bee5eb;
color: #0c5460;
padding: 2px 6px;
border-radius: 3px;
font-size: 10px;
font-weight: bold;
}
.log-warning {
background-color: #fff3cd;
color: #856404;
padding: 2px 6px;
border-radius: 3px;
font-size: 10px;
font-weight: bold;
}
.log-error {
background-color: #f8d7da;
color: #721c24;
padding: 2px 6px;
border-radius: 3px;
font-size: 10px;
font-weight: bold;
}
.log-critical {
background-color: #f5c6cb;
color: #721c24;
padding: 2px 6px;
border-radius: 3px;
font-size: 10px;
font-weight: bold;
}
/* Alert messages */
.alert {
padding: 12px 20px;
margin: 15px 0;
border: 1px solid transparent;
border-radius: 4px;
}
.alert-success {
color: #155724;
background-color: #d4edda;
border-color: #c3e6cb;
}
.alert-info {
color: #0c5460;
background-color: #d1ecf1;
border-color: #bee5eb;
}
.alert-warning {
color: #856404;
background-color: #fff3cd;
border-color: #ffeaa7;
}
.alert-danger {
color: #721c24;
background-color: #f8d7da;
border-color: #f5c6cb;
}
/* Statistics cards */
.stats-card {
background: #fff;
border: 1px solid #dee2e6;
border-radius: 5px;
padding: 20px;
margin-bottom: 20px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.stats-card h3 {
color: #495057;
font-size: 18px;
margin-bottom: 15px;
border-bottom: 1px solid #dee2e6;
padding-bottom: 10px;
}
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
margin-top: 20px;
}
.stat-item {
text-align: center;
padding: 15px;
background: #f8f9fa;
border-radius: 5px;
}
.stat-number {
font-size: 24px;
font-weight: bold;
color: #007bff;
display: block;
}
.stat-label {
font-size: 12px;
color: #6c757d;
margin-top: 5px;
}
/* Responsive design */
@media (max-width: 768px) {
.alert-summary td {
padding: 5px;
font-size: 12px;
}
.alert-summary strong {
font-size: 14px;
}
.action-buttons .btn {
padding: 2px 4px;
font-size: 10px;
margin: 1px;
}
.stats-grid {
grid-template-columns: repeat(2, 1fr);
}
}
/* Loading animations */
.loading-spinner {
display: inline-block;
width: 16px;
height: 16px;
border: 2px solid #f3f3f3;
border-top: 2px solid #007bff;
border-radius: 50%;
animation: spin 1s linear infinite;
margin-right: 5px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* Tooltip styles */
.wazuh-tooltip {
position: relative;
display: inline-block;
cursor: help;
}
.wazuh-tooltip .tooltiptext {
visibility: hidden;
width: 200px;
background-color: #555;
color: #fff;
text-align: center;
border-radius: 6px;
padding: 5px;
position: absolute;
z-index: 1;
bottom: 125%;
left: 50%;
margin-left: -100px;
opacity: 0;
transition: opacity 0.3s;
font-size: 11px;
}
.wazuh-tooltip:hover .tooltiptext {
visibility: visible;
opacity: 1;
}
/* Dark theme support */
@media (prefers-color-scheme: dark) {
.siem-wazuh-header {
background: #343a40;
color: #fff;
}
.alert-filters {
background-color: #343a40;
color: #fff;
}
.json-data {
background-color: #2d3748;
color: #e2e8f0;
border-color: #4a5568;
}
.stats-card {
background: #343a40;
color: #fff;
border-color: #4a5568;
}
}

706
front/wazuhalert.php Normal file
View File

@@ -0,0 +1,706 @@
<?php
/*
* Plugin SIEM-Wazuh pour GLPI
* Classe de gestion des alertes Wazuh
*/
if (!defined('GLPI_ROOT')) {
die("Sorry. You can't access this file directly");
}
class PluginSiemWazuhAlert extends CommonDBTM {
public $dohistory = true;
static $rightname = 'plugin_siem_wazuh_alert';
const MATRIX_FIELD = '';
const SEARCHOPTIONS_INHERITANCE = true;
/**
* Return the localized name of the current Type
*/
static function getTypeName($nb = 0) {
return _n('Wazuh Alert', 'Wazuh Alerts', $nb, 'siem-wazuh');
}
/**
* Define search options
*/
function rawSearchOptions() {
$tab = [];
$tab[] = [
'id' => 'common',
'name' => __('Characteristics')
];
$tab[] = [
'id' => '1',
'table' => $this->getTable(),
'field' => 'alert_id',
'name' => __('Alert ID', 'siem-wazuh'),
'datatype' => 'itemlink',
'massiveaction' => false
];
$tab[] = [
'id' => '2',
'table' => 'glpi_plugin_siem_wazuh_servers',
'field' => 'name',
'name' => __('Wazuh Server', 'siem-wazuh'),
'datatype' => 'dropdown',
'massiveaction' => false,
'linkfield' => 'wazuh_server_id'
];
$tab[] = [
'id' => '3',
'table' => $this->getTable(),
'field' => 'rule_id',
'name' => __('Rule ID', 'siem-wazuh'),
'datatype' => 'integer',
'massiveaction' => false
];
$tab[] = [
'id' => '4',
'table' => $this->getTable(),
'field' => 'rule_level',
'name' => __('Rule Level', 'siem-wazuh'),
'datatype' => 'integer',
'massiveaction' => false
];
$tab[] = [
'id' => '5',
'table' => $this->getTable(),
'field' => 'rule_description',
'name' => __('Rule Description', 'siem-wazuh'),
'datatype' => 'text',
'massiveaction' => false
];
$tab[] = [
'id' => '6',
'table' => $this->getTable(),
'field' => 'agent_name',
'name' => __('Agent Name', 'siem-wazuh'),
'datatype' => 'string',
'massiveaction' => false
];
$tab[] = [
'id' => '7',
'table' => $this->getTable(),
'field' => 'agent_ip',
'name' => __('Agent IP', 'siem-wazuh'),
'datatype' => 'string',
'massiveaction' => false
];
$tab[] = [
'id' => '8',
'table' => $this->getTable(),
'field' => 'timestamp',
'name' => __('Alert Timestamp', 'siem-wazuh'),
'datatype' => 'datetime',
'massiveaction' => false
];
$tab[] = [
'id' => '9',
'table' => $this->getTable(),
'field' => 'status',
'name' => __('Status'),
'datatype' => 'specific',
'searchtype' => 'equals',
'massiveaction' => true
];
$tab[] = [
'id' => '10',
'table' => $this->getTable(),
'field' => 'severity',
'name' => __('Severity', 'siem-wazuh'),
'datatype' => 'specific',
'searchtype' => 'equals',
'massiveaction' => true
];
$tab[] = [
'id' => '11',
'table' => 'glpi_computers',
'field' => 'name',
'name' => __('Associated Computer', 'siem-wazuh'),
'datatype' => 'dropdown',
'massiveaction' => false,
'linkfield' => 'computer_id'
];
$tab[] = [
'id' => '12',
'table' => 'glpi_networkequipments',
'field' => 'name',
'name' => __('Associated Network Equipment', 'siem-wazuh'),
'datatype' => 'dropdown',
'massiveaction' => false,
'linkfield' => 'networkequipment_id'
];
$tab[] = [
'id' => '13',
'table' => 'glpi_tickets',
'field' => 'name',
'name' => __('Associated Ticket', 'siem-wazuh'),
'datatype' => 'dropdown',
'massiveaction' => false,
'linkfield' => 'ticket_id'
];
$tab[] = [
'id' => '30',
'table' => $this->getTable(),
'field' => 'date_creation',
'name' => __('Creation date'),
'datatype' => 'datetime',
'massiveaction' => false
];
$tab[] = [
'id' => '31',
'table' => $this->getTable(),
'field' => 'date_mod',
'name' => __('Last update'),
'datatype' => 'datetime',
'massiveaction' => false
];
return $tab;
}
/**
* Display specific values
*/
static function getSpecificValueToDisplay($field, $values, array $options = []) {
if (!is_array($values)) {
$values = [$field => $values];
}
switch ($field) {
case 'status':
$statuses = self::getStatusArray();
return $statuses[$values[$field]] ?? $values[$field];
case 'severity':
$severities = self::getSeverityArray();
return $severities[$values[$field]] ?? $values[$field];
}
return parent::getSpecificValueToDisplay($field, $values, $options);
}
/**
* Get status array
*/
static function getStatusArray() {
return [
'new' => __('New', 'siem-wazuh'),
'processed' => __('Processed', 'siem-wazuh'),
'ignored' => __('Ignored', 'siem-wazuh'),
'ticket_created' => __('Ticket Created', 'siem-wazuh')
];
}
/**
* Get severity array
*/
static function getSeverityArray() {
return [
'low' => __('Low', 'siem-wazuh'),
'medium' => __('Medium', 'siem-wazuh'),
'high' => __('High', 'siem-wazuh'),
'critical' => __('Critical', 'siem-wazuh')
];
}
/**
* Display form
*/
function showForm($ID, $options = []) {
$this->initForm($ID, $options);
$this->showFormHeader($options);
echo "<tr class='tab_bg_1'>";
echo "<td>".__('Alert ID', 'siem-wazuh')."</td>";
echo "<td>".$this->fields["alert_id"]."</td>";
echo "<td>".__('Rule ID', 'siem-wazuh')."</td>";
echo "<td>".$this->fields["rule_id"]."</td>";
echo "</tr>";
echo "<tr class='tab_bg_1'>";
echo "<td>".__('Rule Level', 'siem-wazuh')."</td>";
echo "<td>";
echo $this->fields["rule_level"];
if ($this->fields["rule_level"]) {
$severity = self::getSeverityFromLevel($this->fields["rule_level"]);
$severities = self::getSeverityArray();
echo " <span class='badge severity-$severity'>".$severities[$severity]."</span>";
}
echo "</td>";
echo "<td>".__('Agent Name', 'siem-wazuh')."</td>";
echo "<td>".$this->fields["agent_name"]."</td>";
echo "</tr>";
echo "<tr class='tab_bg_1'>";
echo "<td>".__('Agent IP', 'siem-wazuh')."</td>";
echo "<td>".$this->fields["agent_ip"]."</td>";
echo "<td>".__('Timestamp', 'siem-wazuh')."</td>";
echo "<td>".Html::convDateTime($this->fields["timestamp"])."</td>";
echo "</tr>";
echo "<tr class='tab_bg_1'>";
echo "<td>".__('Status')."</td>";
echo "<td>";
$statuses = self::getStatusArray();
Dropdown::showFromArray('status', $statuses, ['value' => $this->fields["status"]]);
echo "</td>";
echo "<td>".__('Severity', 'siem-wazuh')."</td>";
echo "<td>";
$severities = self::getSeverityArray();
Dropdown::showFromArray('severity', $severities, ['value' => $this->fields["severity"]]);
echo "</td>";
echo "</tr>";
echo "<tr class='tab_bg_1'>";
echo "<td>".__('Rule Description', 'siem-wazuh')."</td>";
echo "<td colspan='3'>";
echo nl2br(Html::entities_deep($this->fields["rule_description"]));
echo "</td>";
echo "</tr>";
// Affichage des associations
if ($this->fields["computer_id"]) {
$computer = new Computer();
$computer->getFromDB($this->fields["computer_id"]);
echo "<tr class='tab_bg_1'>";
echo "<td>".__('Associated Computer')."</td>";
echo "<td>";
echo $computer->getLink();
echo "</td>";
echo "<td></td><td></td>";
echo "</tr>";
}
if ($this->fields["networkequipment_id"]) {
$netequip = new NetworkEquipment();
$netequip->getFromDB($this->fields["networkequipment_id"]);
echo "<tr class='tab_bg_1'>";
echo "<td>".__('Associated Network Equipment')."</td>";
echo "<td>";
echo $netequip->getLink();
echo "</td>";
echo "<td></td><td></td>";
echo "</tr>";
}
if ($this->fields["ticket_id"]) {
$ticket = new Ticket();
$ticket->getFromDB($this->fields["ticket_id"]);
echo "<tr class='tab_bg_1'>";
echo "<td>".__('Associated Ticket')."</td>";
echo "<td>";
echo $ticket->getLink();
echo "</td>";
echo "<td></td><td></td>";
echo "</tr>";
}
// Affichage des données brutes
if (!empty($this->fields["raw_data"])) {
echo "<tr class='tab_bg_1'>";
echo "<td colspan='4'>";
echo "<details>";
echo "<summary>".__('Raw Alert Data', 'siem-wazuh')."</summary>";
echo "<pre class='json-data'>";
echo json_encode(json_decode($this->fields["raw_data"]), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
echo "</pre>";
echo "</details>";
echo "</td>";
echo "</tr>";
}
$this->showFormButtons($options);
return true;
}
/**
* Process alerts from Wazuh API
*/
function processAlerts($server_id, $alerts_data) {
$processed = 0;
$config = new PluginSiemWazuhConfig();
foreach ($alerts_data as $alert_data) {
$alert_id = $alert_data['id'] ?? $alert_data['_id'] ?? null;
if (!$alert_id) continue;
// Vérifier si l'alerte existe déjà
if ($this->getFromDBByCrit([
'wazuh_server_id' => $server_id,
'alert_id' => $alert_id
])) {
continue; // Alerte déjà traitée
}
// Extraire les informations de l'alerte
$rule_id = $alert_data['rule']['id'] ?? null;
$rule_level = $alert_data['rule']['level'] ?? 0;
$rule_description = $alert_data['rule']['description'] ?? '';
$agent_name = $alert_data['agent']['name'] ?? '';
$agent_ip = $alert_data['agent']['ip'] ?? '';
$timestamp = $alert_data['timestamp'] ?? $alert_data['@timestamp'] ?? date('Y-m-d H:i:s');
// Convertir le timestamp au format MySQL
if (strpos($timestamp, 'T') !== false) {
$timestamp = str_replace('T', ' ', substr($timestamp, 0, 19));
}
// Déterminer la sévérité
$severity = self::getSeverityFromLevel($rule_level);
// Créer l'alerte
$alert_input = [
'wazuh_server_id' => $server_id,
'alert_id' => $alert_id,
'rule_id' => $rule_id,
'rule_level' => $rule_level,
'rule_description' => $rule_description,
'agent_id' => $alert_data['agent']['id'] ?? '',
'agent_name' => $agent_name,
'agent_ip' => $agent_ip,
'timestamp' => $timestamp,
'raw_data' => json_encode($alert_data),
'severity' => $severity,
'status' => 'new'
];
// Tenter d'associer avec un asset
$this->associateWithAsset($alert_input, $agent_name, $agent_ip);
if ($alert_id = $this->add($alert_input)) {
$processed++;
// Créer automatiquement un ticket si configuré
if ($config->getConfiguration('auto_create_ticket', 1)) {
$this->createTicketFromAlert($alert_id);
}
}
}
return $processed;
}
/**
* Associate alert with GLPI asset
*/
private function associateWithAsset(&$alert_input, $agent_name, $agent_ip) {
global $DB;
// Recherche par nom d'agent
if (!empty($agent_name)) {
// Recherche dans les ordinateurs
$computer = $DB->request([
'SELECT' => ['id'],
'FROM' => 'glpi_computers',
'WHERE' => [
'name' => $agent_name,
'is_deleted' => 0
],
'LIMIT' => 1
])->current();
if ($computer) {
$alert_input['computer_id'] = $computer['id'];
return;
}
// Recherche dans les équipements réseau
$netequip = $DB->request([
'SELECT' => ['id'],
'FROM' => 'glpi_networkequipments',
'WHERE' => [
'name' => $agent_name,
'is_deleted' => 0
],
'LIMIT' => 1
])->current();
if ($netequip) {
$alert_input['networkequipment_id'] = $netequip['id'];
return;
}
}
// Recherche par adresse IP
if (!empty($agent_ip)) {
// Recherche dans les ports réseau
$port = $DB->request([
'SELECT' => ['items_id', 'itemtype'],
'FROM' => 'glpi_networkports',
'INNER JOIN' => [
'glpi_ipaddresses' => [
'ON' => [
'glpi_networkports' => 'id',
'glpi_ipaddresses' => 'items_id'
]
]
],
'WHERE' => [
'glpi_ipaddresses.name' => $agent_ip,
'glpi_ipaddresses.itemtype' => 'NetworkPort'
],
'LIMIT' => 1
])->current();
if ($port) {
if ($port['itemtype'] == 'Computer') {
$alert_input['computer_id'] = $port['items_id'];
} elseif ($port['itemtype'] == 'NetworkEquipment') {
$alert_input['networkequipment_id'] = $port['items_id'];
}
}
}
}
/**
* Create ticket from alert
*/
function createTicketFromAlert($alert_id) {
if (!$this->getFromDB($alert_id)) {
return false;
}
$server = new PluginSiemWazuhServer();
if (!$server->getFromDB($this->fields['wazuh_server_id'])) {
return false;
}
$ticket = new Ticket();
$config = new PluginSiemWazuhConfig();
// Déterminer la priorité basée sur le niveau de règle
$priority = self::getPriorityFromLevel($this->fields['rule_level']);
$ticket_input = [
'name' => sprintf(__('Wazuh Alert: %s', 'siem-wazuh'), $this->fields['rule_description']),
'content' => $this->generateTicketContent(),
'type' => $server->fields['ticket_type'] ?: 1,
'itilcategories_id' => $server->fields['ticket_category'],
'priority' => $priority,
'urgency' => $priority,
'impact' => $priority,
'status' => CommonITILObject::INCOMING,
'_add_validation' => 0
];
// Associer le ticket à l'asset si trouvé
if ($this->fields['computer_id']) {
$ticket_input['_link']['items_id'] = $this->fields['computer_id'];
$ticket_input['_link']['itemtype'] = 'Computer';
} elseif ($this->fields['networkequipment_id']) {
$ticket_input['_link']['items_id'] = $this->fields['networkequipment_id'];
$ticket_input['_link']['itemtype'] = 'NetworkEquipment';
}
$ticket_id = $ticket->add($ticket_input);
if ($ticket_id) {
// Mettre à jour l'alerte
$this->update([
'id' => $alert_id,
'ticket_id' => $ticket_id,
'status' => 'ticket_created'
]);
return $ticket_id;
}
return false;
}
/**
* Generate ticket content from alert
*/
private function generateTicketContent() {
$content = "[WAZUH-ALERT]\n\n";
$content .= sprintf(__('Alert ID: %s', 'siem-wazuh'), $this->fields['alert_id']) . "\n";
$content .= sprintf(__('Rule ID: %s', 'siem-wazuh'), $this->fields['rule_id']) . "\n";
$content .= sprintf(__('Rule Level: %s', 'siem-wazuh'), $this->fields['rule_level']) . "\n";
$content .= sprintf(__('Agent: %s (%s)', 'siem-wazuh'), $this->fields['agent_name'], $this->fields['agent_ip']) . "\n";
$content .= sprintf(__('Timestamp: %s', 'siem-wazuh'), $this->fields['timestamp']) . "\n\n";
$content .= sprintf(__('Description: %s', 'siem-wazuh'), $this->fields['rule_description']) . "\n\n";
if ($this->fields['raw_data']) {
$content .= __('Raw Alert Data:', 'siem-wazuh') . "\n";
$content .= "```json\n";
$content .= json_encode(json_decode($this->fields['raw_data']), JSON_PRETTY_PRINT);
$content .= "\n```";
}
return $content;
}
/**
* Get severity from rule level
*/
static function getSeverityFromLevel($level) {
if ($level >= 12) return 'critical';
if ($level >= 10) return 'high';
if ($level >= 7) return 'medium';
return 'low';
}
/**
* Get priority from rule level
*/
static function getPriorityFromLevel($level) {
if ($level >= 12) return 5; // Very high
if ($level >= 10) return 4; // High
if ($level >= 7) return 3; // Medium
if ($level >= 5) return 2; // Low
return 1; // Very low
}
/**
* Show alerts for a server
*/
static function showForServer($server_id) {
global $DB;
$iterator = $DB->request([
'FROM' => 'glpi_plugin_siem_wazuh_alerts',
'WHERE' => ['wazuh_server_id' => $server_id],
'ORDER' => 'timestamp DESC',
'LIMIT' => 50
]);
echo "<div class='spaced'>";
echo "<table class='tab_cadre_fixehov'>";
echo "<tr class='tab_bg_2'>";
echo "<th>".__('Alert ID', 'siem-wazuh')."</th>";
echo "<th>".__('Rule', 'siem-wazuh')."</th>";
echo "<th>".__('Level', 'siem-wazuh')."</th>";
echo "<th>".__('Agent', 'siem-wazuh')."</th>";
echo "<th>".__('Timestamp', 'siem-wazuh')."</th>";
echo "<th>".__('Status')."</th>";
echo "<th>".__('Ticket')."</th>";
echo "</tr>";
$statuses = self::getStatusArray();
foreach ($iterator as $row) {
echo "<tr class='tab_bg_1'>";
echo "<td><a href='".PluginSiemWazuhAlert::getFormURLWithID($row['id'])."'>".$row['alert_id']."</a></td>";
echo "<td>".$row['rule_id']." - ".Html::clean($row['rule_description'])."</td>";
echo "<td>".$row['rule_level']."</td>";
echo "<td>".$row['agent_name']." (".$row['agent_ip'].")</td>";
echo "<td>".Html::convDateTime($row['timestamp'])."</td>";
echo "<td>".$statuses[$row['status']]."</td>";
echo "<td>";
if ($row['ticket_id']) {
$ticket = new Ticket();
if ($ticket->getFromDB($row['ticket_id'])) {
echo $ticket->getLink();
}
}
echo "</td>";
echo "</tr>";
}
echo "</table>";
echo "</div>";
}
/**
* Cron function to sync alerts
*/
static function cronSyncAlerts($task = null) {
global $DB;
$config = new PluginSiemWazuhConfig();
if (!$config->getConfiguration('sync_enabled', 1)) {
return 0; // Synchronisation désactivée
}
$iterator = $DB->request([
'FROM' => 'glpi_plugin_siem_wazuh_servers',
'WHERE' => ['is_active' => 1]
]);
$total_processed = 0;
foreach ($iterator as $server_data) {
$server = new PluginSiemWazuhServer();
$server->fields = $server_data;
$result = $server->syncAlerts();
if ($result['success']) {
$matches = [];
if (preg_match('/(\d+)/', $result['message'], $matches)) {
$total_processed += (int)$matches[1];
}
}
}
if ($task) {
$task->addVolume($total_processed);
return 1;
}
return $total_processed;
}
/**
* Cron function to cleanup old alerts
*/
static function cronCleanupOldAlerts($task = null) {
global $DB;
$config = new PluginSiemWazuhConfig();
$retention_days = $config->getConfiguration('alert_retention_days', 90);
$query = "DELETE FROM glpi_plugin_siem_wazuh_alerts
WHERE date_creation < DATE_SUB(NOW(), INTERVAL $retention_days DAY)";
$result = $DB->query($query);
$deleted = $DB->affectedRows();
if ($task) {
$task->addVolume($deleted);
return 1;
}
return $deleted;
}
/**
* Get menu content
*/
static function getMenuContent() {
$menu = [];
if (Session::haveRight(static::$rightname, READ)) {
$menu['title'] = self::getMenuName();
$menu['page'] = "/plugins/siem-wazuh/front/wazuhalert.php";
$menu['links']['search'] = "/plugins/siem-wazuh/front/wazuhalert.php";
}
return $menu;
}
/**
* Get menu name
*/
static function getMenuName() {
return self::getTypeName(Session::getPluralNumber());
}
}

393
front/wazuhconfig.php Normal file
View File

@@ -0,0 +1,393 @@
<?php
/*
* Plugin SIEM-Wazuh pour GLPI
* Interface de configuration du plugin
*/
include ('../../../inc/includes.php');
// Vérification des droits
Session::checkRight("plugin_siem_wazuh_config", READ);
// Vérification du plugin
if (!Plugin::isPluginActive('siem-wazuh')) {
Html::displayNotFoundError();
}
$config = new PluginSiemWazuhConfig();
// Traitement du formulaire
$config->processConfigForm();
// Initialisation de l'affichage
Html::header(
PluginSiemWazuhConfig::getTypeName(1),
$_SERVER['PHP_SELF'],
'tools',
'PluginSiemWazuhConfig'
);
echo "<div class='spaced'>";
// Affichage des onglets de configuration
$tabs = [
'config' => __('Configuration', 'siem-wazuh'),
'mapping' => __('Asset Mapping', 'siem-wazuh'),
'notifications' => __('Notifications', 'siem-wazuh'),
'debug' => __('Debug & Logs', 'siem-wazuh')
];
$active_tab = $_GET['tab'] ?? 'config';
echo "<div class='config-tabs'>";
echo "<ul class='nav nav-tabs'>";
foreach ($tabs as $tab_key => $tab_name) {
$active_class = ($active_tab == $tab_key) ? ' active' : '';
echo "<li class='nav-item'>";
echo "<a class='nav-link$active_class' href='?tab=$tab_key'>$tab_name</a>";
echo "</li>";
}
echo "</ul>";
echo "</div>";
echo "<div class='tab-content'>";
switch ($active_tab) {
case 'config':
// Configuration générale
$config->showConfigForm();
break;
case 'mapping':
// Configuration du mapping des assets
echo "<div class='tab-pane active'>";
echo "<h3>" . __('Asset Mapping Configuration', 'siem-wazuh') . "</h3>";
showMappingConfiguration($config);
echo "</div>";
break;
case 'notifications':
// Configuration des notifications
echo "<div class='tab-pane active'>";
echo "<h3>" . __('Notification Configuration', 'siem-wazuh') . "</h3>";
showNotificationConfiguration($config);
echo "</div>";
break;
case 'debug':
// Configuration de debug et logs
echo "<div class='tab-pane active'>";
echo "<h3>" . __('Debug & Logs Configuration', 'siem-wazuh') . "</h3>";
showDebugConfiguration($config);
showRecentLogs();
echo "</div>";
break;
}
echo "</div>";
echo "</div>";
/**
* Show mapping configuration
*/
function showMappingConfiguration($config) {
echo "<form method='post' action=''>";
echo "<table class='tab_cadre_fixe'>";
echo "<tr class='tab_bg_2'>";
echo "<th colspan='4'>" . __('Asset Detection Rules', 'siem-wazuh') . "</th>";
echo "</tr>";
echo "<tr class='tab_bg_1'>";
echo "<td>" . __('Match computers by hostname', 'siem-wazuh') . "</td>";
echo "<td>";
Dropdown::showYesNo("match_computers_hostname", $config->getConfiguration('match_computers_hostname', 1));
echo "</td>";
echo "<td>" . __('Match network equipment by hostname', 'siem-wazuh') . "</td>";
echo "<td>";
Dropdown::showYesNo("match_netequip_hostname", $config->getConfiguration('match_netequip_hostname', 1));
echo "</td>";
echo "</tr>";
echo "<tr class='tab_bg_1'>";
echo "<td>" . __('Match by IP address', 'siem-wazuh') . "</td>";
echo "<td>";
Dropdown::showYesNo("match_by_ip", $config->getConfiguration('match_by_ip', 1));
echo "</td>";
echo "<td>" . __('Case sensitive matching', 'siem-wazuh') . "</td>";
echo "<td>";
Dropdown::showYesNo("case_sensitive_matching", $config->getConfiguration('case_sensitive_matching', 0));
echo "</td>";
echo "</tr>";
echo "<tr class='tab_bg_1'>";
echo "<td>" . __('Hostname patterns to ignore', 'siem-wazuh') . "</td>";
echo "<td colspan='3'>";
echo "<textarea name='ignore_hostname_patterns' rows='3' cols='80' placeholder='localhost,127.0.0.1,*.local'>";
echo $config->getConfiguration('ignore_hostname_patterns', '');
echo "</textarea>";
echo "<br><small>" . __('One pattern per line. Use * as wildcard.', 'siem-wazuh') . "</small>";
echo "</td>";
echo "</tr>";
echo "<tr class='tab_bg_2'>";
echo "<td class='center' colspan='4'>";
echo "<input type='submit' name='update_mapping' value='" . _sx('button', 'Save') . "' class='submit'>";
echo "</td>";
echo "</tr>";
echo "</table>";
echo Html::closeForm();
// Test de correspondance
echo "<br>";
echo "<table class='tab_cadre_fixe'>";
echo "<tr class='tab_bg_2'>";
echo "<th colspan='2'>" . __('Test Asset Mapping', 'siem-wazuh') . "</th>";
echo "</tr>";
echo "<tr class='tab_bg_1'>";
echo "<td>" . __('Agent name or IP', 'siem-wazuh') . "</td>";
echo "<td>";
echo "<input type='text' name='test_agent' id='test_agent' size='30' placeholder='agent-hostname or 192.168.1.100'>";
echo "&nbsp;<button type='button' onclick='testAssetMapping()' class='btn btn-primary'>" . __('Test', 'siem-wazuh') . "</button>";
echo "<div id='mapping_result' style='margin-top: 10px;'></div>";
echo "</td>";
echo "</tr>";
echo "</table>";
}
/**
* Show notification configuration
*/
function showNotificationConfiguration($config) {
echo "<form method='post' action=''>";
echo "<table class='tab_cadre_fixe'>";
echo "<tr class='tab_bg_2'>";
echo "<th colspan='4'>" . __('Email Notifications', 'siem-wazuh') . "</th>";
echo "</tr>";
echo "<tr class='tab_bg_1'>";
echo "<td>" . __('Enable email notifications', 'siem-wazuh') . "</td>";
echo "<td>";
Dropdown::showYesNo("email_notifications", $config->getConfiguration('email_notifications', 1));
echo "</td>";
echo "<td>" . __('Notification for critical alerts only', 'siem-wazuh') . "</td>";
echo "<td>";
Dropdown::showYesNo("notify_critical_only", $config->getConfiguration('notify_critical_only', 0));
echo "</td>";
echo "</tr>";
echo "<tr class='tab_bg_1'>";
echo "<td>" . __('Default notification recipients', 'siem-wazuh') . "</td>";
echo "<td colspan='3'>";
echo "<input type='text' name='notification_recipients' size='80' value='" . $config->getConfiguration('notification_recipients', '') . "' placeholder='admin@domain.com, security@domain.com'>";
echo "<br><small>" . __('Comma-separated email addresses', 'siem-wazuh') . "</small>";
echo "</td>";
echo "</tr>";
echo "<tr class='tab_bg_2'>";
echo "<td class='center' colspan='4'>";
echo "<input type='submit' name='update_notifications' value='" . _sx('button', 'Save') . "' class='submit'>";
echo "</td>";
echo "</tr>";
echo "</table>";
echo Html::closeForm();
}
/**
* Show debug configuration
*/
function showDebugConfiguration($config) {
echo "<form method='post' action=''>";
echo "<table class='tab_cadre_fixe'>";
echo "<tr class='tab_bg_2'>";
echo "<th colspan='4'>" . __('Debug Configuration', 'siem-wazuh') . "</th>";
echo "</tr>";
echo "<tr class='tab_bg_1'>";
echo "<td>" . __('Enable debug mode', 'siem-wazuh') . "</td>";
echo "<td>";
Dropdown::showYesNo("debug_mode", $config->getConfiguration('debug_mode', 0));
echo "</td>";
echo "<td>" . __('Log API requests', 'siem-wazuh') . "</td>";
echo "<td>";
Dropdown::showYesNo("log_api_requests", $config->getConfiguration('log_api_requests', 0));
echo "</td>";
echo "</tr>";
echo "<tr class='tab_bg_1'>";
echo "<td>" . __('Log level', 'siem-wazuh') . "</td>";
echo "<td>";
$log_levels = [
'error' => __('Error only', 'siem-wazuh'),
'warning' => __('Warning and above', 'siem-wazuh'),
'info' => __('Info and above', 'siem-wazuh'),
'debug' => __('All messages', 'siem-wazuh')
];
Dropdown::showFromArray('log_level', $log_levels, [
'value' => $config->getConfiguration('log_level', 'info')
]);
echo "</td>";
echo "<td>" . __('Keep logs for (days)', 'siem-wazuh') . "</td>";
echo "<td>";
Dropdown::showNumber("log_retention_days", [
'value' => $config->getConfiguration('log_retention_days', 30),
'min' => 1,
'max' => 365
]);
echo "</td>";
echo "</tr>";
echo "<tr class='tab_bg_2'>";
echo "<td class='center' colspan='2'>";
echo "<input type='submit' name='update_debug' value='" . _sx('button', 'Save') . "' class='submit'>";
echo "</td>";
echo "<td class='center' colspan='2'>";
echo "<button type='button' onclick='clearLogs()' class='btn btn-warning'>" . __('Clear All Logs', 'siem-wazuh') . "</button>";
echo "</td>";
echo "</tr>";
echo "</table>";
echo Html::closeForm();
}
/**
* Show recent logs
*/
function showRecentLogs() {
global $DB;
echo "<br>";
echo "<table class='tab_cadre_fixehov'>";
echo "<tr class='tab_bg_2'>";
echo "<th colspan='4'>" . __('Recent Logs', 'siem-wazuh') . " (100 dernières entrées)</th>";
echo "</tr>";
echo "<tr class='tab_bg_2'>";
echo "<th>" . __('Date') . "</th>";
echo "<th>" . __('Level') . "</th>";
echo "<th>" . __('Server') . "</th>";
echo "<th>" . __('Message') . "</th>";
echo "</tr>";
$iterator = $DB->request([
'SELECT' => [
'glpi_plugin_siem_wazuh_logs.*',
'glpi_plugin_siem_wazuh_servers.name AS server_name'
],
'FROM' => 'glpi_plugin_siem_wazuh_logs',
'LEFT JOIN' => [
'glpi_plugin_siem_wazuh_servers' => [
'ON' => [
'glpi_plugin_siem_wazuh_logs' => 'wazuh_server_id',
'glpi_plugin_siem_wazuh_servers' => 'id'
]
]
],
'ORDER' => 'date_creation DESC',
'LIMIT' => 100
]);
if (count($iterator) == 0) {
echo "<tr class='tab_bg_1'>";
echo "<td colspan='4' class='center'>" . __('No logs found', 'siem-wazuh') . "</td>";
echo "</tr>";
} else {
foreach ($iterator as $log) {
$level_class = 'log-' . $log['level'];
echo "<tr class='tab_bg_1'>";
echo "<td>" . Html::convDateTime($log['date_creation']) . "</td>";
echo "<td><span class='badge $level_class'>" . ucfirst($log['level']) . "</span></td>";
echo "<td>" . ($log['server_name'] ?: __('System', 'siem-wazuh')) . "</td>";
echo "<td>" . Html::clean($log['message']) . "</td>";
echo "</tr>";
}
}
echo "</table>";
}
// JavaScript pour les fonctionnalités interactives
echo "<script>
function testAssetMapping() {
var agentValue = document.getElementById('test_agent').value;
if (!agentValue) {
alert('" . __('Please enter an agent name or IP address', 'siem-wazuh') . "');
return;
}
fetch('" . Plugin::getWebDir('siem-wazuh') . "/ajax/test_mapping.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: 'agent=' + encodeURIComponent(agentValue)
})
.then(response => response.json())
.then(data => {
var resultDiv = document.getElementById('mapping_result');
if (data.success) {
resultDiv.innerHTML = '<div class=\"alert alert-success\">' + data.message + '</div>';
} else {
resultDiv.innerHTML = '<div class=\"alert alert-info\">' + data.message + '</div>';
}
})
.catch(error => {
document.getElementById('mapping_result').innerHTML = '<div class=\"alert alert-danger\">" . __('Test failed', 'siem-wazuh') . "</div>';
});
}
function clearLogs() {
if (confirm('" . __('Are you sure you want to clear all logs?', 'siem-wazuh') . "')) {
fetch('" . Plugin::getWebDir('siem-wazuh') . "/ajax/clear_logs.php', {
method: 'POST'
})
.then(response => response.json())
.then(data => {
if (data.success) {
alert('" . __('Logs cleared successfully', 'siem-wazuh') . "');
location.reload();
} else {
alert('" . __('Failed to clear logs', 'siem-wazuh') . "');
}
});
}
}
</script>";
// CSS pour les logs et badges
echo "<style>
.config-tabs .nav-tabs {
border-bottom: 1px solid #ddd;
margin-bottom: 20px;
}
.config-tabs .nav-item {
display: inline-block;
}
.config-tabs .nav-link {
display: block;
padding: 10px 15px;
text-decoration: none;
color: #337ab7;
border: 1px solid transparent;
border-radius: 4px 4px 0 0;
margin-right: 2px;
}
.config-tabs .nav-link:hover,
.config-tabs .nav-link.active {
background-color: #337ab7;
color: white;
border-color: #337ab7;
}
.log-debug { background-color: #d1ecf1; color: #0c5460; }
.log-info { background-color: #bee5eb; color: #0c5460; }
.log-warning { background-color: #fff3cd; color: #856404; }
.log-error { background-color: #f8d7da; color: #721c24; }
.log-critical { background-color: #f5c6cb; color: #721c24; }
.alert { padding: 10px; margin: 10px 0; border-radius: 4px; }
.alert-success { background-color: #d4edda; color: #155724; border: 1px solid #c3e6cb; }
.alert-danger { background-color: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; }
.alert-info { background-color: #d1ecf1; color: #0c5460; border: 1px solid #bee5eb; }
</style>";
Html::footer();

102
front/wazuhserver.form.php Normal file
View File

@@ -0,0 +1,102 @@
<?php
/*
* Plugin SIEM-Wazuh pour GLPI
* Formulaire de gestion des serveurs Wazuh
*/
include ('../../../inc/includes.php');
// Vérification des droits
Session::checkRight("plugin_siem_wazuh_server", READ);
// Vérification du plugin
if (!Plugin::isPluginActive('siem-wazuh')) {
Html::displayNotFoundError();
}
$server = new PluginSiemWazuhServer();
// Traitement des actions du formulaire
if (isset($_POST["add"])) {
$server->check(-1, CREATE, $_POST);
if ($newID = $server->add($_POST)) {
Event::log(
$newID,
"PluginSiemWazuhServer",
4,
"inventory",
sprintf(__('%1$s adds the item %2$s'), $_SESSION["glpiname"], $_POST["name"])
);
if ($_SESSION['glpibackcreated']) {
Html::redirect($server->getLinkURL());
}
}
Html::back();
} elseif (isset($_POST["delete"])) {
$server->check($_POST["id"], DELETE);
if ($server->delete($_POST)) {
Event::log(
$_POST["id"],
"PluginSiemWazuhServer",
4,
"inventory",
sprintf(__('%s deletes an item'), $_SESSION["glpiname"])
);
}
$server->redirectToList();
} elseif (isset($_POST["restore"])) {
$server->check($_POST["id"], DELETE);
if ($server->restore($_POST)) {
Event::log(
$_POST["id"],
"PluginSiemWazuhServer",
4,
"inventory",
sprintf(__('%s restores an item'), $_SESSION["glpiname"])
);
}
$server->redirectToList();
} elseif (isset($_POST["purge"])) {
$server->check($_POST["id"], PURGE);
if ($server->delete($_POST, 1)) {
Event::log(
$_POST["id"],
"PluginSiemWazuhServer",
4,
"inventory",
sprintf(__('%s purges an item'), $_SESSION["glpiname"])
);
}
$server->redirectToList();
} elseif (isset($_POST["update"])) {
$server->check($_POST["id"], UPDATE);
if ($server->update($_POST)) {
Event::log(
$_POST["id"],
"PluginSiemWazuhServer",
4,
"inventory",
sprintf(__('%s updates an item'), $_SESSION["glpiname"])
);
}
Html::back();
} else {
// Affichage du formulaire
$menus = [
'admin' => 'PluginSiemWazuhServer',
'PluginSiemWazuhServer' => 'PluginSiemWazuhServer'
];
PluginSiemWazuhServer::displayFullPageForItem(
$_GET["id"],
$menus,
[
'formoptions' => "method='post' enctype='multipart/form-data'"
]
);
}

172
front/wazuhserver.php Normal file
View File

@@ -0,0 +1,172 @@
<?php
/*
* Plugin SIEM-Wazuh pour GLPI
* Interface de gestion des serveurs Wazuh
*/
include ('../../../inc/includes.php');
// Vérification des droits
Session::checkRight("plugin_siem_wazuh_server", READ);
// Vérification du plugin
if (!Plugin::isPluginActive('siem-wazuh')) {
Html::displayNotFoundError();
}
// Initialisation de l'affichage
Html::header(
PluginSiemWazuhServer::getTypeName(Session::getPluralNumber()),
$_SERVER['PHP_SELF'],
'admin',
'PluginSiemWazuhServer'
);
// Gestion des actions
if (isset($_GET['action'])) {
$server = new PluginSiemWazuhServer();
switch ($_GET['action']) {
case 'test_connection':
if (isset($_GET['id']) && $server->getFromDB($_GET['id'])) {
$result = $server->testConnection();
echo json_encode($result);
exit;
}
break;
case 'sync_alerts':
if (isset($_GET['id']) && $server->getFromDB($_GET['id'])) {
$result = $server->syncAlerts();
echo json_encode($result);
exit;
}
break;
case 'toggle_active':
if (isset($_GET['id']) && $server->getFromDB($_GET['id'])) {
if (Session::haveRight("plugin_siem_wazuh_server", UPDATE)) {
$new_status = $server->fields['is_active'] ? 0 : 1;
$server->update([
'id' => $_GET['id'],
'is_active' => $new_status
]);
Session::addMessageAfterRedirect(
$new_status ? __('Server activated', 'siem-wazuh') : __('Server deactivated', 'siem-wazuh')
);
}
}
Html::back();
break;
}
}
// Initialisation de la recherche
$search = Search::show('PluginSiemWazuhServer');
// Ajout de CSS pour l'interface
echo "<style>
.server-status {
display: inline-block;
padding: 3px 8px;
border-radius: 3px;
font-size: 11px;
font-weight: bold;
}
.server-status.active {
background-color: #5cb85c;
color: white;
}
.server-status.inactive {
background-color: #d9534f;
color: white;
}
.sync-status {
font-size: 11px;
color: #666;
}
.action-buttons {
white-space: nowrap;
}
.action-buttons .btn {
margin: 0 2px;
padding: 2px 6px;
font-size: 11px;
}
</style>";
// Ajout de JavaScript pour les actions AJAX
echo "<script>
function testWazuhConnection(serverId) {
var button = document.querySelector('.test-connection-' + serverId);
var resultDiv = document.getElementById('test-result-' + serverId);
if (button) {
button.disabled = true;
button.innerHTML = '" . __('Testing...', 'siem-wazuh') . "';
}
fetch('?action=test_connection&id=' + serverId)
.then(response => response.json())
.then(data => {
if (resultDiv) {
if (data.success) {
resultDiv.innerHTML = '<div class=\"alert alert-success\">' + data.message + '</div>';
} else {
resultDiv.innerHTML = '<div class=\"alert alert-danger\">' + data.message + '</div>';
}
}
})
.catch(error => {
if (resultDiv) {
resultDiv.innerHTML = '<div class=\"alert alert-danger\">" . __('Connection test failed', 'siem-wazuh') . "</div>';
}
})
.finally(() => {
if (button) {
button.disabled = false;
button.innerHTML = '" . __('Test Connection', 'siem-wazuh') . "';
}
});
}
function syncWazuhAlerts(serverId) {
if (!confirm('" . __('Are you sure you want to synchronize alerts from this server?', 'siem-wazuh') . "')) {
return;
}
var button = document.querySelector('.sync-alerts-' + serverId);
if (button) {
button.disabled = true;
button.innerHTML = '" . __('Synchronizing...', 'siem-wazuh') . "';
}
fetch('?action=sync_alerts&id=' + serverId)
.then(response => response.json())
.then(data => {
if (data.success) {
alert(data.message);
location.reload();
} else {
alert('" . __('Sync failed:', 'siem-wazuh') . " ' + data.message);
}
})
.catch(error => {
alert('" . __('An error occurred during synchronization', 'siem-wazuh') . "');
})
.finally(() => {
if (button) {
button.disabled = false;
button.innerHTML = '" . __('Sync Alerts', 'siem-wazuh') . "';
}
});
}
function toggleServerStatus(serverId) {
if (confirm('" . __('Are you sure you want to change the status of this server?', 'siem-wazuh') . "')) {
window.location.href = '?action=toggle_active&id=' + serverId;
}
}
</script>";
Html::footer();

287
hook.php Normal file
View File

@@ -0,0 +1,287 @@
<?php
/*
* Plugin SIEM-Wazuh pour GLPI
* Hook file for installation/uninstallation
*/
/**
* Plugin install process
*
* @return boolean
*/
function plugin_siem_wazuh_install() {
global $DB;
$version = plugin_version_siem_wazuh();
// Lecture du fichier SQL d'installation
$sql_file = GLPI_ROOT . "/plugins/siem-wazuh/sql/install.sql";
if (!file_exists($sql_file)) {
return false;
}
$sql_content = file_get_contents($sql_file);
$queries = explode(';', $sql_content);
foreach ($queries as $query) {
$query = trim($query);
if (!empty($query)) {
$DB->queryOrDie($query, "Erreur lors de l'installation du plugin SIEM-Wazuh : " . $DB->error());
}
}
// Création des droits par défaut
plugin_siem_wazuh_create_default_rights();
// Création de la tâche cron
plugin_siem_wazuh_create_cron_tasks();
// Configuration par défaut
plugin_siem_wazuh_create_default_config();
return true;
}
/**
* Plugin uninstall process
*
* @return boolean
*/
function plugin_siem_wazuh_uninstall() {
global $DB;
// Lecture du fichier SQL de désinstallation
$sql_file = GLPI_ROOT . "/plugins/siem-wazuh/sql/uninstall.sql";
if (file_exists($sql_file)) {
$sql_content = file_get_contents($sql_file);
$queries = explode(';', $sql_content);
foreach ($queries as $query) {
$query = trim($query);
if (!empty($query)) {
$DB->queryOrDie($query, "Erreur lors de la désinstallation du plugin SIEM-Wazuh : " . $DB->error());
}
}
}
// Suppression des tâches cron
plugin_siem_wazuh_remove_cron_tasks();
// Suppression des droits
plugin_siem_wazuh_remove_rights();
return true;
}
/**
* Plugin update process
*
* @param string $current_version
* @return boolean
*/
function plugin_siem_wazuh_update($current_version) {
global $DB;
// Mise à jour de la version 1.0.0
if (version_compare($current_version, '1.0.0', '<')) {
// Ajout de nouvelles colonnes si nécessaire
$migration = new Migration(PLUGIN_SIEM_WAZUH_VERSION);
// Exemple de migration
if (!$DB->fieldExists('glpi_plugin_siem_wazuh_servers', 'ticket_category')) {
$migration->addField('glpi_plugin_siem_wazuh_servers', 'ticket_category', 'int(11) DEFAULT NULL');
}
$migration->executeMigration();
}
return true;
}
/**
* Create default rights
*/
function plugin_siem_wazuh_create_default_rights() {
global $DB;
$rights = [
'plugin_siem_wazuh_config' => ['name' => __('SIEM Wazuh Configuration', 'siem-wazuh')],
'plugin_siem_wazuh_server' => ['name' => __('Wazuh Servers', 'siem-wazuh')],
'plugin_siem_wazuh_alert' => ['name' => __('Wazuh Alerts', 'siem-wazuh')]
];
foreach ($rights as $right => $data) {
// Ajout du droit s'il n'existe pas
$query = "SELECT id FROM glpi_profilerights WHERE name = '$right'";
$result = $DB->query($query);
if ($DB->numrows($result) == 0) {
$query = "INSERT INTO glpi_profilerights (profiles_id, name, rights)
SELECT id, '$right', '0' FROM glpi_profiles";
$DB->query($query);
// Attribution des droits au profil Super-Admin
$query = "UPDATE glpi_profilerights SET rights = '" . (READ | UPDATE | CREATE | DELETE | PURGE) . "'
WHERE name = '$right' AND profiles_id IN (
SELECT id FROM glpi_profiles WHERE name = 'Super-Admin'
)";
$DB->query($query);
}
}
}
/**
* Remove rights
*/
function plugin_siem_wazuh_remove_rights() {
global $DB;
$rights = [
'plugin_siem_wazuh_config',
'plugin_siem_wazuh_server',
'plugin_siem_wazuh_alert'
];
foreach ($rights as $right) {
$query = "DELETE FROM glpi_profilerights WHERE name = '$right'";
$DB->query($query);
}
}
/**
* Create cron tasks
*/
function plugin_siem_wazuh_create_cron_tasks() {
CronTask::Register('PluginSiemWazuhAlert', 'sync_alerts', 5 * MINUTE_TIMESTAMP, [
'comment' => __('Synchronize Wazuh alerts', 'siem-wazuh'),
'mode' => CronTask::MODE_EXTERNAL
]);
CronTask::Register('PluginSiemWazuhAlert', 'cleanup_old_alerts', DAY_TIMESTAMP, [
'comment' => __('Cleanup old alerts', 'siem-wazuh'),
'mode' => CronTask::MODE_EXTERNAL
]);
}
/**
* Remove cron tasks
*/
function plugin_siem_wazuh_remove_cron_tasks() {
global $DB;
$query = "DELETE FROM glpi_crontasks WHERE itemtype LIKE 'PluginSiemWazuh%'";
$DB->query($query);
}
/**
* Create default configuration
*/
function plugin_siem_wazuh_create_default_config() {
$config = new PluginSiemWazuhConfig();
$default_configs = [
'auto_create_ticket' => '1',
'default_ticket_priority' => '3',
'alert_retention_days' => '90',
'sync_enabled' => '1',
'max_alerts_per_sync' => '100',
'notification_enabled' => '1'
];
foreach ($default_configs as $name => $value) {
$config->setConfiguration($name, $value);
}
}
/**
* Get database relations
*/
function plugin_siem_wazuh_getDatabaseRelations() {
$plugin_relations = [];
$plugin_relations["glpi_plugin_siem_wazuh_alerts"] = [
"glpi_computers" => "computer_id",
"glpi_networkequipments" => "networkequipment_id",
"glpi_tickets" => "ticket_id"
];
return $plugin_relations;
}
/**
* Define dropdown relations
*/
function plugin_siem_wazuh_getDropdown() {
return [
'PluginSiemWazuhServer' => __('Wazuh Servers', 'siem-wazuh')
];
}
/**
* Hook for profile changes
*/
function plugin_siem_wazuh_profile_form($prof) {
global $DB;
if ($prof->getID()
&& Session::haveRight("profile", READ)) {
$prof_id = $prof->getID();
$query = "SELECT * FROM glpi_plugin_siem_wazuh_profiles WHERE profiles_id = '$prof_id'";
$result = $DB->query($query);
if ($DB->numrows($result)) {
$rights = $DB->fetchAssoc($result);
} else {
$rights = [
'wazuh_config' => '',
'wazuh_server' => '',
'wazuh_alert' => ''
];
}
echo "<div class='spaced-form'>";
echo "<table class='tab_cadre_fixehov'>";
echo "<tr class='tab_bg_1'>";
echo "<th colspan='2'>" . __('SIEM Wazuh Rights', 'siem-wazuh') . "</th>";
echo "</tr>";
$right_names = [
'wazuh_config' => __('Configuration', 'siem-wazuh'),
'wazuh_server' => __('Servers', 'siem-wazuh'),
'wazuh_alert' => __('Alerts', 'siem-wazuh')
];
foreach ($right_names as $field => $label) {
echo "<tr class='tab_bg_2'>";
echo "<td>$label</td>";
echo "<td>";
Profile::dropdownNoneReadWrite($field, $rights[$field], 1, 1, 1);
echo "</td>";
echo "</tr>";
}
echo "</table>";
echo "</div>";
}
}
/**
* Save profile rights
*/
function plugin_siem_wazuh_profile_save($prof) {
global $DB;
$prof_id = $prof->getID();
if (isset($_POST['wazuh_config']) || isset($_POST['wazuh_server']) || isset($_POST['wazuh_alert'])) {
$query = "REPLACE INTO glpi_plugin_siem_wazuh_profiles
(profiles_id, wazuh_config, wazuh_server, wazuh_alert)
VALUES ('$prof_id', '" . $_POST['wazuh_config'] . "',
'" . $_POST['wazuh_server'] . "', '" . $_POST['wazuh_alert'] . "')";
$DB->query($query);
}
}

706
inc/wazuhalert.class.php Normal file
View File

@@ -0,0 +1,706 @@
<?php
/*
* Plugin SIEM-Wazuh pour GLPI
* Classe de gestion des alertes Wazuh
*/
if (!defined('GLPI_ROOT')) {
die("Sorry. You can't access this file directly");
}
class PluginSiemWazuhAlert extends CommonDBTM {
public $dohistory = true;
static $rightname = 'plugin_siem_wazuh_alert';
const MATRIX_FIELD = '';
const SEARCHOPTIONS_INHERITANCE = true;
/**
* Return the localized name of the current Type
*/
static function getTypeName($nb = 0) {
return _n('Wazuh Alert', 'Wazuh Alerts', $nb, 'siem-wazuh');
}
/**
* Define search options
*/
function rawSearchOptions() {
$tab = [];
$tab[] = [
'id' => 'common',
'name' => __('Characteristics')
];
$tab[] = [
'id' => '1',
'table' => $this->getTable(),
'field' => 'alert_id',
'name' => __('Alert ID', 'siem-wazuh'),
'datatype' => 'itemlink',
'massiveaction' => false
];
$tab[] = [
'id' => '2',
'table' => 'glpi_plugin_siem_wazuh_servers',
'field' => 'name',
'name' => __('Wazuh Server', 'siem-wazuh'),
'datatype' => 'dropdown',
'massiveaction' => false,
'linkfield' => 'wazuh_server_id'
];
$tab[] = [
'id' => '3',
'table' => $this->getTable(),
'field' => 'rule_id',
'name' => __('Rule ID', 'siem-wazuh'),
'datatype' => 'integer',
'massiveaction' => false
];
$tab[] = [
'id' => '4',
'table' => $this->getTable(),
'field' => 'rule_level',
'name' => __('Rule Level', 'siem-wazuh'),
'datatype' => 'integer',
'massiveaction' => false
];
$tab[] = [
'id' => '5',
'table' => $this->getTable(),
'field' => 'rule_description',
'name' => __('Rule Description', 'siem-wazuh'),
'datatype' => 'text',
'massiveaction' => false
];
$tab[] = [
'id' => '6',
'table' => $this->getTable(),
'field' => 'agent_name',
'name' => __('Agent Name', 'siem-wazuh'),
'datatype' => 'string',
'massiveaction' => false
];
$tab[] = [
'id' => '7',
'table' => $this->getTable(),
'field' => 'agent_ip',
'name' => __('Agent IP', 'siem-wazuh'),
'datatype' => 'string',
'massiveaction' => false
];
$tab[] = [
'id' => '8',
'table' => $this->getTable(),
'field' => 'timestamp',
'name' => __('Alert Timestamp', 'siem-wazuh'),
'datatype' => 'datetime',
'massiveaction' => false
];
$tab[] = [
'id' => '9',
'table' => $this->getTable(),
'field' => 'status',
'name' => __('Status'),
'datatype' => 'specific',
'searchtype' => 'equals',
'massiveaction' => true
];
$tab[] = [
'id' => '10',
'table' => $this->getTable(),
'field' => 'severity',
'name' => __('Severity', 'siem-wazuh'),
'datatype' => 'specific',
'searchtype' => 'equals',
'massiveaction' => true
];
$tab[] = [
'id' => '11',
'table' => 'glpi_computers',
'field' => 'name',
'name' => __('Associated Computer', 'siem-wazuh'),
'datatype' => 'dropdown',
'massiveaction' => false,
'linkfield' => 'computer_id'
];
$tab[] = [
'id' => '12',
'table' => 'glpi_networkequipments',
'field' => 'name',
'name' => __('Associated Network Equipment', 'siem-wazuh'),
'datatype' => 'dropdown',
'massiveaction' => false,
'linkfield' => 'networkequipment_id'
];
$tab[] = [
'id' => '13',
'table' => 'glpi_tickets',
'field' => 'name',
'name' => __('Associated Ticket', 'siem-wazuh'),
'datatype' => 'dropdown',
'massiveaction' => false,
'linkfield' => 'ticket_id'
];
$tab[] = [
'id' => '30',
'table' => $this->getTable(),
'field' => 'date_creation',
'name' => __('Creation date'),
'datatype' => 'datetime',
'massiveaction' => false
];
$tab[] = [
'id' => '31',
'table' => $this->getTable(),
'field' => 'date_mod',
'name' => __('Last update'),
'datatype' => 'datetime',
'massiveaction' => false
];
return $tab;
}
/**
* Display specific values
*/
static function getSpecificValueToDisplay($field, $values, array $options = []) {
if (!is_array($values)) {
$values = [$field => $values];
}
switch ($field) {
case 'status':
$statuses = self::getStatusArray();
return $statuses[$values[$field]] ?? $values[$field];
case 'severity':
$severities = self::getSeverityArray();
return $severities[$values[$field]] ?? $values[$field];
}
return parent::getSpecificValueToDisplay($field, $values, $options);
}
/**
* Get status array
*/
static function getStatusArray() {
return [
'new' => __('New', 'siem-wazuh'),
'processed' => __('Processed', 'siem-wazuh'),
'ignored' => __('Ignored', 'siem-wazuh'),
'ticket_created' => __('Ticket Created', 'siem-wazuh')
];
}
/**
* Get severity array
*/
static function getSeverityArray() {
return [
'low' => __('Low', 'siem-wazuh'),
'medium' => __('Medium', 'siem-wazuh'),
'high' => __('High', 'siem-wazuh'),
'critical' => __('Critical', 'siem-wazuh')
];
}
/**
* Display form
*/
function showForm($ID, $options = []) {
$this->initForm($ID, $options);
$this->showFormHeader($options);
echo "<tr class='tab_bg_1'>";
echo "<td>".__('Alert ID', 'siem-wazuh')."</td>";
echo "<td>".$this->fields["alert_id"]."</td>";
echo "<td>".__('Rule ID', 'siem-wazuh')."</td>";
echo "<td>".$this->fields["rule_id"]."</td>";
echo "</tr>";
echo "<tr class='tab_bg_1'>";
echo "<td>".__('Rule Level', 'siem-wazuh')."</td>";
echo "<td>";
echo $this->fields["rule_level"];
if ($this->fields["rule_level"]) {
$severity = self::getSeverityFromLevel($this->fields["rule_level"]);
$severities = self::getSeverityArray();
echo " <span class='badge severity-$severity'>".$severities[$severity]."</span>";
}
echo "</td>";
echo "<td>".__('Agent Name', 'siem-wazuh')."</td>";
echo "<td>".$this->fields["agent_name"]."</td>";
echo "</tr>";
echo "<tr class='tab_bg_1'>";
echo "<td>".__('Agent IP', 'siem-wazuh')."</td>";
echo "<td>".$this->fields["agent_ip"]."</td>";
echo "<td>".__('Timestamp', 'siem-wazuh')."</td>";
echo "<td>".Html::convDateTime($this->fields["timestamp"])."</td>";
echo "</tr>";
echo "<tr class='tab_bg_1'>";
echo "<td>".__('Status')."</td>";
echo "<td>";
$statuses = self::getStatusArray();
Dropdown::showFromArray('status', $statuses, ['value' => $this->fields["status"]]);
echo "</td>";
echo "<td>".__('Severity', 'siem-wazuh')."</td>";
echo "<td>";
$severities = self::getSeverityArray();
Dropdown::showFromArray('severity', $severities, ['value' => $this->fields["severity"]]);
echo "</td>";
echo "</tr>";
echo "<tr class='tab_bg_1'>";
echo "<td>".__('Rule Description', 'siem-wazuh')."</td>";
echo "<td colspan='3'>";
echo nl2br(Html::entities_deep($this->fields["rule_description"]));
echo "</td>";
echo "</tr>";
// Affichage des associations
if ($this->fields["computer_id"]) {
$computer = new Computer();
$computer->getFromDB($this->fields["computer_id"]);
echo "<tr class='tab_bg_1'>";
echo "<td>".__('Associated Computer')."</td>";
echo "<td>";
echo $computer->getLink();
echo "</td>";
echo "<td></td><td></td>";
echo "</tr>";
}
if ($this->fields["networkequipment_id"]) {
$netequip = new NetworkEquipment();
$netequip->getFromDB($this->fields["networkequipment_id"]);
echo "<tr class='tab_bg_1'>";
echo "<td>".__('Associated Network Equipment')."</td>";
echo "<td>";
echo $netequip->getLink();
echo "</td>";
echo "<td></td><td></td>";
echo "</tr>";
}
if ($this->fields["ticket_id"]) {
$ticket = new Ticket();
$ticket->getFromDB($this->fields["ticket_id"]);
echo "<tr class='tab_bg_1'>";
echo "<td>".__('Associated Ticket')."</td>";
echo "<td>";
echo $ticket->getLink();
echo "</td>";
echo "<td></td><td></td>";
echo "</tr>";
}
// Affichage des données brutes
if (!empty($this->fields["raw_data"])) {
echo "<tr class='tab_bg_1'>";
echo "<td colspan='4'>";
echo "<details>";
echo "<summary>".__('Raw Alert Data', 'siem-wazuh')."</summary>";
echo "<pre class='json-data'>";
echo json_encode(json_decode($this->fields["raw_data"]), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
echo "</pre>";
echo "</details>";
echo "</td>";
echo "</tr>";
}
$this->showFormButtons($options);
return true;
}
/**
* Process alerts from Wazuh API
*/
function processAlerts($server_id, $alerts_data) {
$processed = 0;
$config = new PluginSiemWazuhConfig();
foreach ($alerts_data as $alert_data) {
$alert_id = $alert_data['id'] ?? $alert_data['_id'] ?? null;
if (!$alert_id) continue;
// Vérifier si l'alerte existe déjà
if ($this->getFromDBByCrit([
'wazuh_server_id' => $server_id,
'alert_id' => $alert_id
])) {
continue; // Alerte déjà traitée
}
// Extraire les informations de l'alerte
$rule_id = $alert_data['rule']['id'] ?? null;
$rule_level = $alert_data['rule']['level'] ?? 0;
$rule_description = $alert_data['rule']['description'] ?? '';
$agent_name = $alert_data['agent']['name'] ?? '';
$agent_ip = $alert_data['agent']['ip'] ?? '';
$timestamp = $alert_data['timestamp'] ?? $alert_data['@timestamp'] ?? date('Y-m-d H:i:s');
// Convertir le timestamp au format MySQL
if (strpos($timestamp, 'T') !== false) {
$timestamp = str_replace('T', ' ', substr($timestamp, 0, 19));
}
// Déterminer la sévérité
$severity = self::getSeverityFromLevel($rule_level);
// Créer l'alerte
$alert_input = [
'wazuh_server_id' => $server_id,
'alert_id' => $alert_id,
'rule_id' => $rule_id,
'rule_level' => $rule_level,
'rule_description' => $rule_description,
'agent_id' => $alert_data['agent']['id'] ?? '',
'agent_name' => $agent_name,
'agent_ip' => $agent_ip,
'timestamp' => $timestamp,
'raw_data' => json_encode($alert_data),
'severity' => $severity,
'status' => 'new'
];
// Tenter d'associer avec un asset
$this->associateWithAsset($alert_input, $agent_name, $agent_ip);
if ($alert_id = $this->add($alert_input)) {
$processed++;
// Créer automatiquement un ticket si configuré
if ($config->getConfiguration('auto_create_ticket', 1)) {
$this->createTicketFromAlert($alert_id);
}
}
}
return $processed;
}
/**
* Associate alert with GLPI asset
*/
private function associateWithAsset(&$alert_input, $agent_name, $agent_ip) {
global $DB;
// Recherche par nom d'agent
if (!empty($agent_name)) {
// Recherche dans les ordinateurs
$computer = $DB->request([
'SELECT' => ['id'],
'FROM' => 'glpi_computers',
'WHERE' => [
'name' => $agent_name,
'is_deleted' => 0
],
'LIMIT' => 1
])->current();
if ($computer) {
$alert_input['computer_id'] = $computer['id'];
return;
}
// Recherche dans les équipements réseau
$netequip = $DB->request([
'SELECT' => ['id'],
'FROM' => 'glpi_networkequipments',
'WHERE' => [
'name' => $agent_name,
'is_deleted' => 0
],
'LIMIT' => 1
])->current();
if ($netequip) {
$alert_input['networkequipment_id'] = $netequip['id'];
return;
}
}
// Recherche par adresse IP
if (!empty($agent_ip)) {
// Recherche dans les ports réseau
$port = $DB->request([
'SELECT' => ['items_id', 'itemtype'],
'FROM' => 'glpi_networkports',
'INNER JOIN' => [
'glpi_ipaddresses' => [
'ON' => [
'glpi_networkports' => 'id',
'glpi_ipaddresses' => 'items_id'
]
]
],
'WHERE' => [
'glpi_ipaddresses.name' => $agent_ip,
'glpi_ipaddresses.itemtype' => 'NetworkPort'
],
'LIMIT' => 1
])->current();
if ($port) {
if ($port['itemtype'] == 'Computer') {
$alert_input['computer_id'] = $port['items_id'];
} elseif ($port['itemtype'] == 'NetworkEquipment') {
$alert_input['networkequipment_id'] = $port['items_id'];
}
}
}
}
/**
* Create ticket from alert
*/
function createTicketFromAlert($alert_id) {
if (!$this->getFromDB($alert_id)) {
return false;
}
$server = new PluginSiemWazuhServer();
if (!$server->getFromDB($this->fields['wazuh_server_id'])) {
return false;
}
$ticket = new Ticket();
$config = new PluginSiemWazuhConfig();
// Déterminer la priorité basée sur le niveau de règle
$priority = self::getPriorityFromLevel($this->fields['rule_level']);
$ticket_input = [
'name' => sprintf(__('Wazuh Alert: %s', 'siem-wazuh'), $this->fields['rule_description']),
'content' => $this->generateTicketContent(),
'type' => $server->fields['ticket_type'] ?: 1,
'itilcategories_id' => $server->fields['ticket_category'],
'priority' => $priority,
'urgency' => $priority,
'impact' => $priority,
'status' => CommonITILObject::INCOMING,
'_add_validation' => 0
];
// Associer le ticket à l'asset si trouvé
if ($this->fields['computer_id']) {
$ticket_input['_link']['items_id'] = $this->fields['computer_id'];
$ticket_input['_link']['itemtype'] = 'Computer';
} elseif ($this->fields['networkequipment_id']) {
$ticket_input['_link']['items_id'] = $this->fields['networkequipment_id'];
$ticket_input['_link']['itemtype'] = 'NetworkEquipment';
}
$ticket_id = $ticket->add($ticket_input);
if ($ticket_id) {
// Mettre à jour l'alerte
$this->update([
'id' => $alert_id,
'ticket_id' => $ticket_id,
'status' => 'ticket_created'
]);
return $ticket_id;
}
return false;
}
/**
* Generate ticket content from alert
*/
private function generateTicketContent() {
$content = "[WAZUH-ALERT]\n\n";
$content .= sprintf(__('Alert ID: %s', 'siem-wazuh'), $this->fields['alert_id']) . "\n";
$content .= sprintf(__('Rule ID: %s', 'siem-wazuh'), $this->fields['rule_id']) . "\n";
$content .= sprintf(__('Rule Level: %s', 'siem-wazuh'), $this->fields['rule_level']) . "\n";
$content .= sprintf(__('Agent: %s (%s)', 'siem-wazuh'), $this->fields['agent_name'], $this->fields['agent_ip']) . "\n";
$content .= sprintf(__('Timestamp: %s', 'siem-wazuh'), $this->fields['timestamp']) . "\n\n";
$content .= sprintf(__('Description: %s', 'siem-wazuh'), $this->fields['rule_description']) . "\n\n";
if ($this->fields['raw_data']) {
$content .= __('Raw Alert Data:', 'siem-wazuh') . "\n";
$content .= "```json\n";
$content .= json_encode(json_decode($this->fields['raw_data']), JSON_PRETTY_PRINT);
$content .= "\n```";
}
return $content;
}
/**
* Get severity from rule level
*/
static function getSeverityFromLevel($level) {
if ($level >= 12) return 'critical';
if ($level >= 10) return 'high';
if ($level >= 7) return 'medium';
return 'low';
}
/**
* Get priority from rule level
*/
static function getPriorityFromLevel($level) {
if ($level >= 12) return 5; // Very high
if ($level >= 10) return 4; // High
if ($level >= 7) return 3; // Medium
if ($level >= 5) return 2; // Low
return 1; // Very low
}
/**
* Show alerts for a server
*/
static function showForServer($server_id) {
global $DB;
$iterator = $DB->request([
'FROM' => 'glpi_plugin_siem_wazuh_alerts',
'WHERE' => ['wazuh_server_id' => $server_id],
'ORDER' => 'timestamp DESC',
'LIMIT' => 50
]);
echo "<div class='spaced'>";
echo "<table class='tab_cadre_fixehov'>";
echo "<tr class='tab_bg_2'>";
echo "<th>".__('Alert ID', 'siem-wazuh')."</th>";
echo "<th>".__('Rule', 'siem-wazuh')."</th>";
echo "<th>".__('Level', 'siem-wazuh')."</th>";
echo "<th>".__('Agent', 'siem-wazuh')."</th>";
echo "<th>".__('Timestamp', 'siem-wazuh')."</th>";
echo "<th>".__('Status')."</th>";
echo "<th>".__('Ticket')."</th>";
echo "</tr>";
$statuses = self::getStatusArray();
foreach ($iterator as $row) {
echo "<tr class='tab_bg_1'>";
echo "<td><a href='".PluginSiemWazuhAlert::getFormURLWithID($row['id'])."'>".$row['alert_id']."</a></td>";
echo "<td>".$row['rule_id']." - ".Html::clean($row['rule_description'])."</td>";
echo "<td>".$row['rule_level']."</td>";
echo "<td>".$row['agent_name']." (".$row['agent_ip'].")</td>";
echo "<td>".Html::convDateTime($row['timestamp'])."</td>";
echo "<td>".$statuses[$row['status']]."</td>";
echo "<td>";
if ($row['ticket_id']) {
$ticket = new Ticket();
if ($ticket->getFromDB($row['ticket_id'])) {
echo $ticket->getLink();
}
}
echo "</td>";
echo "</tr>";
}
echo "</table>";
echo "</div>";
}
/**
* Cron function to sync alerts
*/
static function cronSyncAlerts($task = null) {
global $DB;
$config = new PluginSiemWazuhConfig();
if (!$config->getConfiguration('sync_enabled', 1)) {
return 0; // Synchronisation désactivée
}
$iterator = $DB->request([
'FROM' => 'glpi_plugin_siem_wazuh_servers',
'WHERE' => ['is_active' => 1]
]);
$total_processed = 0;
foreach ($iterator as $server_data) {
$server = new PluginSiemWazuhServer();
$server->fields = $server_data;
$result = $server->syncAlerts();
if ($result['success']) {
$matches = [];
if (preg_match('/(\d+)/', $result['message'], $matches)) {
$total_processed += (int)$matches[1];
}
}
}
if ($task) {
$task->addVolume($total_processed);
return 1;
}
return $total_processed;
}
/**
* Cron function to cleanup old alerts
*/
static function cronCleanupOldAlerts($task = null) {
global $DB;
$config = new PluginSiemWazuhConfig();
$retention_days = $config->getConfiguration('alert_retention_days', 90);
$query = "DELETE FROM glpi_plugin_siem_wazuh_alerts
WHERE date_creation < DATE_SUB(NOW(), INTERVAL $retention_days DAY)";
$result = $DB->query($query);
$deleted = $DB->affectedRows();
if ($task) {
$task->addVolume($deleted);
return 1;
}
return $deleted;
}
/**
* Get menu content
*/
static function getMenuContent() {
$menu = [];
if (Session::haveRight(static::$rightname, READ)) {
$menu['title'] = self::getMenuName();
$menu['page'] = "/plugins/siem-wazuh/front/wazuhalert.php";
$menu['links']['search'] = "/plugins/siem-wazuh/front/wazuhalert.php";
}
return $menu;
}
/**
* Get menu name
*/
static function getMenuName() {
return self::getTypeName(Session::getPluralNumber());
}
}

515
inc/wazuhapi.class.php Normal file
View File

@@ -0,0 +1,515 @@
<?php
/*
* Plugin SIEM-Wazuh pour GLPI
* Classe de gestion de l'API Wazuh
*/
if (!defined('GLPI_ROOT')) {
die("Sorry. You can't access this file directly");
}
class PluginSiemWazuhAPI {
private $server;
private $token;
private $config;
const API_VERSION = 'v1';
const TIMEOUT = 30;
const MAX_RETRIES = 3;
/**
* Constructor
*/
public function __construct(PluginSiemWazuhServer $server) {
$this->server = $server;
$this->config = new PluginSiemWazuhConfig();
}
/**
* Test connection to Wazuh server
*/
public function testConnection() {
try {
$result = $this->authenticate();
if ($result['success']) {
// Test basic API call
$info = $this->makeRequest('GET', '/');
if ($info['success']) {
return [
'success' => true,
'message' => __('Connection successful', 'siem-wazuh'),
'data' => $info['data']
];
} else {
return [
'success' => false,
'message' => __('Connection failed:', 'siem-wazuh') . ' ' . $info['message']
];
}
} else {
return [
'success' => false,
'message' => __('Authentication failed:', 'siem-wazuh') . ' ' . $result['message']
];
}
} catch (Exception $e) {
return [
'success' => false,
'message' => __('Connection error:', 'siem-wazuh') . ' ' . $e->getMessage()
];
}
}
/**
* Authenticate with Wazuh API
*/
private function authenticate() {
if (!empty($this->token)) {
return ['success' => true, 'token' => $this->token];
}
$url = rtrim($this->server->fields['wazuh_url'], '/') . ':' . $this->server->fields['wazuh_port'] . '/security/user/authenticate';
$credentials = base64_encode($this->server->fields['wazuh_login'] . ':' . $this->server->getPassword());
$headers = [
'Authorization: Basic ' . $credentials,
'Content-Type: application/json'
];
try {
$response = $this->httpRequest('POST', $url, null, $headers);
if ($response['success'] && isset($response['data']['data']['token'])) {
$this->token = $response['data']['data']['token'];
return ['success' => true, 'token' => $this->token];
} else {
return [
'success' => false,
'message' => $response['message'] ?? __('Authentication failed', 'siem-wazuh')
];
}
} catch (Exception $e) {
return [
'success' => false,
'message' => $e->getMessage()
];
}
}
/**
* Get alerts from Wazuh
*/
public function getAlerts($params = []) {
$auth_result = $this->authenticate();
if (!$auth_result['success']) {
return $auth_result;
}
$default_params = [
'offset' => 0,
'limit' => $this->config->getConfiguration('max_alerts_per_sync', 100),
'sort' => '-timestamp',
'rule.level' => '>=' . $this->config->getConfiguration('min_rule_level', 5)
];
// Merge with provided parameters
$params = array_merge($default_params, $params);
// Construire l'URL avec les paramètres
$query_string = http_build_query($params);
$endpoint = '/alerts?' . $query_string;
return $this->makeRequest('GET', $endpoint);
}
/**
* Get alert by ID
*/
public function getAlert($alert_id) {
$auth_result = $this->authenticate();
if (!$auth_result['success']) {
return $auth_result;
}
return $this->makeRequest('GET', '/alerts/' . $alert_id);
}
/**
* Get agents
*/
public function getAgents($params = []) {
$auth_result = $this->authenticate();
if (!$auth_result['success']) {
return $auth_result;
}
$default_params = [
'offset' => 0,
'limit' => 500,
'sort' => '+name'
];
$params = array_merge($default_params, $params);
$query_string = http_build_query($params);
$endpoint = '/agents?' . $query_string;
return $this->makeRequest('GET', $endpoint);
}
/**
* Get agent by ID
*/
public function getAgent($agent_id) {
$auth_result = $this->authenticate();
if (!$auth_result['success']) {
return $auth_result;
}
return $this->makeRequest('GET', '/agents/' . $agent_id);
}
/**
* Get rules
*/
public function getRules($params = []) {
$auth_result = $this->authenticate();
if (!$auth_result['success']) {
return $auth_result;
}
$default_params = [
'offset' => 0,
'limit' => 500,
'sort' => '+id'
];
$params = array_merge($default_params, $params);
$query_string = http_build_query($params);
$endpoint = '/rules?' . $query_string;
return $this->makeRequest('GET', $endpoint);
}
/**
* Get decoders
*/
public function getDecoders($params = []) {
$auth_result = $this->authenticate();
if (!$auth_result['success']) {
return $auth_result;
}
$default_params = [
'offset' => 0,
'limit' => 500
];
$params = array_merge($default_params, $params);
$query_string = http_build_query($params);
$endpoint = '/decoders?' . $query_string;
return $this->makeRequest('GET', $endpoint);
}
/**
* Get cluster status
*/
public function getClusterStatus() {
$auth_result = $this->authenticate();
if (!$auth_result['success']) {
return $auth_result;
}
return $this->makeRequest('GET', '/cluster/status');
}
/**
* Get manager information
*/
public function getManagerInfo() {
$auth_result = $this->authenticate();
if (!$auth_result['success']) {
return $auth_result;
}
return $this->makeRequest('GET', '/manager/info');
}
/**
* Make API request
*/
private function makeRequest($method, $endpoint, $data = null, $extra_headers = []) {
if (!$this->token) {
$auth_result = $this->authenticate();
if (!$auth_result['success']) {
return $auth_result;
}
}
$url = rtrim($this->server->fields['wazuh_url'], '/') . ':' . $this->server->fields['wazuh_port'] . $endpoint;
$headers = array_merge([
'Authorization: Bearer ' . $this->token,
'Content-Type: application/json'
], $extra_headers);
return $this->httpRequest($method, $url, $data, $headers);
}
/**
* Make HTTP request with retry logic
*/
private function httpRequest($method, $url, $data = null, $headers = []) {
$retries = 0;
$last_error = null;
while ($retries < self::MAX_RETRIES) {
try {
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => self::TIMEOUT,
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_USERAGENT => 'GLPI-SIEM-Wazuh-Plugin/1.0'
]);
if ($data !== null) {
curl_setopt($ch, CURLOPT_POSTFIELDS, is_array($data) ? json_encode($data) : $data);
}
// Logging for debug mode
if ($this->config->getConfiguration('debug_mode', 0)) {
$this->logDebug("HTTP Request: $method $url", [
'headers' => $headers,
'data' => $data,
'retry' => $retries
]);
}
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$curl_error = curl_error($ch);
curl_close($ch);
if ($response === false) {
throw new Exception("cURL Error: $curl_error");
}
$decoded_response = json_decode($response, true);
if ($this->config->getConfiguration('debug_mode', 0)) {
$this->logDebug("HTTP Response: $http_code", [
'response' => $decoded_response,
'raw_response' => substr($response, 0, 1000)
]);
}
if ($http_code >= 200 && $http_code < 300) {
return [
'success' => true,
'data' => $decoded_response,
'http_code' => $http_code
];
} elseif ($http_code == 401) {
// Token expired, clear it and retry authentication
$this->token = null;
if ($retries < self::MAX_RETRIES - 1) {
$retries++;
continue;
}
}
$error_message = "HTTP $http_code";
if ($decoded_response && isset($decoded_response['detail'])) {
$error_message .= ": " . $decoded_response['detail'];
} elseif ($decoded_response && isset($decoded_response['message'])) {
$error_message .= ": " . $decoded_response['message'];
}
throw new Exception($error_message);
} catch (Exception $e) {
$last_error = $e;
$retries++;
if ($retries < self::MAX_RETRIES) {
sleep(pow(2, $retries)); // Exponential backoff
continue;
}
$this->logError("HTTP Request failed after $retries retries", [
'url' => $url,
'method' => $method,
'error' => $e->getMessage()
]);
break;
}
}
return [
'success' => false,
'message' => $last_error ? $last_error->getMessage() : __('Request failed after maximum retries', 'siem-wazuh')
];
}
/**
* Query Wazuh Indexer (OpenSearch/Elasticsearch)
*/
public function queryIndexer($index, $query = [], $params = []) {
if (empty($this->server->fields['indexer_url'])) {
return [
'success' => false,
'message' => __('Indexer not configured', 'siem-wazuh')
];
}
$url = rtrim($this->server->fields['indexer_url'], '/') . ':' . $this->server->fields['indexer_port'] . '/' . $index . '/_search';
$headers = [
'Content-Type: application/json'
];
if (!empty($this->server->fields['indexer_login'])) {
$credentials = base64_encode($this->server->fields['indexer_login'] . ':' . $this->server->getPassword('indexer_password'));
$headers[] = 'Authorization: Basic ' . $credentials;
}
$default_query = [
'size' => $this->config->getConfiguration('max_alerts_per_sync', 100),
'sort' => [
['timestamp' => ['order' => 'desc']]
]
];
$final_query = array_merge($default_query, $query);
return $this->httpRequest('POST', $url, $final_query, $headers);
}
/**
* Get recent alerts from indexer
*/
public function getRecentAlertsFromIndexer($minutes = 60) {
$query = [
'query' => [
'bool' => [
'must' => [
[
'range' => [
'timestamp' => [
'gte' => 'now-' . $minutes . 'm',
'lt' => 'now'
]
]
]
]
]
]
];
$min_level = $this->config->getConfiguration('min_rule_level', 5);
if ($min_level > 0) {
$query['query']['bool']['must'][] = [
'range' => [
'rule.level' => [
'gte' => $min_level
]
]
];
}
return $this->queryIndexer('wazuh-alerts-*', $query);
}
/**
* Log debug message
*/
private function logDebug($message, $context = []) {
if ($this->config->getConfiguration('debug_mode', 0)) {
$this->log('debug', $message, $context);
}
}
/**
* Log error message
*/
private function logError($message, $context = []) {
$this->log('error', $message, $context);
}
/**
* Log message
*/
private function log($level, $message, $context = []) {
global $DB;
$log_levels = ['debug', 'info', 'warning', 'error', 'critical'];
$current_log_level = $this->config->getConfiguration('log_level', 'info');
$current_level_index = array_search($current_log_level, $log_levels);
$message_level_index = array_search($level, $log_levels);
// Only log if message level is equal or higher than configured level
if ($message_level_index >= $current_level_index) {
try {
$DB->insert('glpi_plugin_siem_wazuh_logs', [
'wazuh_server_id' => $this->server->getID(),
'level' => $level,
'message' => $message,
'context' => json_encode($context),
'date_creation' => $_SESSION['glpi_currenttime']
]);
} catch (Exception $e) {
// Ignore logging errors to prevent recursion
error_log("SIEM-Wazuh Plugin: Failed to log message - " . $e->getMessage());
}
}
}
/**
* Get API statistics
*/
public function getStatistics() {
global $DB;
$stats = [];
// Requests count by server
$iterator = $DB->request([
'SELECT' => ['COUNT' => '* as count'],
'FROM' => 'glpi_plugin_siem_wazuh_logs',
'WHERE' => [
'wazuh_server_id' => $this->server->getID(),
'date_creation' => ['>=', date('Y-m-d 00:00:00')]
]
]);
$stats['requests_today'] = $iterator->current()['count'];
// Error rate
$iterator = $DB->request([
'SELECT' => ['COUNT' => '* as count'],
'FROM' => 'glpi_plugin_siem_wazuh_logs',
'WHERE' => [
'wazuh_server_id' => $this->server->getID(),
'level' => ['IN', ['error', 'critical']],
'date_creation' => ['>=', date('Y-m-d 00:00:00')]
]
]);
$stats['errors_today'] = $iterator->current()['count'];
$stats['error_rate'] = $stats['requests_today'] > 0 ?
round(($stats['errors_today'] / $stats['requests_today']) * 100, 2) : 0;
return $stats;
}
}

423
inc/wazuhconfig.class.php Normal file
View File

@@ -0,0 +1,423 @@
<?php
/*
* Plugin SIEM-Wazuh pour GLPI
* Classe de gestion de la configuration
*/
if (!defined('GLPI_ROOT')) {
die("Sorry. You can't access this file directly");
}
class PluginSiemWazuhConfig extends CommonDBTM {
public $dohistory = true;
static $rightname = 'plugin_siem_wazuh_config';
const MATRIX_FIELD = '';
const SEARCHOPTIONS_INHERITANCE = true;
/**
* Return the localized name of the current Type
*/
static function getTypeName($nb = 0) {
return __('SIEM Wazuh Configuration', 'siem-wazuh');
}
/**
* Get configuration value
*/
function getConfiguration($name, $default = null, $context = 'global') {
global $DB;
$iterator = $DB->request([
'FROM' => $this->getTable(),
'WHERE' => [
'name' => $name,
'context' => $context
],
'LIMIT' => 1
]);
if (count($iterator) > 0) {
$row = $iterator->current();
return $row['value'];
}
return $default;
}
/**
* Set configuration value
*/
function setConfiguration($name, $value, $context = 'global') {
global $DB;
// Vérifier si la configuration existe
$iterator = $DB->request([
'FROM' => $this->getTable(),
'WHERE' => [
'name' => $name,
'context' => $context
],
'LIMIT' => 1
]);
if (count($iterator) > 0) {
// Mettre à jour
$row = $iterator->current();
return $this->update([
'id' => $row['id'],
'value' => $value
]);
} else {
// Créer
return $this->add([
'name' => $name,
'value' => $value,
'context' => $context
]);
}
}
/**
* Display configuration form
*/
function showConfigForm() {
global $CFG_GLPI;
echo "<form name='form' method='post' action='" . Toolbox::getItemTypeFormURL(__CLASS__) . "'>";
echo "<div class='spaced' id='tabsbody'>";
echo "<table class='tab_cadre_fixe'>";
echo "<tr><th colspan='4'>" . __('General Configuration', 'siem-wazuh') . "</th></tr>";
// Configuration générale
echo "<tr class='tab_bg_1'>";
echo "<td width='30%'>" . __('Enable synchronization', 'siem-wazuh') . "</td>";
echo "<td width='20%'>";
Dropdown::showYesNo("sync_enabled", $this->getConfiguration('sync_enabled', 1));
echo "</td>";
echo "<td width='30%'>" . __('Auto-create tickets', 'siem-wazuh') . "</td>";
echo "<td width='20%'>";
Dropdown::showYesNo("auto_create_ticket", $this->getConfiguration('auto_create_ticket', 1));
echo "</td>";
echo "</tr>";
echo "<tr class='tab_bg_1'>";
echo "<td>" . __('Maximum alerts per sync', 'siem-wazuh') . "</td>";
echo "<td>";
Dropdown::showNumber("max_alerts_per_sync", [
'value' => $this->getConfiguration('max_alerts_per_sync', 100),
'min' => 10,
'max' => 1000,
'step' => 10
]);
echo "</td>";
echo "<td>" . __('Alert retention (days)', 'siem-wazuh') . "</td>";
echo "<td>";
Dropdown::showNumber("alert_retention_days", [
'value' => $this->getConfiguration('alert_retention_days', 90),
'min' => 7,
'max' => 365,
'step' => 7
]);
echo "</td>";
echo "</tr>";
echo "<tr class='tab_bg_1'>";
echo "<td>" . __('Minimum rule level', 'siem-wazuh') . "</td>";
echo "<td>";
Dropdown::showNumber("min_rule_level", [
'value' => $this->getConfiguration('min_rule_level', 5),
'min' => 0,
'max' => 15
]);
echo "</td>";
echo "<td>" . __('Enable notifications', 'siem-wazuh') . "</td>";
echo "<td>";
Dropdown::showYesNo("notification_enabled", $this->getConfiguration('notification_enabled', 1));
echo "</td>";
echo "</tr>";
// Configuration des tickets par défaut
echo "<tr><th colspan='4'>" . __('Default Ticket Settings', 'siem-wazuh') . "</th></tr>";
echo "<tr class='tab_bg_1'>";
echo "<td>" . __('Default Priority', 'siem-wazuh') . "</td>";
echo "<td>";
Ticket::dropdownPriority('default_ticket_priority', $this->getConfiguration('default_ticket_priority', 3));
echo "</td>";
echo "<td>" . __('Default Urgency', 'siem-wazuh') . "</td>";
echo "<td>";
Ticket::dropdownUrgency('default_ticket_urgency', $this->getConfiguration('default_ticket_urgency', 3));
echo "</td>";
echo "</tr>";
echo "<tr class='tab_bg_1'>";
echo "<td>" . __('Default Impact', 'siem-wazuh') . "</td>";
echo "<td>";
Ticket::dropdownImpact('default_ticket_impact', $this->getConfiguration('default_ticket_impact', 3));
echo "</td>";
echo "<td>" . __('Auto-assign tickets', 'siem-wazuh') . "</td>";
echo "<td>";
Dropdown::showYesNo("auto_assign_tickets", $this->getConfiguration('auto_assign_tickets', 0));
echo "</td>";
echo "</tr>";
if ($this->getConfiguration('auto_assign_tickets', 0)) {
echo "<tr class='tab_bg_1'>";
echo "<td>" . __('Default Assignee', 'siem-wazuh') . "</td>";
echo "<td>";
User::dropdown([
'name' => 'default_assignee',
'value' => $this->getConfiguration('default_assignee', 0),
'right' => 'own_ticket'
]);
echo "</td>";
echo "<td>" . __('Default Group', 'siem-wazuh') . "</td>";
echo "<td>";
Group::dropdown([
'name' => 'default_group',
'value' => $this->getConfiguration('default_group', 0)
]);
echo "</td>";
echo "</tr>";
}
// Configuration de mapping
echo "<tr><th colspan='4'>" . __('Asset Mapping Configuration', 'siem-wazuh') . "</th></tr>";
echo "<tr class='tab_bg_1'>";
echo "<td>" . __('Match by hostname', 'siem-wazuh') . "</td>";
echo "<td>";
Dropdown::showYesNo("match_by_hostname", $this->getConfiguration('match_by_hostname', 1));
echo "</td>";
echo "<td>" . __('Match by IP address', 'siem-wazuh') . "</td>";
echo "<td>";
Dropdown::showYesNo("match_by_ip", $this->getConfiguration('match_by_ip', 1));
echo "</td>";
echo "</tr>";
echo "<tr class='tab_bg_1'>";
echo "<td>" . __('Case sensitive matching', 'siem-wazuh') . "</td>";
echo "<td>";
Dropdown::showYesNo("case_sensitive_matching", $this->getConfiguration('case_sensitive_matching', 0));
echo "</td>";
echo "<td>" . __('Create unknown assets', 'siem-wazuh') . "</td>";
echo "<td>";
Dropdown::showYesNo("create_unknown_assets", $this->getConfiguration('create_unknown_assets', 0));
echo "</td>";
echo "</tr>";
// Configuration de debug
echo "<tr><th colspan='4'>" . __('Debug Configuration', 'siem-wazuh') . "</th></tr>";
echo "<tr class='tab_bg_1'>";
echo "<td>" . __('Enable debug mode', 'siem-wazuh') . "</td>";
echo "<td>";
Dropdown::showYesNo("debug_mode", $this->getConfiguration('debug_mode', 0));
echo "</td>";
echo "<td>" . __('Log level', 'siem-wazuh') . "</td>";
echo "<td>";
$log_levels = [
'error' => __('Error only', 'siem-wazuh'),
'warning' => __('Warning and above', 'siem-wazuh'),
'info' => __('Info and above', 'siem-wazuh'),
'debug' => __('All messages', 'siem-wazuh')
];
Dropdown::showFromArray('log_level', $log_levels, [
'value' => $this->getConfiguration('log_level', 'info')
]);
echo "</td>";
echo "</tr>";
echo "<tr class='tab_bg_1'>";
echo "<td>" . __('Keep debug logs (days)', 'siem-wazuh') . "</td>";
echo "<td>";
Dropdown::showNumber("debug_retention_days", [
'value' => $this->getConfiguration('debug_retention_days', 30),
'min' => 1,
'max' => 90
]);
echo "</td>";
echo "<td></td><td></td>";
echo "</tr>";
echo "<tr class='tab_bg_2'>";
echo "<td class='center' colspan='4'>";
echo "<input type='submit' name='update_config' value='" . _sx('button', 'Save') . "' class='submit'>";
echo "</td>";
echo "</tr>";
echo "</table>";
echo "</div>";
Html::closeForm();
// Affichage des statistiques
$this->showStatistics();
}
/**
* Process configuration form
*/
function processConfigForm() {
if (isset($_POST['update_config'])) {
$config_fields = [
'sync_enabled', 'auto_create_ticket', 'max_alerts_per_sync', 'alert_retention_days',
'min_rule_level', 'notification_enabled', 'default_ticket_priority',
'default_ticket_urgency', 'default_ticket_impact', 'auto_assign_tickets',
'default_assignee', 'default_group', 'match_by_hostname', 'match_by_ip',
'case_sensitive_matching', 'create_unknown_assets', 'debug_mode',
'log_level', 'debug_retention_days'
];
foreach ($config_fields as $field) {
if (isset($_POST[$field])) {
$this->setConfiguration($field, $_POST[$field]);
}
}
Session::addMessageAfterRedirect(__('Configuration updated successfully', 'siem-wazuh'));
Html::back();
}
}
/**
* Show statistics
*/
function showStatistics() {
global $DB;
echo "<div class='spaced'>";
echo "<table class='tab_cadre_fixe'>";
echo "<tr><th colspan='4'>" . __('Statistics', 'siem-wazuh') . "</th></tr>";
// Statistiques des serveurs
$servers_count = countElementsInTable('glpi_plugin_siem_wazuh_servers');
$active_servers = countElementsInTable('glpi_plugin_siem_wazuh_servers', ['is_active' => 1]);
echo "<tr class='tab_bg_1'>";
echo "<td>" . __('Total servers', 'siem-wazuh') . "</td>";
echo "<td>$servers_count</td>";
echo "<td>" . __('Active servers', 'siem-wazuh') . "</td>";
echo "<td>$active_servers</td>";
echo "</tr>";
// Statistiques des alertes
$total_alerts = countElementsInTable('glpi_plugin_siem_wazuh_alerts');
$new_alerts = countElementsInTable('glpi_plugin_siem_wazuh_alerts', ['status' => 'new']);
$processed_alerts = countElementsInTable('glpi_plugin_siem_wazuh_alerts', ['status' => 'processed']);
$tickets_created = countElementsInTable('glpi_plugin_siem_wazuh_alerts', ['status' => 'ticket_created']);
echo "<tr class='tab_bg_1'>";
echo "<td>" . __('Total alerts', 'siem-wazuh') . "</td>";
echo "<td>$total_alerts</td>";
echo "<td>" . __('New alerts', 'siem-wazuh') . "</td>";
echo "<td>$new_alerts</td>";
echo "</tr>";
echo "<tr class='tab_bg_1'>";
echo "<td>" . __('Processed alerts', 'siem-wazuh') . "</td>";
echo "<td>$processed_alerts</td>";
echo "<td>" . __('Tickets created', 'siem-wazuh') . "</td>";
echo "<td>$tickets_created</td>";
echo "</tr>";
// Alertes par sévérité
$severities = PluginSiemWazuhAlert::getSeverityArray();
foreach ($severities as $severity => $label) {
$count = countElementsInTable('glpi_plugin_siem_wazuh_alerts', ['severity' => $severity]);
echo "<tr class='tab_bg_1'>";
echo "<td>" . sprintf(__('%s alerts', 'siem-wazuh'), $label) . "</td>";
echo "<td>$count</td>";
if (next($severities) !== false) {
$next_severity = key($severities);
$next_label = current($severities);
$next_count = countElementsInTable('glpi_plugin_siem_wazuh_alerts', ['severity' => $next_severity]);
echo "<td>" . sprintf(__('%s alerts', 'siem-wazuh'), $next_label) . "</td>";
echo "<td>$next_count</td>";
next($severities);
} else {
echo "<td></td><td></td>";
}
echo "</tr>";
}
// Dernière synchronisation
$last_sync = $DB->request([
'SELECT' => ['MAX' => 'last_sync AS last_sync'],
'FROM' => 'glpi_plugin_siem_wazuh_servers',
'WHERE' => ['is_active' => 1]
])->current();
echo "<tr class='tab_bg_1'>";
echo "<td>" . __('Last global sync', 'siem-wazuh') . "</td>";
echo "<td colspan='3'>";
echo $last_sync['last_sync'] ? Html::convDateTime($last_sync['last_sync']) : __('Never');
echo "</td>";
echo "</tr>";
echo "</table>";
echo "</div>";
}
/**
* Get menu content
*/
static function getMenuContent() {
$menu = [];
if (Session::haveRight(static::$rightname, READ)) {
$menu['title'] = self::getMenuName();
$menu['page'] = "/plugins/siem-wazuh/front/wazuhconfig.php";
$menu['links']['config'] = "/plugins/siem-wazuh/front/wazuhconfig.php";
}
return $menu;
}
/**
* Get menu name
*/
static function getMenuName() {
return self::getTypeName(1);
}
/**
* Get default configurations
*/
static function getDefaultConfigurations() {
return [
'sync_enabled' => 1,
'auto_create_ticket' => 1,
'max_alerts_per_sync' => 100,
'alert_retention_days' => 90,
'min_rule_level' => 5,
'notification_enabled' => 1,
'default_ticket_priority' => 3,
'default_ticket_urgency' => 3,
'default_ticket_impact' => 3,
'auto_assign_tickets' => 0,
'default_assignee' => 0,
'default_group' => 0,
'match_by_hostname' => 1,
'match_by_ip' => 1,
'case_sensitive_matching' => 0,
'create_unknown_assets' => 0,
'debug_mode' => 0,
'log_level' => 'info',
'debug_retention_days' => 30
];
}
/**
* Install default configuration
*/
static function installDefaultConfiguration() {
$config = new self();
$defaults = self::getDefaultConfigurations();
foreach ($defaults as $name => $value) {
$config->setConfiguration($name, $value);
}
}
}

411
inc/wazuhserver.class.php Normal file
View File

@@ -0,0 +1,411 @@
<?php
/*
* Plugin SIEM-Wazuh pour GLPI
* Classe de gestion des serveurs Wazuh
*/
if (!defined('GLPI_ROOT')) {
die("Sorry. You can't access this file directly");
}
class PluginSiemWazuhServer extends CommonDBTM {
public $dohistory = true;
static protected $forward_entity_to = ['PluginSiemWazuhAlert'];
static $rightname = 'plugin_siem_wazuh_server';
const MATRIX_FIELD = '';
const SEARCHOPTIONS_INHERITANCE = true;
/**
* Return the localized name of the current Type
*/
static function getTypeName($nb = 0) {
return _n('Wazuh Server', 'Wazuh Servers', $nb, 'siem-wazuh');
}
/**
* Define tab name
*/
function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) {
if (!$withtemplate) {
$nb = 0;
switch ($item->getType()) {
case 'PluginSiemWazuhServer':
if ($_SESSION['glpishow_count_on_tabs']) {
$nb = countElementsInTable('glpi_plugin_siem_wazuh_alerts',
"`wazuh_server_id` = '".$item->getID()."'");
}
return self::createTabEntry(__('Alerts', 'siem-wazuh'), $nb);
}
}
return '';
}
/**
* Display tab content
*/
static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $withtemplate = 0) {
if ($item->getType() == 'PluginSiemWazuhServer') {
PluginSiemWazuhAlert::showForServer($item->getID());
}
return true;
}
/**
* Define search options
*/
function rawSearchOptions() {
$tab = [];
$tab[] = [
'id' => 'common',
'name' => __('Characteristics')
];
$tab[] = [
'id' => '1',
'table' => $this->getTable(),
'field' => 'name',
'name' => __('Name'),
'datatype' => 'itemlink',
'massiveaction' => false
];
$tab[] = [
'id' => '2',
'table' => $this->getTable(),
'field' => 'wazuh_url',
'name' => __('Wazuh URL', 'siem-wazuh'),
'datatype' => 'string',
'massiveaction' => false
];
$tab[] = [
'id' => '3',
'table' => $this->getTable(),
'field' => 'wazuh_port',
'name' => __('Wazuh Port', 'siem-wazuh'),
'datatype' => 'integer',
'massiveaction' => false
];
$tab[] = [
'id' => '4',
'table' => $this->getTable(),
'field' => 'is_active',
'name' => __('Active'),
'datatype' => 'bool',
'massiveaction' => true
];
$tab[] = [
'id' => '5',
'table' => $this->getTable(),
'field' => 'sync_interval',
'name' => __('Sync Interval (seconds)', 'siem-wazuh'),
'datatype' => 'integer',
'massiveaction' => false
];
$tab[] = [
'id' => '6',
'table' => $this->getTable(),
'field' => 'last_sync',
'name' => __('Last Sync', 'siem-wazuh'),
'datatype' => 'datetime',
'massiveaction' => false
];
$tab[] = [
'id' => '7',
'table' => 'glpi_itilcategories',
'field' => 'name',
'name' => __('Default Ticket Category', 'siem-wazuh'),
'datatype' => 'dropdown',
'massiveaction' => false,
'linkfield' => 'ticket_category'
];
$tab[] = [
'id' => '30',
'table' => $this->getTable(),
'field' => 'date_creation',
'name' => __('Creation date'),
'datatype' => 'datetime',
'massiveaction' => false
];
$tab[] = [
'id' => '31',
'table' => $this->getTable(),
'field' => 'date_mod',
'name' => __('Last update'),
'datatype' => 'datetime',
'massiveaction' => false
];
return $tab;
}
/**
* Display form
*/
function showForm($ID, $options = []) {
$this->initForm($ID, $options);
$this->showFormHeader($options);
echo "<tr class='tab_bg_1'>";
echo "<td>".__('Name')."</td>";
echo "<td>";
Html::autocompletionTextField($this, "name", ['size' => 50]);
echo "</td>";
echo "<td>".__('Active')."</td>";
echo "<td>";
Dropdown::showYesNo("is_active", $this->fields["is_active"]);
echo "</td>";
echo "</tr>";
echo "<tr class='tab_bg_1'>";
echo "<td>".__('Wazuh Server URL', 'siem-wazuh')."</td>";
echo "<td>";
Html::autocompletionTextField($this, "wazuh_url", ['size' => 50, 'placeholder' => 'https://wazuh-server.domain.com']);
echo "</td>";
echo "<td>".__('Wazuh API Port', 'siem-wazuh')."</td>";
echo "<td>";
Html::autocompletionTextField($this, "wazuh_port", ['size' => 10, 'value' => ($this->fields["wazuh_port"] ?: 55000)]);
echo "</td>";
echo "</tr>";
echo "<tr class='tab_bg_1'>";
echo "<td>".__('Wazuh API Login', 'siem-wazuh')."</td>";
echo "<td>";
Html::autocompletionTextField($this, "wazuh_login", ['size' => 30]);
echo "</td>";
echo "<td>".__('Wazuh API Password', 'siem-wazuh')."</td>";
echo "<td>";
echo "<input type='password' name='wazuh_password' value='' size='30' autocomplete='new-password'>";
if (!empty($this->fields["wazuh_password"])) {
echo "<br><small>".__('Leave empty to keep current password', 'siem-wazuh')."</small>";
}
echo "</td>";
echo "</tr>";
echo "<tr class='tab_bg_1'>";
echo "<td>".__('Indexer Server URL', 'siem-wazuh')."</td>";
echo "<td>";
Html::autocompletionTextField($this, "indexer_url", ['size' => 50, 'placeholder' => 'https://wazuh-indexer.domain.com']);
echo "</td>";
echo "<td>".__('Indexer API Port', 'siem-wazuh')."</td>";
echo "<td>";
Html::autocompletionTextField($this, "indexer_port", ['size' => 10, 'value' => ($this->fields["indexer_port"] ?: 9200)]);
echo "</td>";
echo "</tr>";
echo "<tr class='tab_bg_1'>";
echo "<td>".__('Indexer API Login', 'siem-wazuh')."</td>";
echo "<td>";
Html::autocompletionTextField($this, "indexer_login", ['size' => 30]);
echo "</td>";
echo "<td>".__('Indexer API Password', 'siem-wazuh')."</td>";
echo "<td>";
echo "<input type='password' name='indexer_password' value='' size='30' autocomplete='new-password'>";
if (!empty($this->fields["indexer_password"])) {
echo "<br><small>".__('Leave empty to keep current password', 'siem-wazuh')."</small>";
}
echo "</td>";
echo "</tr>";
echo "<tr class='tab_bg_1'>";
echo "<td>".__('Sync Interval (seconds)', 'siem-wazuh')."</td>";
echo "<td>";
Html::autocompletionTextField($this, "sync_interval", ['size' => 10, 'value' => ($this->fields["sync_interval"] ?: 300)]);
echo "</td>";
echo "<td>".__('Default Ticket Type', 'siem-wazuh')."</td>";
echo "<td>";
Ticket::dropdownType('ticket_type', $this->fields["ticket_type"]);
echo "</td>";
echo "</tr>";
echo "<tr class='tab_bg_1'>";
echo "<td>".__('Default Ticket Category', 'siem-wazuh')."</td>";
echo "<td>";
ITILCategory::dropdown(['name' => 'ticket_category', 'value' => $this->fields["ticket_category"]]);
echo "</td>";
echo "<td>".__('Last Sync', 'siem-wazuh')."</td>";
echo "<td>";
echo ($this->fields["last_sync"] ? Html::convDateTime($this->fields["last_sync"]) : __('Never'));
echo "</td>";
echo "</tr>";
// Bouton de test de connexion
if ($ID > 0) {
echo "<tr class='tab_bg_1'>";
echo "<td colspan='4' class='center'>";
echo "<button type='button' class='btn btn-primary' onclick='testWazuhConnection($ID)'>";
echo __('Test Connection', 'siem-wazuh');
echo "</button>";
echo "<div id='test-result-$ID' class='mt-2'></div>";
echo "</td>";
echo "</tr>";
}
$this->showFormButtons($options);
return true;
}
/**
* Prepare input for add
*/
function prepareInputForAdd($input) {
if (!empty($input['wazuh_password'])) {
$input['wazuh_password'] = Toolbox::encrypt($input['wazuh_password'], GLPIKEY);
}
if (!empty($input['indexer_password'])) {
$input['indexer_password'] = Toolbox::encrypt($input['indexer_password'], GLPIKEY);
}
return $input;
}
/**
* Prepare input for update
*/
function prepareInputForUpdate($input) {
if (!empty($input['wazuh_password'])) {
$input['wazuh_password'] = Toolbox::encrypt($input['wazuh_password'], GLPIKEY);
} else {
unset($input['wazuh_password']);
}
if (!empty($input['indexer_password'])) {
$input['indexer_password'] = Toolbox::encrypt($input['indexer_password'], GLPIKEY);
} else {
unset($input['indexer_password']);
}
return $input;
}
/**
* Get decrypted password
*/
function getPassword($field = 'wazuh_password') {
if (!empty($this->fields[$field])) {
return Toolbox::decrypt($this->fields[$field], GLPIKEY);
}
return '';
}
/**
* Test connection to Wazuh server
*/
function testConnection() {
if (empty($this->fields['wazuh_url']) || empty($this->fields['wazuh_login'])) {
return ['success' => false, 'message' => __('Missing connection parameters', 'siem-wazuh')];
}
$api = new PluginSiemWazuhAPI($this);
return $api->testConnection();
}
/**
* Synchronize alerts from this server
*/
function syncAlerts() {
if (!$this->fields['is_active']) {
return ['success' => false, 'message' => __('Server is not active', 'siem-wazuh')];
}
$api = new PluginSiemWazuhAPI($this);
$result = $api->getAlerts();
if ($result['success']) {
$alert = new PluginSiemWazuhAlert();
$processed = $alert->processAlerts($this->getID(), $result['data']);
// Mise à jour de la dernière synchronisation
$this->update([
'id' => $this->getID(),
'last_sync' => $_SESSION['glpi_currenttime']
]);
return [
'success' => true,
'message' => sprintf(__('%d alerts processed', 'siem-wazuh'), $processed)
];
}
return $result;
}
/**
* Get servers for dropdown
*/
static function getDropdownValues($post) {
global $DB;
$where = ['is_active' => 1];
if (isset($post['searchText']) && !empty($post['searchText'])) {
$where[] = ['name' => ['LIKE', '%' . $post['searchText'] . '%']];
}
$iterator = $DB->request([
'FROM' => 'glpi_plugin_siem_wazuh_servers',
'WHERE' => $where,
'ORDER' => 'name'
]);
$values = [];
foreach ($iterator as $row) {
$values[] = [
'id' => $row['id'],
'text' => $row['name']
];
}
return $values;
}
/**
* Get menu content
*/
static function getMenuContent() {
$menu = [];
if (Session::haveRight(static::$rightname, READ)) {
$menu['title'] = self::getMenuName();
$menu['page'] = "/plugins/siem-wazuh/front/wazuhserver.php";
$menu['links']['search'] = "/plugins/siem-wazuh/front/wazuhserver.php";
if (Session::haveRight(static::$rightname, CREATE)) {
$menu['links']['add'] = "/plugins/siem-wazuh/front/wazuhserver.form.php";
}
}
return $menu;
}
/**
* Get menu name
*/
static function getMenuName() {
return self::getTypeName(Session::getPluralNumber());
}
/**
* Clean database relations
*/
function cleanDBonPurge() {
$this->deleteChildrenAndRelationsFromDb(
[
PluginSiemWazuhAlert::class
]
);
}
/**
* Get used configuration
*/
static function getUsedConfig() {
return ['plugin_siem_wazuh_server'];
}
}

454
inc/wazuhtab.class.php Normal file
View File

@@ -0,0 +1,454 @@
<?php
/*
* Plugin SIEM-Wazuh pour GLPI
* Classe de gestion des onglets Wazuh sur les assets
*/
if (!defined('GLPI_ROOT')) {
die("Sorry. You can't access this file directly");
}
class PluginSiemWazuhTab extends CommonGLPI {
static $rightname = 'plugin_siem_wazuh_alert';
/**
* Get tab name for item
*/
function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) {
if (!$withtemplate && Session::haveRight(static::$rightname, READ)) {
if (in_array($item->getType(), ['Computer', 'NetworkEquipment', 'Peripheral', 'Phone', 'Printer'])) {
$nb = 0;
if ($_SESSION['glpishow_count_on_tabs']) {
$nb = self::countForItem($item);
}
return self::createTabEntry(__('Wazuh Alerts', 'siem-wazuh'), $nb);
}
}
return '';
}
/**
* Display tab content
*/
static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $withtemplate = 0) {
if (in_array($item->getType(), ['Computer', 'NetworkEquipment', 'Peripheral', 'Phone', 'Printer'])) {
self::showForItem($item);
}
return true;
}
/**
* Count alerts for item
*/
static function countForItem(CommonGLPI $item) {
global $DB;
$itemtype = $item->getType();
$items_id = $item->getID();
$field_map = [
'Computer' => 'computer_id',
'NetworkEquipment' => 'networkequipment_id',
'Peripheral' => 'peripheral_id',
'Phone' => 'phone_id',
'Printer' => 'printer_id'
];
if (!isset($field_map[$itemtype])) {
return 0;
}
return countElementsInTable('glpi_plugin_siem_wazuh_alerts', [
$field_map[$itemtype] => $items_id
]);
}
/**
* Show alerts for item
*/
static function showForItem(CommonGLPI $item) {
global $DB, $CFG_GLPI;
$itemtype = $item->getType();
$items_id = $item->getID();
$field_map = [
'Computer' => 'computer_id',
'NetworkEquipment' => 'networkequipment_id',
'Peripheral' => 'peripheral_id',
'Phone' => 'phone_id',
'Printer' => 'printer_id'
];
if (!isset($field_map[$itemtype])) {
return;
}
$field = $field_map[$itemtype];
$canupdate = Session::haveRight(static::$rightname, UPDATE);
// Récupération des alertes
$iterator = $DB->request([
'SELECT' => [
'glpi_plugin_siem_wazuh_alerts.*',
'glpi_plugin_siem_wazuh_servers.name AS server_name'
],
'FROM' => 'glpi_plugin_siem_wazuh_alerts',
'LEFT JOIN' => [
'glpi_plugin_siem_wazuh_servers' => [
'ON' => [
'glpi_plugin_siem_wazuh_alerts' => 'wazuh_server_id',
'glpi_plugin_siem_wazuh_servers' => 'id'
]
]
],
'WHERE' => [$field => $items_id],
'ORDER' => ['timestamp DESC', 'rule_level DESC'],
'LIMIT' => 100
]);
$alerts = iterator_to_array($iterator);
echo "<div class='spaced'>";
// Résumé des alertes
self::showAlertsSummary($alerts);
if (count($alerts) > 0) {
// Filtres
self::showAlertsFilters($item, $field);
// Tableau des alertes
self::showAlertsTable($alerts, $canupdate);
// Actions de masse
if ($canupdate && count($alerts) > 0) {
self::showMassActions($item, $field);
}
} else {
echo "<div class='center'>";
echo "<p>" . __('No Wazuh alerts found for this item', 'siem-wazuh') . "</p>";
echo "</div>";
}
echo "</div>";
}
/**
* Show alerts summary
*/
static function showAlertsSummary($alerts) {
$stats = [
'total' => count($alerts),
'new' => 0,
'processed' => 0,
'ticket_created' => 0,
'ignored' => 0,
'critical' => 0,
'high' => 0,
'medium' => 0,
'low' => 0
];
foreach ($alerts as $alert) {
$stats[$alert['status']]++;
$stats[$alert['severity']]++;
}
echo "<div class='alert-summary'>";
echo "<table class='tab_cadre_fixe'>";
echo "<tr class='tab_bg_2'>";
echo "<th colspan='8'>" . __('Alerts Summary', 'siem-wazuh') . "</th>";
echo "</tr>";
echo "<tr class='tab_bg_1'>";
echo "<td class='center'><strong>" . $stats['total'] . "</strong><br>" . __('Total', 'siem-wazuh') . "</td>";
echo "<td class='center status-new'><strong>" . $stats['new'] . "</strong><br>" . __('New', 'siem-wazuh') . "</td>";
echo "<td class='center status-processed'><strong>" . $stats['processed'] . "</strong><br>" . __('Processed', 'siem-wazuh') . "</td>";
echo "<td class='center status-ticket'><strong>" . $stats['ticket_created'] . "</strong><br>" . __('Ticket Created', 'siem-wazuh') . "</td>";
echo "<td class='center severity-critical'><strong>" . $stats['critical'] . "</strong><br>" . __('Critical', 'siem-wazuh') . "</td>";
echo "<td class='center severity-high'><strong>" . $stats['high'] . "</strong><br>" . __('High', 'siem-wazuh') . "</td>";
echo "<td class='center severity-medium'><strong>" . $stats['medium'] . "</strong><br>" . __('Medium', 'siem-wazuh') . "</td>";
echo "<td class='center severity-low'><strong>" . $stats['low'] . "</strong><br>" . __('Low', 'siem-wazuh') . "</td>";
echo "</tr>";
echo "</table>";
echo "</div>";
echo "<br>";
}
/**
* Show alerts filters
*/
static function showAlertsFilters($item, $field) {
echo "<div class='alert-filters'>";
echo "<form method='get' action=''>";
echo "<input type='hidden' name='id' value='" . $item->getID() . "'>";
echo "<input type='hidden' name='_glpi_tab' value='PluginSiemWazuhTab$1'>";
echo "<table class='tab_cadre_fixe'>";
echo "<tr class='tab_bg_2'>";
echo "<th colspan='4'>" . __('Filters', 'siem-wazuh') . "</th>";
echo "</tr>";
echo "<tr class='tab_bg_1'>";
echo "<td>" . __('Status') . "</td>";
echo "<td>";
$statuses = ['all' => __('All')] + PluginSiemWazuhAlert::getStatusArray();
Dropdown::showFromArray('filter_status', $statuses, [
'value' => $_GET['filter_status'] ?? 'all'
]);
echo "</td>";
echo "<td>" . __('Severity', 'siem-wazuh') . "</td>";
echo "<td>";
$severities = ['all' => __('All')] + PluginSiemWazuhAlert::getSeverityArray();
Dropdown::showFromArray('filter_severity', $severities, [
'value' => $_GET['filter_severity'] ?? 'all'
]);
echo "</td>";
echo "</tr>";
echo "<tr class='tab_bg_1'>";
echo "<td>" . __('Date from', 'siem-wazuh') . "</td>";
echo "<td>";
Html::showDateField('filter_date_from', [
'value' => $_GET['filter_date_from'] ?? ''
]);
echo "</td>";
echo "<td>" . __('Date to', 'siem-wazuh') . "</td>";
echo "<td>";
Html::showDateField('filter_date_to', [
'value' => $_GET['filter_date_to'] ?? ''
]);
echo "</td>";
echo "</tr>";
echo "<tr class='tab_bg_1'>";
echo "<td colspan='4' class='center'>";
echo "<input type='submit' value='" . _sx('button', 'Filter') . "' class='submit'>";
echo "&nbsp;";
echo "<input type='button' value='" . _sx('button', 'Reset') . "' class='submit' onclick='window.location.href=\"" . $item->getLinkURL() . "&_glpi_tab=PluginSiemWazuhTab$1\"'>";
echo "</td>";
echo "</tr>";
echo "</table>";
echo "</form>";
echo "</div>";
echo "<br>";
}
/**
* Show alerts table
*/
static function showAlertsTable($alerts, $canupdate) {
echo "<div class='alert-list'>";
echo "<form method='post' name='alerts_form' id='alerts_form' action='" . Plugin::getWebDir('siem-wazuh') . "/front/wazuhalert.form.php'>";
echo "<table class='tab_cadre_fixehov'>";
$header = "<tr class='tab_bg_2'>";
if ($canupdate) {
$header .= "<th width='10'>";
$header .= "<input type='checkbox' name='select_all' onclick='checkAll(this)'>";
$header .= "</th>";
}
$header .= "<th>" . __('Alert ID', 'siem-wazuh') . "</th>";
$header .= "<th>" . __('Server', 'siem-wazuh') . "</th>";
$header .= "<th>" . __('Rule', 'siem-wazuh') . "</th>";
$header .= "<th>" . __('Level', 'siem-wazuh') . "</th>";
$header .= "<th>" . __('Agent', 'siem-wazuh') . "</th>";
$header .= "<th>" . __('Timestamp', 'siem-wazuh') . "</th>";
$header .= "<th>" . __('Status') . "</th>";
$header .= "<th>" . __('Severity', 'siem-wazuh') . "</th>";
$header .= "<th>" . __('Ticket') . "</th>";
$header .= "</tr>";
echo $header;
if (count($alerts) == 0) {
echo "<tr class='tab_bg_1'>";
echo "<td colspan='" . ($canupdate ? "10" : "9") . "' class='center'>";
echo __('No alerts found', 'siem-wazuh');
echo "</td>";
echo "</tr>";
}
$statuses = PluginSiemWazuhAlert::getStatusArray();
$severities = PluginSiemWazuhAlert::getSeverityArray();
foreach ($alerts as $alert) {
echo "<tr class='tab_bg_1'>";
if ($canupdate) {
echo "<td>";
echo "<input type='checkbox' name='selected_alerts[]' value='" . $alert['id'] . "'>";
echo "</td>";
}
echo "<td>";
echo "<a href='" . PluginSiemWazuhAlert::getFormURLWithID($alert['id']) . "'>";
echo $alert['alert_id'];
echo "</a>";
echo "</td>";
echo "<td>" . $alert['server_name'] . "</td>";
echo "<td>";
echo "<strong>" . $alert['rule_id'] . "</strong><br>";
echo "<small>" . Html::clean($alert['rule_description']) . "</small>";
echo "</td>";
echo "<td class='center'>";
echo "<span class='rule-level-" . $alert['rule_level'] . "'>";
echo $alert['rule_level'];
echo "</span>";
echo "</td>";
echo "<td>";
echo $alert['agent_name'] . "<br>";
echo "<small>" . $alert['agent_ip'] . "</small>";
echo "</td>";
echo "<td>" . Html::convDateTime($alert['timestamp']) . "</td>";
echo "<td>";
echo "<span class='status-badge status-" . $alert['status'] . "'>";
echo $statuses[$alert['status']];
echo "</span>";
echo "</td>";
echo "<td>";
echo "<span class='severity-badge severity-" . $alert['severity'] . "'>";
echo $severities[$alert['severity']];
echo "</span>";
echo "</td>";
echo "<td>";
if ($alert['ticket_id']) {
$ticket = new Ticket();
if ($ticket->getFromDB($alert['ticket_id'])) {
echo $ticket->getLink();
}
} else {
echo "-";
}
echo "</td>";
echo "</tr>";
}
echo "</table>";
if ($canupdate && count($alerts) > 0) {
echo "<div class='center' style='margin-top: 10px;'>";
echo "<input type='submit' name='mark_processed' value='" . __('Mark as Processed', 'siem-wazuh') . "' class='submit'>";
echo "&nbsp;";
echo "<input type='submit' name='mark_ignored' value='" . __('Mark as Ignored', 'siem-wazuh') . "' class='submit'>";
echo "&nbsp;";
echo "<input type='submit' name='create_tickets' value='" . __('Create Tickets', 'siem-wazuh') . "' class='submit'>";
echo "</div>";
}
echo Html::closeForm();
echo "</div>";
}
/**
* Show mass actions
*/
static function showMassActions($item, $field) {
echo "<br>";
echo "<div class='mass-actions'>";
echo "<table class='tab_cadre_fixe'>";
echo "<tr class='tab_bg_2'>";
echo "<th colspan='2'>" . __('Mass Actions', 'siem-wazuh') . "</th>";
echo "</tr>";
echo "<tr class='tab_bg_1'>";
echo "<td>" . __('Sync new alerts', 'siem-wazuh') . "</td>";
echo "<td>";
echo "<button type='button' class='btn btn-primary' onclick='syncAlertsForItem(" . $item->getID() . ", \"" . $item->getType() . "\")'>";
echo __('Sync Now', 'siem-wazuh');
echo "</button>";
echo "</td>";
echo "</tr>";
echo "<tr class='tab_bg_1'>";
echo "<td>" . __('Export alerts', 'siem-wazuh') . "</td>";
echo "<td>";
echo "<a href='" . Plugin::getWebDir('siem-wazuh') . "/front/wazuhalert.php?export=1&" . $field . "=" . $item->getID() . "' class='btn'>";
echo __('Export CSV', 'siem-wazuh');
echo "</a>";
echo "</td>";
echo "</tr>";
echo "</table>";
echo "</div>";
}
/**
* Get search options for item
*/
static function getSearchOptionsForItem($itemtype) {
$tab = [];
$tab[5150]['table'] = 'glpi_plugin_siem_wazuh_alerts';
$tab[5150]['field'] = 'id';
$tab[5150]['name'] = __('Wazuh Alerts', 'siem-wazuh');
$tab[5150]['forcegroupby'] = true;
$tab[5150]['usehaving'] = true;
$tab[5150]['datatype'] = 'count';
$tab[5150]['massiveaction'] = false;
$field_map = [
'Computer' => 'computer_id',
'NetworkEquipment' => 'networkequipment_id',
'Peripheral' => 'peripheral_id',
'Phone' => 'phone_id',
'Printer' => 'printer_id'
];
if (isset($field_map[$itemtype])) {
$tab[5150]['linkfield'] = $field_map[$itemtype];
}
return $tab;
}
}
// JavaScript pour les fonctionnalités interactives
echo "<script type='text/javascript'>
function checkAll(checkbox) {
var checkboxes = document.querySelectorAll('input[name=\"selected_alerts[]\"]');
for (var i = 0; i < checkboxes.length; i++) {
checkboxes[i].checked = checkbox.checked;
}
}
function syncAlertsForItem(itemId, itemType) {
if (confirm('" . __('Are you sure you want to sync alerts for this item?', 'siem-wazuh') . "')) {
// AJAX call to sync alerts
fetch('" . Plugin::getWebDir('siem-wazuh') . "/ajax/sync_alerts.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: 'item_id=' + itemId + '&item_type=' + itemType
})
.then(response => response.json())
.then(data => {
if (data.success) {
alert('" . __('Sync completed successfully', 'siem-wazuh') . "');
location.reload();
} else {
alert('" . __('Sync failed:', 'siem-wazuh') . " ' + data.message);
}
})
.catch(error => {
alert('" . __('An error occurred during sync', 'siem-wazuh') . "');
});
}
}
</script>";

0
js/config.js Normal file
View File

487
js/wazuh.js Normal file
View File

@@ -0,0 +1,487 @@
/**
* SIEM-Wazuh Plugin for GLPI - Main JavaScript
* Handles all interactive features for the Wazuh plugin
*/
// Plugin namespace
var WazuhPlugin = WazuhPlugin || {};
/**
* Initialize the plugin
*/
WazuhPlugin.init = function() {
// Initialize tooltips
this.initTooltips();
// Initialize auto-refresh
this.initAutoRefresh();
// Initialize form validation
this.initFormValidation();
// Initialize keyboard shortcuts
this.initKeyboardShortcuts();
console.log('SIEM-Wazuh Plugin initialized');
};
/**
* Test connection to Wazuh server
*/
WazuhPlugin.testConnection = function(serverId) {
const button = document.querySelector('.test-connection-' + serverId);
const resultDiv = document.getElementById('test-result-' + serverId);
if (!button || !resultDiv) {
console.error('Test connection elements not found');
return;
}
// Show loading state
button.disabled = true;
button.innerHTML = '<span class="loading-spinner"></span>' + LANG.TESTING;
const formData = new FormData();
formData.append('server_id', serverId);
formData.append('_glpi_csrf_token', getAjaxCsrfToken());
fetch(CFG_GLPI.root_doc + '/plugins/siem-wazuh/ajax/test_connection.php', {
method: 'POST',
body: formData
})
.then(response => {
if (!response.ok) {
throw new Error('HTTP ' + response.status);
}
return response.json();
})
.then(data => {
let alertClass = data.success ? 'alert-success' : 'alert-danger';
let message = data.message;
if (data.success && data.server_info) {
message += '<br><small><strong>Server Info:</strong><br>';
message += 'Version: ' + (data.server_info.api_version || 'Unknown') + '<br>';
message += 'Timestamp: ' + data.timestamp + '</small>';
}
resultDiv.innerHTML = '<div class="alert ' + alertClass + '">' + message + '</div>';
// Auto-hide after 10 seconds for success messages
if (data.success) {
setTimeout(() => {
resultDiv.innerHTML = '';
}, 10000);
}
})
.catch(error => {
console.error('Connection test error:', error);
resultDiv.innerHTML = '<div class="alert alert-danger">' + LANG.CONNECTION_TEST_FAILED + ': ' + error.message + '</div>';
})
.finally(() => {
button.disabled = false;
button.innerHTML = LANG.TEST_CONNECTION;
});
};
/**
* Synchronize alerts from Wazuh server
*/
WazuhPlugin.syncAlerts = function(serverId, showConfirm = true) {
if (showConfirm && !confirm(LANG.CONFIRM_SYNC_ALERTS)) {
return;
}
const button = document.querySelector('.sync-alerts-' + serverId);
if (button) {
button.disabled = true;
button.innerHTML = '<span class="loading-spinner"></span>' + LANG.SYNCHRONIZING;
}
const formData = new FormData();
formData.append('server_id', serverId);
formData.append('action', 'sync');
formData.append('_glpi_csrf_token', getAjaxCsrfToken());
fetch(CFG_GLPI.root_doc + '/plugins/siem-wazuh/ajax/sync_alerts.php', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
this.showNotification(data.message, 'success');
// Update statistics if available
if (data.stats) {
this.updateStatistics(data.stats);
}
// Refresh the page after 2 seconds
setTimeout(() => {
location.reload();
}, 2000);
} else {
this.showNotification(LANG.SYNC_FAILED + ' ' + data.message, 'error');
}
})
.catch(error => {
console.error('Sync error:', error);
this.showNotification(LANG.SYNC_ERROR, 'error');
})
.finally(() => {
if (button) {
button.disabled = false;
button.innerHTML = LANG.SYNC_ALERTS;
}
});
};
/**
* Sync alerts for specific item
*/
WazuhPlugin.syncAlertsForItem = function(itemId, itemType) {
if (!confirm(LANG.CONFIRM_SYNC_ITEM)) {
return;
}
const formData = new FormData();
formData.append('item_id', itemId);
formData.append('item_type', itemType);
formData.append('action', 'sync_for_item');
formData.append('_glpi_csrf_token', getAjaxCsrfToken());
fetch(CFG_GLPI.root_doc + '/plugins/siem-wazuh/ajax/sync_alerts.php', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
this.showNotification(data.message, 'success');
setTimeout(() => location.reload(), 2000);
} else {
this.showNotification(LANG.SYNC_FAILED + ' ' + data.message, 'error');
}
})
.catch(error => {
console.error('Item sync error:', error);
this.showNotification(LANG.SYNC_ERROR, 'error');
});
};
/**
* Toggle server active status
*/
WazuhPlugin.toggleServerStatus = function(serverId) {
if (confirm(LANG.CONFIRM_TOGGLE_STATUS)) {
window.location.href = '?action=toggle_active&id=' + serverId;
}
};
/**
* Check/uncheck all alerts
*/
WazuhPlugin.checkAllAlerts = function(checkbox) {
const checkboxes = document.querySelectorAll('input[name="selected_alerts[]"]');
for (let i = 0; i < checkboxes.length; i++) {
checkboxes[i].checked = checkbox.checked;
}
this.updateBulkActionButtons();
};
/**
* Update bulk action buttons based on selection
*/
WazuhPlugin.updateBulkActionButtons = function() {
const checkboxes = document.querySelectorAll('input[name="selected_alerts[]"]:checked');
const bulkActions = document.querySelectorAll('.bulk-action-btn');
bulkActions.forEach(button => {
button.disabled = checkboxes.length === 0;
});
// Update counter if exists
const counter = document.getElementById('selected-count');
if (counter) {
counter.textContent = checkboxes.length;
}
};
/**
* Filter alerts table
*/
WazuhPlugin.filterAlerts = function(filters) {
const table = document.querySelector('.alert-list table');
if (!table) return;
const rows = table.querySelectorAll('tbody tr');
rows.forEach(row => {
let visible = true;
// Apply filters
Object.keys(filters).forEach(filterKey => {
const filterValue = filters[filterKey];
if (filterValue && filterValue !== 'all') {
const cell = row.querySelector('[data-' + filterKey + ']');
if (cell && cell.getAttribute('data-' + filterKey) !== filterValue) {
visible = false;
}
}
});
row.style.display = visible ? '' : 'none';
});
this.updateFilterStats();
};
/**
* Update filter statistics
*/
WazuhPlugin.updateFilterStats = function() {
const visibleRows = document.querySelectorAll('.alert-list tbody tr:not([style*="none"])');
const totalRows = document.querySelectorAll('.alert-list tbody tr');
const statsElement = document.getElementById('filter-stats');
if (statsElement) {
statsElement.textContent = `${visibleRows.length} of ${totalRows.length} alerts shown`;
}
};
/**
* Export alerts to CSV
*/
WazuhPlugin.exportAlerts = function(params = {}) {
const url = new URL(CFG_GLPI.root_doc + '/plugins/siem-wazuh/front/wazuhalert.php');
url.searchParams.append('export', '1');
Object.keys(params).forEach(key => {
url.searchParams.append(key, params[key]);
});
window.open(url.toString(), '_blank');
};
/**
* Show notification message
*/
WazuhPlugin.showNotification = function(message, type = 'info', duration = 5000) {
// Try to use GLPI's notification system first
if (typeof displayAjaxMessageAfterRedirect === 'function') {
displayAjaxMessageAfterRedirect();
return;
}
// Fallback to custom notification
const notification = document.createElement('div');
notification.className = `alert alert-${type === 'error' ? 'danger' : type} wazuh-notification`;
notification.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
z-index: 9999;
max-width: 400px;
animation: slideIn 0.3s ease-out;
`;
notification.innerHTML = `
<button type="button" class="close" onclick="this.parentElement.remove()">
<span>&times;</span>
</button>
${message}
`;
document.body.appendChild(notification);
// Auto-remove after duration
if (duration > 0) {
setTimeout(() => {
if (notification.parentNode) {
notification.remove();
}
}, duration);
}
};
/**
* Update statistics display
*/
WazuhPlugin.updateStatistics = function(stats) {
Object.keys(stats).forEach(key => {
const element = document.getElementById('stat-' + key);
if (element) {
element.textContent = stats[key];
}
});
};
/**
* Initialize tooltips
*/
WazuhPlugin.initTooltips = function() {
// Simple tooltip implementation
const tooltipElements = document.querySelectorAll('[data-tooltip]');
tooltipElements.forEach(element => {
element.addEventListener('mouseenter', function() {
const tooltip = document.createElement('div');
tooltip.className = 'wazuh-tooltip-popup';
tooltip.textContent = this.getAttribute('data-tooltip');
tooltip.style.cssText = `
position: absolute;
background: #333;
color: white;
padding: 5px 10px;
border-radius: 4px;
font-size: 12px;
z-index: 1000;
pointer-events: none;
`;
document.body.appendChild(tooltip);
// Position tooltip
const rect = this.getBoundingClientRect();
tooltip.style.left = (rect.left + rect.width / 2 - tooltip.offsetWidth / 2) + 'px';
tooltip.style.top = (rect.top - tooltip.offsetHeight - 5) + 'px';
this._tooltip = tooltip;
});
element.addEventListener('mouseleave', function() {
if (this._tooltip) {
this._tooltip.remove();
this._tooltip = null;
}
});
});
};
/**
* Initialize auto-refresh functionality
*/
WazuhPlugin.initAutoRefresh = function() {
const refreshInterval = parseInt(document.body.getAttribute('data-refresh-interval')) || 0;
if (refreshInterval > 0) {
setInterval(() => {
// Only refresh if page is visible
if (!document.hidden) {
this.refreshData();
}
}, refreshInterval * 1000);
}
};
/**
* Refresh data without full page reload
*/
WazuhPlugin.refreshData = function() {
// Update statistics
fetch(CFG_GLPI.root_doc + '/plugins/siem-wazuh/ajax/sync_alerts.php?action=status')
.then(response => response.json())
.then(data => {
if (data.success) {
this.updateStatistics(data.stats);
}
})
.catch(error => console.warn('Auto-refresh failed:', error));
};
/**
* Initialize form validation
*/
WazuhPlugin.initFormValidation = function() {
// Validate server URLs
const urlInputs = document.querySelectorAll('input[name="wazuh_url"], input[name="indexer_url"]');
urlInputs.forEach(input => {
input.addEventListener('blur', function() {
if (this.value && !this.value.match(/^https?:\/\/.+/)) {
this.setCustomValidity('Please enter a valid URL starting with http:// or https://');
} else {
this.setCustomValidity('');
}
});
});
// Validate port numbers
const portInputs = document.querySelectorAll('input[name="wazuh_port"], input[name="indexer_port"]');
portInputs.forEach(input => {
input.addEventListener('blur', function() {
const port = parseInt(this.value);
if (this.value && (isNaN(port) || port < 1 || port > 65535)) {
this.setCustomValidity('Please enter a valid port number (1-65535)');
} else {
this.setCustomValidity('');
}
});
});
};
/**
* Initialize keyboard shortcuts
*/
WazuhPlugin.initKeyboardShortcuts = function() {
document.addEventListener('keydown', function(e) {
// Ctrl+Shift+S: Sync all servers
if (e.ctrlKey && e.shiftKey && e.key === 'S') {
e.preventDefault();
const syncButton = document.querySelector('.sync-all-btn');
if (syncButton) {
syncButton.click();
}
}
// Ctrl+Shift+T: Test connection
if (e.ctrlKey && e.shiftKey && e.key === 'T') {
e.preventDefault();
const testButton = document.querySelector('.test-connection-btn');
if (testButton) {
testButton.click();
}
}
// Escape: Close modals/notifications
if (e.key === 'Escape') {
const notifications = document.querySelectorAll('.wazuh-notification');
notifications.forEach(notification => notification.remove());
}
});
};
/**
* Utility function to get CSRF token
*/
function getAjaxCsrfToken() {
return $('meta[name="glpi-csrf-token"]').attr('content') || '';
}
/**
* Language strings (will be populated by PHP)
*/
var LANG = LANG || {
TESTING: 'Testing...',
SYNCHRONIZING: 'Synchronizing...',
TEST_CONNECTION: 'Test Connection',
SYNC_ALERTS: 'Sync Alerts',
CONNECTION_TEST_FAILED: 'Connection test failed',
SYNC_FAILED: 'Sync failed:',
SYNC_ERROR: 'An error occurred during synchronization',
CONFIRM_SYNC_ALERTS: 'Are you sure you want to synchronize alerts from this server?',
CONFIRM_SYNC_ITEM: 'Are you sure you want to sync alerts for this item?',
CONFIRM_TOGGLE_STATUS: 'Are you sure you want to change the status of this server?'
};
// Initialize when DOM is ready
document.addEventListener('DOMContentLoaded', function() {
WazuhPlugin.init();
});
// Expose to global scope for legacy compatibility
window.WazuhPlugin = WazuhPlugin;
window.testWazuhConnection = WazuhPlugin.testConnection.bind(WazuhPlugin);
window.syncWazuhAlerts = WazuhPlugin.syncAlerts.bind(WazuhPlugin);
window.syncAlertsForItem = WazuhPlugin.syncAlertsForItem.bind(WazuhPlugin);
window.toggleServerStatus = WazuhPlugin.toggleServerStatus.bind(WazuhPlugin);
window.checkAll = WazuhPlugin.checkAllAlerts.bind(WazuhPlugin);

0
locales/de_DE.mo Normal file
View File

188
locales/de_DE.po Normal file
View File

@@ -0,0 +1,188 @@
# SIEM-Wazuh Plugin for GLPI - German Translation
# Copyright (C) 2024 SIEM-Wazuh Team
# This file is distributed under the same license as GLPI.
#
msgid ""
msgstr ""
"Project-Id-Version: GLPI Plugin SIEM-Wazuh 1.0.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-01-01 00:00+0000\n"
"PO-Revision-Date: 2024-01-01 00:00+0000\n"
"Last-Translator: SIEM-Wazuh Team\n"
"Language-Team: German\n"
"Language: de_DE\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
# Plugin information
msgid "SIEM - Wazuh"
msgstr "SIEM - Wazuh"
msgid "Wazuh Server"
msgid_plural "Wazuh Servers"
msgstr[0] "Wazuh Server"
msgstr[1] "Wazuh Server"
msgid "Wazuh Alert"
msgid_plural "Wazuh Alerts"
msgstr[0] "Wazuh Warnung"
msgstr[1] "Wazuh Warnungen"
msgid "SIEM Wazuh Configuration"
msgstr "SIEM Wazuh Konfiguration"
# Server configuration
msgid "Wazuh Server URL"
msgstr "Wazuh Server URL"
msgid "Wazuh API Port"
msgstr "Wazuh API Port"
msgid "Wazuh API Login"
msgstr "Wazuh API Anmeldung"
msgid "Wazuh API Password"
msgstr "Wazuh API Passwort"
msgid "Indexer Server URL"
msgstr "Indexer Server URL"
msgid "Sync Interval (seconds)"
msgstr "Synchronisationsintervall (Sekunden)"
msgid "Last Sync"
msgstr "Letzte Synchronisation"
msgid "Default Ticket Type"
msgstr "Standard Ticket-Typ"
msgid "Default Ticket Category"
msgstr "Standard Ticket-Kategorie"
# Alerts
msgid "Alert ID"
msgstr "Warn-ID"
msgid "Rule ID"
msgstr "Regel-ID"
msgid "Rule Level"
msgstr "Regelebene"
msgid "Rule Description"
msgstr "Regelbeschreibung"
msgid "Agent Name"
msgstr "Agent Name"
msgid "Agent IP"
msgstr "Agent IP"
msgid "Alert Timestamp"
msgstr "Warnzeit"
msgid "Severity"
msgstr "Schweregrad"
# Status values
msgid "New"
msgstr "Neu"
msgid "Processed"
msgstr "Bearbeitet"
msgid "Ignored"
msgstr "Ignoriert"
msgid "Ticket Created"
msgstr "Ticket erstellt"
# Severity values
msgid "Low"
msgstr "Niedrig"
msgid "Medium"
msgstr "Mittel"
msgid "High"
msgstr "Hoch"
msgid "Critical"
msgstr "Kritisch"
# Actions
msgid "Test Connection"
msgstr "Verbindung testen"
msgid "Sync Alerts"
msgstr "Warnungen synchronisieren"
msgid "Sync Now"
msgstr "Jetzt synchronisieren"
msgid "Export CSV"
msgstr "CSV exportieren"
# Configuration
msgid "General Configuration"
msgstr "Allgemeine Konfiguration"
msgid "Enable synchronization"
msgstr "Synchronisation aktivieren"
msgid "Auto-create tickets"
msgstr "Tickets automatisch erstellen"
msgid "Maximum alerts per sync"
msgstr "Maximale Warnungen pro Synchronisation"
msgid "Alert retention (days)"
msgstr "Warnungsaufbewahrung (Tage)"
msgid "Configuration"
msgstr "Konfiguration"
msgid "Servers"
msgstr "Server"
msgid "Alerts"
msgstr "Warnungen"
# Messages
msgid "Connection successful"
msgstr "Verbindung erfolgreich"
msgid "Connection failed:"
msgstr "Verbindung fehlgeschlagen:"
msgid "Server activated"
msgstr "Server aktiviert"
msgid "Server deactivated"
msgstr "Server deaktiviert"
msgid "Testing..."
msgstr "Teste..."
msgid "Synchronizing..."
msgstr "Synchronisiere..."
msgid "Never"
msgstr "Nie"
msgid "Statistics"
msgstr "Statistiken"
msgid "Total servers"
msgstr "Server insgesamt"
msgid "Active servers"
msgstr "Aktive Server"
msgid "Total alerts"
msgstr "Warnungen insgesamt"
msgid "New alerts"
msgstr "Neue Warnungen"

0
locales/en_GB.mo Normal file
View File

543
locales/en_GB.po Normal file
View File

@@ -0,0 +1,543 @@
# SIEM-Wazuh Plugin for GLPI - English Translation
# Copyright (C) 2024 SIEM-Wazuh Team
# This file is distributed under the same license as GLPI.
#
msgid ""
msgstr ""
"Project-Id-Version: GLPI Plugin SIEM-Wazuh 1.0.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-01-01 00:00+0000\n"
"PO-Revision-Date: 2024-01-01 00:00+0000\n"
"Last-Translator: SIEM-Wazuh Team\n"
"Language-Team: English\n"
"Language: en_GB\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
# Plugin information
msgid "SIEM - Wazuh"
msgstr "SIEM - Wazuh"
msgid "Wazuh Server"
msgid_plural "Wazuh Servers"
msgstr[0] "Wazuh Server"
msgstr[1] "Wazuh Servers"
msgid "Wazuh Alert"
msgid_plural "Wazuh Alerts"
msgstr[0] "Wazuh Alert"
msgstr[1] "Wazuh Alerts"
msgid "SIEM Wazuh Configuration"
msgstr "SIEM Wazuh Configuration"
# Server configuration
msgid "Wazuh Server URL"
msgstr "Wazuh Server URL"
msgid "Wazuh API Port"
msgstr "Wazuh API Port"
msgid "Wazuh API Login"
msgstr "Wazuh API Login"
msgid "Wazuh API Password"
msgstr "Wazuh API Password"
msgid "Indexer Server URL"
msgstr "Indexer Server URL"
msgid "Indexer API Port"
msgstr "Indexer API Port"
msgid "Indexer API Login"
msgstr "Indexer API Login"
msgid "Indexer API Password"
msgstr "Indexer API Password"
msgid "Sync Interval (seconds)"
msgstr "Sync Interval (seconds)"
msgid "Last Sync"
msgstr "Last Sync"
msgid "Default Ticket Type"
msgstr "Default Ticket Type"
msgid "Default Ticket Category"
msgstr "Default Ticket Category"
msgid "Leave empty to keep current password"
msgstr "Leave empty to keep current password"
# Alerts
msgid "Alert ID"
msgstr "Alert ID"
msgid "Rule ID"
msgstr "Rule ID"
msgid "Rule Level"
msgstr "Rule Level"
msgid "Rule Description"
msgstr "Rule Description"
msgid "Agent Name"
msgstr "Agent Name"
msgid "Agent IP"
msgstr "Agent IP"
msgid "Alert Timestamp"
msgstr "Alert Timestamp"
msgid "Severity"
msgstr "Severity"
msgid "Associated Computer"
msgstr "Associated Computer"
msgid "Associated Network Equipment"
msgstr "Associated Network Equipment"
msgid "Associated Ticket"
msgstr "Associated Ticket"
msgid "Raw Alert Data"
msgstr "Raw Alert Data"
# Status values
msgid "New"
msgstr "New"
msgid "Processed"
msgstr "Processed"
msgid "Ignored"
msgstr "Ignored"
msgid "Ticket Created"
msgstr "Ticket Created"
# Severity values
msgid "Low"
msgstr "Low"
msgid "Medium"
msgstr "Medium"
msgid "High"
msgstr "High"
msgid "Critical"
msgstr "Critical"
# Actions
msgid "Test Connection"
msgstr "Test Connection"
msgid "Sync Alerts"
msgstr "Sync Alerts"
msgid "Sync Now"
msgstr "Sync Now"
msgid "Export CSV"
msgstr "Export CSV"
msgid "Mark as Processed"
msgstr "Mark as Processed"
msgid "Mark as Ignored"
msgstr "Mark as Ignored"
msgid "Create Tickets"
msgstr "Create Tickets"
# Configuration
msgid "General Configuration"
msgstr "General Configuration"
msgid "Enable synchronization"
msgstr "Enable synchronization"
msgid "Auto-create tickets"
msgstr "Auto-create tickets"
msgid "Maximum alerts per sync"
msgstr "Maximum alerts per sync"
msgid "Alert retention (days)"
msgstr "Alert retention (days)"
msgid "Minimum rule level"
msgstr "Minimum rule level"
msgid "Enable notifications"
msgstr "Enable notifications"
msgid "Default Ticket Settings"
msgstr "Default Ticket Settings"
msgid "Default Priority"
msgstr "Default Priority"
msgid "Default Urgency"
msgstr "Default Urgency"
msgid "Default Impact"
msgstr "Default Impact"
msgid "Auto-assign tickets"
msgstr "Auto-assign tickets"
msgid "Default Assignee"
msgstr "Default Assignee"
msgid "Default Group"
msgstr "Default Group"
msgid "Asset Mapping Configuration"
msgstr "Asset Mapping Configuration"
msgid "Match by hostname"
msgstr "Match by hostname"
msgid "Match by IP address"
msgstr "Match by IP address"
msgid "Case sensitive matching"
msgstr "Case sensitive matching"
msgid "Create unknown assets"
msgstr "Create unknown assets"
msgid "Debug Configuration"
msgstr "Debug Configuration"
msgid "Enable debug mode"
msgstr "Enable debug mode"
msgid "Log level"
msgstr "Log level"
msgid "Keep debug logs (days)"
msgstr "Keep debug logs (days)"
msgid "Error only"
msgstr "Error only"
msgid "Warning and above"
msgstr "Warning and above"
msgid "Info and above"
msgstr "Info and above"
msgid "All messages"
msgstr "All messages"
# Statistics
msgid "Statistics"
msgstr "Statistics"
msgid "Total servers"
msgstr "Total servers"
msgid "Active servers"
msgstr "Active servers"
msgid "Total alerts"
msgstr "Total alerts"
msgid "New alerts"
msgstr "New alerts"
msgid "Processed alerts"
msgstr "Processed alerts"
msgid "Tickets created"
msgstr "Tickets created"
msgid "%s alerts"
msgstr "%s alerts"
msgid "Last global sync"
msgstr "Last global sync"
msgid "Never"
msgstr "Never"
# Tab interface
msgid "Wazuh Alerts"
msgstr "Wazuh Alerts"
msgid "Alerts Summary"
msgstr "Alerts Summary"
msgid "Total"
msgstr "Total"
msgid "Filters"
msgstr "Filters"
msgid "Date from"
msgstr "Date from"
msgid "Date to"
msgstr "Date to"
msgid "Reset"
msgstr "Reset"
msgid "Filter"
msgstr "Filter"
msgid "No Wazuh alerts found for this item"
msgstr "No Wazuh alerts found for this item"
msgid "No alerts found"
msgstr "No alerts found"
msgid "Mass Actions"
msgstr "Mass Actions"
msgid "Sync new alerts"
msgstr "Sync new alerts"
msgid "Export alerts"
msgstr "Export alerts"
# Messages
msgid "Connection successful"
msgstr "Connection successful"
msgid "Connection failed:"
msgstr "Connection failed:"
msgid "Authentication failed:"
msgstr "Authentication failed:"
msgid "Connection error:"
msgstr "Connection error:"
msgid "Missing connection parameters"
msgstr "Missing connection parameters"
msgid "Server is not active"
msgstr "Server is not active"
msgid "%d alerts processed"
msgstr "%d alerts processed"
msgid "Configuration updated successfully"
msgstr "Configuration updated successfully"
msgid "Server activated"
msgstr "Server activated"
msgid "Server deactivated"
msgstr "Server deactivated"
msgid "Testing..."
msgstr "Testing..."
msgid "Connection test failed"
msgstr "Connection test failed"
msgid "Synchronizing..."
msgstr "Synchronizing..."
msgid "Sync completed successfully"
msgstr "Sync completed successfully"
msgid "Sync failed:"
msgstr "Sync failed:"
msgid "An error occurred during sync"
msgstr "An error occurred during sync"
msgid "An error occurred during synchronization"
msgstr "An error occurred during synchronization"
msgid "Are you sure you want to change the status of this server?"
msgstr "Are you sure you want to change the status of this server?"
msgid "Are you sure you want to synchronize alerts from this server?"
msgstr "Are you sure you want to synchronize alerts from this server?"
msgid "Are you sure you want to sync alerts for this item?"
msgstr "Are you sure you want to sync alerts for this item?"
# Ticket content
msgid "Wazuh Alert: %s"
msgstr "Wazuh Alert: %s"
msgid "Alert ID: %s"
msgstr "Alert ID: %s"
msgid "Rule ID: %s"
msgstr "Rule ID: %s"
msgid "Rule Level: %s"
msgstr "Rule Level: %s"
msgid "Agent: %s (%s)"
msgstr "Agent: %s (%s)"
msgid "Timestamp: %s"
msgstr "Timestamp: %s"
msgid "Description: %s"
msgstr "Description: %s"
msgid "Raw Alert Data:"
msgstr "Raw Alert Data:"
# Cron tasks
msgid "Synchronize Wazuh alerts"
msgstr "Synchronize Wazuh alerts"
msgid "Cleanup old alerts"
msgstr "Cleanup old alerts"
# Rights
msgid "SIEM Wazuh Rights"
msgstr "SIEM Wazuh Rights"
msgid "Configuration"
msgstr "Configuration"
msgid "Servers"
msgstr "Servers"
msgid "Alerts"
msgstr "Alerts"
# Error messages
msgid "Access denied"
msgstr "Access denied"
msgid "Invalid CSRF token"
msgstr "Invalid CSRF token"
msgid "Invalid server ID"
msgstr "Invalid server ID"
msgid "Server not found"
msgstr "Server not found"
msgid "Invalid item parameters"
msgstr "Invalid item parameters"
msgid "Invalid item type"
msgstr "Invalid item type"
msgid "Item not found"
msgstr "Item not found"
msgid "Unknown action"
msgstr "Unknown action"
msgid "Request failed after maximum retries"
msgstr "Request failed after maximum retries"
msgid "Indexer not configured"
msgstr "Indexer not configured"
msgid "Authentication failed"
msgstr "Authentication failed"
msgid "Status retrieved successfully"
msgstr "Status retrieved successfully"
# Additional configuration
msgid "Asset Mapping"
msgstr "Asset Mapping"
msgid "Notifications"
msgstr "Notifications"
msgid "Debug & Logs"
msgstr "Debug & Logs"
msgid "Email Notifications"
msgstr "Email Notifications"
msgid "Enable email notifications"
msgstr "Enable email notifications"
msgid "Notification for critical alerts only"
msgstr "Notification for critical alerts only"
msgid "Default notification recipients"
msgstr "Default notification recipients"
msgid "Comma-separated email addresses"
msgstr "Comma-separated email addresses"
msgid "Asset Detection Rules"
msgstr "Asset Detection Rules"
msgid "Match computers by hostname"
msgstr "Match computers by hostname"
msgid "Match network equipment by hostname"
msgstr "Match network equipment by hostname"
msgid "Hostname patterns to ignore"
msgstr "Hostname patterns to ignore"
msgid "One pattern per line. Use * as wildcard."
msgstr "One pattern per line. Use * as wildcard."
msgid "Test Asset Mapping"
msgstr "Test Asset Mapping"
msgid "Agent name or IP"
msgstr "Agent name or IP"
msgid "Test"
msgstr "Test"
msgid "Please enter an agent name or IP address"
msgstr "Please enter an agent name or IP address"
msgid "Test failed"
msgstr "Test failed"
msgid "Log API requests"
msgstr "Log API requests"
msgid "Keep logs for (days)"
msgstr "Keep logs for (days)"
msgid "Clear All Logs"
msgstr "Clear All Logs"
msgid "Are you sure you want to clear all logs?"
msgstr "Are you sure you want to clear all logs?"
msgid "Logs cleared successfully"
msgstr "Logs cleared successfully"
msgid "Failed to clear logs"
msgstr "Failed to clear logs"
msgid "Recent Logs"
msgstr "Recent Logs"
msgid "Level"
msgstr "Level"
msgid "Message"
msgstr "Message"
msgid "System"
msgstr "System"
msgid "No logs found"
msgstr "No logs found"

0
locales/es_ES.mo Normal file
View File

0
locales/es_ES.po Normal file
View File

0
locales/fr_FR.mo Normal file
View File

543
locales/fr_FR.po Normal file
View File

@@ -0,0 +1,543 @@
# SIEM-Wazuh Plugin for GLPI - French Translation
# Copyright (C) 2024 SIEM-Wazuh Team
# This file is distributed under the same license as GLPI.
#
msgid ""
msgstr ""
"Project-Id-Version: GLPI Plugin SIEM-Wazuh 1.0.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-01-01 00:00+0000\n"
"PO-Revision-Date: 2024-01-01 00:00+0000\n"
"Last-Translator: SIEM-Wazuh Team\n"
"Language-Team: French\n"
"Language: fr_FR\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
# Plugin information
msgid "SIEM - Wazuh"
msgstr "SIEM - Wazuh"
msgid "Wazuh Server"
msgid_plural "Wazuh Servers"
msgstr[0] "Serveur Wazuh"
msgstr[1] "Serveurs Wazuh"
msgid "Wazuh Alert"
msgid_plural "Wazuh Alerts"
msgstr[0] "Alerte Wazuh"
msgstr[1] "Alertes Wazuh"
msgid "SIEM Wazuh Configuration"
msgstr "Configuration SIEM Wazuh"
# Server configuration
msgid "Wazuh Server URL"
msgstr "URL du serveur Wazuh"
msgid "Wazuh API Port"
msgstr "Port API Wazuh"
msgid "Wazuh API Login"
msgstr "Login API Wazuh"
msgid "Wazuh API Password"
msgstr "Mot de passe API Wazuh"
msgid "Indexer Server URL"
msgstr "URL du serveur Indexer"
msgid "Indexer API Port"
msgstr "Port API Indexer"
msgid "Indexer API Login"
msgstr "Login API Indexer"
msgid "Indexer API Password"
msgstr "Mot de passe API Indexer"
msgid "Sync Interval (seconds)"
msgstr "Intervalle de synchronisation (secondes)"
msgid "Last Sync"
msgstr "Dernière synchronisation"
msgid "Default Ticket Type"
msgstr "Type de ticket par défaut"
msgid "Default Ticket Category"
msgstr "Catégorie de ticket par défaut"
msgid "Leave empty to keep current password"
msgstr "Laisser vide pour conserver le mot de passe actuel"
# Alerts
msgid "Alert ID"
msgstr "ID d'alerte"
msgid "Rule ID"
msgstr "ID de règle"
msgid "Rule Level"
msgstr "Niveau de règle"
msgid "Rule Description"
msgstr "Description de la règle"
msgid "Agent Name"
msgstr "Nom de l'agent"
msgid "Agent IP"
msgstr "IP de l'agent"
msgid "Alert Timestamp"
msgstr "Horodatage de l'alerte"
msgid "Severity"
msgstr "Sévérité"
msgid "Associated Computer"
msgstr "Ordinateur associé"
msgid "Associated Network Equipment"
msgstr "Équipement réseau associé"
msgid "Associated Ticket"
msgstr "Ticket associé"
msgid "Raw Alert Data"
msgstr "Données brutes de l'alerte"
# Status values
msgid "New"
msgstr "Nouveau"
msgid "Processed"
msgstr "Traité"
msgid "Ignored"
msgstr "Ignoré"
msgid "Ticket Created"
msgstr "Ticket créé"
# Severity values
msgid "Low"
msgstr "Faible"
msgid "Medium"
msgstr "Moyen"
msgid "High"
msgstr "Élevé"
msgid "Critical"
msgstr "Critique"
# Actions
msgid "Test Connection"
msgstr "Tester la connexion"
msgid "Sync Alerts"
msgstr "Synchroniser les alertes"
msgid "Sync Now"
msgstr "Synchroniser maintenant"
msgid "Export CSV"
msgstr "Exporter CSV"
msgid "Mark as Processed"
msgstr "Marquer comme traité"
msgid "Mark as Ignored"
msgstr "Marquer comme ignoré"
msgid "Create Tickets"
msgstr "Créer des tickets"
# Configuration
msgid "General Configuration"
msgstr "Configuration générale"
msgid "Enable synchronization"
msgstr "Activer la synchronisation"
msgid "Auto-create tickets"
msgstr "Création automatique de tickets"
msgid "Maximum alerts per sync"
msgstr "Maximum d'alertes par synchronisation"
msgid "Alert retention (days)"
msgstr "Rétention des alertes (jours)"
msgid "Minimum rule level"
msgstr "Niveau de règle minimum"
msgid "Enable notifications"
msgstr "Activer les notifications"
msgid "Default Ticket Settings"
msgstr "Paramètres de ticket par défaut"
msgid "Default Priority"
msgstr "Priorité par défaut"
msgid "Default Urgency"
msgstr "Urgence par défaut"
msgid "Default Impact"
msgstr "Impact par défaut"
msgid "Auto-assign tickets"
msgstr "Attribution automatique des tickets"
msgid "Default Assignee"
msgstr "Assigné par défaut"
msgid "Default Group"
msgstr "Groupe par défaut"
msgid "Asset Mapping Configuration"
msgstr "Configuration du mapping des assets"
msgid "Match by hostname"
msgstr "Correspondance par nom d'hôte"
msgid "Match by IP address"
msgstr "Correspondance par adresse IP"
msgid "Case sensitive matching"
msgstr "Correspondance sensible à la casse"
msgid "Create unknown assets"
msgstr "Créer les assets inconnus"
msgid "Debug Configuration"
msgstr "Configuration de débogage"
msgid "Enable debug mode"
msgstr "Activer le mode débogage"
msgid "Log level"
msgstr "Niveau de log"
msgid "Keep debug logs (days)"
msgstr "Conserver les logs de débogage (jours)"
msgid "Error only"
msgstr "Erreurs seulement"
msgid "Warning and above"
msgstr "Avertissements et plus"
msgid "Info and above"
msgstr "Informations et plus"
msgid "All messages"
msgstr "Tous les messages"
# Statistics
msgid "Statistics"
msgstr "Statistiques"
msgid "Total servers"
msgstr "Total des serveurs"
msgid "Active servers"
msgstr "Serveurs actifs"
msgid "Total alerts"
msgstr "Total des alertes"
msgid "New alerts"
msgstr "Nouvelles alertes"
msgid "Processed alerts"
msgstr "Alertes traitées"
msgid "Tickets created"
msgstr "Tickets créés"
msgid "%s alerts"
msgstr "Alertes %s"
msgid "Last global sync"
msgstr "Dernière synchronisation globale"
msgid "Never"
msgstr "Jamais"
# Tab interface
msgid "Wazuh Alerts"
msgstr "Alertes Wazuh"
msgid "Alerts Summary"
msgstr "Résumé des alertes"
msgid "Total"
msgstr "Total"
msgid "Filters"
msgstr "Filtres"
msgid "Date from"
msgstr "Date de début"
msgid "Date to"
msgstr "Date de fin"
msgid "Reset"
msgstr "Réinitialiser"
msgid "Filter"
msgstr "Filtrer"
msgid "No Wazuh alerts found for this item"
msgstr "Aucune alerte Wazuh trouvée pour cet élément"
msgid "No alerts found"
msgstr "Aucune alerte trouvée"
msgid "Mass Actions"
msgstr "Actions de masse"
msgid "Sync new alerts"
msgstr "Synchroniser les nouvelles alertes"
msgid "Export alerts"
msgstr "Exporter les alertes"
# Messages
msgid "Connection successful"
msgstr "Connexion réussie"
msgid "Connection failed:"
msgstr "Échec de la connexion :"
msgid "Authentication failed:"
msgstr "Échec de l'authentification :"
msgid "Connection error:"
msgstr "Erreur de connexion :"
msgid "Missing connection parameters"
msgstr "Paramètres de connexion manquants"
msgid "Server is not active"
msgstr "Le serveur n'est pas actif"
msgid "%d alerts processed"
msgstr "%d alertes traitées"
msgid "Configuration updated successfully"
msgstr "Configuration mise à jour avec succès"
msgid "Server activated"
msgstr "Serveur activé"
msgid "Server deactivated"
msgstr "Serveur désactivé"
msgid "Testing..."
msgstr "Test en cours..."
msgid "Connection test failed"
msgstr "Échec du test de connexion"
msgid "Synchronizing..."
msgstr "Synchronisation en cours..."
msgid "Sync completed successfully"
msgstr "Synchronisation terminée avec succès"
msgid "Sync failed:"
msgstr "Échec de la synchronisation :"
msgid "An error occurred during sync"
msgstr "Une erreur s'est produite lors de la synchronisation"
msgid "An error occurred during synchronization"
msgstr "Une erreur s'est produite lors de la synchronisation"
msgid "Are you sure you want to change the status of this server?"
msgstr "Êtes-vous sûr de vouloir changer le statut de ce serveur ?"
msgid "Are you sure you want to synchronize alerts from this server?"
msgstr "Êtes-vous sûr de vouloir synchroniser les alertes de ce serveur ?"
msgid "Are you sure you want to sync alerts for this item?"
msgstr "Êtes-vous sûr de vouloir synchroniser les alertes pour cet élément ?"
# Ticket content
msgid "Wazuh Alert: %s"
msgstr "Alerte Wazuh : %s"
msgid "Alert ID: %s"
msgstr "ID d'alerte : %s"
msgid "Rule ID: %s"
msgstr "ID de règle : %s"
msgid "Rule Level: %s"
msgstr "Niveau de règle : %s"
msgid "Agent: %s (%s)"
msgstr "Agent : %s (%s)"
msgid "Timestamp: %s"
msgstr "Horodatage : %s"
msgid "Description: %s"
msgstr "Description : %s"
msgid "Raw Alert Data:"
msgstr "Données brutes de l'alerte :"
# Cron tasks
msgid "Synchronize Wazuh alerts"
msgstr "Synchroniser les alertes Wazuh"
msgid "Cleanup old alerts"
msgstr "Nettoyer les anciennes alertes"
# Rights
msgid "SIEM Wazuh Rights"
msgstr "Droits SIEM Wazuh"
msgid "Configuration"
msgstr "Configuration"
msgid "Servers"
msgstr "Serveurs"
msgid "Alerts"
msgstr "Alertes"
# Error messages
msgid "Access denied"
msgstr "Accès refusé"
msgid "Invalid CSRF token"
msgstr "Token CSRF invalide"
msgid "Invalid server ID"
msgstr "ID de serveur invalide"
msgid "Server not found"
msgstr "Serveur non trouvé"
msgid "Invalid item parameters"
msgstr "Paramètres d'élément invalides"
msgid "Invalid item type"
msgstr "Type d'élément invalide"
msgid "Item not found"
msgstr "Élément non trouvé"
msgid "Unknown action"
msgstr "Action inconnue"
msgid "Request failed after maximum retries"
msgstr "Échec de la requête après le nombre maximum de tentatives"
msgid "Indexer not configured"
msgstr "Indexer non configuré"
msgid "Authentication failed"
msgstr "Échec de l'authentification"
msgid "Status retrieved successfully"
msgstr "Statut récupéré avec succès"
# Additional configuration
msgid "Asset Mapping"
msgstr "Mapping des Assets"
msgid "Notifications"
msgstr "Notifications"
msgid "Debug & Logs"
msgstr "Debug et Logs"
msgid "Email Notifications"
msgstr "Notifications par Email"
msgid "Enable email notifications"
msgstr "Activer les notifications par email"
msgid "Notification for critical alerts only"
msgstr "Notifications pour les alertes critiques uniquement"
msgid "Default notification recipients"
msgstr "Destinataires par défaut des notifications"
msgid "Comma-separated email addresses"
msgstr "Adresses email séparées par des virgules"
msgid "Asset Detection Rules"
msgstr "Règles de détection des assets"
msgid "Match computers by hostname"
msgstr "Correspondance ordinateurs par nom d'hôte"
msgid "Match network equipment by hostname"
msgstr "Correspondance équipements réseau par nom d'hôte"
msgid "Hostname patterns to ignore"
msgstr "Motifs de nom d'hôte à ignorer"
msgid "One pattern per line. Use * as wildcard."
msgstr "Un motif par ligne. Utilisez * comme caractère générique."
msgid "Test Asset Mapping"
msgstr "Tester le mapping des assets"
msgid "Agent name or IP"
msgstr "Nom d'agent ou IP"
msgid "Test"
msgstr "Tester"
msgid "Please enter an agent name or IP address"
msgstr "Veuillez saisir un nom d'agent ou une adresse IP"
msgid "Test failed"
msgstr "Échec du test"
msgid "Log API requests"
msgstr "Journaliser les requêtes API"
msgid "Keep logs for (days)"
msgstr "Conserver les logs pendant (jours)"
msgid "Clear All Logs"
msgstr "Effacer tous les logs"
msgid "Are you sure you want to clear all logs?"
msgstr "Êtes-vous sûr de vouloir effacer tous les logs ?"
msgid "Logs cleared successfully"
msgstr "Logs effacés avec succès"
msgid "Failed to clear logs"
msgstr "Échec de l'effacement des logs"
msgid "Recent Logs"
msgstr "Logs récents"
msgid "Level"
msgstr "Niveau"
msgid "Message"
msgstr "Message"
msgid "System"
msgstr "Système"
msgid "No logs found"
msgstr "Aucun log trouvé"

0
locales/it_IT.mo Normal file
View File

0
locales/it_IT.po Normal file
View File

0
locales/pl_PL.mo Normal file
View File

0
locales/pl_PL.po Normal file
View File

0
locales/pt_BR.mo Normal file
View File

0
locales/pt_BR.po Normal file
View File

235
setup.php Normal file
View File

@@ -0,0 +1,235 @@
<?php
/*
* Plugin SIEM-Wazuh pour GLPI
* Description: Intégration SIEM Wazuh avec GLPI
* Version: 1.0.0
*/
define('PLUGIN_SIEM_WAZUH_VERSION', '1.0.0');
define('PLUGIN_SIEM_WAZUH_MIN_GLPI', '10.0.0');
define('PLUGIN_SIEM_WAZUH_MAX_GLPI', '10.0.99');
/**
* Plugin init function
*/
function plugin_init_siem_wazuh() {
global $PLUGIN_HOOKS, $CFG_GLPI;
$PLUGIN_HOOKS['csrf_compliant']['siem-wazuh'] = true;
// Enregistrement du plugin
Plugin::registerClass('PluginSiemWazuhServer', [
'linkgroup' => 'admin',
'linktext' => __('Wazuh Servers', 'siem-wazuh'),
'icon' => 'fas fa-shield-alt'
]);
Plugin::registerClass('PluginSiemWazuhConfig', [
'linkgroup' => 'tools',
'linktext' => __('SIEM Wazuh Configuration', 'siem-wazuh'),
'icon' => 'fas fa-cogs'
]);
Plugin::registerClass('PluginSiemWazuhAlert');
// Ajout des menus
if (Session::haveRight('plugin_siem_wazuh_server', READ)) {
$PLUGIN_HOOKS['menu_toadd']['siem-wazuh']['admin'] = 'PluginSiemWazuhServer';
}
if (Session::haveRight('plugin_siem_wazuh_config', READ)) {
$PLUGIN_HOOKS['menu_toadd']['siem-wazuh']['tools'] = 'PluginSiemWazuhConfig';
}
// Ajout des onglets sur les éléments
$PLUGIN_HOOKS['item_add_targets']['siem-wazuh'] = [
'Computer' => ['PluginSiemWazuhTab'],
'NetworkEquipment' => ['PluginSiemWazuhTab'],
'Peripheral' => ['PluginSiemWazuhTab'],
'Phone' => ['PluginSiemWazuhTab'],
'Printer' => ['PluginSiemWazuhTab']
];
// Hook pour l'affichage des onglets
$PLUGIN_HOOKS['display_item']['siem-wazuh'] = 'plugin_siem_wazuh_display_item';
// Hook pour les actions automatiques (cron)
$PLUGIN_HOOKS['cron']['siem-wazuh'] = 1;
// Hook pour les droits
$PLUGIN_HOOKS['change_profile']['siem-wazuh'] = ['PluginSiemWazuhProfile', 'changeProfile'];
$PLUGIN_HOOKS['init_profile']['siem-wazuh'] = ['PluginSiemWazuhProfile', 'initProfile'];
// CSS et JS
$PLUGIN_HOOKS['add_css']['siem-wazuh'][] = 'css/style.css';
$PLUGIN_HOOKS['add_javascript']['siem-wazuh'][] = 'js/wazuh.js';
// Import/Export
$PLUGIN_HOOKS['import_item']['siem-wazuh'] = ['Computer', 'NetworkEquipment'];
// Notification
$PLUGIN_HOOKS['item_get_events']['siem-wazuh'] = [
'PluginSiemWazuhAlert' => ['PluginSiemWazuhAlert', 'getEvents']
];
}
/**
* Plugin version function
*/
function plugin_version_siem_wazuh() {
return [
'name' => 'SIEM - Wazuh',
'version' => PLUGIN_SIEM_WAZUH_VERSION,
'author' => 'SIEM-Wazuh Team',
'license' => 'GPLv2+',
'homepage' => 'https://github.com/siem-wazuh/glpi-plugin',
'requirements' => [
'glpi' => [
'min' => PLUGIN_SIEM_WAZUH_MIN_GLPI,
'max' => PLUGIN_SIEM_WAZUH_MAX_GLPI,
],
'php' => [
'min' => '7.4',
],
'params' => [
'check_prerequisites' => true,
]
]
];
}
/**
* Check plugin prerequisites
*/
function plugin_siem_wazuh_check_prerequisites() {
// Vérification de la version PHP
if (version_compare(PHP_VERSION, '7.4', '<')) {
echo "Ce plugin nécessite PHP 7.4 ou supérieur";
return false;
}
// Vérification de la version GLPI
if (!method_exists('Plugin', 'checkGlpiVersion')) {
echo "Cette version de GLPI n'est pas supportée";
return false;
}
if (!Plugin::checkGlpiVersion(PLUGIN_SIEM_WAZUH_MIN_GLPI, PLUGIN_SIEM_WAZUH_MAX_GLPI)) {
echo "Ce plugin nécessite GLPI >= " . PLUGIN_SIEM_WAZUH_MIN_GLPI . " et < " . PLUGIN_SIEM_WAZUH_MAX_GLPI;
return false;
}
// Vérification des extensions PHP nécessaires
$required_extensions = ['curl', 'json', 'mbstring', 'openssl'];
foreach ($required_extensions as $ext) {
if (!extension_loaded($ext)) {
echo "Extension PHP manquante: $ext";
return false;
}
}
return true;
}
/**
* Check plugin configuration
*/
function plugin_siem_wazuh_check_config() {
return true;
}
/**
* Plugin display item hook
*/
function plugin_siem_wazuh_display_item($item) {
if (in_array($item->getType(), ['Computer', 'NetworkEquipment', 'Peripheral', 'Phone', 'Printer'])) {
if (Session::haveRight('plugin_siem_wazuh_alert', READ)) {
$tab = new PluginSiemWazuhTab();
$tab->showForItem($item);
}
}
}
/**
* Get cron description
*/
function plugin_siem_wazuh_cron_description($name) {
switch ($name) {
case 'sync_alerts':
return __('Synchronize Wazuh alerts', 'siem-wazuh');
case 'cleanup_old_alerts':
return __('Cleanup old alerts', 'siem-wazuh');
default:
return '';
}
}
/**
* Execute cron task
*/
function plugin_siem_wazuh_cron($name) {
global $DB;
switch ($name) {
case 'sync_alerts':
return PluginSiemWazuhAlert::cronSyncAlerts();
case 'cleanup_old_alerts':
return PluginSiemWazuhAlert::cronCleanupOldAlerts();
default:
return false;
}
}
/**
* Get additional menu entries
*/
function plugin_siem_wazuh_get_additional_menu_entries($forcetab = '') {
$entries = [];
if (Session::haveRight('plugin_siem_wazuh_server', READ)) {
$entries['<img src="' . Plugin::getWebDir('siem-wazuh') . '/pics/wazuh-logo.png" width="16" height="16" alt="">&nbsp;' .
__('Wazuh Servers', 'siem-wazuh')] = '/plugins/siem-wazuh/front/wazuhserver.php';
}
return $entries;
}
/**
* Get dropdown values
*/
function plugin_siem_wazuh_get_dropdown_values($post, $dropdown_name = '') {
switch ($dropdown_name) {
case 'PluginSiemWazuhServer':
return PluginSiemWazuhServer::getDropdownValues($post);
default:
return [];
}
}
/**
* Get search options
*/
function plugin_siem_wazuh_getAddSearchOptions($itemtype) {
$sopt = [];
switch ($itemtype) {
case 'Computer':
case 'NetworkEquipment':
$sopt[5150]['table'] = 'glpi_plugin_siem_wazuh_alerts';
$sopt[5150]['field'] = 'id';
$sopt[5150]['name'] = __('Wazuh Alerts', 'siem-wazuh');
$sopt[5150]['forcegroupby'] = true;
$sopt[5150]['usehaving'] = true;
$sopt[5150]['datatype'] = 'count';
$sopt[5150]['massiveaction'] = false;
$sopt[5150]['joinparams'] = [
'jointype' => 'itemtype_item',
'specific_itemtype' => $itemtype
];
break;
}
return $sopt;
}

148
sql/install.sql Normal file
View File

@@ -0,0 +1,148 @@
-- Plugin SIEM-Wazuh - Installation script
-- Table des serveurs Wazuh
CREATE TABLE IF NOT EXISTS `glpi_plugin_siem_wazuh_servers` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NOT NULL COMMENT 'Nom de la connexion',
`wazuh_url` VARCHAR(255) NOT NULL COMMENT 'URL du serveur Wazuh',
`wazuh_port` INT(11) DEFAULT 55000 COMMENT 'Port API Wazuh',
`wazuh_login` VARCHAR(255) NOT NULL COMMENT 'Login API Wazuh',
`wazuh_password` TEXT NOT NULL COMMENT 'Mot de passe API Wazuh (crypté)',
`indexer_url` VARCHAR(255) DEFAULT NULL COMMENT 'URL du serveur Indexer',
`indexer_port` INT(11) DEFAULT 9200 COMMENT 'Port API Indexer',
`indexer_login` VARCHAR(255) DEFAULT NULL COMMENT 'Login API Indexer',
`indexer_password` TEXT DEFAULT NULL COMMENT 'Mot de passe API Indexer (crypté)',
`sync_interval` INT(11) DEFAULT 300 COMMENT 'Intervalle de synchronisation en secondes',
`is_active` TINYINT(1) DEFAULT 1 COMMENT 'Serveur actif',
`last_sync` DATETIME DEFAULT NULL COMMENT 'Dernière synchronisation',
`ticket_type` INT(11) DEFAULT 1 COMMENT 'Type de ticket par défaut',
`ticket_category` INT(11) DEFAULT NULL COMMENT 'Catégorie de ticket par défaut',
`date_creation` DATETIME DEFAULT CURRENT_TIMESTAMP,
`date_mod` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `is_active` (`is_active`),
INDEX `last_sync` (`last_sync`),
INDEX `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- Table des alertes Wazuh
CREATE TABLE IF NOT EXISTS `glpi_plugin_siem_wazuh_alerts` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`wazuh_server_id` INT(11) NOT NULL COMMENT 'ID du serveur Wazuh',
`alert_id` VARCHAR(255) NOT NULL COMMENT 'ID unique de l\'alerte Wazuh',
`rule_id` INT(11) DEFAULT NULL COMMENT 'ID de la règle Wazuh',
`rule_level` INT(11) DEFAULT NULL COMMENT 'Niveau de la règle',
`rule_description` TEXT DEFAULT NULL COMMENT 'Description de la règle',
`agent_id` VARCHAR(255) DEFAULT NULL COMMENT 'ID de l\'agent Wazuh',
`agent_name` VARCHAR(255) DEFAULT NULL COMMENT 'Nom de l\'agent Wazuh',
`agent_ip` VARCHAR(45) DEFAULT NULL COMMENT 'IP de l\'agent',
`timestamp` DATETIME NOT NULL COMMENT 'Timestamp de l\'alerte',
`raw_data` LONGTEXT DEFAULT NULL COMMENT 'Données brutes de l\'alerte (JSON)',
`computer_id` INT(11) DEFAULT NULL COMMENT 'ID de l\'ordinateur GLPI associé',
`networkequipment_id` INT(11) DEFAULT NULL COMMENT 'ID de l\'équipement réseau GLPI associé',
`peripheral_id` INT(11) DEFAULT NULL COMMENT 'ID du périphérique GLPI associé',
`phone_id` INT(11) DEFAULT NULL COMMENT 'ID du téléphone GLPI associé',
`printer_id` INT(11) DEFAULT NULL COMMENT 'ID de l\'imprimante GLPI associée',
`ticket_id` INT(11) DEFAULT NULL COMMENT 'ID du ticket GLPI créé',
`status` ENUM('new', 'processed', 'ignored', 'ticket_created') DEFAULT 'new',
`severity` ENUM('low', 'medium', 'high', 'critical') DEFAULT 'medium',
`date_creation` DATETIME DEFAULT CURRENT_TIMESTAMP,
`date_mod` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `unique_alert` (`wazuh_server_id`, `alert_id`),
INDEX `agent_name` (`agent_name`),
INDEX `agent_ip` (`agent_ip`),
INDEX `status` (`status`),
INDEX `severity` (`severity`),
INDEX `timestamp` (`timestamp`),
INDEX `rule_level` (`rule_level`),
INDEX `computer_id` (`computer_id`),
INDEX `networkequipment_id` (`networkequipment_id`),
INDEX `peripheral_id` (`peripheral_id`),
INDEX `phone_id` (`phone_id`),
INDEX `printer_id` (`printer_id`),
INDEX `ticket_id` (`ticket_id`),
FOREIGN KEY (`wazuh_server_id`) REFERENCES `glpi_plugin_siem_wazuh_servers` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- Table de configuration
CREATE TABLE IF NOT EXISTS `glpi_plugin_siem_wazuh_config` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NOT NULL COMMENT 'Nom du paramètre',
`value` TEXT DEFAULT NULL COMMENT 'Valeur du paramètre',
`context` VARCHAR(100) DEFAULT 'global' COMMENT 'Contexte du paramètre',
`date_creation` DATETIME DEFAULT CURRENT_TIMESTAMP,
`date_mod` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `name_context` (`name`, `context`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- Table des profils/droits
CREATE TABLE IF NOT EXISTS `glpi_plugin_siem_wazuh_profiles` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`profiles_id` INT(11) NOT NULL COMMENT 'ID du profil GLPI',
`wazuh_config` CHAR(1) DEFAULT NULL COMMENT 'Droit configuration Wazuh',
`wazuh_server` CHAR(1) DEFAULT NULL COMMENT 'Droit serveur Wazuh',
`wazuh_alert` CHAR(1) DEFAULT NULL COMMENT 'Droit alerte Wazuh',
PRIMARY KEY (`id`),
UNIQUE KEY `profiles_id` (`profiles_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- Table de logs
CREATE TABLE IF NOT EXISTS `glpi_plugin_siem_wazuh_logs` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`wazuh_server_id` INT(11) DEFAULT NULL COMMENT 'ID du serveur Wazuh',
`level` ENUM('debug', 'info', 'warning', 'error', 'critical') DEFAULT 'info',
`message` TEXT NOT NULL,
`context` JSON DEFAULT NULL COMMENT 'Contexte supplémentaire',
`date_creation` DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `level` (`level`),
INDEX `wazuh_server_id` (`wazuh_server_id`),
INDEX `date_creation` (`date_creation`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- Table des règles de correspondance
CREATE TABLE IF NOT EXISTS `glpi_plugin_siem_wazuh_rules` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NOT NULL COMMENT 'Nom de la règle',
`wazuh_rule_id` INT(11) DEFAULT NULL COMMENT 'ID de la règle Wazuh',
`wazuh_rule_level` INT(11) DEFAULT NULL COMMENT 'Niveau de la règle Wazuh',
`pattern_agent_name` VARCHAR(255) DEFAULT NULL COMMENT 'Pattern nom agent',
`pattern_agent_ip` VARCHAR(255) DEFAULT NULL COMMENT 'Pattern IP agent',
`ticket_type` INT(11) DEFAULT 1 COMMENT 'Type de ticket à créer',
`ticket_category` INT(11) DEFAULT NULL COMMENT 'Catégorie de ticket',
`ticket_priority` INT(11) DEFAULT 3 COMMENT 'Priorité du ticket',
`ticket_urgency` INT(11) DEFAULT 3 COMMENT 'Urgence du ticket',
`ticket_impact` INT(11) DEFAULT 3 COMMENT 'Impact du ticket',
`auto_assign` TINYINT(1) DEFAULT 0 COMMENT 'Assignment automatique',
`assigned_to` INT(11) DEFAULT NULL COMMENT 'Utilisateur assigné',
`assigned_group` INT(11) DEFAULT NULL COMMENT 'Groupe assigné',
`is_active` TINYINT(1) DEFAULT 1,
`date_creation` DATETIME DEFAULT CURRENT_TIMESTAMP,
`date_mod` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `wazuh_rule_id` (`wazuh_rule_id`),
INDEX `wazuh_rule_level` (`wazuh_rule_level`),
INDEX `is_active` (`is_active`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- Insertion des données par défaut
INSERT INTO `glpi_plugin_siem_wazuh_config` (`name`, `value`, `context`) VALUES
('auto_create_ticket', '1', 'global'),
('default_ticket_priority', '3', 'global'),
('default_ticket_urgency', '3', 'global'),
('default_ticket_impact', '3', 'global'),
('alert_retention_days', '90', 'global'),
('sync_enabled', '1', 'global'),
('max_alerts_per_sync', '100', 'global'),
('notification_enabled', '1', 'global'),
('min_rule_level', '5', 'global'),
('debug_mode', '0', 'global');
-- Insertion des règles par défaut
INSERT INTO `glpi_plugin_siem_wazuh_rules` (`name`, `wazuh_rule_level`, `ticket_type`, `ticket_priority`, `is_active`) VALUES
('Alertes critiques (niveau 12+)', 12, 1, 5, 1),
('Alertes élevées (niveau 10-11)', 10, 1, 4, 1),
('Alertes moyennes (niveau 7-9)', 7, 1, 3, 1),
('Alertes faibles (niveau 5-6)', 5, 1, 2, 0);

46
sql/uninstall.sql Normal file
View File

@@ -0,0 +1,46 @@
-- Plugin SIEM-Wazuh - Uninstallation script
-- Désactivation des contraintes de clés étrangères temporairement
SET FOREIGN_KEY_CHECKS = 0;
-- Suppression des tables dans l'ordre inverse des dépendances
DROP TABLE IF EXISTS `glpi_plugin_siem_wazuh_logs`;
DROP TABLE IF EXISTS `glpi_plugin_siem_wazuh_rules`;
DROP TABLE IF EXISTS `glpi_plugin_siem_wazuh_alerts`;
DROP TABLE IF EXISTS `glpi_plugin_siem_wazuh_profiles`;
DROP TABLE IF EXISTS `glpi_plugin_siem_wazuh_config`;
DROP TABLE IF EXISTS `glpi_plugin_siem_wazuh_servers`;
-- Réactivation des contraintes de clés étrangères
SET FOREIGN_KEY_CHECKS = 1;
-- Suppression des droits du plugin
DELETE FROM `glpi_profilerights` WHERE `name` LIKE 'plugin_siem_wazuh_%';
-- Suppression des tâches cron
DELETE FROM `glpi_crontasks` WHERE `itemtype` LIKE 'PluginSiemWazuh%';
-- Suppression des notifications
DELETE FROM `glpi_notifications` WHERE `itemtype` LIKE 'PluginSiemWazuh%';
DELETE FROM `glpi_notificationtemplates` WHERE `itemtype` LIKE 'PluginSiemWazuh%';
-- Suppression des événements de log
DELETE FROM `glpi_events` WHERE `type` = 'siem-wazuh';
-- Suppression des configurations dans la table des configurations générales
DELETE FROM `glpi_configs` WHERE `name` LIKE 'plugin_siem_wazuh_%';
-- Suppression des préférences utilisateur liées au plugin
DELETE FROM `glpi_users_configs` WHERE `name` LIKE 'plugin_siem_wazuh_%';
-- Nettoyage des liens avec les tickets (optionnel - conserve les tickets créés)
-- UPDATE `glpi_tickets` SET `content` = REPLACE(`content`, '[WAZUH-ALERT]', '') WHERE `content` LIKE '%[WAZUH-ALERT]%';
-- Nettoyage des recherches sauvegardées liées au plugin
DELETE FROM `glpi_savedsearches` WHERE `type` LIKE 'PluginSiemWazuh%';
-- Suppression des affichages personnalisés
DELETE FROM `glpi_displaypreferences` WHERE `itemtype` LIKE 'PluginSiemWazuh%';
-- Suppression des options de recherche personnalisées
DELETE FROM `glpi_searchoptions` WHERE `itemtype` LIKE 'PluginSiemWazuh%';

0
wazuhapi.class.php Normal file
View File