From 2c7b833f322e990e083de047b57092da8993eda0 Mon Sep 17 00:00:00 2001 From: theronakpatel Date: Thu, 8 Jan 2026 14:14:35 +0530 Subject: [PATCH 1/4] Invalidate sessions when user is changed to enable/disabled status --- appinfo/info.xml | 2 +- lib/Listeners/UserChangedListener.php | 41 ++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/appinfo/info.xml b/appinfo/info.xml index 52998c54..02a51972 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -10,7 +10,7 @@ - 13.1.2 + 13.1.3 agpl Murena SAS EcloudAccounts diff --git a/lib/Listeners/UserChangedListener.php b/lib/Listeners/UserChangedListener.php index f720dc38..39849f88 100644 --- a/lib/Listeners/UserChangedListener.php +++ b/lib/Listeners/UserChangedListener.php @@ -5,11 +5,16 @@ 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\Db\MailboxMapper; use OCA\EcloudAccounts\Service\LDAPConnectionService; +use OCA\EcloudAccounts\Service\SSOService; use OCA\EcloudAccounts\Service\UserService; use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventListener; +use OCP\ISession; +use OCP\IUserSession; use OCP\User\Events\UserChangedEvent; use OCP\Util; use Psr\Log\LoggerInterface; @@ -26,13 +31,21 @@ class UserChangedListener implements IEventListener { private $userService; private $LDAPConnectionService; + private SSOService $ssoService; + private ISession $session; + private IUserSession $userSession; + private TokenProvider $tokenProvider; - public function __construct(Util $util, LoggerInterface $logger, MailboxMapper $mailboxMapper, UserService $userService, LDAPConnectionService $LDAPConnectionService) { + public function __construct(Util $util, LoggerInterface $logger, MailboxMapper $mailboxMapper, UserService $userService, LDAPConnectionService $LDAPConnectionService, SSOService $ssoService, ISession $session, IUserSession $userSession, TokenProvider $tokenProvider) { $this->util = $util; $this->mailboxMapper = $mailboxMapper; $this->logger = $logger; $this->userService = $userService; $this->LDAPConnectionService = $LDAPConnectionService; + $this->ssoService = $ssoService; + $this->session = $session; + $this->userSession = $userSession; + $this->tokenProvider = $tokenProvider; } public function handle(Event $event): void { @@ -56,6 +69,7 @@ class UserChangedListener implements IEventListener { if ($feature === self::ENABLED_FEATURE) { try { $this->userService->mapActiveAttributesInLDAP($username, $newValue); + $this->invalidateUserSessions($username); } catch (Exception $e) { $this->logger->error('Failed to update LDAP attributes for user: ' . $username, ['exception' => $e]); } @@ -77,4 +91,29 @@ class UserChangedListener implements IEventListener { $this->logger->error("Error setting quota for user $username " . $e->getMessage()); } } + + private function invalidateUserSessions(string $username): 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) + try { + if ($this->userSession->isLoggedIn() && $this->userSession->getUser() && $this->userSession->getUser()->getUID() === $username) { + $this->userSession->logout(); + } + } catch (Exception $e) { + $this->logger->error($e, ['app' => Application::APP_ID]); + } + } } -- GitLab From 5328286a85c8e02127744bc51a2fda1cdcce6b91 Mon Sep 17 00:00:00 2001 From: theronakpatel Date: Thu, 8 Jan 2026 15:18:04 +0530 Subject: [PATCH 2/4] common code --- lib/Listeners/PasswordUpdatedListener.php | 34 +++------------- lib/Listeners/UserChangedListener.php | 42 +------------------- lib/Service/UserService.php | 47 ++++++++++++++++++++++- 3 files changed, 54 insertions(+), 69 deletions(-) diff --git a/lib/Listeners/PasswordUpdatedListener.php b/lib/Listeners/PasswordUpdatedListener.php index 92ef52a9..bf1d8a3f 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 39849f88..21159912 100644 --- a/lib/Listeners/UserChangedListener.php +++ b/lib/Listeners/UserChangedListener.php @@ -5,16 +5,11 @@ 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\Db\MailboxMapper; use OCA\EcloudAccounts\Service\LDAPConnectionService; -use OCA\EcloudAccounts\Service\SSOService; use OCA\EcloudAccounts\Service\UserService; use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventListener; -use OCP\ISession; -use OCP\IUserSession; use OCP\User\Events\UserChangedEvent; use OCP\Util; use Psr\Log\LoggerInterface; @@ -31,21 +26,13 @@ class UserChangedListener implements IEventListener { private $userService; private $LDAPConnectionService; - private SSOService $ssoService; - private ISession $session; - private IUserSession $userSession; - private TokenProvider $tokenProvider; - public function __construct(Util $util, LoggerInterface $logger, MailboxMapper $mailboxMapper, UserService $userService, LDAPConnectionService $LDAPConnectionService, SSOService $ssoService, ISession $session, IUserSession $userSession, TokenProvider $tokenProvider) { + public function __construct(Util $util, LoggerInterface $logger, MailboxMapper $mailboxMapper, UserService $userService, LDAPConnectionService $LDAPConnectionService) { $this->util = $util; $this->mailboxMapper = $mailboxMapper; $this->logger = $logger; $this->userService = $userService; $this->LDAPConnectionService = $LDAPConnectionService; - $this->ssoService = $ssoService; - $this->session = $session; - $this->userSession = $userSession; - $this->tokenProvider = $tokenProvider; } public function handle(Event $event): void { @@ -69,7 +56,7 @@ class UserChangedListener implements IEventListener { if ($feature === self::ENABLED_FEATURE) { try { $this->userService->mapActiveAttributesInLDAP($username, $newValue); - $this->invalidateUserSessions($username); + $this->userService->invalidateUserSessions($username); } catch (Exception $e) { $this->logger->error('Failed to update LDAP attributes for user: ' . $username, ['exception' => $e]); } @@ -91,29 +78,4 @@ class UserChangedListener implements IEventListener { $this->logger->error("Error setting quota for user $username " . $e->getMessage()); } } - - private function invalidateUserSessions(string $username): 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) - try { - if ($this->userSession->isLoggedIn() && $this->userSession->getUser() && $this->userSession->getUser()->getUID() === $username) { - $this->userSession->logout(); - } - } catch (Exception $e) { - $this->logger->error($e, ['app' => Application::APP_ID]); - } - } } diff --git a/lib/Service/UserService.php b/lib/Service/UserService.php index b2962bf1..e68b7a46 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,39 @@ 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) + if ($logoutCurrentSession) { + try { + if ($this->userSession->isLoggedIn() && $this->userSession->getUser() && $this->userSession->getUser()->getUID() === $username) { + $this->userSession->logout(); + } + } catch (Exception $e) { + $this->logger->error($e, ['app' => Application::APP_ID]); + } + } + } } -- GitLab From b7214225461b8aedcb2427b9bc4e4c0eb12d0d2f Mon Sep 17 00:00:00 2001 From: theronakpatel Date: Thu, 8 Jan 2026 15:26:35 +0530 Subject: [PATCH 3/4] logged in checked first --- lib/Service/UserService.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/Service/UserService.php b/lib/Service/UserService.php index e68b7a46..7e7510d8 100644 --- a/lib/Service/UserService.php +++ b/lib/Service/UserService.php @@ -532,10 +532,15 @@ class UserService { } // 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 { - if ($this->userSession->isLoggedIn() && $this->userSession->getUser() && $this->userSession->getUser()->getUID() === $username) { - $this->userSession->logout(); + // 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]); -- GitLab From b45cd73a552183c28fa82234fe19c801e8c2c1aa Mon Sep 17 00:00:00 2001 From: Ronak Patel Date: Fri, 9 Jan 2026 01:15:57 +0530 Subject: [PATCH 4/4] Apply 1 suggestion(s) to 1 file(s) Co-authored-by: Fahim Salam Chowdhury --- appinfo/info.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appinfo/info.xml b/appinfo/info.xml index 02a51972..136fe025 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -10,7 +10,7 @@ - 13.1.3 + 13.2.0 agpl Murena SAS EcloudAccounts -- GitLab