[!!!][TASK] Remove constant TYPO3_PROCEED_IF_NO_USER
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Http / BackendModuleRequestHandler.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\ServerRequestInterface;
18 use TYPO3\CMS\Backend\Utility\BackendUtility;
19 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
20 use TYPO3\CMS\Core\Core\Bootstrap;
21 use TYPO3\CMS\Core\Exception;
22 use TYPO3\CMS\Core\FormProtection\BackendFormProtection;
23 use TYPO3\CMS\Core\FormProtection\FormProtectionFactory;
24 use TYPO3\CMS\Core\Http\Dispatcher;
25 use TYPO3\CMS\Core\Http\RequestHandlerInterface;
26 use TYPO3\CMS\Core\Http\Response;
27 use TYPO3\CMS\Core\Utility\GeneralUtility;
28 use TYPO3\CMS\Core\Utility\MathUtility;
29
30 /**
31 * Handles the request for backend modules and wizards
32 * Juggles with $GLOBALS['TBE_MODULES']
33 */
34 class BackendModuleRequestHandler implements RequestHandlerInterface
35 {
36 /**
37 * @var Bootstrap
38 */
39 protected $bootstrap;
40
41 /**
42 * @var array
43 */
44 protected $moduleRegistry = array();
45
46 /**
47 * @var BackendUserAuthentication
48 */
49 protected $backendUserAuthentication;
50
51 /**
52 * Instance of the current Http Request
53 * @var ServerRequestInterface
54 */
55 protected $request;
56
57 /**
58 * Constructor handing over the bootstrap and the original request
59 *
60 * @param Bootstrap $bootstrap
61 */
62 public function __construct(Bootstrap $bootstrap)
63 {
64 $this->bootstrap = $bootstrap;
65 }
66
67 /**
68 * Handles the request, evaluating the configuration and executes the module accordingly
69 *
70 * @param ServerRequestInterface $request
71 * @return NULL|\Psr\Http\Message\ResponseInterface
72 * @throws Exception
73 */
74 public function handleRequest(ServerRequestInterface $request)
75 {
76 $this->request = $request;
77 $this->boot();
78
79 $this->moduleRegistry = $GLOBALS['TBE_MODULES'];
80
81 if (!$this->isValidModuleRequest()) {
82 throw new Exception('The CSRF protection token for the requested module is missing or invalid', 1417988921);
83 }
84
85 // Set to empty as it is not needed / always coming from typo3/index.php
86 $GLOBALS['BACK_PATH'] = '';
87
88 $this->backendUserAuthentication = $GLOBALS['BE_USER'];
89
90 $moduleName = (string)$this->request->getQueryParams()['M'];
91 return $this->dispatchModule($moduleName);
92 }
93
94 /**
95 * Execute TYPO3 bootstrap
96 *
97 * @return void
98 */
99 protected function boot()
100 {
101 $this->bootstrap->checkLockedBackendAndRedirectOrDie()
102 ->checkBackendIpOrDie()
103 ->checkSslBackendAndRedirectIfNeeded()
104 ->initializeBackendRouter()
105 ->loadExtensionTables()
106 ->initializeBackendUser()
107 ->initializeBackendAuthentication()
108 ->initializeLanguageObject()
109 ->initializeBackendTemplate()
110 ->endOutputBufferingAndCleanPreviousOutput()
111 ->initializeOutputCompression()
112 ->sendHttpHeaders();
113 }
114
115 /**
116 * This request handler can handle any backend request coming from index.php
117 *
118 * @param ServerRequestInterface $request
119 * @return bool
120 */
121 public function canHandleRequest(ServerRequestInterface $request)
122 {
123 return $request->getAttribute('isModuleRequest', false);
124 }
125
126 /**
127 * Checks if all parameters are met.
128 *
129 * @return bool
130 */
131 protected function isValidModuleRequest()
132 {
133 return $this->getFormProtection() instanceof BackendFormProtection
134 && $this->getFormProtection()->validateToken((string)$this->request->getQueryParams()['moduleToken'], 'moduleCall', (string)$this->request->getQueryParams()['M']);
135 }
136
137 /**
138 * Executes the modules configured via Extbase
139 *
140 * @param string $moduleName
141 * @return Response A PSR-7 response object
142 * @throws \RuntimeException
143 */
144 protected function dispatchModule($moduleName)
145 {
146 $moduleConfiguration = $this->getModuleConfiguration($moduleName);
147
148 // Check permissions and exit if the user has no permission for entry
149 $this->backendUserAuthentication->modAccess($moduleConfiguration, true);
150 $id = isset($this->request->getQueryParams()['id']) ? $this->request->getQueryParams()['id'] : $this->request->getParsedBody()['id'];
151 if ($id && MathUtility::canBeInterpretedAsInteger($id)) {
152 // Check page access
153 $permClause = $this->backendUserAuthentication->getPagePermsClause(true);
154 $access = is_array(BackendUtility::readPageAccess((int)$id, $permClause));
155 if (!$access) {
156 throw new \RuntimeException('You don\'t have access to this page', 1289917924);
157 }
158 }
159
160 /** @var Response $response */
161 $response = GeneralUtility::makeInstance(Response::class);
162
163 // Use Core Dispatching
164 if (isset($moduleConfiguration['routeTarget'])) {
165 $dispatcher = GeneralUtility::makeInstance(Dispatcher::class);
166 $this->request = $this->request->withAttribute('target', $moduleConfiguration['routeTarget']);
167 $response = $dispatcher->dispatch($this->request, $response);
168 } else {
169 // extbase module
170 $configuration = array(
171 'extensionName' => $moduleConfiguration['extensionName'],
172 'pluginName' => $moduleName
173 );
174 if (isset($moduleConfiguration['vendorName'])) {
175 $configuration['vendorName'] = $moduleConfiguration['vendorName'];
176 }
177
178 // Run Extbase
179 $bootstrap = GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Core\Bootstrap::class);
180 $content = $bootstrap->run('', $configuration);
181
182 $response->getBody()->write($content);
183 }
184
185 return $response;
186 }
187
188 /**
189 * Returns the module configuration which is provided during module registration
190 *
191 * @param string $moduleName
192 * @return array
193 * @throws \RuntimeException
194 */
195 protected function getModuleConfiguration($moduleName)
196 {
197 if (!isset($this->moduleRegistry['_configuration'][$moduleName])) {
198 throw new \RuntimeException('Module ' . $moduleName . ' is not configured.', 1289918325);
199 }
200 return $this->moduleRegistry['_configuration'][$moduleName];
201 }
202
203 /**
204 * Returns the priority - how eager the handler is to actually handle the request.
205 *
206 * @return int The priority of the request handler.
207 */
208 public function getPriority()
209 {
210 return 90;
211 }
212
213 /**
214 * Wrapper method for static form protection utility
215 *
216 * @return \TYPO3\CMS\Core\FormProtection\AbstractFormProtection
217 */
218 protected function getFormProtection()
219 {
220 return FormProtectionFactory::get();
221 }
222 }