From 12595d7c48c82e71e98612a0235acec5115a385d Mon Sep 17 00:00:00 2001
From: Benni Mack <benni@typo3.org>
Date: Mon, 20 Apr 2020 20:51:33 +0200
Subject: [PATCH] [BUGFIX] Properly initialize backend user base state in
 middlewares

Due to the fact that backend user objects have not been initialized
properly in PSR-15 middlewares defining the current in-memory state
for workspaces falls back to the users' default workspace.

Basically `BackendUserAuthentication::groupData['workspace_perms']`
was not initialized which results in the mentioned behavior for
non-admin users.

`fetchGroupData` was split up into public `initializeGroupData`
to be used internally only and protected `enrichGroupData`.

Resolves: #90954
Releases: master, 9.5
Change-Id: I75ad15ac600ca489b9951199482e97bcb54d1778
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/64264
Tested-by: Oliver Hader <oliver.hader@typo3.org>
Tested-by: TYPO3com <noreply@typo3.com>
Tested-by: Benni Mack <benni@typo3.org>
Reviewed-by: Tobi Kretschmann <tobi@tobishome.de>
Reviewed-by: Benni Mack <benni@typo3.org>
---
 .../Classes/Middleware/BackendUserAuthenticator.php |  8 ++++----
 .../Classes/Middleware/BackendUserAuthenticator.php | 13 ++++++++++---
 .../Classes/Middleware/BackendUserAuthenticator.php |  6 +++---
 3 files changed, 17 insertions(+), 10 deletions(-)

diff --git a/typo3/sysext/backend/Classes/Middleware/BackendUserAuthenticator.php b/typo3/sysext/backend/Classes/Middleware/BackendUserAuthenticator.php
index 41a5ba78b47d..7dc2e083570a 100644
--- a/typo3/sysext/backend/Classes/Middleware/BackendUserAuthenticator.php
+++ b/typo3/sysext/backend/Classes/Middleware/BackendUserAuthenticator.php
@@ -66,13 +66,13 @@ class BackendUserAuthenticator extends \TYPO3\CMS\Core\Middleware\BackendUserAut
         // might trigger code which relies on it. See: #45625
         $GLOBALS['BE_USER'] = GeneralUtility::makeInstance(BackendUserAuthentication::class);
         $GLOBALS['BE_USER']->start();
-        // Initializing workspace by evaluating and setting the workspace, possibly updating it in the user record!
-        $GLOBALS['BE_USER']->setWorkspace($GLOBALS['BE_USER']->user['workspace_id']);
-        // Register the backend user as aspect
-        $this->setBackendUserAspect($GLOBALS['BE_USER']);
+        // Register the backend user as aspect and initializing workspace once for TSconfig conditions
+        $this->setBackendUserAspect($GLOBALS['BE_USER'], (int)$GLOBALS['BE_USER']->user['workspace_id']);
         // @todo: once this logic is in this method, the redirect URL should be handled as response here
         $GLOBALS['BE_USER']->backendCheckLogin($this->isLoggedInBackendUserRequired($pathToRoute));
         $GLOBALS['LANG'] = LanguageService::createFromUserPreferences($GLOBALS['BE_USER']);
+        // Re-setting the user and take the workspace from the user object now
+        $this->setBackendUserAspect($GLOBALS['BE_USER']);
 
         $response = $handler->handle($request);
 
diff --git a/typo3/sysext/core/Classes/Middleware/BackendUserAuthenticator.php b/typo3/sysext/core/Classes/Middleware/BackendUserAuthenticator.php
index f03129223375..47f4295bf25f 100644
--- a/typo3/sysext/core/Classes/Middleware/BackendUserAuthenticator.php
+++ b/typo3/sysext/core/Classes/Middleware/BackendUserAuthenticator.php
@@ -90,10 +90,17 @@ abstract class BackendUserAuthenticator implements MiddlewareInterface
      * Register the backend user as aspect
      *
      * @param BackendUserAuthentication|null $user
+     * @param int|null $alternativeWorkspaceId
      */
-    protected function setBackendUserAspect(?BackendUserAuthentication $user): void
+    protected function setBackendUserAspect(?BackendUserAuthentication $user, int $alternativeWorkspaceId = null): void
     {
-        $this->context->setAspect('backend.user', GeneralUtility::makeInstance(UserAspect::class, $user));
-        $this->context->setAspect('workspace', GeneralUtility::makeInstance(WorkspaceAspect::class, $user ? $user->workspace : 0));
+        $this->context->setAspect(
+            'backend.user',
+            GeneralUtility::makeInstance(UserAspect::class, $user)
+        );
+        $this->context->setAspect(
+            'workspace',
+            GeneralUtility::makeInstance(WorkspaceAspect::class, $alternativeWorkspaceId ?? $user->workspace ?? 0)
+        );
     }
 }
diff --git a/typo3/sysext/frontend/Classes/Middleware/BackendUserAuthenticator.php b/typo3/sysext/frontend/Classes/Middleware/BackendUserAuthenticator.php
index 3f1d84bdcf34..1f6e4f8d15f5 100644
--- a/typo3/sysext/frontend/Classes/Middleware/BackendUserAuthenticator.php
+++ b/typo3/sysext/frontend/Classes/Middleware/BackendUserAuthenticator.php
@@ -58,11 +58,9 @@ class BackendUserAuthenticator extends \TYPO3\CMS\Core\Middleware\BackendUserAut
         // like $GLOBALS['LANG'] for labels in the language of the BE User, the router, and ext_tables.php for all modules
         // So things like Frontend Editing and Admin Panel can use this for generating links to the TYPO3 Backend.
         if ($GLOBALS['BE_USER'] instanceof FrontendBackendUserAuthentication) {
-            // Initializing workspace by evaluating and setting the workspace, possibly updating it in the user record!
-            $GLOBALS['BE_USER']->setWorkspace($GLOBALS['BE_USER']->user['workspace_id']);
-            $this->setBackendUserAspect($GLOBALS['BE_USER']);
             $GLOBALS['LANG'] = LanguageService::createFromUserPreferences($GLOBALS['BE_USER']);
             Bootstrap::loadExtTables();
+            $this->setBackendUserAspect($GLOBALS['BE_USER']);
         }
 
         $response = $handler->handle($request);
@@ -88,11 +86,13 @@ class BackendUserAuthenticator extends \TYPO3\CMS\Core\Middleware\BackendUserAut
         $backendUserObject->start();
         $backendUserObject->unpack_uc();
         if (!empty($backendUserObject->user['uid'])) {
+            $this->setBackendUserAspect($backendUserObject, (int)$backendUserObject->user['workspace_id']);
             $backendUserObject->fetchGroupData();
         }
         // Unset the user initialization if any setting / restriction applies
         if (!$this->isAuthenticated($backendUserObject, $request->getAttribute('normalizedParams'))) {
             $backendUserObject = null;
+            $this->setBackendUserAspect(null);
         }
         return $backendUserObject;
     }
-- 
GitLab