diff --git a/config/widgets.php b/config/widgets.php index 59a7be49..9df460e9 100644 --- a/config/widgets.php +++ b/config/widgets.php @@ -40,7 +40,7 @@ return [ 'title' => 'Systemstatus', 'icon' => 'SS', 'zone' => 'sidebar', - 'default_enabled' => true, + 'default_enabled' => false, 'supports_public_home' => true, 'summary' => 'Zeigt Desktop-Skin, Shell-Status und den aktuellen Ausbaugrad.', 'content' => 'Shell, Fenster-Manager und Registry laufen bereits. Login und Fachmodule folgen spaeter.', diff --git a/public/api/user-self-management/index.php b/public/api/user-self-management/index.php index f5194a2a..d9e0bc99 100644 --- a/public/api/user-self-management/index.php +++ b/public/api/user-self-management/index.php @@ -6,6 +6,7 @@ require_once dirname(__DIR__, 3) . '/src/App/bootstrap.php'; use App\ConfigLoader; use App\KeycloakAuth; +use App\LdapProvisioner; use App\UserSelfManagementService; use Desktop\AppRegistry; use Desktop\AppVisibility; @@ -29,6 +30,8 @@ $auth = new KeycloakAuth($keycloakConfig); $registry = new AppRegistry($projectRoot . '/config/apps.php'); $widgetRegistry = new WidgetRegistry($projectRoot . '/config/widgets.php'); $service = new UserSelfManagementService($projectRoot); +$registrationConfig = ConfigLoader::load($projectRoot, 'registration'); +$ldap = new LdapProvisioner($registrationConfig); $isAuthenticated = $auth->isAuthenticated(); $authUser = $isAuthenticated && is_array($_SESSION['desktop_auth']['user'] ?? null) ? $_SESSION['desktop_auth']['user'] @@ -58,6 +61,22 @@ $after = $service->save($decoded, $authUser, $visibleApps, $widgets, $skins); $payload = $service->buildBootstrapPayload($authUser, $visibleApps, $widgets, $skins); $payload['preferences'] = $after; $payload['meta']['requires_reload'] = requiresReload($before, $after); +$payload['meta']['ldap_profile_sync'] = [ + 'attempted' => false, + 'success' => false, + 'message' => 'LDAP-Sync nicht ausgefuehrt.', +]; + +$username = trim((string) ($authUser['username'] ?? '')); +if ($username !== '' && $ldap->isEnabled()) { + $payload['meta']['ldap_profile_sync']['attempted'] = true; + $ldapResult = $ldap->updateUserProfile($username, is_array($after['profile'] ?? null) ? $after['profile'] : []); + $payload['meta']['ldap_profile_sync']['success'] = (bool) ($ldapResult['success'] ?? false); + $payload['meta']['ldap_profile_sync']['message'] = (string) ($ldapResult['message'] ?? 'LDAP-Sync ohne Rueckmeldung.'); + if (isset($ldapResult['updated_fields']) && is_array($ldapResult['updated_fields'])) { + $payload['meta']['ldap_profile_sync']['updated_fields'] = array_values(array_map('strval', $ldapResult['updated_fields'])); + } +} respond($payload); diff --git a/public/assets/apps/user-self-management/app.js b/public/assets/apps/user-self-management/app.js index 8eb5d7ef..cf0c6dd9 100644 --- a/public/assets/apps/user-self-management/app.js +++ b/public/assets/apps/user-self-management/app.js @@ -345,11 +345,16 @@ const payload = await response.json(); const after = payload.preferences; + const ldapSync = payload.meta?.ldap_profile_sync || null; state.bootstrap = payload; state.draft = clone(after); - state.success = payload.meta?.requires_reload + const baseMessage = payload.meta?.requires_reload ? 'Gespeichert. Desktop wird fuer Skin- oder App-Aenderungen neu geladen.' : 'Einstellungen wurden gespeichert.'; + const ldapMessage = ldapSync && ldapSync.attempted + ? ` LDAP: ${ldapSync.message || (ldapSync.success ? 'Synchronisiert.' : 'Nicht synchronisiert.')}` + : ''; + state.success = `${baseMessage}${ldapMessage}`; state.saving = false; renderApp(root, state); diff --git a/src/App/LdapProvisioner.php b/src/App/LdapProvisioner.php index 8432b31e..11e9cb20 100644 --- a/src/App/LdapProvisioner.php +++ b/src/App/LdapProvisioner.php @@ -202,6 +202,63 @@ final class LdapProvisioner } } + /** + * @param array $profile + * @return array{success: bool, message: string, dn?: string, updated_fields?: array, skipped_fields?: array} + */ + public function updateUserProfile(string $username, array $profile): array + { + try { + $link = $this->connectAsService(); + $userDn = $this->userDnForUsername($username); + $fullName = trim((string) ($profile['name'] ?? '')); + [$givenName, $surname] = $this->splitDisplayName($fullName, $username); + $attributeMap = [ + 'cn' => $fullName, + 'displayName' => $fullName, + 'givenName' => $givenName, + 'sn' => $surname, + 'mail' => trim((string) ($profile['email'] ?? '')), + 'telephoneNumber' => trim((string) ($profile['phone'] ?? '')), + 'title' => trim((string) ($profile['title'] ?? '')), + 'l' => trim((string) ($profile['city'] ?? '')), + ]; + $updatedFields = []; + $skippedFields = []; + + foreach ($attributeMap as $attribute => $value) { + if ($value === '' && in_array($attribute, ['cn', 'displayName', 'givenName', 'sn'], true)) { + $skippedFields[] = $attribute; + continue; + } + + if ($value === '') { + @ldap_mod_del($link, $userDn, [$attribute => []]); + continue; + } + + if (!@ldap_mod_replace($link, $userDn, [$attribute => [$value]])) { + throw new RuntimeException('LDAP-Profilaktualisierung fehlgeschlagen fuer ' . $attribute . ': ' . $this->lastError($link)); + } + + $updatedFields[] = $attribute; + } + + return [ + 'success' => true, + 'message' => 'LDAP-Profil wurde aktualisiert.', + 'dn' => $userDn, + 'updated_fields' => $updatedFields, + 'skipped_fields' => $skippedFields, + ]; + } catch (\Throwable $exception) { + return [ + 'success' => false, + 'message' => $exception->getMessage(), + ]; + } + } + /** * @param array $request * @param array $provisioning @@ -452,6 +509,32 @@ final class LdapProvisioner return array_values(array_map('strval', (array) ($this->config['ldap']['default_groups'] ?? []))); } + /** + * @return array{0: string, 1: string} + */ + private function splitDisplayName(string $fullName, string $username): array + { + $normalized = preg_replace('/\s+/', ' ', trim($fullName)) ?? ''; + + if ($normalized === '') { + return [$username, $username]; + } + + $parts = explode(' ', $normalized); + + if (count($parts) === 1) { + return [$parts[0], $parts[0]]; + } + + $surname = (string) array_pop($parts); + $givenName = trim(implode(' ', $parts)); + + return [ + $givenName !== '' ? $givenName : $surname, + $surname !== '' ? $surname : $username, + ]; + } + /** * @return resource|\LDAP\Connection */