‪TYPO3CMS  ‪main
Maintenance.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\Container\ContainerInterface;
21 use Psr\Http\Message\ResponseInterface;
22 use Psr\Http\Message\ServerRequestInterface;
23 use Psr\Http\Server\MiddlewareInterface;
24 use Psr\Http\Server\RequestHandlerInterface;
25 use TYPO3\CMS\Core\Configuration\ConfigurationManager;
47 use TYPO3\CMS\Install\Service\SessionService;
48 
54 class ‪Maintenance implements MiddlewareInterface
55 {
59  protected array ‪$controllers = [
60  'icon' => IconController::class,
61  'layout' => LayoutController::class,
62  'login' => LoginController::class,
63  'maintenance' => MaintenanceController::class,
64  'settings' => SettingsController::class,
65  'upgrade' => UpgradeController::class,
66  'environment' => EnvironmentController::class,
67  ];
68 
69  public function ‪__construct(
70  protected readonly ‪FailsafePackageManager $packageManager,
71  protected readonly ConfigurationManager $configurationManager,
72  protected readonly ‪PasswordHashFactory $passwordHashFactory,
73  protected readonly ContainerInterface $container,
74  protected readonly ‪FormProtectionFactory $formProtectionFactory
75  ) {
76  }
77 
81  public function ‪process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
82  {
83  if (!$this->‪canHandleRequest($request)) {
84  return $handler->handle($request);
85  }
86 
87  $controllerName = $request->getQueryParams()['install']['controller'] ?? 'layout';
88  $actionName = $request->getParsedBody()['install']['action'] ?? $request->getQueryParams()['install']['action'] ?? 'init';
89 
90  if ($actionName === 'showEnableInstallToolFile' && ‪EnableFileService::isInstallToolEnableFilePermanent()) {
91  $actionName = 'showLogin';
92  }
93 
94  $action = $actionName . 'Action';
95 
96  // not session related actions
97  if ($actionName === 'init') {
98  $controller = $this->container->get(LayoutController::class);
99  return $controller->initAction($request);
100  }
101  if ($actionName === 'checkEnableInstallToolFile') {
102  return new ‪JsonResponse([
103  'success' => $this->‪checkEnableInstallToolFile(),
104  ]);
105  }
106  if ($actionName === 'showEnableInstallToolFile') {
107  $controller = $this->container->get(LoginController::class);
108  return $controller->showEnableInstallToolFileAction($request);
109  }
110  if ($actionName === 'showLogin') {
111  if (!$this->‪checkEnableInstallToolFile()) {
112  throw new \RuntimeException('Not authorized', 1505564888);
113  }
114  $controller = $this->container->get(LoginController::class);
115  return $controller->showLoginAction($request);
116  }
117 
118  // session related actions
119  $session = new SessionService();
120 
121  // the backend user has an active session but the admin / maintainer
122  // rights have been revoked or the user was disabled or deleted in the meantime
123  if ($session->isAuthorizedBackendUserSession($request) && !$session->hasActiveBackendUserRoleAndSession()) {
124  // log out the user and destroy the session
125  $session->resetSession();
126  $session->destroySession($request);
127  $formProtection = $this->formProtectionFactory->createFromRequest($request);
128  $formProtection->clean();
129 
130  return new ‪HtmlResponse('', 403);
131  }
132 
133  if ($actionName === 'preAccessCheck') {
134  $response = new ‪JsonResponse([
135  'installToolLocked' => !$this->‪checkEnableInstallToolFile(),
136  'isAuthorized' => $session->isAuthorized($request),
137  ]);
138  } elseif ($actionName === 'checkLogin') {
139  if (!$this->‪checkEnableInstallToolFile() && !$session->isAuthorizedBackendUserSession($request)) {
140  throw new \RuntimeException('Not authorized', 1505563556);
141  }
142  if ($session->isAuthorized($request)) {
143  $session->refreshSession();
144  $response = new ‪JsonResponse([
145  'success' => true,
146  ]);
147  } else {
148  // Session expired, log out user, start new session
149  $session->resetSession();
150  $session->startSession();
151  $response = new ‪JsonResponse([
152  'success' => false,
153  ]);
154  }
155  } elseif ($actionName === 'login') {
156  $session->initializeSession();
157  if (!$this->‪checkEnableInstallToolFile()) {
158  throw new \RuntimeException('Not authorized', 1505567462);
159  }
160  $this->‪checkSessionToken($request, $session);
161  $this->‪checkSessionLifetime($request, $session);
162  $password = $request->getParsedBody()['install']['password'] ?? null;
163  $authService = $this->container->get(AuthenticationService::class);
164  if ($authService->loginWithPassword($password, $request, $session)) {
165  $response = new ‪JsonResponse([
166  'success' => true,
167  ]);
168  } else {
169  if ($password === null || empty($password)) {
170  $messageQueue = new ‪FlashMessageQueue('install');
171  $messageQueue->enqueue(
172  new ‪FlashMessage('Please enter the install tool password', '', ContextualFeedbackSeverity::ERROR)
173  );
174  } else {
175  $hashInstance = $this->passwordHashFactory->getDefaultHashInstance('BE');
176  $hashedPassword = $hashInstance->getHashedPassword($password);
177  $messageQueue = new ‪FlashMessageQueue('install');
178  $messageQueue->enqueue(
179  new ‪FlashMessage(
180  'Given password does not match the install tool login password. Calculated hash: ' . $hashedPassword,
181  '',
182  ContextualFeedbackSeverity::ERROR
183  )
184  );
185  }
186  $response = new ‪JsonResponse([
187  'success' => false,
188  'status' => $messageQueue,
189  ]);
190  }
191  } elseif ($actionName === 'logout') {
194  }
195  $formProtection = $this->formProtectionFactory->createFromRequest($request);
196  $formProtection->clean();
197  $session->destroySession($request);
198  $response = new ‪JsonResponse([
199  'success' => true,
200  ]);
201  } else {
202  $enforceReferrerResponse = $this->‪enforceReferrer($request);
203  if ($enforceReferrerResponse instanceof ResponseInterface) {
204  return $enforceReferrerResponse;
205  }
206  $session->initializeSession();
207  if (
208  !$this->‪checkSessionToken($request, $session)
209  || !$this->‪checkSessionLifetime($request, $session)
210  || !$session->isAuthorized($request)
211  ) {
212  return new ‪HtmlResponse('', 403);
213  }
214  $session->refreshSession();
215  if (!array_key_exists($controllerName, $this->controllers)) {
216  throw new \RuntimeException(
217  'Unknown controller ' . $controllerName,
218  1505215756
219  );
220  }
221  $this->packageManager->recreatePackageStatesFileIfMissing();
222  $className = $this->controllers[$controllerName];
224  $controller = $this->container->get($className);
225  if (!method_exists($controller, $action)) {
226  throw new \RuntimeException(
227  'Unknown action method ' . $action . ' in controller ' . $controllerName,
228  1505216027
229  );
230  }
231  $response = $controller->$action($request);
232  }
233 
234  return $response;
235  }
236 
244  protected function ‪canHandleRequest(ServerRequestInterface $request): bool
245  {
246  $basicIntegrity = $this->‪checkIfEssentialConfigurationExists()
247  && !empty(‪$GLOBALS['TYPO3_CONF_VARS']['BE']['installToolPassword'])
249  if (!$basicIntegrity) {
250  return false;
251  }
252  return true;
253  }
254 
260  protected function ‪checkEnableInstallToolFile()
261  {
263  }
264 
268  protected function ‪checkSessionToken(ServerRequestInterface $request, SessionService $session): bool
269  {
270  $postValues = $request->getParsedBody()['install'] ?? null;
271  // no post data is there, so no token check necessary
272  if (empty($postValues)) {
273  return true;
274  }
275  $tokenOk = false;
276  // A token must be given as soon as there is POST data
277  if (isset($postValues['token'])) {
278  $formProtection = $this->formProtectionFactory->createFromRequest($request);
279  $action = (string)$postValues['action'];
280  if ($action === '') {
281  throw new \RuntimeException(
282  'No POST action given for token check',
283  1369326593
284  );
285  }
286  $tokenOk = $formProtection->validateToken($postValues['token'], 'installTool', $action);
287  }
288  if (!$tokenOk) {
289  $session->resetSession();
290  $session->startSession();
291  }
292  return $tokenOk;
293  }
294 
301  protected function ‪checkSessionLifetime(ServerRequestInterface $request, SessionService $session): bool
302  {
303  $isExpired = $session->isExpired($request);
304  if ($isExpired) {
305  // Session expired, log out user, start new session
306  $session->resetSession();
307  $session->startSession();
308  }
309  return !$isExpired;
310  }
311 
317  protected function ‪checkIfEssentialConfigurationExists(): bool
318  {
319  if (file_exists($this->configurationManager->getSystemConfigurationFileLocation())) {
320  return true;
321  }
322  // Check can be removed with TYPO3 v14.0
323  if (file_exists($this->configurationManager->getLocalConfigurationFileLocation())) {
324  mkdir(dirname($this->configurationManager->getSystemConfigurationFileLocation()), 02775, true);
325  rename($this->configurationManager->getLocalConfigurationFileLocation(), $this->configurationManager->getSystemConfigurationFileLocation());
326  if (file_exists(‪Environment::getLegacyConfigPath() . '/AdditionalConfiguration.php')) {
327  rename(‪Environment::getLegacyConfigPath() . '/AdditionalConfiguration.php', $this->configurationManager->getAdditionalConfigurationFileLocation());
328  }
329 
330  return file_exists($this->configurationManager->getSystemConfigurationFileLocation());
331  }
332  return false;
333  }
334 
340  protected function ‪enforceReferrer(ServerRequestInterface $request): ?ResponseInterface
341  {
342  if (!(new ‪Features())->isFeatureEnabled('security.backend.enforceReferrer')) {
343  return null;
344  }
345  return (new ‪ReferrerEnforcer($request))->handle([
346  'flags' => ['refresh-always'],
347  'subject' => 'Install Tool',
348  ]);
349  }
350 }
‪TYPO3\CMS\Core\Http\Security\ReferrerEnforcer
Definition: ReferrerEnforcer.php:32
‪TYPO3\CMS\Install\Middleware\Maintenance\enforceReferrer
‪enforceReferrer(ServerRequestInterface $request)
Definition: Maintenance.php:340
‪TYPO3\CMS\Core\Crypto\PasswordHashing\PasswordHashFactory
Definition: PasswordHashFactory.php:27
‪TYPO3\CMS\Install\Service\EnableFileService\checkInstallToolEnableFile
‪static checkInstallToolEnableFile()
Definition: EnableFileService.php:103
‪TYPO3\CMS\Core\Package\FailsafePackageManager
Definition: FailsafePackageManager.php:27
‪TYPO3\CMS\Install\Middleware\Maintenance
Definition: Maintenance.php:55
‪TYPO3\CMS\Install\Controller\UpgradeController
Definition: UpgradeController.php:83
‪TYPO3\CMS\Install\Controller\EnvironmentController
Definition: EnvironmentController.php:56
‪TYPO3\CMS\Install\Middleware\Maintenance\checkSessionToken
‪checkSessionToken(ServerRequestInterface $request, SessionService $session)
Definition: Maintenance.php:268
‪TYPO3\CMS\Install\Service\EnableFileService
Definition: EnableFileService.php:26
‪TYPO3\CMS\Install\Middleware\Maintenance\canHandleRequest
‪bool canHandleRequest(ServerRequestInterface $request)
Definition: Maintenance.php:244
‪TYPO3\CMS\Core\Core\Environment\getLegacyConfigPath
‪static getLegacyConfigPath()
Definition: Environment.php:268
‪TYPO3\CMS\Install\Controller\IconController
Definition: IconController.php:32
‪TYPO3\CMS\Core\Type\ContextualFeedbackSeverity
‪ContextualFeedbackSeverity
Definition: ContextualFeedbackSeverity.php:25
‪TYPO3\CMS\Install\Service\EnableFileService\installToolEnableFileExists
‪static installToolEnableFileExists()
Definition: EnableFileService.php:95
‪TYPO3\CMS\Install\Controller\LoginController
Definition: LoginController.php:32
‪TYPO3\CMS\Install\Middleware\Maintenance\process
‪process(ServerRequestInterface $request, RequestHandlerInterface $handler)
Definition: Maintenance.php:81
‪TYPO3\CMS\Core\Configuration\Features
Definition: Features.php:56
‪TYPO3\CMS\Install\Middleware\Maintenance\__construct
‪__construct(protected readonly FailsafePackageManager $packageManager, protected readonly ConfigurationManager $configurationManager, protected readonly PasswordHashFactory $passwordHashFactory, protected readonly ContainerInterface $container, protected readonly FormProtectionFactory $formProtectionFactory)
Definition: Maintenance.php:69
‪TYPO3\CMS\Install\Middleware\Maintenance\$controllers
‪array $controllers
Definition: Maintenance.php:59
‪TYPO3\CMS\Install\Service\EnableFileService\isInstallToolEnableFilePermanent
‪static isInstallToolEnableFilePermanent()
Definition: EnableFileService.php:121
‪TYPO3\CMS\Install\Controller\LayoutController
Definition: LayoutController.php:47
‪TYPO3\CMS\Install\Service\EnableFileService\removeInstallToolEnableFile
‪static removeInstallToolEnableFile()
Definition: EnableFileService.php:70
‪TYPO3\CMS\Core\Messaging\FlashMessage
Definition: FlashMessage.php:27
‪TYPO3\CMS\Core\FormProtection\FormProtectionFactory
Definition: FormProtectionFactory.php:44
‪TYPO3\CMS\Install\Service\EnableFileService\isFirstInstallAllowed
‪static isFirstInstallAllowed()
Definition: EnableFileService.php:42
‪TYPO3\CMS\Core\Http\JsonResponse
Definition: JsonResponse.php:28
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Core\Core\Environment
Definition: Environment.php:41
‪TYPO3\CMS\Install\Middleware\Maintenance\checkEnableInstallToolFile
‪bool checkEnableInstallToolFile()
Definition: Maintenance.php:260
‪TYPO3\CMS\Install\Controller\MaintenanceController
Definition: MaintenanceController.php:54
‪TYPO3\CMS\Install\Controller\AbstractController
Definition: AbstractController.php:35
‪TYPO3\CMS\Install\Middleware\Maintenance\checkIfEssentialConfigurationExists
‪bool checkIfEssentialConfigurationExists()
Definition: Maintenance.php:317
‪TYPO3\CMS\Install\Authentication\AuthenticationService
Definition: AuthenticationService.php:39
‪TYPO3\CMS\Install\Middleware\Maintenance\checkSessionLifetime
‪bool checkSessionLifetime(ServerRequestInterface $request, SessionService $session)
Definition: Maintenance.php:301
‪TYPO3\CMS\Install\Controller\SettingsController
Definition: SettingsController.php:53
‪TYPO3\CMS\Install\Middleware
Definition: Installer.php:18
‪TYPO3\CMS\Core\Messaging\FlashMessageQueue
Definition: FlashMessageQueue.php:30
‪TYPO3\CMS\Core\Http\HtmlResponse
Definition: HtmlResponse.php:28