Passed
Push — master ( 25a926...39145a )
by
unknown
20:30
created

MfaConfigurationController::addOverviewButtons()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 20
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 15
c 1
b 0
f 0
dl 0
loc 20
rs 9.7666
cc 2
nc 2
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
44
    /**
45
     * Main entry point, checking prerequisite, initializing and setting
46
     * up the view and finally dispatching to the requested action.
47
     *
48
     * @param ServerRequestInterface $request
49
     * @return ResponseInterface
50
     */
51
    public function handleRequest(ServerRequestInterface $request): ResponseInterface
52
    {
53
        $action = (string)($request->getQueryParams()['action'] ?? $request->getParsedBody()['action'] ?? 'overview');
54
55
        if (!$this->isActionAllowed($action)) {
56
            return new HtmlResponse('Action not allowed', 400);
57
        }
58
59
        $this->initializeAction($request);
60
        // All actions expect "overview" require a provider to deal with.
61
        // If non is found at this point, initiate a redirect to the overview.
62
        if ($this->mfaProvider === null && $action !== 'overview') {
63
            $this->addFlashMessage($this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_mfa.xlf:providerNotFound'), '', FlashMessage::ERROR);
64
            return new RedirectResponse($this->getActionUri('overview'));
65
        }
66
        $this->initializeView($action);
67
68
        $result = $this->{$action . 'Action'}($request);
69
        if ($result instanceof ResponseInterface) {
70
            return $result;
71
        }
72
        $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

72
        $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...
73
        return new HtmlResponse($this->moduleTemplate->renderContent());
74
    }
75
76
    /**
77
     * Setup the overview with all available MFA providers
78
     *
79
     * @param ServerRequestInterface $request
80
     */
81
    public function overviewAction(ServerRequestInterface $request): void
82
    {
83
        $this->addOverviewButtons($request);
84
        $this->view->assignMultiple([
85
            'providers' => $this->allowedProviders,
86
            'defaultProvider' => $this->getDefaultProviderIdentifier(),
87
            'recommendedProvider' => $this->getRecommendedProviderIdentifier(),
88
            'setupRequired' => $this->mfaRequired && !$this->mfaProviderRegistry->hasActiveProviders($this->getBackendUser())
89
        ]);
90
    }
91
92
    /**
93
     * Render form to setup a provider by using provider specific content
94
     *
95
     * @param ServerRequestInterface $request
96
     * @return ResponseInterface
97
     */
98
    public function setupAction(ServerRequestInterface $request): ResponseInterface
99
    {
100
        $this->addFormButtons();
101
        $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

101
        $propertyManager = MfaProviderPropertyManager::create(/** @scrutinizer ignore-type */ $this->mfaProvider, $this->getBackendUser());
Loading history...
102
        $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

102
        /** @scrutinizer ignore-call */ 
103
        $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...
103
        $this->view->assignMultiple([
104
            'provider' => $this->mfaProvider,
105
            'providerContent' => $providerResponse->getBody()
106
        ]);
107
        $this->moduleTemplate->setContent($this->view->render());
108
        return new HtmlResponse($this->moduleTemplate->renderContent());
109
    }
110
111
    /**
112
     * Handle activate request, receiving from the setup view
113
     * by forwarding the request to the appropriate provider.
114
     * Furthermore, add the provider as default provider in case
115
     * it is the recommended provider for this user, or no default
116
     * provider is yet defined the newly activated provider is allowed
117
     * to be a default provider and there are no other providers which
118
     * would suite as default provider.
119
     *
120
     * @param ServerRequestInterface $request
121
     * @return ResponseInterface
122
     */
123
    public function activateAction(ServerRequestInterface $request): ResponseInterface
124
    {
125
        $backendUser = $this->getBackendUser();
126
        $isRecommendedProvider = $this->getRecommendedProviderIdentifier() === $this->mfaProvider->getIdentifier();
127
        $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

127
        $propertyManager = MfaProviderPropertyManager::create(/** @scrutinizer ignore-type */ $this->mfaProvider, $backendUser);
Loading history...
128
        if (!$this->mfaProvider->activate($request, $propertyManager)) {
129
            $this->addFlashMessage(sprintf($this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_mfa.xlf:activate.failure'), $this->getLocalizedProviderTitle()), '', FlashMessage::ERROR);
130
            return new RedirectResponse($this->getActionUri('setup', ['identifier' => $this->mfaProvider->getIdentifier()]));
131
        }
132
        if ($isRecommendedProvider
133
            || (
134
                $this->getDefaultProviderIdentifier() === ''
135
                && $this->mfaProvider->isDefaultProviderAllowed()
136
                && !$this->hasSuitableDefaultProviders([$this->mfaProvider->getIdentifier()])
137
            )
138
        ) {
139
            $this->setDefaultProvider();
140
        }
141
        // If this is the first activated provider, the user has logged in without being required
142
        // to pass the MFA challenge. Therefore no session entry exists. To prevent the challenge
143
        // from showing up after the activation we need to set the session data here.
144
        if (!(bool)($backendUser->getSessionData('mfa') ?? false)) {
145
            $backendUser->setSessionData('mfa', true);
146
        }
147
        $this->addFlashMessage(sprintf($this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_mfa.xlf:activate.success'), $this->getLocalizedProviderTitle()), '', FlashMessage::OK);
148
        return new RedirectResponse($this->getActionUri('overview'));
149
    }
150
151
    /**
152
     * Handle deactivate request by forwarding the request to the
153
     * appropriate provider. Also remove the provider as default
154
     * provider from user UC, if set.
155
     *
156
     * @param ServerRequestInterface $request
157
     * @return ResponseInterface
158
     */
159
    public function deactivateAction(ServerRequestInterface $request): ResponseInterface
160
    {
161
        $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

161
        $propertyManager = MfaProviderPropertyManager::create(/** @scrutinizer ignore-type */ $this->mfaProvider, $this->getBackendUser());
Loading history...
162
        if (!$this->mfaProvider->deactivate($request, $propertyManager)) {
163
            $this->addFlashMessage(sprintf($this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_mfa.xlf:deactivate.failure'), $this->getLocalizedProviderTitle()), '', FlashMessage::ERROR);
164
        } else {
165
            if ($this->isDefaultProvider()) {
166
                $this->removeDefaultProvider();
167
            }
168
            $this->addFlashMessage(sprintf($this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_mfa.xlf:deactivate.success'), $this->getLocalizedProviderTitle()), '', FlashMessage::OK);
169
        }
170
        return new RedirectResponse($this->getActionUri('overview'));
171
    }
172
173
    /**
174
     * Handle unlock request by forwarding the request to the appropriate provider
175
     *
176
     * @param ServerRequestInterface $request
177
     * @return ResponseInterface
178
     */
179
    public function unlockAction(ServerRequestInterface $request): ResponseInterface
180
    {
181
        $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

181
        $propertyManager = MfaProviderPropertyManager::create(/** @scrutinizer ignore-type */ $this->mfaProvider, $this->getBackendUser());
Loading history...
182
        if (!$this->mfaProvider->unlock($request, $propertyManager)) {
183
            $this->addFlashMessage(sprintf($this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_mfa.xlf:unlock.failure'), $this->getLocalizedProviderTitle()), '', FlashMessage::ERROR);
184
        } else {
185
            $this->addFlashMessage(sprintf($this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_mfa.xlf:unlock.success'), $this->getLocalizedProviderTitle()), '', FlashMessage::OK);
186
        }
187
        return new RedirectResponse($this->getActionUri('overview'));
188
    }
189
190
    /**
191
     * Render form to edit a provider by using provider specific content
192
     *
193
     * @param ServerRequestInterface $request
194
     * @return ResponseInterface
195
     */
196
    public function editAction(ServerRequestInterface $request): ResponseInterface
197
    {
198
        $this->addFormButtons();
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
        $providerResponse = $this->mfaProvider->handleRequest($request, $propertyManager, MfaViewType::EDIT);
201
        $this->view->assignMultiple([
202
            'provider' => $this->mfaProvider,
203
            'providerContent' => $providerResponse->getBody(),
204
            'isDefaultProvider' => $this->isDefaultProvider()
205
        ]);
206
        $this->moduleTemplate->setContent($this->view->render());
207
        return new HtmlResponse($this->moduleTemplate->renderContent());
208
    }
209
210
    /**
211
     * Handle save request, receiving from the edit view by
212
     * forwarding the request to the appropriate provider.
213
     *
214
     * @param ServerRequestInterface $request
215
     * @return ResponseInterface
216
     */
217
    public function saveAction(ServerRequestInterface $request): ResponseInterface
218
    {
219
        $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

219
        $propertyManager = MfaProviderPropertyManager::create(/** @scrutinizer ignore-type */ $this->mfaProvider, $this->getBackendUser());
Loading history...
220
        if (!$this->mfaProvider->update($request, $propertyManager)) {
221
            $this->addFlashMessage(sprintf($this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_mfa.xlf:save.failure'), $this->getLocalizedProviderTitle()), '', FlashMessage::ERROR);
222
        } else {
223
            if ((bool)($request->getParsedBody()['defaultProvider'] ?? false)) {
224
                $this->setDefaultProvider();
225
            } elseif ($this->isDefaultProvider()) {
226
                $this->removeDefaultProvider();
227
            }
228
            $this->addFlashMessage(sprintf($this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_mfa.xlf:save.success'), $this->getLocalizedProviderTitle()), '', FlashMessage::OK);
229
        }
230
        return new RedirectResponse($this->getActionUri('edit', ['identifier' => $this->mfaProvider->getIdentifier()]));
231
    }
232
233
    /**
234
     * Initialize the action by fetching the requested provider by its identifier
235
     *
236
     * @param ServerRequestInterface $request
237
     */
238
    protected function initializeAction(ServerRequestInterface $request): void
239
    {
240
        $identifier = (string)($request->getQueryParams()['identifier'] ?? $request->getParsedBody()['identifier'] ?? '');
241
        // Check if given identifier is valid
242
        if ($this->isValidIdentifier($identifier)) {
243
            $this->mfaProvider = $this->mfaProviderRegistry->getProvider($identifier);
244
        }
245
    }
246
247
    /**
248
     * Initialize the standalone view and set the template name
249
     *
250
     * @param string $templateName
251
     */
252
    protected function initializeView(string $templateName): void
253
    {
254
        $this->view = GeneralUtility::makeInstance(StandaloneView::class);
255
        $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

255
        $this->view->/** @scrutinizer ignore-call */ 
256
                     setTemplateRootPaths(['EXT:backend/Resources/Private/Templates/Mfa']);
Loading history...
256
        $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

256
        $this->view->/** @scrutinizer ignore-call */ 
257
                     setPartialRootPaths(['EXT:backend/Resources/Private/Partials']);
Loading history...
257
        $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

257
        $this->view->/** @scrutinizer ignore-call */ 
258
                     setLayoutRootPaths(['EXT:backend/Resources/Private/Layouts']);
Loading history...
258
        $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

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