Passed
Push — master ( 738d52...2688e0 )
by
unknown
12:36
created

MfaConfigurationController::saveAction()   A

Complexity

Conditions 5
Paths 8

Size

Total Lines 17
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 12
c 1
b 0
f 0
dl 0
loc 17
rs 9.5555
cc 5
nc 8
nop 1
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
18
namespace TYPO3\CMS\Backend\Controller;
19
20
use Psr\Http\Message\ResponseInterface;
21
use Psr\Http\Message\ServerRequestInterface;
22
use Psr\Http\Message\UriInterface;
23
use TYPO3\CMS\Backend\Template\Components\ButtonBar;
24
use TYPO3\CMS\Core\Authentication\Mfa\MfaProviderPropertyManager;
25
use TYPO3\CMS\Core\Authentication\Mfa\MfaViewType;
26
use TYPO3\CMS\Core\Http\HtmlResponse;
27
use TYPO3\CMS\Core\Http\RedirectResponse;
28
use TYPO3\CMS\Core\Imaging\Icon;
29
use TYPO3\CMS\Core\Messaging\FlashMessage;
30
use TYPO3\CMS\Core\Messaging\FlashMessageService;
31
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
32
use TYPO3\CMS\Core\Utility\GeneralUtility;
33
use TYPO3\CMS\Fluid\View\StandaloneView;
34
35
/**
36
 * Controller to configure MFA providers in the backend
37
 *
38
 * @internal This class is a specific Backend controller implementation and is not considered part of the Public TYPO3 API.
39
 */
