1<?php 2 3declare(strict_types=1); 4 5/* 6 * This file is part of the TYPO3 CMS project. 7 * 8 * It is free software; you can redistribute it and/or modify it under 9 * the terms of the GNU General Public License, either version 2 10 * of the License, or any later version. 11 * 12 * For the full copyright and license information, please read the 13 * LICENSE.txt file that was distributed with this source code. 14 * 15 * The TYPO3 project - inspiring people to share! 16 */ 17 18namespace TYPO3\CMS\FrontendLogin\Redirect; 19 20use TYPO3\CMS\Core\Authentication\LoginType; 21use TYPO3\CMS\Core\Context\Context; 22use TYPO3\CMS\FrontendLogin\Configuration\RedirectConfiguration; 23 24/** 25 * Resolve felogin related redirects based on the current login type and the selected configuration (redirect mode) 26 * 27 * @internal this is a concrete TYPO3 implementation and solely used for EXT:felogin and not part of TYPO3's Core API. 28 */ 29class RedirectHandler 30{ 31 /** 32 * @var bool 33 */ 34 protected $userIsLoggedIn = false; 35 36 /** 37 * @var ServerRequestHandler 38 */ 39 protected $requestHandler; 40 41 /** 42 * @var RedirectModeHandler 43 */ 44 protected $redirectModeHandler; 45 46 public function __construct( 47 ServerRequestHandler $requestHandler, 48 RedirectModeHandler $redirectModeHandler, 49 Context $context 50 ) { 51 $this->requestHandler = $requestHandler; 52 $this->redirectModeHandler = $redirectModeHandler; 53 $this->userIsLoggedIn = (bool)$context->getPropertyFromAspect('frontend.user', 'isLoggedIn'); 54 } 55 56 /** 57 * Process redirect modes. The function searches for a redirect url using all configured modes. 58 * 59 * @param string $loginType 60 * @param RedirectConfiguration $configuration 61 * @param string $redirectModeReferrer 62 * @return string Redirect URL 63 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\NoSuchArgumentException 64 */ 65 public function processRedirect(string $loginType, RedirectConfiguration $configuration, string $redirectModeReferrer): string 66 { 67 if ($this->isUserLoginFailedAndLoginErrorActive($configuration->getModes(), $loginType)) { 68 return $this->redirectModeHandler->redirectModeLoginError($configuration->getPageOnLoginError()); 69 } 70 71 $redirectUrlList = []; 72 foreach ($configuration->getModes() as $redirectMode) { 73 $redirectUrl = ''; 74 75 if ($loginType === LoginType::LOGIN) { 76 $redirectUrl = $this->handleSuccessfulLogin($redirectMode, $configuration->getPageOnLogin(), $configuration->getDomains(), $redirectModeReferrer); 77 } elseif ($loginType === LoginType::LOGOUT) { 78 $redirectUrl = $this->handleSuccessfulLogout($redirectMode, $configuration->getPageOnLogout()); 79 } 80 81 if ($redirectUrl !== '') { 82 $redirectUrlList[] = $redirectUrl; 83 } 84 } 85 86 return $this->fetchReturnUrlFromList($redirectUrlList, $configuration->getFirstMode()); 87 } 88 89 /** 90 * Get alternative logout form redirect url if logout and page not accessible 91 * 92 * @param array $redirectModes 93 * @param int $redirectPageLogout 94 * @return string 95 */ 96 protected function getLogoutRedirectUrl(array $redirectModes, int $redirectPageLogout = 0): string 97 { 98 if ($this->userIsLoggedIn && $this->isRedirectModeActive($redirectModes, RedirectMode::LOGOUT)) { 99 return $this->redirectModeHandler->redirectModeLogout($redirectPageLogout); 100 } 101 return $this->getGetpostRedirectUrl($redirectModes); 102 } 103 104 /** 105 * Get alternative login form redirect url 106 * 107 * @param array $redirectModes 108 * @param int $redirectPageLogin 109 * @return string 110 */ 111 protected function getLoginRedirectUrl(array $redirectModes, int $redirectPageLogin): string 112 { 113 if ($this->isRedirectModeActive($redirectModes, RedirectMode::LOGIN)) { 114 return $this->redirectModeHandler->redirectModeLogin($redirectPageLogin); 115 } 116 return $this->getGetpostRedirectUrl($redirectModes); 117 } 118 119 /** 120 * Is used for alternative redirect urls on redirect mode "getpost" 121 * 122 * @param array $redirectModes 123 * @return string 124 */ 125 protected function getGetpostRedirectUrl(array $redirectModes): string 126 { 127 return $this->isRedirectModeActive($redirectModes, RedirectMode::GETPOST) 128 ? $this->requestHandler->getRedirectUrlRequestParam() 129 : ''; 130 } 131 132 /** 133 * Handle redirect mode logout 134 * 135 * @param string $redirectMode 136 * @param int $redirectPageLogout 137 * @return string 138 */ 139 protected function handleSuccessfulLogout(string $redirectMode, int $redirectPageLogout): string 140 { 141 if ($redirectMode === RedirectMode::LOGOUT) { 142 return $this->redirectModeHandler->redirectModeLogout($redirectPageLogout); 143 } 144 return ''; 145 } 146 147 /** 148 * Base on setting redirectFirstMethod get first or last entry from redirect url list. 149 * 150 * @param array $redirectUrlList 151 * @param string $redirectFirstMethod 152 * @return string 153 */ 154 protected function fetchReturnUrlFromList(array $redirectUrlList, $redirectFirstMethod): string 155 { 156 if (count($redirectUrlList) === 0) { 157 return ''; 158 } 159 160 // Remove empty values, but keep "0" as value (that's why "strlen" is used as second parameter) 161 $redirectUrlList = array_filter($redirectUrlList, static function (string $value): bool { 162 return strlen($value) > 0; 163 }); 164 165 return $redirectFirstMethod 166 ? array_shift($redirectUrlList) 167 : array_pop($redirectUrlList); 168 } 169 170 /** 171 * Generate redirect_url for case that the user was successfully logged in 172 * 173 * @param string $redirectMode 174 * @param int $redirectPageLogin 175 * @param string $domains 176 * @param string $redirectModeReferrer 177 * @return string 178 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\NoSuchArgumentException 179 */ 180 protected function handleSuccessfulLogin(string $redirectMode, int $redirectPageLogin = 0, string $domains = '', string $redirectModeReferrer = ''): string 181 { 182 if (!$this->userIsLoggedIn) { 183 return ''; 184 } 185 186 // Logintype is needed because the login-page wouldn't be accessible anymore after a login (would always redirect) 187 switch ($redirectMode) { 188 case RedirectMode::GROUP_LOGIN: 189 $redirectUrl = $this->redirectModeHandler->redirectModeGroupLogin(); 190 break; 191 case RedirectMode::USER_LOGIN: 192 $redirectUrl = $this->redirectModeHandler->redirectModeUserLogin(); 193 break; 194 case RedirectMode::LOGIN: 195 $redirectUrl = $this->redirectModeHandler->redirectModeLogin($redirectPageLogin); 196 break; 197 case RedirectMode::GETPOST: 198 $redirectUrl = $this->requestHandler->getRedirectUrlRequestParam(); 199 break; 200 case RedirectMode::REFERER: 201 $redirectUrl = $this->redirectModeHandler->redirectModeReferrer($redirectModeReferrer); 202 break; 203 case RedirectMode::REFERER_DOMAINS: 204 $redirectUrl = $this->redirectModeHandler->redirectModeRefererDomains($domains, $redirectModeReferrer); 205 break; 206 default: 207 $redirectUrl = ''; 208 } 209 210 return $redirectUrl; 211 } 212 213 protected function isUserLoginFailedAndLoginErrorActive(array $redirectModes, string $loginType): bool 214 { 215 return $loginType === LoginType::LOGIN 216 && !$this->userIsLoggedIn 217 && $this->isRedirectModeActive($redirectModes, RedirectMode::LOGIN_ERROR); 218 } 219 220 /** 221 * Checks if the give mode is active or not 222 * 223 * @param string $mode 224 * @param array $redirectModes 225 * @return bool 226 */ 227 protected function isRedirectModeActive(array $redirectModes, string $mode): bool 228 { 229 return in_array($mode, $redirectModes, true); 230 } 231 232 /** 233 * Returns the redirect Url that should be used in login form 234 * 235 * @param RedirectConfiguration $configuration 236 * @param bool $redirectDisabled 237 * @return string 238 */ 239 public function getLoginFormRedirectUrl(RedirectConfiguration $configuration, bool $redirectDisabled): string 240 { 241 if (!$redirectDisabled) { 242 return $this->getLoginRedirectUrl($configuration->getModes(), $configuration->getPageOnLogin()); 243 } 244 return $this->requestHandler->getRedirectUrlRequestParam(); 245 } 246 247 /** 248 * Returns the redirect Url that should be used in logout form 249 * 250 * @param RedirectConfiguration $configuration 251 * @param int $redirectPageLogout 252 * @param bool $redirectDisabled 253 * @return string 254 */ 255 public function getLogoutFormRedirectUrl(RedirectConfiguration $configuration, int $redirectPageLogout, bool $redirectDisabled): string 256 { 257 if (!$redirectDisabled) { 258 return $this->getLogoutRedirectUrl($configuration->getModes(), $redirectPageLogout); 259 } 260 return $this->requestHandler->getRedirectUrlRequestParam(); 261 } 262} 263