diff --git a/appinfo/info.xml b/appinfo/info.xml index 52998c5466c8b3f565ee11060f068855c94fd330..136fe025ea4a28b6225d165a0b13708085ff1c73 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -10,7 +10,7 @@ - 13.1.2 + 13.2.0 agpl Murena SAS EcloudAccounts diff --git a/lib/Listeners/PasswordUpdatedListener.php b/lib/Listeners/PasswordUpdatedListener.php index 92ef52a90b44d9f82799129f5698a033e717cf20..bf1d8a3feed05eba77432669d5fe6c3483d0e3e8 100644 --- a/lib/Listeners/PasswordUpdatedListener.php +++ b/lib/Listeners/PasswordUpdatedListener.php @@ -5,9 +5,7 @@ declare(strict_types=1); namespace OCA\EcloudAccounts\Listeners; use Exception; -use OC\Authentication\Token\IProvider as TokenProvider; -use OCA\EcloudAccounts\AppInfo\Application; -use OCA\EcloudAccounts\Service\SSOService; +use OCA\EcloudAccounts\Service\UserService; use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventListener; use OCP\ISession; @@ -17,19 +15,16 @@ use Psr\Log\LoggerInterface; class PasswordUpdatedListener implements IEventListener { - private SSOService $ssoService; - + private UserService $userService; private LoggerInterface $logger; private ISession $session; private IUserSession $userSession; - private TokenProvider $tokenProvider; - public function __construct(SSOService $ssoService, LoggerInterface $logger, ISession $session, IUserSession $userSession, TokenProvider $tokenProvider) { - $this->ssoService = $ssoService; + public function __construct(UserService $userService, LoggerInterface $logger, ISession $session, IUserSession $userSession) { + $this->userService = $userService; $this->logger = $logger; $this->session = $session; $this->userSession = $userSession; - $this->tokenProvider = $tokenProvider; } public function handle(Event $event): void { @@ -44,24 +39,7 @@ class PasswordUpdatedListener implements IEventListener { $user = $event->getUser(); $username = $user->getUID(); - try { - $this->ssoService->logout($username); - } catch (Exception $e) { - $this->logger->error($e->getMessage(), ['exception' => $e, 'app' => Application::APP_ID]); - } - - // Remove all Nextcloud sessions/tokens for the user (invalidate cache + storage) - try { - $this->tokenProvider->invalidateTokensOfUser($username, null); - } catch (Exception $e) { - $this->logger->error($e, ['app' => Application::APP_ID]); - } - - // Finally, log out the current session (also clears remember-me cookies) - try { - $this->userSession->logout(); - } catch (Exception $e) { - $this->logger->error($e, ['app' => Application::APP_ID]); - } + // Invalidate all sessions and tokens for the user + $this->userService->invalidateUserSessions($username); } } diff --git a/lib/Listeners/UserChangedListener.php b/lib/Listeners/UserChangedListener.php index f720dc38ef4ede75d6f3f2e208f2a64ce1ffbae3..21159912d13f2586480a272ac0910dda4e950f57 100644 --- a/lib/Listeners/UserChangedListener.php +++ b/lib/Listeners/UserChangedListener.php @@ -56,6 +56,7 @@ class UserChangedListener implements IEventListener { if ($feature === self::ENABLED_FEATURE) { try { $this->userService->mapActiveAttributesInLDAP($username, $newValue); + $this->userService->invalidateUserSessions($username); } catch (Exception $e) { $this->logger->error('Failed to update LDAP attributes for user: ' . $username, ['exception' => $e]); } diff --git a/lib/Service/UserService.php b/lib/Service/UserService.php index b2962bf10f17f1dd8e07405a86fcf2dd79b122b2..7e7510d8ba2781dc2146c9d120a321e166403309 100644 --- a/lib/Service/UserService.php +++ b/lib/Service/UserService.php @@ -7,15 +7,18 @@ namespace OCA\EcloudAccounts\Service; require __DIR__ . '/../../vendor/autoload.php'; use Exception; +use OC\Authentication\Token\IProvider as TokenProvider; use OCA\EcloudAccounts\AppInfo\Application; use OCA\EcloudAccounts\Event\BeforeUserRegisteredEvent; use OCA\EcloudAccounts\Exception\AddUsernameToCommonStoreException; use OCA\EcloudAccounts\Exception\LDAPUserCreationException; +use OCA\EcloudAccounts\Service\SSOService; use OCP\Defaults; use OCP\EventDispatcher\IEventDispatcher; use OCP\IConfig; use OCP\IUser; use OCP\IUserManager; +use OCP\IUserSession; use OCP\L10N\IFactory; use OCP\Util; use Psr\Log\LoggerInterface; @@ -42,7 +45,11 @@ class UserService { /** @var LDAPConnectionService */ private $LDAPConnectionService; private IEventDispatcher $dispatcher; - public function __construct($appName, IUserManager $userManager, IConfig $config, CurlService $curlService, LoggerInterface $logger, Defaults $defaults, IFactory $l10nFactory, LDAPConnectionService $LDAPConnectionService, IEventDispatcher $dispatcher) { + private SSOService $ssoService; + private IUserSession $userSession; + private TokenProvider $tokenProvider; + + public function __construct($appName, IUserManager $userManager, IConfig $config, CurlService $curlService, LoggerInterface $logger, Defaults $defaults, IFactory $l10nFactory, LDAPConnectionService $LDAPConnectionService, IEventDispatcher $dispatcher, SSOService $ssoService, IUserSession $userSession, TokenProvider $tokenProvider) { $this->userManager = $userManager; $this->config = $config; $this->appConfig = $this->config->getSystemValue($appName); @@ -52,6 +59,9 @@ class UserService { $this->l10nFactory = $l10nFactory; $this->LDAPConnectionService = $LDAPConnectionService; $this->dispatcher = $dispatcher; + $this->ssoService = $ssoService; + $this->userSession = $userSession; + $this->tokenProvider = $tokenProvider; $commonServiceURL = $this->config->getSystemValue('common_services_url', ''); if (!empty($commonServiceURL)) { @@ -497,4 +507,44 @@ class UserService { $legacyDomain = $this->config->getSystemValue('legacy_domain', ''); return str_ireplace('@' . $legacyDomain, '', $username); } + + /** + * Invalidate all sessions and tokens for a user. + * This includes SSO logout, Nextcloud token invalidation, and current session logout. + * + * @param string $username The username of the user whose sessions should be invalidated + * @param bool $logoutCurrentSession Whether to logout the current session if it matches the user (default: true) + * @return void + */ + public function invalidateUserSessions(string $username, bool $logoutCurrentSession = true): void { + // Logout from SSO service + try { + $this->ssoService->logout($username); + } catch (Exception $e) { + $this->logger->error($e->getMessage(), ['exception' => $e, 'app' => Application::APP_ID]); + } + + // Remove all Nextcloud sessions/tokens for the user (invalidate cache + storage) + try { + $this->tokenProvider->invalidateTokensOfUser($username, null); + } catch (Exception $e) { + $this->logger->error($e, ['app' => Application::APP_ID]); + } + + // Finally, log out the current session if it's the same user (also clears remember-me cookies) + // Note: In OCC/admin scenarios, isLoggedIn() will be false, so this block won't execute + if ($logoutCurrentSession) { + try { + // Check if there's an active session first (safely handles OCC/admin scenarios) + if ($this->userSession->isLoggedIn()) { + $currentUser = $this->userSession->getUser(); + if ($currentUser && $currentUser->getUID() === $username) { + $this->userSession->logout(); + } + } + } catch (Exception $e) { + $this->logger->error($e, ['app' => Application::APP_ID]); + } + } + } }