‪TYPO3CMS  ‪main
MfaInfoElement.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 
24 use TYPO3\CMS\Core\Imaging\IconSize;
29 
37 {
38  private const ‪ALLOWED_TABLES = ['be_users', 'fe_users'];
39 
40  public function ‪__construct(
41  private readonly ‪IconFactory $iconFactory,
42  private readonly ‪MfaProviderRegistry $mfaProviderRegistry,
43  ) {}
44 
45  public function ‪render(): array
46  {
47  $resultArray = $this->‪initializeResultArray();
48 
49  $currentBackendUser = $this->‪getBackendUser();
50  $tableName = $this->data['tableName'];
51 
52  // This renderType only works for user tables: be_users, fe_users
53  if (!in_array($tableName, self::ALLOWED_TABLES, true)) {
54  return $resultArray;
55  }
56 
57  // Initialize a user based on the current table name
58  $targetUser = $tableName === 'be_users'
59  ? GeneralUtility::makeInstance(BackendUserAuthentication::class)
60  : GeneralUtility::makeInstance(FrontendUserAuthentication::class);
61 
62  $userId = (int)($this->data['databaseRow'][$targetUser->userid_column] ?? 0);
63  $targetUser->enablecolumns = ['deleted' => true];
64  $targetUser->setBeUserByUid($userId);
65 
66  $isDeactivationAllowed = true;
67  // Providers from system maintainers can only be deactivated by system maintainers.
68  // However, this check is only necessary if the target is a backend user.
69  if (($targetUser instanceof ‪BackendUserAuthentication)
70  && $targetUser->isSystemMaintainer(true)
71  && !$currentBackendUser->isSystemMaintainer()
72  ) {
73  $isDeactivationAllowed = false;
74  }
75 
76  // Fetch providers from the mfa field
77  $mfaProviders = json_decode($this->data['parameterArray']['itemFormElValue'] ?? '', true) ?? [];
78 
79  // Initialize variables
80  $html = $childHtml = $activeProviders = $lockedProviders = [];
81  $lang = $this->‪getLanguageService();
82  $enabledLabel = htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.mfa.enabled'));
83  $disabledLabel = htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.mfa.disabled'));
84  $status = '<span class="badge badge-danger badge-space-end t3js-mfa-status-label" data-alternative-label="' . $enabledLabel . '">' . $disabledLabel . '</span>';
85 
86  // Unset invalid providers
87  foreach ($mfaProviders as ‪$identifier => $providerSettings) {
88  if (!$this->mfaProviderRegistry->hasProvider(‪$identifier)) {
89  unset($mfaProviders[‪$identifier]);
90  }
91  }
92 
93  if ($mfaProviders !== []) {
94  // Check if remaining providers are active and/or locked for the user
95  foreach ($mfaProviders as ‪$identifier => $providerSettings) {
96  $provider = $this->mfaProviderRegistry->getProvider(‪$identifier);
97  $propertyManager = ‪MfaProviderPropertyManager::create($provider, $targetUser);
98  if (!$provider->isActive($propertyManager)) {
99  continue;
100  }
101  $activeProviders[‪$identifier] = $provider;
102  if ($provider->isLocked($propertyManager)) {
103  $lockedProviders[] = ‪$identifier;
104  }
105  }
106 
107  if ($activeProviders !== []) {
108  // Change status label to MFA being enabled
109  $status = '<span class="badge badge-success badge-space-end t3js-mfa-status-label"' . ' data-alternative-label="' . $disabledLabel . '">' . $enabledLabel . '</span>';
110 
111  // Add providers list
112  $childHtml[] = '<ul class="list-group t3js-mfa-active-providers-list">';
113  foreach ($activeProviders as ‪$identifier => $activeProvider) {
114  $childHtml[] = '<li class="list-group-item" id="provider-' . htmlspecialchars((string)‪$identifier) . '" style="line-height: 2.1em;">';
115  $childHtml[] = $this->iconFactory->getIcon($activeProvider->getIconIdentifier(), IconSize::SMALL);
116  $childHtml[] = htmlspecialchars($lang->sL($activeProvider->getTitle()));
117  if (in_array(‪$identifier, $lockedProviders, true)) {
118  $childHtml[] = '<span class="badge badge-danger">' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.locked')) . '</span>';
119  } else {
120  $childHtml[] = '<span class="badge badge-success">' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.active')) . '</span>';
121  }
122  if ($isDeactivationAllowed) {
123  $childHtml[] = '<button type="button"';
124  $childHtml[] = ' class="btn btn-default btn-sm float-end t3js-deactivate-provider-button"';
125  $childHtml[] = ' data-confirmation-title="' . htmlspecialchars(sprintf($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:buttons.deactivateMfaProvider'), $lang->sL($activeProvider->getTitle()))) . '"';
126  $childHtml[] = ' data-confirmation-content="' . htmlspecialchars(sprintf($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:buttons.deactivateMfaProvider.confirmation.text'), $lang->sL($activeProvider->getTitle()))) . '"';
127  $childHtml[] = ' data-confirmation-cancel-text="' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.cancel')) . '"';
128  $childHtml[] = ' data-confirmation-deactivate-text="' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.deactivate')) . '"';
129  $childHtml[] = ' data-provider="' . htmlspecialchars((string)‪$identifier) . '"';
130  $childHtml[] = ' title="' . htmlspecialchars(sprintf($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:buttons.deactivateMfaProvider'), $lang->sL($activeProvider->getTitle()))) . '"';
131  $childHtml[] = '>';
132  $childHtml[] = $this->iconFactory->getIcon('actions-delete', IconSize::SMALL)->render('inline');
133  $childHtml[] = '</button>';
134  }
135  $childHtml[] = '</li>';
136  }
137  $childHtml[] = '</ul>';
138  }
139  }
140 
141  $fieldId = 't3js-form-field-mfa-id' . ‪StringUtility::getUniqueId('-');
142 
143  $html[] = '<div class="formengine-field-item t3js-formengine-field-item" id="' . htmlspecialchars($fieldId) . '">';
144  $html[] = '<div class="form-control-wrap" style="max-width: ' . $this->‪formMaxWidth($this->defaultInputWidth) . 'px">';
145  $html[] = '<div class="form-wizards-wrap">';
146  $html[] = '<div class="form-wizards-element">';
147  $html[] = implode(PHP_EOL, $childHtml);
148  if ($isDeactivationAllowed) {
149  $html[] = '<div class="form-wizards-items-bottom">';
150  $html[] = '<button type="button"';
151  $html[] = ' class="t3js-deactivate-mfa-button btn btn-danger ' . ($activeProviders === [] ? 'disabled" disabled="disabled' : '') . '"';
152  $html[] = ' data-confirmation-title="' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:buttons.deactivateMfa')) . '"';
153  $html[] = ' data-confirmation-content="' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:buttons.deactivateMfa.confirmation.text')) . '"';
154  $html[] = ' data-confirmation-cancel-text="' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.cancel')) . '"';
155  $html[] = ' data-confirmation-deactivate-text="' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.deactivate')) . '"';
156  $html[] = '>';
157  $html[] = $this->iconFactory->getIcon('actions-toggle-off', IconSize::SMALL)->render('inline');
158  $html[] = htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:buttons.deactivateMfa'));
159  $html[] = '</button>';
160  $html[] = '</div>';
161  }
162  $html[] = '</div>';
163  $html[] = '</div>';
164  $html[] = '</div>';
165  $html[] = '</div>';
166 
167  // JavaScript is not needed in case deactivation is not allowed or no active providers exist
168  if ($isDeactivationAllowed && $activeProviders !== []) {
169  $resultArray['javaScriptModules'][] = ‪JavaScriptModuleInstruction::create(
170  '@typo3/backend/form-engine/element/mfa-info-element.js'
171  )->instance('#' . $fieldId, ['userId' => $userId, 'tableName' => $tableName]);
172  }
173 
174  $resultArray['html'] = $this->‪wrapWithFieldsetAndLegend($status . implode(PHP_EOL, $html));
175  return $resultArray;
176  }
177 }
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\getBackendUser
‪getBackendUser()
Definition: AbstractFormElement.php:461
‪TYPO3\CMS\Core\Page\JavaScriptModuleInstruction\create
‪static create(string $name, string $exportName=null)
Definition: JavaScriptModuleInstruction.php:47
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement
Definition: AbstractFormElement.php:37
‪TYPO3\CMS\Core\Imaging\IconFactory
Definition: IconFactory.php:34
‪TYPO3\CMS\Core\Page\JavaScriptModuleInstruction
Definition: JavaScriptModuleInstruction.php:23
‪TYPO3\CMS\Backend\Form\Element
Definition: AbstractFormElement.php:16
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\wrapWithFieldsetAndLegend
‪wrapWithFieldsetAndLegend(string $innerHTML)
Definition: AbstractFormElement.php:133
‪TYPO3\CMS\Core\Authentication\Mfa\MfaProviderPropertyManager\create
‪static create(MfaProviderManifestInterface $provider, AbstractUserAuthentication $user)
Definition: MfaProviderPropertyManager.php:193
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\getLanguageService
‪getLanguageService()
Definition: AbstractFormElement.php:456
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication
Definition: BackendUserAuthentication.php:62
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\formMaxWidth
‪int formMaxWidth($size=48)
Definition: AbstractFormElement.php:332
‪TYPO3\CMS\Core\Authentication\Mfa\MfaProviderPropertyManager
Definition: MfaProviderPropertyManager.php:33
‪TYPO3\CMS\Backend\Form\Element\MfaInfoElement\ALLOWED_TABLES
‪const ALLOWED_TABLES
Definition: MfaInfoElement.php:38
‪TYPO3\CMS\Frontend\Authentication\FrontendUserAuthentication
Definition: FrontendUserAuthentication.php:33
‪TYPO3\CMS\Backend\Form\Element\MfaInfoElement\render
‪render()
Definition: MfaInfoElement.php:45
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Core\Utility\StringUtility
Definition: StringUtility.php:24
‪TYPO3\CMS\Backend\Form\Element\MfaInfoElement\__construct
‪__construct(private readonly IconFactory $iconFactory, private readonly MfaProviderRegistry $mfaProviderRegistry,)
Definition: MfaInfoElement.php:40
‪TYPO3\CMS\Backend\Form\Element\MfaInfoElement
Definition: MfaInfoElement.php:37
‪TYPO3\CMS\Webhooks\Message\$identifier
‪identifier readonly string $identifier
Definition: FileAddedMessage.php:37
‪TYPO3\CMS\Core\Utility\StringUtility\getUniqueId
‪static getUniqueId(string $prefix='')
Definition: StringUtility.php:57
‪TYPO3\CMS\Backend\Form\AbstractNode\initializeResultArray
‪initializeResultArray()
Definition: AbstractNode.php:77
‪TYPO3\CMS\Core\Authentication\Mfa\MfaProviderRegistry
Definition: MfaProviderRegistry.php:28