From 8085e538dd013a09faa2198d49078804a9f1f96f Mon Sep 17 00:00:00 2001
From: Torben Hansen <derhansen@gmail.com>
Date: Wed, 15 Feb 2023 09:17:44 +0100
Subject: [PATCH] [BUGFIX] Consider failed logins for felogin redirect mode
 'referer'

The redirect mode `referer` has been fixed with #91844. The fix is
however incomplete, since it always uses the current HTTP_REFERER
for redirect evaluation. This is problematic, if the login fails
due to wrong credentials. In such a scenario, the user is
redirected to the login page, which also overwrites the original
HTTP_REFERER and results in the user being redirected to the
login page after successful login.

This patch ensures, that the original HTTP_REFERER is evaluated in
the loginAction and passed as a variable to the login form, where
it is used in the hidden field `referer`. This ensures, that the
initial evaluated referer is kept in the failed login scenario.

Resolves: #99920
Related: #91844
Releases: main, 11.5
Signed-off-by: Torben Hansen <derhansen@gmail.com>
Change-Id: Ibe572832f443beaa9b1997f767a8777f282038c4
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/77859
Reviewed-by: Felix Nagel
Reviewed-by: Benni Mack <benni@typo3.org>
Tested-by: core-ci <typo3@b13.com>
Tested-by: Benni Mack <benni@typo3.org>
Reviewed-by: Markus Klein <markus.klein@typo3.org>
Tested-by: Markus Klein <markus.klein@typo3.org>
Tested-by: Felix Nagel
Reviewed-by: Thomas Hohn <tho@gyldendal.dk>
---
 .../Classes/Controller/LoginController.php    | 30 ++++++++++++++++++-
 .../Classes/Redirect/RedirectModeHandler.php  |  3 --
 2 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/typo3/sysext/felogin/Classes/Controller/LoginController.php b/typo3/sysext/felogin/Classes/Controller/LoginController.php
index 9e4289d3397c..80105916dfb2 100644
--- a/typo3/sysext/felogin/Classes/Controller/LoginController.php
+++ b/typo3/sysext/felogin/Classes/Controller/LoginController.php
@@ -31,6 +31,7 @@ use TYPO3\CMS\FrontendLogin\Event\LogoutConfirmedEvent;
 use TYPO3\CMS\FrontendLogin\Event\ModifyLoginFormViewEvent;
 use TYPO3\CMS\FrontendLogin\Redirect\RedirectHandler;
 use TYPO3\CMS\FrontendLogin\Service\UserService;
+use TYPO3\CMS\FrontendLogin\Validation\RedirectUrlValidator;
 
 /**
  * Used for plugin login
@@ -52,6 +53,7 @@ class LoginController extends AbstractLoginFormController
     public function __construct(
         protected RedirectHandler $redirectHandler,
         protected UserService $userService,
+        protected RedirectUrlValidator $redirectUrlValidator,
         protected Context $context
     ) {
         $this->userAspect = $context->getAspect('frontend.user');
@@ -107,7 +109,7 @@ class LoginController extends AbstractLoginFormController
                 'permaloginStatus' => $this->getPermaloginStatus(),
                 'redirectURL' => $this->redirectHandler->getLoginFormRedirectUrl($this->request, $this->configuration, $this->isRedirectDisabled()),
                 'redirectReferrer' => $this->request->hasArgument('redirectReferrer') ? (string)$this->request->getArgument('redirectReferrer') : '',
-                'referer' => (string)($this->request->getParsedBody()['referer'] ?? $this->request->getQueryParams()['referer'] ?? ''),
+                'referer' => $this->getRefererForLoginForm(),
                 'noRedirect' => $this->isRedirectDisabled(),
                 'requestToken' => RequestToken::create('core/user-auth/fe')
                     ->withMergedParams(['pid' => implode(',', $this->getStorageFolders())]),
@@ -168,6 +170,32 @@ class LoginController extends AbstractLoginFormController
         return $this->htmlResponse();
     }
 
+    /**
+     * Determines the `referer` variable used in the login form for loginMode=referer depending on the
+     * following evaluation order:
+     *
+     * - HTTP POST parameter `referer`
+     * - HTTP GET parameter `referer`
+     * - HTTP_REFERER
+     *
+     * The evaluated `referer` is only returned, if it is considered as valid.
+     */
+    protected function getRefererForLoginForm(): string
+    {
+        $referer = (string)(
+            $this->request->getParsedBody()['referer'] ??
+            $this->request->getQueryParams()['referer'] ??
+            $this->request->getServerParams()['HTTP_REFERER'] ??
+            ''
+        );
+
+        if ($this->redirectUrlValidator->isValid($this->request, $referer)) {
+            return $referer;
+        }
+
+        return '';
+    }
+
     /**
      * Handles the redirect when $this->redirectUrl is not empty
      */
diff --git a/typo3/sysext/felogin/Classes/Redirect/RedirectModeHandler.php b/typo3/sysext/felogin/Classes/Redirect/RedirectModeHandler.php
index 0f0fa3f5680f..3a9e7e07b6d4 100644
--- a/typo3/sysext/felogin/Classes/Redirect/RedirectModeHandler.php
+++ b/typo3/sysext/felogin/Classes/Redirect/RedirectModeHandler.php
@@ -186,9 +186,6 @@ class RedirectModeHandler
     {
         $referer = '';
         $requestReferer = (string)($request->getParsedBody()['referer'] ?? $request->getQueryParams()['referer'] ?? '');
-        if ($requestReferer === '') {
-            $requestReferer = $request->getServerParams()['HTTP_REFERER'] ?? '';
-        }
 
         if ($this->redirectUrlValidator->isValid($request, $requestReferer)) {
             $referer = $requestReferer;
-- 
GitLab