diff --git a/app/Controllers/AuthController.php b/app/Controllers/AuthController.php new file mode 100644 index 0000000..0785f4d --- /dev/null +++ b/app/Controllers/AuthController.php @@ -0,0 +1,167 @@ + Konfigurationswerte der Anwendung (aus config.php) */ + private array $config; + + /** @var LdapAuthService Service, der die eigentliche LDAP/AD-Authentifizierung übernimmt */ + private LdapAuthService $ldapAuthService; + + /** + * Übergibt die Konfiguration an den Controller und initialisiert den LDAP-Authentifizierungsservice. + * + * @param array $config Vollständige Konfiguration aus config.php + */ + public function __construct(array $config) + { + // Komplette Config in der Instanz speichern (z. B. für Zugriff auf security- oder ldap-Settings) + $this->config = $config; + + // LdapAuthService mit dem Teilbereich "ldap" aus der Konfiguration initialisieren. + // Wenn 'ldap' nicht gesetzt ist, wird ein leeres Array übergeben (Fail fast erfolgt dann im Service). + $this->ldapAuthService = new LdapAuthService($config['ldap'] ?? []); + } + + /** + * Zeigt das Login-Formular an. + * Optional kann eine Fehlermeldung übergeben werden, die in der View dargestellt wird. + */ + public function showLoginForm(?string $errorMessage = null): void + { + // Pfad zur Login-View (Template-Datei) ermitteln. + $viewPath = __DIR__ . '/../../public/views/login.php'; + + // Variable für die View vorbereiten (wird in der eingebundenen Datei verwendet). + $error = $errorMessage; + + // Falls die View-Datei (noch) nicht existiert, einen Fallback-HTML-Output verwenden. + if (file_exists($viewPath) === false) { + $this->renderInlineLogin($error); + return; + } + + // View-Datei einbinden. Variablen aus dieser Methode (z. B. $error) sind dort verfügbar. + require $viewPath; + } + + /** + * Verarbeitet das Login-Formular: + * - Liest Benutzername und Passwort aus $_POST + * - Ruft den LdapAuthService zur Authentifizierung auf + * - Setzt bei Erfolg die Session und leitet zum Dashboard weiter + * - Zeigt bei Fehlern erneut das Login-Formular mit Fehlermeldung an + */ + public function processLogin(): void + { + // Formulardaten aus dem POST-Request lesen. + $username = trim($_POST['username'] ?? ''); + $password = (string)($_POST['password'] ?? ''); + + try { + // Versuch, den Benutzer per LDAP/AD zu authentifizieren. + // true = Authentifizierung erfolgreich + // false = Anmeldedaten fachlich ungültig (Benutzer/Passwort falsch) + $authenticated = $this->ldapAuthService->authenticate($username, $password); + } catch (\Throwable $exception) { + // Technischer Fehler (z. B. LDAP-Server nicht erreichbar, falsche Konfiguration). + // In diesem Fall wird eine technische Fehlermeldung im Login-Formular angezeigt. + $this->showLoginForm('Technischer Fehler bei der Anmeldung: ' . $exception->getMessage()); + return; + } + + // Fachlich fehlgeschlagene Anmeldung (z. B. falsches Passwort). + if ($authenticated === false) { + $this->showLoginForm('Benutzername oder Passwort ist ungültig.'); + return; + } + + // Ab hier ist die Anmeldung erfolgreich. + + // Session-Key für den eingeloggten Benutzer aus der Konfiguration lesen. + // Wenn nicht gesetzt, wird "admin_user" als Standard verwendet. + $sessionKey = $this->config['security']['session_key_user'] ?? 'admin_user'; + + // Benutzerinformationen in der Session hinterlegen. + // Diese Daten werden später von requireLogin() ausgewertet. + $_SESSION[$sessionKey] = [ + 'username' => $username, + 'login_at' => date('c'), // ISO-8601 Datum/Zeit der Anmeldung + ]; + + // Nach erfolgreicher Anmeldung zum Dashboard weiterleiten. + header('Location: index.php?route=dashboard'); + exit; + } + + /** + * Meldet den aktuell eingeloggten Benutzer ab, indem der entsprechende Session-Eintrag entfernt wird, + * und leitet anschließend zurück auf die Login-Seite. + */ + public function logout(): void + { + // Session-Key für den eingeloggten Benutzer aus der Konfiguration lesen. + $sessionKey = $this->config['security']['session_key_user'] ?? 'admin_user'; + + // Eintrag aus der Session entfernen → Benutzer gilt als ausgeloggt. + unset($_SESSION[$sessionKey]); + + // Zur Login-Seite zurückleiten. + header('Location: index.php?route=login'); + exit; + } + + /** + * Fallback-Ausgabe für das Login-Formular, falls noch keine separate View-Datei existiert. + * Gibt direkt HTML aus (inline-Template). + */ + private function renderInlineLogin(?string $errorMessage): void + { + ?> + + + + + AD Admin Tool – Login + + +

AD Admin Tool – Login

+ + + +

+ + + +
+
+ + +
+ +
+ + +
+ + +
+ + + + Anmeldedaten sind gültig + * - false -> Anmeldedaten sind fachlich ungültig (z. B. falsches Passwort) + * Technische Fehler (z. B. falsche Konfiguration, keine Verbindung) werden als Exception geworfen. + */ +class LdapAuthService +{ + /** @var array LDAP-spezifische Konfiguration (Server, Port, Domain-Suffix, Timeout, etc.) */ + private array $config; + + /** + * Erwartet den Teilbereich "ldap" aus der allgemeinen Konfiguration (config.php). + * + * @param array $ldapConfig Konfiguration für die LDAP-Verbindung + */ + public function __construct(array $ldapConfig) + { + // LDAP-Konfiguration in der Instanz speichern. + $this->config = $ldapConfig; + } + + /** + * Führt die eigentliche LDAP/AD-Authentifizierung durch. + * + * @param string $username Benutzername (ohne Domain-Suffix, z. B. "administrator") + * @param string $password Passwort im Klartext (wird direkt an ldap_bind übergeben) + * + * @return bool true bei erfolgreicher Anmeldung, false bei fachlich ungültigen Anmeldedaten + * + * @throws RuntimeException bei technischen Problemen (z. B. fehlende Konfiguration, Verbindungsfehler) + */ + public function authenticate(string $username, string $password): bool + { + // Wenn Benutzername oder Passwort leer sind, gar nicht erst versuchen zu binden. + // Das ist ein fachlich ungültiger Login und wird mit false behandelt. + if ($username === '' || $password === '') { + return false; + } + + // Benötigte Werte aus der LDAP-Konfiguration auslesen. + // Falls einzelne Werte fehlen, werden sinnvolle Standardwerte gesetzt. + $server = (string)($this->config['server'] ?? ''); + $port = (int)($this->config['port'] ?? 636); + $domainSuffix = (string)($this->config['domain_suffix'] ?? ''); + $timeout = (int)($this->config['timeout'] ?? 5); + + // Ohne Server-Adresse oder Domain-Suffix ist eine sinnvolle Anmeldung nicht möglich. + // Das ist ein Konfigurationsfehler und wird als technischer Fehler behandelt. + if ($server === '' || $domainSuffix === '') { + throw new RuntimeException('LDAP-Konfiguration ist unvollständig.'); + } + + // Verbindung zum LDAP/AD-Server herstellen. + // Rückgabewert ist eine Ressource (Verbindungshandle) oder false bei Fehlern. + $connection = ldap_connect($server, $port); + + if ($connection === false) { + throw new RuntimeException('LDAP-Verbindung konnte nicht aufgebaut werden.'); + } + + // LDAP-Optionen setzen: + // - Protokollversion 3 (Standard in aktuellen Umgebungen) + // - Netzwerk-Timeout, damit die Anfrage nicht unendlich hängt + ldap_set_option($connection, LDAP_OPT_PROTOCOL_VERSION, 3); + ldap_set_option($connection, LDAP_OPT_NETWORK_TIMEOUT, $timeout); + + // UPN (User Principal Name) aus Benutzername und Domain-Suffix bilden. + // Beispiel: "administrator" + "@ITFA-PROJ-DOM.local" -> "administrator@ITFA-PROJ-DOM.local" + $bindRdn = $username . $domainSuffix; + + // Eigentliche Authentifizierung: + // ldap_bind versucht, sich mit den angegebenen Anmeldedaten am AD/LDAP anzumelden. + // Rückgabewerte: + // - true -> Anmeldedaten sind gültig + // - false -> Anmeldedaten sind ungültig (z. B. falsches Passwort) + // + // Das @-Zeichen unterdrückt PHP-Warnings, damit Fehlermeldungen nicht unformatiert im HTML landen. + $bindResult = @ldap_bind($connection, $bindRdn, $password); + + // Verbindung zum LDAP-Server wieder schließen. + ldap_unbind($connection); + + // Bei erfolgreichem Bind (true) -> Authentifizierung erfolgreich. + // Bei false -> fachlich fehlgeschlagene Anmeldung (z. B. falsche Credentials). + return $bindResult === true; + } +} diff --git a/config/config.php b/config/config.php new file mode 100644 index 0000000..d0dbd22 --- /dev/null +++ b/config/config.php @@ -0,0 +1,27 @@ + [ + // LDAP-URL des Domain Controllers + 'server' => 'ITFA-PROJ-SRV.ITFA-PROJ-DOM.local', + 'port' => 389, + + // wird an den Benutzernamen angehängt (z.B. "admin" + "@ITFA-PROJ-DOM.local") + 'domain_suffix' => '@ITFA-PROJ-DOM.local', + + // Base DN der Domäne + 'base_dn' => 'DC=ITFA-PROJ-DOM,DC=local', + + // Optional: Timeout in Sekunden + 'timeout' => 5, + ], + + 'security' => [ + // Session-Key unter dem der eingeloggte Admin gespeichert wird + 'session_key_user' => 'admin_user', + ], +]; diff --git a/public/index.php b/public/index.php new file mode 100644 index 0000000..c8d556a --- /dev/null +++ b/public/index.php @@ -0,0 +1,100 @@ + $config */ +$config = require $configPath; + +use App\Controllers\AuthController; + +// Hilfsfunktion für geschützte Routen +function requireLogin(array $config): void +{ + // session_key_user aus dem Config-Array lesen. Wenn nicht gesetzt oder null, Standard "admin_user" verwenden. + $sessionKey = $config['security']['session_key_user'] ?? 'admin_user'; + + // Prüfen, ob in $_SESSION unter diesem Key ein eingeloggter Benutzer hinterlegt ist. + // Falls nicht, zurück zur Login-Seite umleiten. + if (isset($_SESSION[$sessionKey]) === false) { + header('Location: index.php?route=login'); + exit; + } +} + +// Route aus dem GET-Parameter lesen. Wenn nicht gesetzt, Standardroute "login" verwenden. +$route = $_GET['route'] ?? 'login'; + +// Neue Instanz der Klasse AuthController erstellen (wird bei Bedarf über den Autoloader geladen). +$authController = new AuthController($config); + +// Anhand des Routing-Ziels (route) entscheiden, welcher Code ausgeführt wird. +switch ($route) { + case 'login': + $authController->showLoginForm(); + break; + + case 'login.submit': + if ($_SERVER['REQUEST_METHOD'] !== 'POST') { + header('Location: index.php?route=login'); + exit; + } + $authController->processLogin(); + break; + + case 'logout': + $authController->logout(); + break; + + case 'dashboard': + requireLogin($config); + // Später: DashboardController aufrufen + echo '

Dashboard (Platzhalter)

'; + echo '

Hier kommt später dein SNMP/Server-Status hin.

'; + echo '

Logout

'; + break; + + default: + http_response_code(404); + echo 'Route nicht gefunden.'; + break; +} diff --git a/public/login.php b/public/login.php index 50eb7e0..9e39ad9 100644 --- a/public/login.php +++ b/public/login.php @@ -1,33 +1,9 @@ @@ -73,12 +49,12 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {

Welcome Back!

- + -
+
+ + + + + + + + + + + + + SB Admin 2 - Login + + + + + + + + + + + + +
+ + +
+ +
+ +
+
+ +
+ +
+
+
+

Welcome Back!

+
+ + + + +
+ +
+
+ +
+
+
+ + +
+
+ + +
+ + +
+
+
+
+
+ +
+ +
+ +
+ + + + + + + + + + + + + + \ No newline at end of file