diff --git a/README.md b/README.md
index 0887cd6..bfaa5f0 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,351 @@
-# SIEM---Wazuh
+# Plugin GLPI SIEM-Wazuh
-Plugin GLPI pour intéger Wazuh dans GLPI
\ No newline at end of file
+[](https://github.com/siem-wazuh/glpi-plugin)
+[](https://glpi-project.org/)
+[](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
+
+
+ webhook
+ https://glpi.domain.com/plugins/siem-wazuh/webhook.php
+ 7
+ 100001,100002
+ json
+
+```
+
+## 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**
\ No newline at end of file
diff --git a/SIEM-Wazuh.xml b/SIEM-Wazuh.xml
new file mode 100644
index 0000000..6f355a9
--- /dev/null
+++ b/SIEM-Wazuh.xml
@@ -0,0 +1,106 @@
+
+
+ SIEM - Wazuh
+ siem-wazuh
+ stable
+ https://raw.githubusercontent.com/siem-wazuh/glpi-plugin/main/pics/wazuh-logo.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ https://github.com/siem-wazuh/glpi-plugin
+ https://github.com/siem-wazuh/glpi-plugin/releases
+ https://github.com/siem-wazuh/glpi-plugin/issues
+ https://github.com/siem-wazuh/glpi-plugin/blob/main/README.md
+
+ SIEM-Wazuh Team
+
+
+
+ 1.0.0
+ ~10.0.0
+ https://github.com/siem-wazuh/glpi-plugin/releases/download/1.0.0/glpi-siem-wazuh-1.0.0.tar.gz
+
+ 7.4
+ 10.0.0
+ 10.0.99
+
+
+
+ fr_FR
+ en_GB
+ de_DE
+ es_ES
+ it_IT
+ pt_BR
+ pl_PL
+
+ GPL v2+
+
+
+ SIEM
+ Sécurité
+ Wazuh
+ Alertes
+ Monitoring
+ Intégration
+
+
+ SIEM
+ Security
+ Wazuh
+ Alerts
+ Monitoring
+ Integration
+
+
+
+ https://raw.githubusercontent.com/siem-wazuh/glpi-plugin/main/pics/screenshot-1.png
+ https://raw.githubusercontent.com/siem-wazuh/glpi-plugin/main/pics/screenshot-2.png
+ https://raw.githubusercontent.com/siem-wazuh/glpi-plugin/main/pics/screenshot-3.png
+
+
\ No newline at end of file
diff --git a/ajax/sync_alerts.php b/ajax/sync_alerts.php
new file mode 100644
index 0000000..e1cb8b1
--- /dev/null
+++ b/ajax/sync_alerts.php
@@ -0,0 +1,342 @@
+ 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')
+ ];
+}
\ No newline at end of file
diff --git a/ajax/test_connection.php b/ajax/test_connection.php
new file mode 100644
index 0000000..d96f216
--- /dev/null
+++ b/ajax/test_connection.php
@@ -0,0 +1,81 @@
+ 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);
\ No newline at end of file
diff --git a/css/style.css b/css/style.css
new file mode 100644
index 0000000..cb53700
--- /dev/null
+++ b/css/style.css
@@ -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;
+ }
+}
\ No newline at end of file
diff --git a/front/wazuhalert.php b/front/wazuhalert.php
new file mode 100644
index 0000000..ad80d13
--- /dev/null
+++ b/front/wazuhalert.php
@@ -0,0 +1,706 @@
+ '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 "
";
+ echo "".__('Alert ID', 'siem-wazuh')." | ";
+ echo "".$this->fields["alert_id"]." | ";
+ echo "".__('Rule ID', 'siem-wazuh')." | ";
+ echo "".$this->fields["rule_id"]." | ";
+ echo "
";
+
+ echo "";
+ echo "".__('Rule Level', 'siem-wazuh')." | ";
+ echo "";
+ echo $this->fields["rule_level"];
+ if ($this->fields["rule_level"]) {
+ $severity = self::getSeverityFromLevel($this->fields["rule_level"]);
+ $severities = self::getSeverityArray();
+ echo " ".$severities[$severity]."";
+ }
+ echo " | ";
+ echo "".__('Agent Name', 'siem-wazuh')." | ";
+ echo "".$this->fields["agent_name"]." | ";
+ echo "
";
+
+ echo "";
+ echo "".__('Agent IP', 'siem-wazuh')." | ";
+ echo "".$this->fields["agent_ip"]." | ";
+ echo "".__('Timestamp', 'siem-wazuh')." | ";
+ echo "".Html::convDateTime($this->fields["timestamp"])." | ";
+ echo "
";
+
+ echo "";
+ echo "".__('Status')." | ";
+ echo "";
+ $statuses = self::getStatusArray();
+ Dropdown::showFromArray('status', $statuses, ['value' => $this->fields["status"]]);
+ echo " | ";
+ echo "".__('Severity', 'siem-wazuh')." | ";
+ echo "";
+ $severities = self::getSeverityArray();
+ Dropdown::showFromArray('severity', $severities, ['value' => $this->fields["severity"]]);
+ echo " | ";
+ echo "
";
+
+ echo "";
+ echo "".__('Rule Description', 'siem-wazuh')." | ";
+ echo "";
+ echo nl2br(Html::entities_deep($this->fields["rule_description"]));
+ echo " | ";
+ echo "
";
+
+ // Affichage des associations
+ if ($this->fields["computer_id"]) {
+ $computer = new Computer();
+ $computer->getFromDB($this->fields["computer_id"]);
+ echo "";
+ echo "".__('Associated Computer')." | ";
+ echo "";
+ echo $computer->getLink();
+ echo " | ";
+ echo " | | ";
+ echo "
";
+ }
+
+ if ($this->fields["networkequipment_id"]) {
+ $netequip = new NetworkEquipment();
+ $netequip->getFromDB($this->fields["networkequipment_id"]);
+ echo "";
+ echo "".__('Associated Network Equipment')." | ";
+ echo "";
+ echo $netequip->getLink();
+ echo " | ";
+ echo " | | ";
+ echo "
";
+ }
+
+ if ($this->fields["ticket_id"]) {
+ $ticket = new Ticket();
+ $ticket->getFromDB($this->fields["ticket_id"]);
+ echo "";
+ echo "".__('Associated Ticket')." | ";
+ echo "";
+ echo $ticket->getLink();
+ echo " | ";
+ echo " | | ";
+ echo "
";
+ }
+
+ // Affichage des données brutes
+ if (!empty($this->fields["raw_data"])) {
+ echo "";
+ echo "";
+ echo "";
+ echo "".__('Raw Alert Data', 'siem-wazuh')."";
+ echo "";
+ echo json_encode(json_decode($this->fields["raw_data"]), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
+ echo " ";
+ echo " ";
+ echo " | ";
+ echo "
";
+ }
+
+ $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 "";
+ echo "
";
+ echo "";
+ echo "".__('Alert ID', 'siem-wazuh')." | ";
+ echo "".__('Rule', 'siem-wazuh')." | ";
+ echo "".__('Level', 'siem-wazuh')." | ";
+ echo "".__('Agent', 'siem-wazuh')." | ";
+ echo "".__('Timestamp', 'siem-wazuh')." | ";
+ echo "".__('Status')." | ";
+ echo "".__('Ticket')." | ";
+ echo "
";
+
+ $statuses = self::getStatusArray();
+
+ foreach ($iterator as $row) {
+ echo "";
+ echo "".$row['alert_id']." | ";
+ echo "".$row['rule_id']." - ".Html::clean($row['rule_description'])." | ";
+ echo "".$row['rule_level']." | ";
+ echo "".$row['agent_name']." (".$row['agent_ip'].") | ";
+ echo "".Html::convDateTime($row['timestamp'])." | ";
+ echo "".$statuses[$row['status']]." | ";
+ echo "";
+ if ($row['ticket_id']) {
+ $ticket = new Ticket();
+ if ($ticket->getFromDB($row['ticket_id'])) {
+ echo $ticket->getLink();
+ }
+ }
+ echo " | ";
+ echo "
";
+ }
+
+ echo "
";
+ echo "
";
+ }
+
+ /**
+ * 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());
+ }
+}
\ No newline at end of file
diff --git a/front/wazuhconfig.php b/front/wazuhconfig.php
new file mode 100644
index 0000000..20acd94
--- /dev/null
+++ b/front/wazuhconfig.php
@@ -0,0 +1,393 @@
+processConfigForm();
+
+// Initialisation de l'affichage
+Html::header(
+ PluginSiemWazuhConfig::getTypeName(1),
+ $_SERVER['PHP_SELF'],
+ 'tools',
+ 'PluginSiemWazuhConfig'
+);
+
+echo "";
+
+// 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 "
";
+echo "
";
+foreach ($tabs as $tab_key => $tab_name) {
+ $active_class = ($active_tab == $tab_key) ? ' active' : '';
+ echo "- ";
+ echo "$tab_name";
+ echo "
";
+}
+echo "
";
+echo "
";
+
+echo "
";
+
+switch ($active_tab) {
+ case 'config':
+ // Configuration générale
+ $config->showConfigForm();
+ break;
+
+ case 'mapping':
+ // Configuration du mapping des assets
+ echo "
";
+ echo "
" . __('Asset Mapping Configuration', 'siem-wazuh') . "
";
+ showMappingConfiguration($config);
+ echo "";
+ break;
+
+ case 'notifications':
+ // Configuration des notifications
+ echo "
";
+ echo "
" . __('Notification Configuration', 'siem-wazuh') . "
";
+ showNotificationConfiguration($config);
+ echo "";
+ break;
+
+ case 'debug':
+ // Configuration de debug et logs
+ echo "
";
+ echo "
" . __('Debug & Logs Configuration', 'siem-wazuh') . "
";
+ showDebugConfiguration($config);
+ showRecentLogs();
+ echo "";
+ break;
+}
+
+echo "
";
+echo "
";
+
+/**
+ * Show mapping configuration
+ */
+function showMappingConfiguration($config) {
+ echo "