From 7961dcb190fe02d0f1233d9001bf06779df3f615 Mon Sep 17 00:00:00 2001 From: Serhii Korneliuk Date: Wed, 2 Sep 2026 15:34:28 +0300 Subject: [PATCH 1/2] fix(manager): rotate CSRF tokens on login and safely restore tabs Ported from evolution-cms/evolution@11d86de36 (core/vendor/evolutioncms-services/user-manager). --- .../Users/SafelyDestroyUserSessionTrait.php | 10 ++++++++ src/Services/Users/UserLogin.php | 25 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/src/Services/Users/SafelyDestroyUserSessionTrait.php b/src/Services/Users/SafelyDestroyUserSessionTrait.php index b8c1a2a..ec2999a 100644 --- a/src/Services/Users/SafelyDestroyUserSessionTrait.php +++ b/src/Services/Users/SafelyDestroyUserSessionTrait.php @@ -2,6 +2,7 @@ namespace EvolutionCMS\UserManager\Services\Users; +/** Removes authentication state for one context without destroying unrelated session data. */ trait SafelyDestroyUserSessionTrait { private $userSessionFields = [ @@ -19,6 +20,12 @@ trait SafelyDestroyUserSessionTrait 'Token', ]; + /** + * Clears this context's identity and, for manager logout, its CSRF credential. + * Web-context logout must not invalidate a still-authenticated manager session. + * + * @return void + */ protected function safelyDestroyUserSession() { if (defined('NO_SESSION')) { @@ -28,5 +35,8 @@ protected function safelyDestroyUserSession() foreach ($this->userSessionFields as $field) { unset($_SESSION[$this->context . $field]); } + if ($this->context === 'mgr') { + unset($_SESSION['_token']); + } } } diff --git a/src/Services/Users/UserLogin.php b/src/Services/Users/UserLogin.php index 94c66e8..e0838d4 100644 --- a/src/Services/Users/UserLogin.php +++ b/src/Services/Users/UserLogin.php @@ -8,6 +8,10 @@ use Carbon\Carbon; use Illuminate\Support\Str; +/** + * Validates login credentials and creates the authenticated context's session. + * Manager logins rotate CSRF credentials without discarding unrelated web-session data. + */ class UserLogin implements UserServiceInterface { use SafelyDestroyUserSessionTrait; @@ -337,6 +341,12 @@ public function writeSession() } + /** + * Creates a fresh native session after login, preserving unrelated session data. + * Manager authentication also rotates CSRF; a web login keeps the manager token. + * + * @return string Newly assigned session identifier. + */ protected function regenerateSessionId(): string { $sessionId = Str::random(40); @@ -354,12 +364,24 @@ protected function regenerateSessionId(): string $_SESSION[$key] = $value; } + if ($this->context === 'mgr') { + // A new authenticated manager session must not inherit its predecessor's token. + $_SESSION['_token'] = Str::random(40); + } + $this->syncLaravelSessionId($sessionId); $this->refreshSessionCookie($sessionId); return $sessionId; } + /** + * Mirrors the native session ID and rotated manager token into Laravel when enabled. + * Native session state remains authoritative if no compatible store is available. + * + * @param string $sessionId Newly generated native session identifier. + * @return void + */ protected function syncLaravelSessionId(string $sessionId): void { if (!defined('EVO_SESSION') || !EVO_SESSION || !function_exists('session')) { @@ -370,6 +392,9 @@ protected function syncLaravelSessionId(string $sessionId): void $store = session()->driver(); if (is_object($store) && method_exists($store, 'setId')) { $store->setId($sessionId); + if ($this->context === 'mgr' && method_exists($store, 'put')) { + $store->put('_token', $_SESSION['_token']); + } } } catch (\Throwable $exception) { // Native PHP session remains the source of truth when Laravel sync is unavailable. From 16125784f9605a5730afab4aff2226567534b2ca Mon Sep 17 00:00:00 2001 From: Artur Kyryliuk Date: Mon, 21 Sep 2026 20:17:36 +0200 Subject: [PATCH 2/2] fix(core): error handler middleware when session is disabled Ported from evolution-cms/evolution@3f9ea9220 (core/vendor/evolutioncms-services/user-manager). --- src/Services/Users/UserLogin.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Services/Users/UserLogin.php b/src/Services/Users/UserLogin.php index e0838d4..1223844 100644 --- a/src/Services/Users/UserLogin.php +++ b/src/Services/Users/UserLogin.php @@ -284,7 +284,7 @@ public function authProcess() EvolutionCMS()->cleanupExpiredLocks(); EvolutionCMS()->cleanupMultipleActiveUsers(); - if(!defined('NO_SESSION')) { + if (!(class_exists('EvoSessionProxy', false) && \EvoSessionProxy::disabled())) { $this->writeSession(); } // successful login so reset fail count and update key values