40
class MfaConfigurationController extends AbstractMfaController
41
{
42
    protected array $allowedActions = ['overview', 'setup', 'activate', 'deactivate', 'unlock', 'edit', 'save'];
43
    private array $providerActionsWhenInactive = ['setup', 'activate'];
44
    private array $providerActionsWhenActive = ['deactivate', 'unlock', 'edit', 'save'];
45
46
    /**
47
     * Main entry point, checking prerequisite, initializing and setting
48
     * up the view and finally dispatching to the requested action.
49
     *
50
     * @param ServerRequestInterface $request
51
     * @return ResponseInterface
52
     */
53
    public function handleRequest(ServerRequestInterface $request): ResponseInterface
54
    {
55
        $action = (string)($request->getQueryParams()['action'] ?? $request->getParsedBody()['action'] ?? 'overview');
56
57
        if (!$this->isActionAllowed($action)) {
58
            return new HtmlResponse('Action not allowed', 400);
59
        }
60
61
        $this->initializeAction($request);
62
        // All actions expect "overview" require a provider to deal with.
63
        // If non is found at this point, initiate a redirect to the overview.
64
        if ($this->mfaProvider === null && $action !== 'overview') {
65
            $this->addFlashMessage($this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_mfa.xlf:providerNotFound'), '', FlashMessage::ERROR);
66
            return new RedirectResponse($this->getActionUri('overview'));
67
        }
68
        // If a valid provider is given, check if the requested action can be performed on this provider
69
        if ($this->mfaProvider !== null) {
70
            $isProviderActive = $this->mfaProvider->isActive(
71
                MfaProviderPropertyManager::create($this->mfaProvider, $this->getBackendUser())
72
            );
73
            // Some actions require the provider to be inactive
74
            if ($isProviderActive && in_array($action, $this->providerActionsWhenInactive, true)) {
75
                $this->addFlashMessage($this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_mfa.xlf:providerActive'), '', FlashMessage::ERROR);
76
                return new RedirectResponse($this->getActionUri('overview'));
77
            }
78
            // Some actions require the provider to be active
79
            if (!$isProviderActive && in_array($action, $this->providerActionsWhenActive, true)) {
80
                $this->addFlashMessage($this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_mfa.xlf:providerNotActive'), '', FlashMessage::ERROR);
81
                return new RedirectResponse($this->getActionUri('overview'));
82
            }
83
        }
84
        $this->initializeView($action);
85
86
        $result = $this->{$action . 'Action'}($request);
87
        if ($result instanceof ResponseInterface) {
88
            return $result;
89
        }
90
        $this->moduleTemplate->setContent($this->view->render());
0 ignored issues
show
Bug introduced by
The method render() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

90
        $this->moduleTemplate->setContent($this->view->/** @scrutinizer ignore-call */ render());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
91
        return new HtmlResponse($this->moduleTemplate->renderContent());
92
    }
93
94
    /**
95
     * Setup the overview with all available MFA providers
96
     *
97
     * @param ServerRequestInterface $request
98
     */
99
    public function overviewAction(ServerRequestInterface $request): void
100
    {
101
        $this->addOverviewButtons($request);
102
        $this->view->assignMultiple([
103
            'providers' => $this->allowedProviders,
104
            'defaultProvider' => $this->getDefaultProviderIdentifier(),
105
            'recommendedProvider' => $this->getRecommendedProviderIdentifier(),
106
            'setupRequired' => $this->mfaRequired && !$this->mfaProviderRegistry->hasActiveProviders($this->getBackendUser())
107
        ]);
108
    }
109
110
    /**
111
     * Render form to setup a provider by using provider specific content
112
     *
113
     * @param ServerRequestInterface $request
114
     * @return ResponseInterface
115
     */
116
    public function setupAction(ServerRequestInterface $request): ResponseInterface
117
    {
118
        $this->addFormButtons();
119
        $propertyManager = MfaProviderPropertyManager::create($this->mfaProvider, $this->getBackendUser());
0 ignored issues
show
Bug introduced by
It seems like $this->mfaProvider can also be of type null; however, parameter $provider of TYPO3\CMS\Core\Authentic...opertyManager::create() does only seem to accept TYPO3\CMS\Core\Authentic...oviderManifestInterface, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

119
        $propertyManager = MfaProviderPropertyManager::create(/** @scrutinizer ignore-type */ $this->mfaProvider, $this->getBackendUser());
Loading history...
120
        $providerResponse = $this->mfaProvider->handleRequest($request, $propertyManager, MfaViewType::SETUP);
0 ignored issues
show
Bug introduced by
The method handleRequest() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

120
        /** @scrutinizer ignore-call */ 
121
        $providerResponse = $this->mfaProvider->handleRequest($request, $propertyManager, MfaViewType::SETUP);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
121
        $this->view->assignMultiple([
122
            'provider' => $this->mfaProvider,
123
            'providerContent' => $providerResponse->getBody()
124
        ]);
125
        $this->moduleTemplate->setContent($this->view->render());
126
        return new HtmlResponse($this->moduleTemplate->renderContent());
127
    }
128
129
    /**
130
     * Handle activate request, receiving from the setup view
131
     * by forwarding the request to the appropriate provider.
132
     * Furthermore, add the provider as default provider in case
133
     * it is the recommended provider for this user, or no default
134
     * provider is yet defined the newly activated provider is allowed
135
     * to be a default provider and there are no other providers which
136
     * would suite as default provider.
137
     *
138
     * @param ServerRequestInterface $request
139
     * @return ResponseInterface
140
     */
141
    public function activateAction(ServerRequestInterface $request): ResponseInterface
142
    {
143
        $backendUser = $this->getBackendUser();
144
        $isRecommendedProvider = $this->getRecommendedProviderIdentifier() === $this->mfaProvider->getIdentifier();
145
        $propertyManager = MfaProviderPropertyManager::create($this->mfaProvider, $backendUser);
0 ignored issues
show
Bug introduced by
It seems like $this->mfaProvider can also be of type null; however, parameter $provider of TYPO3\CMS\Core\Authentic...opertyManager::create() does only seem to accept TYPO3\CMS\Core\Authentic...oviderManifestInterface, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

145
        $propertyManager = MfaProviderPropertyManager::create(/** @scrutinizer ignore-type */ $this->mfaProvider, $backendUser);
Loading history...
146
        if (!$this->mfaProvider->activate($request, $propertyManager)) {
147
            $this->addFlashMessage(sprintf($this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_mfa.xlf:activate.failure'), $this->getLocalizedProviderTitle()), '', FlashMessage::ERROR);
148
            return new RedirectResponse($this->getActionUri('setup', ['identifier' => $this->mfaProvider->getIdentifier()]));
149
        }
150
        if ($isRecommendedProvider
151
            || (
152
                $this->getDefaultProviderIdentifier() === ''
153
                && $this->mfaProvider->isDefaultProviderAllowed()
154
                && !$this->hasSuitableDefaultProviders([$this->mfaProvider->getIdentifier()])
155
            )
156
        ) {
157
            $this->setDefaultProvider();
158
        }
159
        // If this is the first activated provider, the user has logged in without being required
160
        // to pass the MFA challenge. Therefore no session entry exists. To prevent the challenge
161
        // from showing up after the activation we need to set the session data here.
162
        if (!(bool)($backendUser->getSessionData('mfa') ?? false)) {
163
            $backendUser->setSessionData('mfa', true);
164
        }
165
        $this->addFlashMessage(sprintf($this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_mfa.xlf:activate.success'), $this->getLocalizedProviderTitle()), '', FlashMessage::OK);
166
        return new RedirectResponse($this->getActionUri('overview'));
167
    }
168
169
    /**
170
     * Handle deactivate request by forwarding the request to the
171
     * appropriate provider. Also remove the provider as default
172
     * provider from user UC, if set.
173
     *
174
     * @param ServerRequestInterface $request
175
     * @return ResponseInterface
176
     */
177
    public function deactivateAction(ServerRequestInterface $request): ResponseInterface
178
    {
179
        $propertyManager = MfaProviderPropertyManager::create($this->mfaProvider, $this->getBackendUser());
0 ignored issues
show
Bug introduced by
It seems like $this->mfaProvider can also be of type null; however, parameter $provider of TYPO3\CMS\Core\Authentic...opertyManager::create() does only seem to accept TYPO3\CMS\Core\Authentic...oviderManifestInterface, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

179
        $propertyManager = MfaProviderPropertyManager::create(/** @scrutinizer ignore-type */ $this->mfaProvider, $this->getBackendUser());
Loading history...
180
        if (!$this->mfaProvider->deactivate($request, $propertyManager)) {
181
            $this->addFlashMessage(sprintf($this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_mfa.xlf:deactivate.failure'), $this->getLocalizedProviderTitle()), '', FlashMessage::ERROR);
182
        } else {
183
            if ($this->isDefaultProvider()) {
184
                $this->removeDefaultProvider();
185
            }
186
            $this->addFlashMessage(sprintf($this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_mfa.xlf:deactivate.success'), $this->getLocalizedProviderTitle()), '', FlashMessage::OK);
187
        }
188
        return new RedirectResponse($this->getActionUri('overview'));
189
    }
190
191
    /**
192
     * Handle unlock request by forwarding the request to the appropriate provider
193
     *
194
     * @param ServerRequestInterface $request
195
     * @return ResponseInterface
196
     */
197
    public function unlockAction(ServerRequestInterface $request): ResponseInterface
198
    {
199
        $propertyManager = MfaProviderPropertyManager::create($this->mfaProvider, $this->getBackendUser());
0 ignored issues
show
Bug introduced by
It seems like $this->mfaProvider can also be of type null; however, parameter $provider of TYPO3\CMS\Core\Authentic...opertyManager::create() does only seem to accept TYPO3\CMS\Core\Authentic...oviderManifestInterface, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

199
        $propertyManager = MfaProviderPropertyManager::create(/** @scrutinizer ignore-type */ $this->mfaProvider, $this->getBackendUser());
Loading history...
200
        if (!$this->mfaProvider->unlock($request, $propertyManager)) {
201
            $this->addFlashMessage(sprintf($this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_mfa.xlf:unlock.failure'), $this->getLocalizedProviderTitle()), '', FlashMessage::ERROR);
202
        } else {
203
            $this->addFlashMessage(sprintf($this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_mfa.xlf:unlock.success'), $this->getLocalizedProviderTitle()), '', FlashMessage::OK);
204
        }
205
        return new RedirectResponse($this->getActionUri('overview'));
206
    }
207
208
    /**
209
     * Render form to edit a provider by using provider specific content
210
     *
211
     * @param ServerRequestInterface $request
212
     * @return ResponseInterface
213
     */
214
    public function editAction(ServerRequestInterface $request): ResponseInterface
215
    {
216
        $propertyManager = MfaProviderPropertyManager::create($this->mfaProvider, $this->getBackendUser());
0 ignored issues
show
Bug introduced by
It seems like $this->mfaProvider can also be of type null; however, parameter $provider of TYPO3\CMS\Core\Authentic...opertyManager::create() does only seem to accept TYPO3\CMS\Core\Authentic...oviderManifestInterface, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

216
        $propertyManager = MfaProviderPropertyManager::create(/** @scrutinizer ignore-type */ $this->mfaProvider, $this->getBackendUser());
Loading history...
217
        if ($this->mfaProvider->isLocked($propertyManager)) {
218
            // Do not show edit view for locked providers
219
            $this->addFlashMessage($this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_mfa.xlf:providerIsLocked'), '', FlashMessage::ERROR);
220
            return new RedirectResponse($this->getActionUri('overview'));
221
        }
222
        $this->addFormButtons();
223
        $providerResponse = $this->mfaProvider->handleRequest($request, $propertyManager, MfaViewType::EDIT);
224
        $this->view->assignMultiple([
225
            'provider' => $this->mfaProvider,
226
            'providerContent' => $providerResponse->getBody(),
227
            'isDefaultProvider' => $this->isDefaultProvider()
228
        ]);
229
        $this->moduleTemplate->setContent($this->view->render());
230
        return new HtmlResponse($this->moduleTemplate->renderContent());
231
    }
232
233
    /**
234
     * Handle save request, receiving from the edit view by
235
     * forwarding the request to the appropriate provider.
236
     *
237
     * @param ServerRequestInterface $request
238
     * @return ResponseInterface
239
     */
240
    public function saveAction(ServerRequestInterface $request): ResponseInterface
241
    {
242
        $propertyManager = MfaProviderPropertyManager::create($this->mfaProvider, $this->getBackendUser());
0 ignored issues
show
Bug introduced by
It seems like $this->mfaProvider can also be of type null; however, parameter $provider of TYPO3\CMS\Core\Authentic...opertyManager::create() does only seem to accept TYPO3\CMS\Core\Authentic...oviderManifestInterface, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

242
        $propertyManager = MfaProviderPropertyManager::create(/** @scrutinizer ignore-type */ $this->mfaProvider, $this->getBackendUser());
Loading history...
243
        if (!$this->mfaProvider->update($request, $propertyManager)) {
244
            $this->addFlashMessage(sprintf($this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_mfa.xlf:save.failure'), $this->getLocalizedProviderTitle()), '', FlashMessage::ERROR);
245
        } else {
246
            if ((bool)($request->getParsedBody()['defaultProvider'] ?? false)) {
247
                $this->setDefaultProvider();
248
            } elseif ($this->isDefaultProvider()) {
249
                $this->removeDefaultProvider();
250
            }
251
            $this->addFlashMessage(sprintf($this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_mfa.xlf:save.success'), $this->getLocalizedProviderTitle()), '', FlashMessage::OK);
252
        }
253
        if (!$this->mfaProvider->isActive($propertyManager)) {
254
            return new RedirectResponse($this->getActionUri('overview'));
255
        }
256
        return new RedirectResponse($this->getActionUri('edit', ['identifier' => $this->mfaProvider->getIdentifier()]));
257
    }
258
259
    /**
260
     * Initialize the action by fetching the requested provider by its identifier
261
     *
262
     * @param ServerRequestInterface $request
263
     */
264
    protected function initializeAction(ServerRequestInterface $request): void
265
    {
266
        $identifier = (string)($request->getQueryParams()['identifier'] ?? $request->getParsedBody()['identifier'] ?? '');
267
        // Check if given identifier is valid
268
        if ($this->isValidIdentifier($identifier)) {
269
            $this->mfaProvider = $this->mfaProviderRegistry->getProvider($identifier);
270
        }
271
    }
272
273
    /**
274
     * Initialize the standalone view and set the template name
275
     *
276
     * @param string $templateName
277
     */
278
    protected function initializeView(string $templateName): void
279
    {
280
        $this->view = GeneralUtility::makeInstance(StandaloneView::class);
281
        $this->view->setTemplateRootPaths(['EXT:backend/Resources/Private/Templates/Mfa']);
0 ignored issues
show
Bug introduced by
The method setTemplateRootPaths() does not exist on TYPO3\CMS\Extbase\Mvc\View\ViewInterface. It seems like you code against a sub-type of said class. However, the method does not exist in TYPO3\CMS\Extbase\Mvc\View\AbstractView or TYPO3\CMS\Extbase\Mvc\View\JsonView. Are you sure you never get one of those? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

281
        $this->view->/** @scrutinizer ignore-call */ 
282
                     setTemplateRootPaths(['EXT:backend/Resources/Private/Templates/Mfa']);
Loading history...
282
        $this->view->setPartialRootPaths(['EXT:backend/Resources/Private/Partials']);
0 ignored issues
show
Bug introduced by
The method setPartialRootPaths() does not exist on TYPO3\CMS\Extbase\Mvc\View\ViewInterface. It seems like you code against a sub-type of said class. However, the method does not exist in TYPO3\CMS\Extbase\Mvc\View\AbstractView or TYPO3\CMS\Extbase\Mvc\View\JsonView. Are you sure you never get one of those? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

282
        $this->view->/** @scrutinizer ignore-call */ 
283
                     setPartialRootPaths(['EXT:backend/Resources/Private/Partials']);
Loading history...
283
        $this->view->setLayoutRootPaths(['EXT:backend/Resources/Private/Layouts']);
0 ignored issues
show
Bug introduced by
The method setLayoutRootPaths() does not exist on TYPO3\CMS\Extbase\Mvc\View\ViewInterface. It seems like you code against a sub-type of said class. However, the method does not exist in TYPO3\CMS\Extbase\Mvc\View\AbstractView or TYPO3\CMS\Extbase\Mvc\View\JsonView. Are you sure you never get one of those? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

283
        $this->view->/** @scrutinizer ignore-call */ 
284
                     setLayoutRootPaths(['EXT:backend/Resources/Private/Layouts']);
Loading history...
284
        $this->view->setTemplate($templateName);
0 ignored issues
show
Bug introduced by
The method setTemplate() does not exist on TYPO3\CMS\Extbase\Mvc\View\ViewInterface. It seems like you code against a sub-type of TYPO3\CMS\Extbase\Mvc\View\ViewInterface such as TYPO3\CMS\Extbase\Mvc\View\EmptyView or TYPO3\CMS\Fluid\View\AbstractTemplateView or TYPO3\CMS\Extbase\Mvc\View\NotFoundView. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

284
        $this->view->/** @scrutinizer ignore-call */ 
285
                     setTemplate($templateName);
Loading history...
285
    }
286
287
    /**
288
     * Build a uri for the current controller based on the
289
     * given action, respecting additional parameters.
290
     *
291
     * @param string $action
292
     * @param array  $additionalParameters
293
     *
294
     * @return UriInterface
295
     */
296
    protected function getActionUri(string $action, array $additionalParameters = []): UriInterface
297
    {
298
        if (!$this->isActionAllowed($action)) {
299
            $action = 'overview';
300
        }
301
        return $this->uriBuilder->buildUriFromRoute('mfa', array_merge(['action' => $action], $additionalParameters));
302
    }
303
304
    /**
305
     * Check if there are more suitable default providers for the current user
306
     *
307
     * @param array $excludedProviders
308
     * @return bool
309
     */
310
    protected function hasSuitableDefaultProviders(array $excludedProviders = []): bool
311
    {
312
        foreach ($this->allowedProviders as $identifier => $provider) {
313
            if (!in_array($identifier, $excludedProviders, true)
314
                && $provider->isDefaultProviderAllowed()
315
                && $provider->isActive(MfaProviderPropertyManager::create($provider, $this->getBackendUser()))
316
            ) {
317
                return true;
318
            }
319
        }
320
        return false;
321
    }
322
323
    /**
324
     * Get the default provider
325
     *
326
     * @return string The identifier of the default provider
327
     */
328
    protected function getDefaultProviderIdentifier(): string
329
    {
330
        $defaultProviderIdentifier = (string)($this->getBackendUser()->uc['mfa']['defaultProvider'] ?? '');
331
        // The default provider value is only valid, if the corresponding provider exist and is allowed
332
        if ($this->isValidIdentifier($defaultProviderIdentifier)) {
333
            $defaultProvider = $this->mfaProviderRegistry->getProvider($defaultProviderIdentifier);
334
            $propertyManager = MfaProviderPropertyManager::create($defaultProvider, $this->getBackendUser());
335
            // Also check if the provider is activated for the user
336
            if ($defaultProvider->isActive($propertyManager)) {
337
                return $defaultProviderIdentifier;
338
            }
339
        }
340
341
        // If the stored provider is not valid, clean up the UC
342
        $this->removeDefaultProvider();
343
        return '';
344
    }
345
346
    /**
347
     * Get the recommended provider
348
     *
349
     * @return string The identifier of the recommended provider
350
     */
351
    protected function getRecommendedProviderIdentifier(): string
352
    {
353
        $recommendedProviderIdentifier = (string)($this->mfaTsConfig['recommendedProvider'] ?? '');
354
        // Check if valid and allowed to be default provider, which is obviously a prerequisite
355
        if (!$this->isValidIdentifier($recommendedProviderIdentifier)
356
            || !$this->mfaProviderRegistry->getProvider($recommendedProviderIdentifier)->isDefaultProviderAllowed()
357
        ) {
358
            // If the provider, defined in user TSconfig is not valid or is not set, check the globally defined
359
            $recommendedProviderIdentifier = (string)($GLOBALS['TYPO3_CONF_VARS']['BE']['recommendedMfaProvider'] ?? '');
360
            if (!$this->isValidIdentifier($recommendedProviderIdentifier)
361
                || !$this->mfaProviderRegistry->getProvider($recommendedProviderIdentifier)->isDefaultProviderAllowed()
362
            ) {
363
                // If also not valid or not set, return
364
                return '';
365
            }
366
        }
367
368
        $provider = $this->mfaProviderRegistry->getProvider($recommendedProviderIdentifier);
369
        $propertyManager = MfaProviderPropertyManager::create($provider, $this->getBackendUser());
370
        // If the defined recommended provider is valid, check if it is not yet activated
371
        return !$provider->isActive($propertyManager) ? $recommendedProviderIdentifier : '';
372
    }
373
374
    protected function isDefaultProvider(): bool
375
    {
376
        return $this->getDefaultProviderIdentifier() === $this->mfaProvider->getIdentifier();
377
    }
378
379
    protected function setDefaultProvider(): void
380
    {
381
        $this->getBackendUser()->uc['mfa']['defaultProvider'] = $this->mfaProvider->getIdentifier();
382
        $this->getBackendUser()->writeUC();
383
    }
384
385
    protected function removeDefaultProvider(): void
386
    {
387
        $this->getBackendUser()->uc['mfa']['defaultProvider'] = '';
388
        $this->getBackendUser()->writeUC();
389
    }
390
391
    protected function addFlashMessage(string $message, string $title = '', int $severity = FlashMessage::INFO): void
392
    {
393
        $flashMessage = GeneralUtility::makeInstance(FlashMessage::class, $message, $title, $severity, true);
394
        $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
395
        $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
396
        $defaultFlashMessageQueue->enqueue($flashMessage);
397
    }
398
399
    protected function addOverviewButtons(ServerRequestInterface $request): void
400
    {
401
        $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
402
403
        if (($returnUrl = $this->getReturnUrl($request)) !== '') {
404
            $button = $buttonBar
405
                ->makeLinkButton()
406
                ->setHref($returnUrl)
407
                ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-view-go-back', Icon::SIZE_SMALL))
408
                ->setTitle($this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.goBack'))
409
                ->setShowLabelText(true);
410
            $buttonBar->addButton($button);
411
        }
412
413
        $reloadButton = $buttonBar
414
            ->makeLinkButton()
415
            ->setHref($request->getAttribute('normalizedParams')->getRequestUri())
416
            ->setTitle($this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.reload'))
417
            ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-refresh', Icon::SIZE_SMALL));
418
        $buttonBar->addButton($reloadButton, ButtonBar::BUTTON_POSITION_RIGHT);
419
    }
420
421
    protected function addFormButtons(): void
422
    {
423
        $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
424
        $lang = $this->getLanguageService();
425
426
        $closeButton = $buttonBar
427
            ->makeLinkButton()
428
            ->setHref($this->uriBuilder->buildUriFromRoute('mfa', ['action' => 'overview']))
429
            ->setClasses('t3js-editform-close')
430
            ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:rm.closeDoc'))
431
            ->setShowLabelText(true)
432
            ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-close', Icon::SIZE_SMALL));
433
        $buttonBar->addButton($closeButton);
434
435
        $saveButton = $buttonBar
436
            ->makeInputButton()
437
            ->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:rm.saveDoc'))
438
            ->setName('save')
439
            ->setValue('1')
440
            ->setShowLabelText(true)
441
            ->setForm('mfaConfigurationController')
442
            ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-document-save', Icon::SIZE_SMALL));
443
        $buttonBar->addButton($saveButton, ButtonBar::BUTTON_POSITION_LEFT, 2);
444
    }
445
446
    protected function getReturnUrl(ServerRequestInterface $request): string
447
    {
448
        $returnUrl = GeneralUtility::sanitizeLocalUrl(
449
            $request->getQueryParams()['returnUrl'] ?? $request->getParsedBody()['returnUrl'] ?? ''
450
        );
451
452
        if ($returnUrl === '' && ExtensionManagementUtility::isLoaded('setup')) {
453
            $returnUrl = (string)$this->uriBuilder->buildUriFromRoute('user_setup');
454
        }
455
456
        return $returnUrl;
457
    }
458
}
459