‪TYPO3CMS  11.5
MfaController.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;
22 use Psr\Log\LoggerAwareInterface;
23 use Psr\Log\LoggerAwareTrait;
35 use TYPO3\CMS\Core\Page\PageRenderer;
37 use ‪TYPO3\CMS\Core\SysLog\Error as SystemLogErrorClassification;
38 use ‪TYPO3\CMS\Core\SysLog\Type as SystemLogType;
39 
45 class ‪MfaController extends ‪AbstractMfaController implements LoggerAwareInterface
46 {
47  use LoggerAwareTrait;
48 
50  protected PageRenderer ‪$pageRenderer;
51 
52  public function ‪__construct(
57  PageRenderer ‪$pageRenderer
58  ) {
60  $this->authenticationStyleInformation = ‪$authenticationStyleInformation;
61  $this->pageRenderer = ‪$pageRenderer;
62  }
63 
68  public function ‪handleRequest(ServerRequestInterface $request): ResponseInterface
69  {
70  $this->moduleTemplate = $this->moduleTemplateFactory->create($request);
71  $action = (string)($request->getQueryParams()['action'] ?? $request->getParsedBody()['action'] ?? 'auth');
72 
73  switch ($action) {
74  case 'auth':
75  case 'verify':
76  $mfaProvider = $this->‪getMfaProviderFromRequest($request);
77  // All actions except "cancel" require a provider to deal with.
78  // If non is found at this point, throw an exception since this should never happen.
79  if ($mfaProvider === null) {
80  throw new \InvalidArgumentException('No active MFA provider was found!', 1611879242);
81  }
82  return $this->{$action . 'Action'}($request, $mfaProvider);
83  case 'cancel':
84  return $this->‪cancelAction($request);
85  default:
86  throw new \InvalidArgumentException('Action not allowed', 1611879244);
87  }
88  }
89 
93  public function ‪authAction(ServerRequestInterface $request, ‪MfaProviderManifestInterface $mfaProvider): ResponseInterface
94  {
95  $view = $this->moduleTemplate->getView();
96  $view->setTemplateRootPaths(['EXT:backend/Resources/Private/Templates/Mfa']);
97  $view->setTemplate('Auth');
98  $view->assign('formUrl', $this->uriBuilder->buildUriWithRedirect(
99  'auth_mfa',
100  [
101  'action' => 'verify',
102  ],
104  ));
105  $view->assign('redirectRoute', $request->getQueryParams()['redirect'] ?? '');
106  $view->assign('redirectParams', $request->getQueryParams()['redirectParams'] ?? '');
107  $view->assign('hasAuthError', (bool)($request->getQueryParams()['failure'] ?? false));
108  $propertyManager = ‪MfaProviderPropertyManager::create($mfaProvider, $this->‪getBackendUser());
109  $providerResponse = $mfaProvider->‪handleRequest($request, $propertyManager, ‪MfaViewType::AUTH);
110  $view->assignMultiple([
111  'provider' => $mfaProvider,
112  'alternativeProviders' => $this->‪getAlternativeProviders($mfaProvider),
113  'isLocked' => $mfaProvider->‪isLocked($propertyManager),
114  'providerContent' => $providerResponse->getBody(),
115  'footerNote' => $this->authenticationStyleInformation->getFooterNote(),
116  ]);
117  $this->moduleTemplate->setTitle('TYPO3 CMS Login: ' . ‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename']);
119  return new ‪HtmlResponse($this->moduleTemplate->renderContent());
120  }
121 
126  public function ‪verifyAction(ServerRequestInterface $request, ‪MfaProviderManifestInterface $mfaProvider): ResponseInterface
127  {
128  $propertyManager = ‪MfaProviderPropertyManager::create($mfaProvider, $this->‪getBackendUser());
129 
130  // Check if the provider can process the request and is not temporarily blocked
131  if (!$mfaProvider->‪canProcess($request) || $mfaProvider->‪isLocked($propertyManager)) {
132  // If this fails, cancel the authentication
133  return $this->‪cancelAction($request);
134  }
135  // Call the provider to verify the request
136  if (!$mfaProvider->‪verify($request, $propertyManager)) {
137  $this->‪log('Multi-factor authentication failed for user ###USERNAME###');
138  // If failed, initiate a redirect back to the auth view
139  return new ‪RedirectResponse($this->uriBuilder->buildUriWithRedirect(
140  'auth_mfa',
141  [
142  'identifier' => $mfaProvider->‪getIdentifier(),
143  'failure' => true,
144  ],
146  ));
147  }
148  $this->‪log('Multi-factor authentication successful for user ###USERNAME###');
149  // If verified, store this information in the session
150  // and initiate a redirect back to the login view.
151  $this->‪getBackendUser()->setAndSaveSessionData('mfa', true);
152  return new ‪RedirectResponse(
153  $this->uriBuilder->buildUriWithRedirect('login', [], ‪RouteRedirect::createFromRequest($request))
154  );
155  }
156 
163  public function ‪cancelAction(ServerRequestInterface $request): ResponseInterface
164  {
165  $this->‪log('Multi-factor authentication canceled for user ###USERNAME###');
166  $this->‪getBackendUser()->logoff();
167  return new ‪RedirectResponse($this->uriBuilder->buildUriWithRedirect('login', [], ‪RouteRedirect::createFromRequest($request)));
168  }
169 
175  protected function ‪getAlternativeProviders(‪MfaProviderManifestInterface $mfaProvider): array
176  {
177  return array_filter($this->allowedProviders, function ($provider) use ($mfaProvider) {
178  return $provider !== $mfaProvider
179  && $provider->‪isActive(‪MfaProviderPropertyManager::create($provider, $this->‪getBackendUser()));
180  });
181  }
182 
186  protected function ‪log(string $message, array $additionalData = [], ?‪MfaProviderManifestInterface $mfaProvider = null): void
187  {
188  $user = $this->‪getBackendUser();
189  $username = $user->user[$user->username_column];
190  $context = [
191  'user' => [
192  'uid' => $user->user[$user->userid_column],
193  'username' => $username,
194  ],
195  ];
196  if ($mfaProvider !== null) {
197  $context['provider'] = $mfaProvider->getIdentifier();
198  $context['isProviderLocked'] = $mfaProvider->isLocked(
199  ‪MfaProviderPropertyManager::create($mfaProvider, $user)
200  );
201  }
202  $message = str_replace('###USERNAME###', $username, $message);
203  $data = array_replace_recursive($context, $additionalData);
204  $this->logger->debug($message, $data);
205  if ($user->writeStdLog) {
206  // Write to sys_log if enabled
207  $user->writelog(SystemLogType::LOGIN, ‪Login::LOGIN, SystemLogErrorClassification::MESSAGE, 1, $message, $data);
208  }
209  }
210 
211  protected function ‪getMfaProviderFromRequest(ServerRequestInterface $request): ?‪MfaProviderManifestInterface
212  {
213  $identifier = (string)($request->getQueryParams()['identifier'] ?? $request->getParsedBody()['identifier'] ?? '');
214  // Check if given identifier is valid
215  if ($this->‪isValidIdentifier($identifier)) {
216  $provider = $this->mfaProviderRegistry->getProvider($identifier);
217  // Only add provider if it was activated by the current user
218  if ($provider->isActive(‪MfaProviderPropertyManager::create($provider, $this->getBackendUser()))) {
219  return $provider;
220  }
221  }
222  return null;
223  }
224 
225  protected function ‪addCustomAuthenticationFormStyles(): void
226  {
227  if (($backgroundImageStyles = $this->authenticationStyleInformation->getBackgroundImageStyles()) !== '') {
228  $this->pageRenderer->addCssInlineBlock('loginBackgroundImage', $backgroundImageStyles);
229  }
230  if (($highlightColorStyles = $this->authenticationStyleInformation->getHighlightColorStyles()) !== '') {
231  $this->pageRenderer->addCssInlineBlock('loginHighlightColor', $highlightColorStyles);
232  }
233  }
234 }
‪TYPO3\CMS\Core\Authentication\Mfa\MfaProviderInterface\verify
‪bool verify(ServerRequestInterface $request, MfaProviderPropertyManager $propertyManager)
‪TYPO3\CMS\Backend\View\AuthenticationStyleInformation
Definition: AuthenticationStyleInformation.php:32
‪TYPO3\CMS\Backend\Controller\AbstractMfaController\isValidIdentifier
‪isValidIdentifier(string $identifier)
Definition: AbstractMfaController.php:76
‪TYPO3\CMS\Backend\Controller\MfaController\cancelAction
‪cancelAction(ServerRequestInterface $request)
Definition: MfaController.php:163
‪TYPO3\CMS\Backend\Controller\MfaController\__construct
‪__construct(UriBuilder $uriBuilder, MfaProviderRegistry $mfaProviderRegistry, ModuleTemplateFactory $moduleTemplateFactory, AuthenticationStyleInformation $authenticationStyleInformation, PageRenderer $pageRenderer)
Definition: MfaController.php:52
‪TYPO3\CMS\Core\Authentication\Mfa\MfaViewType\AUTH
‪const AUTH
Definition: MfaViewType.php:29
‪TYPO3\CMS\Backend\Controller\AbstractMfaController\getBackendUser
‪getBackendUser()
Definition: AbstractMfaController.php:122
‪TYPO3\CMS\Backend\Controller\MfaController\authAction
‪authAction(ServerRequestInterface $request, MfaProviderManifestInterface $mfaProvider)
Definition: MfaController.php:93
‪TYPO3\CMS\Backend\Template\ModuleTemplateFactory
Definition: ModuleTemplateFactory.php:29
‪TYPO3\CMS\Core\Authentication\Mfa\MfaProviderManifestInterface\getIdentifier
‪string getIdentifier()
‪TYPO3\CMS\Backend\Controller\MfaController\$authenticationStyleInformation
‪AuthenticationStyleInformation $authenticationStyleInformation
Definition: MfaController.php:49
‪TYPO3\CMS\Backend\Controller\AbstractMfaController\$moduleTemplateFactory
‪ModuleTemplateFactory $moduleTemplateFactory
Definition: AbstractMfaController.php:40
‪TYPO3\CMS\Core\Authentication\Mfa\MfaProviderManifestInterface
Definition: MfaProviderManifestInterface.php:26
‪TYPO3\CMS\Core\Authentication\Mfa\MfaProviderInterface\canProcess
‪bool canProcess(ServerRequestInterface $request)
‪TYPO3\CMS\Core\SysLog\Action\Login\LOGIN
‪const LOGIN
Definition: Login.php:25
‪TYPO3\CMS\Core\Authentication\Mfa\MfaProviderInterface\isActive
‪bool isActive(MfaProviderPropertyManager $propertyManager)
‪TYPO3\CMS\Backend\Controller\AbstractMfaController\$mfaProviderRegistry
‪MfaProviderRegistry $mfaProviderRegistry
Definition: AbstractMfaController.php:39
‪TYPO3\CMS\Core\SysLog\Action\Login
Definition: Login.php:24
‪TYPO3\CMS\Backend\Controller\MfaController\handleRequest
‪handleRequest(ServerRequestInterface $request)
Definition: MfaController.php:68
‪TYPO3\CMS\Backend\Controller\MfaController\$pageRenderer
‪PageRenderer $pageRenderer
Definition: MfaController.php:50
‪TYPO3\CMS\Backend\Controller\MfaController\addCustomAuthenticationFormStyles
‪addCustomAuthenticationFormStyles()
Definition: MfaController.php:225
‪TYPO3\CMS\Backend\Routing\RouteRedirect
Definition: RouteRedirect.php:30
‪TYPO3\CMS\Backend\Routing\UriBuilder
Definition: UriBuilder.php:40
‪TYPO3\CMS\Backend\ContextMenu\ItemProviders\ProviderInterface
Definition: ProviderInterface.php:24
‪TYPO3\CMS\Core\SysLog\Error
Definition: Error.php:24
‪TYPO3\CMS\Backend\Controller\MfaController\verifyAction
‪verifyAction(ServerRequestInterface $request, MfaProviderManifestInterface $mfaProvider)
Definition: MfaController.php:126
‪TYPO3\CMS\Core\Authentication\Mfa\MfaProviderPropertyManager
Definition: MfaProviderPropertyManager.php:33
‪TYPO3\CMS\Core\Http\RedirectResponse
Definition: RedirectResponse.php:28
‪TYPO3\CMS\Backend\Controller\MfaController\getMfaProviderFromRequest
‪getMfaProviderFromRequest(ServerRequestInterface $request)
Definition: MfaController.php:211
‪TYPO3\CMS\Backend\Controller\MfaController
Definition: MfaController.php:46
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Core\Authentication\Mfa\MfaViewType
Definition: MfaViewType.php:26
‪TYPO3\CMS\Core\Authentication\Mfa\MfaProviderPropertyManager\create
‪static MfaProviderPropertyManager create(MfaProviderManifestInterface $provider, AbstractUserAuthentication $user)
Definition: MfaProviderPropertyManager.php:224
‪TYPO3\CMS\Backend\Controller\MfaController\getAlternativeProviders
‪ProviderInterface[] getAlternativeProviders(MfaProviderManifestInterface $mfaProvider)
Definition: MfaController.php:175
‪TYPO3\CMS\Backend\Controller\MfaController\log
‪log(string $message, array $additionalData=[], ?MfaProviderManifestInterface $mfaProvider=null)
Definition: MfaController.php:186
‪TYPO3\CMS\Core\Authentication\Mfa\MfaProviderInterface\handleRequest
‪ResponseInterface handleRequest(ServerRequestInterface $request, MfaProviderPropertyManager $propertyManager, string $type)
‪TYPO3\CMS\Backend\Routing\RouteRedirect\createFromRequest
‪static createFromRequest(ServerRequestInterface $request)
Definition: RouteRedirect.php:58
‪TYPO3\CMS\Core\Authentication\Mfa\MfaProviderInterface\isLocked
‪bool isLocked(MfaProviderPropertyManager $propertyManager)
‪TYPO3\CMS\Backend\Controller
Definition: AboutController.php:16
‪TYPO3\CMS\Backend\Controller\AbstractMfaController\$uriBuilder
‪UriBuilder $uriBuilder
Definition: AbstractMfaController.php:38
‪TYPO3\CMS\Core\Http\HtmlResponse
Definition: HtmlResponse.php:26
‪TYPO3\CMS\Core\SysLog\Type
Definition: Type.php:28
‪TYPO3\CMS\Core\Authentication\Mfa\MfaProviderRegistry
Definition: MfaProviderRegistry.php:28
‪TYPO3\CMS\Backend\Controller\AbstractMfaController
Definition: AbstractMfaController.php:37