‪TYPO3CMS  ‪main
MfaAjaxController.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\Http\Message\ResponseInterface;
21 use Psr\Http\Message\ServerRequestInterface;
33 
39 #[AsController]
41 {
42  private const ‪ALLOWED_ACTIONS = ['deactivate'];
43 
45 
47  {
48  $this->mfaProviderRegistry = ‪$mfaProviderRegistry;
49  }
50 
54  public function ‪handleRequest(ServerRequestInterface $request): ResponseInterface
55  {
56  $action = (string)($request->getQueryParams()['action'] ?? $request->getParsedBody()['action'] ?? '');
57 
58  if (!in_array($action, self::ALLOWED_ACTIONS, true)) {
59  return new ‪JsonResponse($this->‪getResponseData(false, $this->‪getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_mfa.xlf:ajax.invalidRequest')));
60  }
61 
62  $userId = (int)($request->getParsedBody()['userId'] ?? 0);
63  $tableName = (string)($request->getParsedBody()['tableName'] ?? '');
64 
65  if (!$userId || !in_array($tableName, ['be_users', 'fe_users'], true)) {
66  return new ‪JsonResponse($this->‪getResponseData(false, $this->‪getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_mfa.xlf:ajax.invalidRequest')));
67  }
68 
69  $user = $this->‪initializeUser($userId, $tableName);
70 
71  if (!$this->‪isAllowedToPerformAction($action, $user)) {
72  return new ‪JsonResponse($this->‪getResponseData(false, $this->‪getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_mfa.xlf:ajax.insufficientPermissions')));
73  }
74 
75  return new ‪JsonResponse($this->{$action . 'Action'}($request, $user));
76  }
77 
83  protected function ‪deactivateAction(ServerRequestInterface $request, ‪AbstractUserAuthentication $user): array
84  {
85  $lang = $this->‪getLanguageService();
86  $userName = (string)($user->user[$user->username_column] ?? '');
87  $providerToDeactivate = (string)($request->getParsedBody()['provider'] ?? '');
88 
89  if ($providerToDeactivate === '') {
90  // In case no provider is given, try to deactivate all active providers
91  $providersToDeactivate = $this->mfaProviderRegistry->getActiveProviders($user);
92  if ($providersToDeactivate === []) {
93  return $this->‪getResponseData(
94  false,
95  $lang->sL('LLL:EXT:backend/Resources/Private/Language/locallang_mfa.xlf:ajax.deactivate.providersNotDeactivated'),
96  $user
97  );
98  }
99  foreach ($providersToDeactivate as ‪$identifier => $provider) {
100  $propertyManager = ‪MfaProviderPropertyManager::create($provider, $user);
101  if (!$provider->deactivate($request, $propertyManager)) {
102  return $this->‪getResponseData(
103  false,
104  sprintf($lang->sL('LLL:EXT:backend/Resources/Private/Language/locallang_mfa.xlf:ajax.deactivate.providerNotDeactivated'), $lang->sL($provider->getTitle())),
105  $user
106  );
107  }
108  }
109  return $this->‪getResponseData(
110  true,
111  sprintf($lang->sL('LLL:EXT:backend/Resources/Private/Language/locallang_mfa.xlf:ajax.deactivate.providersDeactivated'), $userName),
112  $user
113  );
114  }
115 
116  if (!$this->mfaProviderRegistry->hasProvider($providerToDeactivate)) {
117  return $this->‪getResponseData(
118  false,
119  sprintf($lang->sL('LLL:EXT:backend/Resources/Private/Language/locallang_mfa.xlf:ajax.deactivate.providerNotFound'), $providerToDeactivate),
120  $user
121  );
122  }
123 
124  $provider = $this->mfaProviderRegistry->getProvider($providerToDeactivate);
125  $propertyManager = ‪MfaProviderPropertyManager::create($provider, $user);
126 
127  if (!$provider->isActive($propertyManager) || !$provider->deactivate($request, $propertyManager)) {
128  return $this->‪getResponseData(
129  false,
130  sprintf($lang->sL('LLL:EXT:backend/Resources/Private/Language/locallang_mfa.xlf:ajax.deactivate.providerNotDeactivated'), $lang->sL($provider->getTitle())),
131  $user
132  );
133  }
134 
135  return $this->‪getResponseData(
136  true,
137  sprintf($lang->sL('LLL:EXT:backend/Resources/Private/Language/locallang_mfa.xlf:ajax.deactivate.providerDeactivated'), $lang->sL($provider->getTitle()), $userName),
138  $user
139  );
140  }
141 
145  protected function ‪initializeUser(int $userId, string $tableName): ‪AbstractUserAuthentication
146  {
147  $user = $tableName === 'be_users'
148  ? GeneralUtility::makeInstance(BackendUserAuthentication::class)
149  : GeneralUtility::makeInstance(FrontendUserAuthentication::class);
150 
151  $user->enablecolumns = ['deleted' => true];
152  $user->setBeUserByUid($userId);
153 
154  return $user;
155  }
156 
160  protected function ‪getResponseData(bool $success, string $message, ?‪AbstractUserAuthentication $user = null): array
161  {
162  $flashMessageQueue = new ‪FlashMessageQueue('backend');
163  $flashMessageQueue->enqueue(
164  new ‪FlashMessage(
165  $message,
166  $this->‪getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_mfa.xlf:ajax.' . ($success ? 'success' : 'error'))
167  )
168  );
169  $payload = [
170  'success' => $success,
171  'status' => $flashMessageQueue,
172  ];
173 
174  if ($user !== null) {
175  $payload['remaining'] = count($this->mfaProviderRegistry->getActiveProviders($user));
176  }
177 
178  return $payload;
179  }
180 
185  protected function ‪isAllowedToPerformAction(string $action, ‪AbstractUserAuthentication $user): bool
186  {
187  if ($action === 'deactivate') {
188  $currentBackendUser = $this->‪getBackendUser();
189  // Only admins are allowed to deactivate providers
190  if (!$currentBackendUser->isAdmin()) {
191  return false;
192  }
193  // Providers from system maintainers can only be deactivated by system maintainers.
194  // This check is however only be necessary if the target is a backend user.
195  if ($user instanceof ‪BackendUserAuthentication) {
196  $systemMaintainers = array_map(intval(...), ‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['systemMaintainers'] ?? []);
197  $isTargetUserSystemMaintainer = $user->isAdmin() && in_array((int)$user->user[$user->userid_column], $systemMaintainers, true);
198  if ($isTargetUserSystemMaintainer && !$this->‪getBackendUser()->isSystemMaintainer()) {
199  return false;
200  }
201  }
202  return true;
203  }
204 
205  return false;
206  }
207 
209  {
210  return ‪$GLOBALS['BE_USER'];
211  }
212 
214  {
215  return ‪$GLOBALS['LANG'];
216  }
217 }
‪TYPO3\CMS\Backend\Controller\MfaAjaxController\isAllowedToPerformAction
‪isAllowedToPerformAction(string $action, AbstractUserAuthentication $user)
Definition: MfaAjaxController.php:185
‪TYPO3\CMS\Backend\Controller\MfaAjaxController\deactivateAction
‪deactivateAction(ServerRequestInterface $request, AbstractUserAuthentication $user)
Definition: MfaAjaxController.php:83
‪TYPO3\CMS\Backend\Controller\MfaAjaxController\__construct
‪__construct(MfaProviderRegistry $mfaProviderRegistry)
Definition: MfaAjaxController.php:46
‪TYPO3\CMS\Backend\Controller\MfaAjaxController\initializeUser
‪initializeUser(int $userId, string $tableName)
Definition: MfaAjaxController.php:145
‪TYPO3\CMS\Backend\Controller\MfaAjaxController
Definition: MfaAjaxController.php:41
‪TYPO3\CMS\Core\Authentication\Mfa\MfaProviderPropertyManager\create
‪static create(MfaProviderManifestInterface $provider, AbstractUserAuthentication $user)
Definition: MfaProviderPropertyManager.php:193
‪TYPO3\CMS\Backend\Controller\MfaAjaxController\getBackendUser
‪getBackendUser()
Definition: MfaAjaxController.php:208
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication
Definition: BackendUserAuthentication.php:61
‪TYPO3\CMS\Core\Authentication\Mfa\MfaProviderPropertyManager
Definition: MfaProviderPropertyManager.php:33
‪TYPO3\CMS\Core\Messaging\FlashMessage
Definition: FlashMessage.php:27
‪TYPO3\CMS\Backend\Controller\MfaAjaxController\$mfaProviderRegistry
‪MfaProviderRegistry $mfaProviderRegistry
Definition: MfaAjaxController.php:44
‪TYPO3\CMS\Core\Http\JsonResponse
Definition: JsonResponse.php:28
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Backend\Controller\MfaAjaxController\getLanguageService
‪getLanguageService()
Definition: MfaAjaxController.php:213
‪TYPO3\CMS\Backend\Controller\MfaAjaxController\handleRequest
‪handleRequest(ServerRequestInterface $request)
Definition: MfaAjaxController.php:54
‪TYPO3\CMS\Backend\Attribute\AsController
Definition: AsController.php:25
‪TYPO3\CMS\Core\Localization\LanguageService
Definition: LanguageService.php:46
‪TYPO3\CMS\Frontend\Authentication\FrontendUserAuthentication
Definition: FrontendUserAuthentication.php:33
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Backend\Controller\MfaAjaxController\ALLOWED_ACTIONS
‪const ALLOWED_ACTIONS
Definition: MfaAjaxController.php:42
‪TYPO3\CMS\Core\Messaging\FlashMessageQueue
Definition: FlashMessageQueue.php:29
‪TYPO3\CMS\Backend\Controller
Definition: AboutController.php:18
‪TYPO3\CMS\Backend\Controller\MfaAjaxController\getResponseData
‪getResponseData(bool $success, string $message, ?AbstractUserAuthentication $user=null)
Definition: MfaAjaxController.php:160
‪TYPO3\CMS\Webhooks\Message\$identifier
‪identifier readonly string $identifier
Definition: FileAddedMessage.php:37
‪TYPO3\CMS\Core\Authentication\AbstractUserAuthentication
Definition: AbstractUserAuthentication.php:64
‪TYPO3\CMS\Core\Authentication\Mfa\MfaProviderRegistry
Definition: MfaProviderRegistry.php:28