diff --git a/simpleAPI/config/config.php b/simpleAPI/config/config.php index 619e73e11d..f6a537950d 100644 --- a/simpleAPI/config/config.php +++ b/simpleAPI/config/config.php @@ -4,7 +4,7 @@ // MQTT Broker Konfiguration 'mqtt' => [ 'server' => 'localhost', - 'port' => 1884, + 'port' => 8883, 'validate_cert' => false, 'username' => '', 'password' => '', @@ -19,7 +19,7 @@ // Authentifizierung 'auth' => [ - 'enabled' => false, + 'enabled' => true, 'require_https' => false, // Gültige Tokens diff --git a/simpleAPI/simpleapi.php b/simpleAPI/simpleapi.php index 1aa678ee0d..8deb63b2b5 100644 --- a/simpleAPI/simpleapi.php +++ b/simpleAPI/simpleapi.php @@ -31,8 +31,8 @@ public function __construct() // Parameter Handler initialisieren $this->parameterHandler = new ParameterHandler($this->mqttClient); - // Authenticator initialisieren - $this->authenticator = new Authenticator($this->config); + // Authenticator initialisieren (mit MqttClient für Anmeldedaten-Test) + $this->authenticator = new Authenticator($this->config, $this->mqttClient); } /** @@ -61,6 +61,7 @@ public function handleRequest() $params = array_merge($_GET, $_POST); // Debug-Modus + $debugInfo = []; if (isset($params['debug']) && $params['debug'] === 'true') { $this->config['debug'] = true; } @@ -75,6 +76,20 @@ public function handleRequest() return; } + // MQTT-Anmeldedaten aus Parametern übernehmen falls vorhanden + if (isset($params['username']) && isset($params['password'])) { + $this->mqttClient->setCredentials($params['username'], $params['password']); + + if ($this->config['debug']) { + $debugInfo[] = "Using MQTT credentials from parameters: username={$params['username']}"; + } + } else { + // Keine Parameter-Anmeldedaten vorhanden + if ($this->config['debug']) { + $debugInfo[] = "No credentials provided via parameters, using config or anonymous access"; + } + } + // Schreibvorgänge prüfen $writeParams = $this->getWriteParameters($params); if (!empty($writeParams)) { @@ -96,7 +111,7 @@ public function handleRequest() // Lesevorgänge verarbeiten $readParams = $this->getReadParameters($params); if (!empty($readParams)) { - $result = $this->handleReadRequest($readParams, $params); + $result = $this->handleReadRequest($readParams, $params, $debugInfo); // Raw-Ausgabe Validierung if (isset($params['raw']) && $params['raw'] === 'true') { @@ -345,9 +360,14 @@ private function handleWriteRequest($writeParams, $allParams) /** * Leseanfrage verarbeiten */ - private function handleReadRequest($readParams, $allParams) + private function handleReadRequest($readParams, $allParams, $debugInfo = []) { $result = []; + + // Debug-Informationen hinzufügen wenn vorhanden + if (!empty($debugInfo) && $this->config['debug']) { + $result['debug_info'] = $debugInfo; + } foreach ($readParams as $param => $id) { try { diff --git a/simpleAPI/src/Authenticator.php b/simpleAPI/src/Authenticator.php index f0047d6648..a93af05052 100644 --- a/simpleAPI/src/Authenticator.php +++ b/simpleAPI/src/Authenticator.php @@ -8,10 +8,12 @@ class Authenticator { private $config; + private $mqttClient; - public function __construct($config) + public function __construct($config, $mqttClient = null) { $this->config = $config; + $this->mqttClient = $mqttClient; } /** @@ -39,6 +41,11 @@ public function authenticate($params) return true; } + // Fallback: Prüfen ob MQTT Broker ohne Authentifizierung zugänglich ist + if ($this->checkMqttNoAuth()) { + return true; + } + return false; } @@ -130,20 +137,27 @@ private function validateCredentials($username, $password) { $users = $this->config['auth']['users'] ?? []; - if (!isset($users[$username])) { - return false; + // Zuerst gegen definierte Benutzer prüfen + if (!empty($users) && isset($users[$username])) { + $storedPassword = $users[$username]; + + // Passwort-Hash prüfen + if (strpos($storedPassword, '$') === 0) { + // Gehashtes Passwort + return password_verify($password, $storedPassword); + } else { + // Klartext (nicht empfohlen) + return hash_equals($storedPassword, $password); + } } - $storedPassword = $users[$username]; - - // Passwort-Hash prüfen - if (strpos($storedPassword, '$') === 0) { - // Gehashtes Passwort - return password_verify($password, $storedPassword); - } else { - // Klartext (nicht empfohlen) - return hash_equals($storedPassword, $password); + // Wenn keine lokalen Benutzer definiert sind oder MqttClient verfügbar ist: + // Anmeldedaten gegen MQTT Broker testen + if ($this->mqttClient && (empty($users) || !isset($users[$username]))) { + return $this->mqttClient->testCredentials($username, $password); } + + return false; } /** @@ -181,4 +195,18 @@ private function isHttps() $_SERVER['SERVER_PORT'] == 443 || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https'); } + + /** + * Prüfen ob MQTT Broker ohne Authentifizierung zugänglich ist + */ + private function checkMqttNoAuth() + { + // Nur wenn MqttClient verfügbar ist + if (!$this->mqttClient) { + return false; + } + + // Test-Verbindung ohne Anmeldedaten + return $this->mqttClient->testCredentials('', ''); + } } diff --git a/simpleAPI/src/MqttClient.php b/simpleAPI/src/MqttClient.php index 4e2e896042..c45f81cc1b 100644 --- a/simpleAPI/src/MqttClient.php +++ b/simpleAPI/src/MqttClient.php @@ -28,6 +28,15 @@ public function __construct($config) $this->clientid = $config['mqtt']['clientid'] ?? 'SimpleAPI_' . uniqid(); } + /** + * MQTT-Anmeldedaten aktualisieren + */ + public function setCredentials($username, $password) + { + $this->username = $username; + $this->password = $password; + } + /** * Verbindung testen */ @@ -41,6 +50,28 @@ public function connect() return !preg_match('/error|failed|unable/i', $result ?? ''); } + /** + * Anmeldedaten am MQTT Broker testen + */ + public function testCredentials($username, $password) + { + // Test-Verbindung mit mosquitto_sub (sehr kurzes Timeout) + $cmd = $this->buildMosquittoCommandWithCredentials('sub', '$SYS/broker/uptime', '', 1, 2, $username, $password); + $result = shell_exec($cmd . ' 2>&1'); + + // Prüfen auf Authentifizierungsfehler + if (preg_match('/not authorised|connection refused|authentication failed|username or password invalid/i', $result ?? '')) { + return false; + } + + // Prüfen auf andere schwerwiegende Fehler + if (preg_match('/connection error|network unreachable|no such host/i', $result ?? '')) { + return false; + } + + return true; + } + /** * Wert aus MQTT Topic lesen */ @@ -107,6 +138,14 @@ public function setValue($topic, $value) * Mosquitto-Kommando erstellen */ private function buildMosquittoCommand($type, $topics, $message = '', $count = null, $timeout = 1, $extraArgs = []) + { + return $this->buildMosquittoCommandWithCredentials($type, $topics, $message, $count, $timeout, $this->username, $this->password, $extraArgs); + } + + /** + * Mosquitto-Kommando mit spezifischen Anmeldedaten erstellen + */ + private function buildMosquittoCommandWithCredentials($type, $topics, $message = '', $count = null, $timeout = 1, $username = null, $password = null, $extraArgs = []) { $binary = $type === 'sub' ? 'mosquitto_sub' : 'mosquitto_pub'; @@ -123,11 +162,14 @@ private function buildMosquittoCommand($type, $topics, $message = '', $count = n } // Username/Passwort hinzufügen falls konfiguriert - if (!empty($this->username)) { - $cmd .= sprintf(" -u %s", escapeshellarg($this->username)); + $useUsername = $username !== null ? $username : $this->username; + $usePassword = $password !== null ? $password : $this->password; + + if (!empty($useUsername)) { + $cmd .= sprintf(" -u %s", escapeshellarg($useUsername)); } - if (!empty($this->password)) { - $cmd .= sprintf(" -P %s", escapeshellarg($this->password)); + if (!empty($usePassword)) { + $cmd .= sprintf(" -P %s", escapeshellarg($usePassword)); } // Topic(s) hinzufügen