From 6033fd0c8d2699a129365b8df178a95c07603781 Mon Sep 17 00:00:00 2001
From: catch <catch@35733.no-reply.drupal.org>
Date: Wed, 15 Dec 2021 10:26:57 +0000
Subject: [PATCH] Issue #3253889 by BR0kEN, murilohp, longwave:
 `?check_logged_in=1` causes `TrustedRedirectResponse` to fail

---
 .../src/Authentication/Provider/Cookie.php    |  7 +++
 .../user/tests/src/Unit/UserAuthTest.php      | 60 +++++++++++++++++++
 2 files changed, 67 insertions(+)

diff --git a/core/modules/user/src/Authentication/Provider/Cookie.php b/core/modules/user/src/Authentication/Provider/Cookie.php
index 0fcac24a0d09..aea58f67ea80 100644
--- a/core/modules/user/src/Authentication/Provider/Cookie.php
+++ b/core/modules/user/src/Authentication/Provider/Cookie.php
@@ -6,6 +6,7 @@
 use Drupal\Core\Authentication\AuthenticationProviderInterface;
 use Drupal\Core\Database\Connection;
 use Drupal\Core\Messenger\MessengerInterface;
+use Drupal\Core\Routing\TrustedRedirectResponse;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Session\UserSession;
 use Drupal\Core\Session\SessionConfigurationInterface;
@@ -136,6 +137,12 @@ public function addCheckToUrl(ResponseEvent $event) {
         if (!empty($options['#fragment'])) {
           $url .= '#' . $options['#fragment'];
         }
+        // In the case of trusted redirect, we have to update the list of
+        // trusted URLs because here we've just modified its target URL
+        // which is in the list.
+        if ($response instanceof TrustedRedirectResponse) {
+          $response->setTrustedTargetUrl($url);
+        }
         $response->setTargetUrl($url);
       }
     }
diff --git a/core/modules/user/tests/src/Unit/UserAuthTest.php b/core/modules/user/tests/src/Unit/UserAuthTest.php
index 2ac6d0c05c11..10526a403927 100644
--- a/core/modules/user/tests/src/Unit/UserAuthTest.php
+++ b/core/modules/user/tests/src/Unit/UserAuthTest.php
@@ -3,8 +3,15 @@
 namespace Drupal\Tests\user\Unit;
 
 use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Routing\RequestContext;
+use Drupal\Core\Routing\TrustedRedirectResponse;
 use Drupal\Tests\UnitTestCase;
+use Drupal\user\Authentication\Provider\Cookie;
 use Drupal\user\UserAuth;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Session\SessionInterface;
+use Symfony\Component\HttpKernel\Event\ResponseEvent;
 
 /**
  * @coversDefaultClass \Drupal\user\UserAuth
@@ -220,4 +227,57 @@ public function testAuthenticateWithCorrectPasswordAndNewPasswordHash() {
     $this->assertSame(1, $this->userAuth->authenticate($this->username, $this->password));
   }
 
+  /**
+   * Tests the auth that ends in a redirect from subdomain to TLD.
+   */
+  public function testAddCheckToUrlForTrustedRedirectResponse(): void {
+    $site_domain = 'site.com';
+    $frontend_url = "https://$site_domain";
+    $backend_url = "https://api.$site_domain";
+    $request = Request::create($backend_url);
+    $response = new TrustedRedirectResponse($frontend_url);
+
+    $request_context = $this->createMock(RequestContext::class);
+    $request_context
+      ->method('getCompleteBaseUrl')
+      ->willReturn($backend_url);
+
+    $container = new ContainerBuilder();
+    $container->set('router.request_context', $request_context);
+    \Drupal::setContainer($container);
+
+    $session_mock = $this->createMock(SessionInterface::class);
+    $session_mock
+      ->expects($this->once())
+      ->method('has')
+      ->with('check_logged_in')
+      ->willReturn(TRUE);
+    $session_mock
+      ->expects($this->once())
+      ->method('remove')
+      ->with('check_logged_in');
+
+    $event_mock = $this->createMock(ResponseEvent::class);
+    $event_mock
+      ->expects($this->once())
+      ->method('getResponse')
+      ->willReturn($response);
+    $event_mock
+      ->expects($this->exactly(3))
+      ->method('getRequest')
+      ->willReturn($request);
+
+    $request
+      ->setSession($session_mock);
+
+    $this
+      ->getMockBuilder(Cookie::class)
+      ->disableOriginalConstructor()
+      ->onlyMethods([])
+      ->getMock()
+      ->addCheckToUrl($event_mock);
+
+    $this->assertSame("$frontend_url?check_logged_in=1", $response->getTargetUrl());
+  }
+
 }
-- 
GitLab