[TASK] Clean up user permission checking in FE request handling
[Packages/TYPO3.CMS.git] / typo3 / sysext / frontend / Classes / Http / RequestHandler.php
1 <?php
2 declare(strict_types = 1);
3 namespace TYPO3\CMS\Frontend\Http;
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
18 use Psr\Http\Message\ResponseInterface;
19 use Psr\Http\Message\ServerRequestInterface;
20 use Psr\Http\Server\RequestHandlerInterface as PsrRequestHandlerInterface;
21 use TYPO3\CMS\Backend\FrontendBackendUserAuthentication;
22 use TYPO3\CMS\Core\FrontendEditing\FrontendEditingController;
23 use TYPO3\CMS\Core\Http\NullResponse;
24 use TYPO3\CMS\Core\Http\RequestHandlerInterface;
25 use TYPO3\CMS\Core\Http\Response;
26 use TYPO3\CMS\Core\TimeTracker\TimeTracker;
27 use TYPO3\CMS\Core\Type\Bitmask\Permission;
28 use TYPO3\CMS\Core\Utility\GeneralUtility;
29 use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
30 use TYPO3\CMS\Frontend\Page\PageGenerator;
31
32 /**
33 * This is the main entry point of the TypoScript driven standard front-end
34 *
35 * Basically put, this is the script which all requests for TYPO3 delivered pages goes to in the
36 * frontend (the website). The script instantiates a $TSFE object, includes libraries and does a little logic here
37 * and there in order to instantiate the right classes to create the webpage.
38 * Previously, this was called index_ts.php and also included the logic for the lightweight "eID" concept,
39 * which is now handled in a separate middleware (EidHandler).
40 */
41 class RequestHandler implements RequestHandlerInterface, PsrRequestHandlerInterface
42 {
43 /**
44 * Instance of the timetracker
45 * @var TimeTracker
46 */
47 protected $timeTracker;
48
49 /**
50 * Handles a frontend request
51 *
52 * @param ServerRequestInterface $request
53 * @return ResponseInterface
54 */
55 public function handleRequest(ServerRequestInterface $request): ResponseInterface
56 {
57 return $this->handle($request);
58 }
59
60 /**
61 * Handles a frontend request, after finishing running middlewares
62 *
63 * @param ServerRequestInterface $request
64 * @return ResponseInterface|null
65 */
66 public function handle(ServerRequestInterface $request): ResponseInterface
67 {
68 // Fetch the initialized time tracker object
69 $this->timeTracker = GeneralUtility::makeInstance(TimeTracker::class);
70 /** @var TypoScriptFrontendController $controller */
71 $controller = $GLOBALS['TSFE'];
72
73 // Process the ID, type and other parameters.
74 // After this point we have an array, $page in TSFE, which is the page-record
75 // of the current page, $id.
76 $this->timeTracker->push('Process ID', '');
77 $controller->checkAlternativeIdMethods();
78 $controller->clear_preview();
79 $controller->determineId();
80
81 // Now, if there is a backend user logged in and he has NO access to this page,
82 // then re-evaluate the id shown!.
83 if ($controller->isBackendUserLoggedIn() && !$GLOBALS['BE_USER']->doesUserHaveAccess($controller->page, Permission::PAGE_SHOW)) {
84 // Remove user
85 unset($GLOBALS['BE_USER']);
86 $controller->beUserLogin = false;
87 // Re-evaluate the page-id.
88 $controller->checkAlternativeIdMethods();
89 $controller->clear_preview();
90 $controller->determineId();
91 }
92
93 $controller->makeCacheHash();
94 $this->timeTracker->pull();
95
96 // Admin Panel & Frontend editing
97 if ($controller->isBackendUserLoggedIn()) {
98 $GLOBALS['BE_USER']->initializeFrontendEdit();
99 if ($GLOBALS['BE_USER']->frontendEdit instanceof FrontendEditingController) {
100 $GLOBALS['BE_USER']->frontendEdit->initConfigOptions();
101 }
102 }
103
104 // Starts the template
105 $this->timeTracker->push('Start Template', '');
106 $controller->initTemplate();
107 $this->timeTracker->pull();
108 // Get from cache
109 $this->timeTracker->push('Get Page from cache', '');
110 $controller->getFromCache();
111 $this->timeTracker->pull();
112 // Get config if not already gotten
113 // After this, we should have a valid config-array ready
114 $controller->getConfigArray();
115 // Setting language and locale
116 $this->timeTracker->push('Setting language and locale', '');
117 $controller->settingLanguage();
118 $controller->settingLocale();
119 $this->timeTracker->pull();
120
121 // Convert POST data to utf-8 for internal processing if metaCharset is different
122 $controller->convPOSTCharset();
123
124 $controller->initializeRedirectUrlHandlers();
125
126 $controller->handleDataSubmission();
127
128 // Check for shortcut page and redirect
129 $controller->checkPageForShortcutRedirect();
130 $controller->checkPageForMountpointRedirect();
131
132 // Generate page
133 $controller->setUrlIdToken();
134 $this->timeTracker->push('Page generation', '');
135 if ($controller->isGeneratePage()) {
136 $controller->generatePage_preProcessing();
137 $controller->preparePageContentGeneration();
138 // Content generation
139 if (!$controller->isINTincScript()) {
140 PageGenerator::renderContent();
141 $controller->setAbsRefPrefix();
142 }
143 $controller->generatePage_postProcessing();
144 } elseif ($controller->isINTincScript()) {
145 $controller->preparePageContentGeneration();
146 }
147 $controller->releaseLocks();
148 $this->timeTracker->pull();
149
150 // Render non-cached parts
151 if ($controller->isINTincScript()) {
152 $this->timeTracker->push('Non-cached objects', '');
153 $controller->INTincScript();
154 $this->timeTracker->pull();
155 }
156
157 // Create a Response object when sending content
158 $response = new Response();
159
160 // Output content
161 $isOutputting = $controller->isOutputting();
162 if ($isOutputting) {
163 $this->timeTracker->push('Print Content', '');
164 $controller->processOutput();
165 $this->timeTracker->pull();
166 }
167 // Store session data for fe_users
168 $controller->storeSessionData();
169
170 $redirectResponse = $controller->redirectToExternalUrl();
171 if ($redirectResponse instanceof ResponseInterface) {
172 return $redirectResponse;
173 }
174
175 // Statistics
176 $GLOBALS['TYPO3_MISC']['microtime_end'] = microtime(true);
177 if ($isOutputting && ($controller->config['config']['debug'] ?? !empty($GLOBALS['TYPO3_CONF_VARS']['FE']['debug']))) {
178 $response = $response->withHeader('X-TYPO3-Parsetime', $this->timeTracker->getParseTime() . 'ms');
179 }
180
181 // Preview info
182 $controller->previewInfo();
183 // Hook for end-of-frontend
184 $controller->hook_eofe();
185 // Finish timetracking
186 $this->timeTracker->pull();
187
188 // Admin panel
189 if ($controller->isBackendUserLoggedIn() && $GLOBALS['BE_USER'] instanceof FrontendBackendUserAuthentication && $GLOBALS['BE_USER']->isAdminPanelVisible()) {
190 $controller->content = str_ireplace('</body>', $GLOBALS['BE_USER']->displayAdminPanel() . '</body>', $controller->content);
191 }
192
193 if ($isOutputting) {
194 $response->getBody()->write($controller->content);
195 }
196
197 return $isOutputting ? $response : new NullResponse();
198 }
199
200 /**
201 * This request handler can handle any frontend request.
202 *
203 * @param ServerRequestInterface $request
204 * @return bool If the request is not an eID request, TRUE otherwise FALSE
205 */
206 public function canHandleRequest(ServerRequestInterface $request): bool
207 {
208 return true;
209 }
210
211 /**
212 * Returns the priority - how eager the handler is to actually handle the
213 * request.
214 *
215 * @return int The priority of the request handler.
216 */
217 public function getPriority(): int
218 {
219 return 50;
220 }
221 }