[BUGFIX] Redirect BE user to login on invalid module/route token
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Http / RouteDispatcher.php
1 <?php
2 namespace TYPO3\CMS\Backend\Http;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use Psr\Http\Message\ResponseInterface;
18 use Psr\Http\Message\ServerRequestInterface;
19 use TYPO3\CMS\Backend\Routing\Exception\InvalidRequestTokenException;
20 use TYPO3\CMS\Backend\Routing\Route;
21 use TYPO3\CMS\Backend\Routing\Router;
22 use TYPO3\CMS\Core\FormProtection\FormProtectionFactory;
23 use TYPO3\CMS\Core\Http\Dispatcher;
24 use TYPO3\CMS\Core\Http\DispatcherInterface;
25 use TYPO3\CMS\Core\Utility\GeneralUtility;
26
27 /**
28 * Dispatcher which resolves a route to call a controller and method (but also a callable)
29 */
30 class RouteDispatcher extends Dispatcher implements DispatcherInterface
31 {
32 /**
33 * Main method to resolve the route and checks the target of the route, and tries to call it.
34 *
35 * @param ServerRequestInterface $request the current server request
36 * @param ResponseInterface $response the prepared response
37 * @return ResponseInterface the filled response by the callable / controller/action
38 * @throws RouteNotFoundException if the route was not found
39 * @throws \InvalidArgumentException if the defined target for the route is invalid
40 */
41 public function dispatch(ServerRequestInterface $request, ResponseInterface $response)
42 {
43 /** @var Router $router */
44 $router = GeneralUtility::makeInstance(Router::class);
45 /** @var Route $route */
46 $route = $router->matchRequest($request);
47 $request = $request->withAttribute('route', $route);
48 if (!$this->isValidRequest($request)) {
49 throw new InvalidRequestTokenException('Invalid request for route "' . $route->getPath() . '"', 1425389455);
50 }
51
52 $targetIdentifier = $route->getOption('target');
53 $target = $this->getCallableFromTarget($targetIdentifier);
54 return call_user_func_array($target, [$request, $response]);
55 }
56
57 /**
58 * Wrapper method for static form protection utility
59 *
60 * @return \TYPO3\CMS\Core\FormProtection\AbstractFormProtection
61 */
62 protected function getFormProtection()
63 {
64 return FormProtectionFactory::get();
65 }
66
67 /**
68 * Checks if the request token is valid. This is checked to see if the route is really
69 * created by the same instance. Should be called for all routes in the backend except
70 * for the ones that don't require a login.
71 *
72 * @param \Psr\Http\Message\ServerRequestInterface $request
73 * @return bool
74 * @see \TYPO3\CMS\Backend\Routing\UriBuilder where the token is generated.
75 */
76 protected function isValidRequest($request)
77 {
78 $route = $request->getAttribute('route');
79 if ($route->getOption('access') === 'public') {
80 return true;
81 } elseif ($route->getOption('ajax')) {
82 $token = (string)(isset($request->getParsedBody()['ajaxToken']) ? $request->getParsedBody()['ajaxToken'] : $request->getQueryParams()['ajaxToken']);
83 return $this->getFormProtection()->validateToken($token, 'ajaxCall', $route->getOption('_identifier'));
84 } else {
85 $token = (string)(isset($request->getParsedBody()['token']) ? $request->getParsedBody()['token'] : $request->getQueryParams()['token']);
86 return $this->getFormProtection()->validateToken($token, 'route', $route->getOption('_identifier'));
87 }
88 }
89 }