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]);
+ }
+ }
+ }
}