‪TYPO3CMS  ‪main
RedirectUrlValidator.php
Go to the documentation of this file.
1 <?php
2 
3 declare(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 
19 
20 use Psr\EventDispatcher\EventDispatcherInterface;
21 use Psr\Log\LoggerAwareInterface;
22 use Psr\Log\LoggerAwareTrait;
27 
34 class ‪RedirectUrlValidator implements LoggerAwareInterface
35 {
36  use LoggerAwareTrait;
37 
38  public function ‪__construct(
39  protected ‪SiteFinder $siteFinder,
40  protected EventDispatcherInterface $eventDispatcher
41  ) {}
42 
46  public function ‪isValid(‪RequestInterface $request, string $value): bool
47  {
48  if ($value === '') {
49  return false;
50  }
51 
52  // Validate the URL
53  $result = false;
54  if ($this->‪isRelativeUrl($value) || $this->‪isInCurrentDomain($request, $value) || $this->‪isInLocalDomain($value)) {
55  $result = true;
56  }
57 
58  // Allow to change the validation result via a PSR-14 event
59  $event = new ‪ModifyRedirectUrlValidationResultEvent($value, $result, $request);
60  $event = $this->eventDispatcher->dispatch($event);
61  $result = $event->getValidationResult();
62 
63  // URL is not allowed
64  if (!$result) {
65  $this->logger->debug('Url "{url}" was not accepted.', ['url' => $value]);
66  }
67 
68  return $result;
69  }
70 
75  protected function ‪isInCurrentDomain(‪RequestInterface $request, string ‪$url): bool
76  {
77  $urlWithoutSchema = preg_replace('#^https?://#', '', ‪$url) ?? '';
78  $siteUrlWithoutSchema = preg_replace('#^https?://#', '', $request->getAttribute('normalizedParams')->getSiteUrl()) ?? '';
79  // this condition only exists to satisfy phpstan, which complains that this could be an array, too.
80  if (is_array($siteUrlWithoutSchema)) {
81  $siteUrlWithoutSchema = $siteUrlWithoutSchema[0];
82  }
83  return str_starts_with($urlWithoutSchema . '/', $request->getAttribute('normalizedParams')->getHttpHost() . '/')
84  && str_starts_with($urlWithoutSchema, $siteUrlWithoutSchema);
85  }
86 
90  protected function ‪isInLocalDomain(string ‪$url): bool
91  {
93  return false;
94  }
95  $parsedUrl = parse_url(‪$url);
96  if ($parsedUrl['scheme'] === 'http' || $parsedUrl['scheme'] === 'https') {
97  $host = $parsedUrl['host'];
98  foreach ($this->siteFinder->getAllSites() as $site) {
99  if ($site->getBase()->getHost() === $host) {
100  return true;
101  }
102  }
103  }
104  return false;
105  }
106 
110  protected function ‪isRelativeUrl(string ‪$url): bool
111  {
112  ‪$url = GeneralUtility::sanitizeLocalUrl(‪$url);
113  if (!empty(‪$url)) {
114  $parsedUrl = @parse_url(‪$url);
115  if ($parsedUrl !== false && !isset($parsedUrl['scheme']) && !isset($parsedUrl['host'])) {
116  // If the relative URL starts with a slash, we need to check if it's within the current site path
117  return $parsedUrl['path'][0] !== '/' || str_starts_with($parsedUrl['path'], GeneralUtility::getIndpEnv('TYPO3_SITE_PATH'));
118  }
119  }
120  return false;
121  }
122 }
‪TYPO3\CMS\Core\Site\SiteFinder
Definition: SiteFinder.php:31
‪TYPO3\CMS\FrontendLogin\Validation\RedirectUrlValidator\isInLocalDomain
‪isInLocalDomain(string $url)
Definition: RedirectUrlValidator.php:90
‪TYPO3\CMS\FrontendLogin\Validation\RedirectUrlValidator\isValid
‪isValid(RequestInterface $request, string $value)
Definition: RedirectUrlValidator.php:46
‪TYPO3\CMS\Extbase\Mvc\RequestInterface
Definition: RequestInterface.php:24
‪TYPO3\CMS\Webhooks\Message\$url
‪identifier readonly UriInterface $url
Definition: LoginErrorOccurredMessage.php:36
‪TYPO3\CMS\Core\Utility\GeneralUtility\isValidUrl
‪static bool isValidUrl(string $url)
Definition: GeneralUtility.php:713
‪TYPO3\CMS\FrontendLogin\Validation\RedirectUrlValidator\isInCurrentDomain
‪isInCurrentDomain(RequestInterface $request, string $url)
Definition: RedirectUrlValidator.php:75
‪TYPO3\CMS\FrontendLogin\Event\ModifyRedirectUrlValidationResultEvent
Definition: ModifyRedirectUrlValidationResultEvent.php:26
‪TYPO3\CMS\FrontendLogin\Validation\RedirectUrlValidator
Definition: RedirectUrlValidator.php:35
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\FrontendLogin\Validation
Definition: RedirectUrlValidator.php:18
‪TYPO3\CMS\FrontendLogin\Validation\RedirectUrlValidator\isRelativeUrl
‪isRelativeUrl(string $url)
Definition: RedirectUrlValidator.php:110
‪TYPO3\CMS\FrontendLogin\Validation\RedirectUrlValidator\__construct
‪__construct(protected SiteFinder $siteFinder, protected EventDispatcherInterface $eventDispatcher)
Definition: RedirectUrlValidator.php:38