• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

FluidTYPO3 / vhs / 28228377173

26 Jun 2026 09:04AM UTC coverage: 70.01% (-1.3%) from 71.316%
28228377173

Pull #1979

github

web-flow
Merge 7dd6a8665 into ea896bbf1
Pull Request #1979: Prep for TYPO3v14

0 of 2 new or added lines in 1 file covered. (0.0%)

92 existing lines in 6 files now uncovered.

4816 of 6879 relevant lines covered (70.01%)

8.18 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

63.59
/Classes/ViewHelpers/Security/AbstractSecurityViewHelper.php
1
<?php
2
namespace FluidTYPO3\Vhs\ViewHelpers\Security;
3

4
/*
5
 * This file is part of the FluidTYPO3/Vhs project under GPLv2 or later.
6
 *
7
 * For the full copyright and license information, please read the
8
 * LICENSE.md file that was distributed with this source code.
9
 */
10

11
use FluidTYPO3\Vhs\Utility\ContextUtility;
12
use Psr\Http\Message\ServerRequestInterface;
13
use TYPO3\CMS\Core\Context\Context;
14
use TYPO3\CMS\Core\Context\Exception\AspectNotFoundException;
15
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
16
use TYPO3\CMS\Core\Utility\GeneralUtility;
17
use TYPO3\CMS\Core\Utility\VersionNumberUtility;
18
use TYPO3\CMS\Extbase\Domain\Model\BackendUser;
19
use TYPO3\CMS\Extbase\Domain\Model\FrontendUser;
20
use TYPO3\CMS\Extbase\Domain\Model\FrontendUserGroup;
21
use TYPO3\CMS\Extbase\Domain\Repository\FrontendUserRepository;
22
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
23
use TYPO3\CMS\Frontend\Authentication\FrontendUserAuthentication;
24
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
25
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
26
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractConditionViewHelper;
27

28
/**
29
 * Base class: Security ViewHelpers
30
 */
31
abstract class AbstractSecurityViewHelper extends AbstractConditionViewHelper
32
{
33
    /**
34
     * @var FrontendUserRepository
35
     */
36
    protected $frontendUserRepository;
37

38
    public function __construct()
39
    {
UNCOV
40
        if (version_compare(VersionNumberUtility::getCurrentTypo3Version(), '12.0', '>=')
×
UNCOV
41
            && !ExtensionManagementUtility::isLoaded('feuserextrafields')
×
42
        ) {
43
            throw new \Exception('On TYPO3v12, v:security.* requires EXT:feuserextrafields', 1670521759);
×
44
        }
45
        /** @var FrontendUserRepository $frontendUserRepository */
UNCOV
46
        $frontendUserRepository = GeneralUtility::makeInstance(FrontendUserRepository::class);
×
UNCOV
47
        $this->frontendUserRepository = $frontendUserRepository;
×
UNCOV
48
        $query = $this->frontendUserRepository->createQuery();
×
UNCOV
49
        $querySettings = $query->getQuerySettings();
×
UNCOV
50
        $querySettings->setRespectStoragePage(false);
×
UNCOV
51
        $querySettings->setRespectSysLanguage(false);
×
UNCOV
52
        $this->frontendUserRepository->setDefaultQuerySettings($querySettings);
×
53
    }
54

55
    public function initializeArguments(): void
56
    {
57
        parent::initializeArguments();
12✔
58
        $this->registerArgument(
12✔
59
            'anyFrontendUser',
12✔
60
            'boolean',
12✔
61
            'If TRUE, allows any FrontendUser unless other arguments disallows each specific FrontendUser',
12✔
62
            false,
12✔
63
            false
12✔
64
        );
12✔
65
        $this->registerArgument(
12✔
66
            'anyFrontendUserGroup',
12✔
67
            'boolean',
12✔
68
            'If TRUE, allows any FrontendUserGroup unless other arguments disallows each specific FrontendUser',
12✔
69
            false,
12✔
70
            false
12✔
71
        );
12✔
72
        $this->registerArgument(
12✔
73
            'frontendUser',
12✔
74
            FrontendUser::class,
12✔
75
            'The FrontendUser to allow/deny'
12✔
76
        );
12✔
77
        $this->registerArgument(
12✔
78
            'frontendUsers',
12✔
79
            '<TYPO3\CMS\Extbase\Persistence\ObjectStorage>\TYPO3\CMS\Extbase\Domain\Model\FrontendUser',
12✔
80
            'The FrontendUsers ObjectStorage to allow/deny'
12✔
81
        );
12✔
82
        $this->registerArgument(
12✔
83
            'frontendUserGroup',
12✔
84
            FrontendUserGroup::class,
12✔
85
            'The FrontendUserGroup to allow/deny'
12✔
86
        );
12✔
87
        $this->registerArgument(
12✔
88
            'frontendUserGroups',
12✔
89
            '<TYPO3\CMS\Extbase\Persistence\ObjectStorage>\TYPO3\CMS\Extbase\Domain\Model\FrontendUserGroup',
12✔
90
            'The FrontendUserGroups ObjectStorage to allow/deny'
12✔
91
        );
12✔
92
        $this->registerArgument(
12✔
93
            'anyBackendUser',
12✔
94
            'boolean',
12✔
95
            'If TRUE, allows any backend user unless other arguments disallows each specific backend user',
12✔
96
            false,
12✔
97
            false
12✔
98
        );
12✔
99
        $this->registerArgument(
12✔
100
            'backendUser',
12✔
101
            'integer',
12✔
102
            'The uid of a backend user to allow/deny'
12✔
103
        );
12✔
104
        $this->registerArgument(
12✔
105
            'backendUsers',
12✔
106
            'mixed',
12✔
107
            'The backend users list to allow/deny. If string, CSV of uids assumed, if array, array of uids assumed'
12✔
108
        );
12✔
109
        $this->registerArgument(
12✔
110
            'backendUserGroup',
12✔
111
            'integer',
12✔
112
            'The uid of the backend user group to allow/deny'
12✔
113
        );
12✔
114
        $this->registerArgument(
12✔
115
            'backendUserGroups',
12✔
116
            'mixed',
12✔
117
            'The backend user groups list to allow/deny. If string, CSV of uids is assumed, if array, ' .
12✔
118
            'array of uids is assumed'
12✔
119
        );
12✔
120
        $this->registerArgument(
12✔
121
            'admin',
12✔
122
            'boolean',
12✔
123
            'If TRUE, a backend user which is also an admin is required'
12✔
124
        );
12✔
125
        $this->registerArgument(
12✔
126
            'evaluationType',
12✔
127
            'string',
12✔
128
            'Specify AND or OR (case sensitive) to determine how arguments must be processed. Default is AND, ' .
12✔
129
            'requiring all arguments to be satisfied if used',
12✔
130
            false,
12✔
131
            'AND'
12✔
132
        );
12✔
133
    }
134

135
    public static function verdict(array $arguments, RenderingContextInterface $renderingContext): bool
136
    {
137
        /** @var static $proxy */
138
        $proxy = GeneralUtility::makeInstance(static::class);
4✔
139
        $proxy->setArguments((array) $arguments);
4✔
140
        return $proxy->evaluateArguments();
4✔
141
    }
142

143

144
    /**
145
     * Returns TRUE if all conditions from arguments are satisfied. The
146
     * type of evaluation (AND or OR) can be set using argument "evaluationType".
147
     */
148
    public function evaluateArguments(): bool
149
    {
150
        /** @var FrontendUser|null $frontendUser */
151
        $frontendUser = $this->arguments['frontendUser'] ?? null;
4✔
152

153
        /** @var ObjectStorage|null $frontendUsers */
154
        $frontendUsers = $this->arguments['frontendUsers'] ?? null;
4✔
155

156
        /** @var BackendUser|null $backendUser */
157
        $backendUser = $this->arguments['backendUser'] ?? null;
4✔
158

159
        $evaluationType = $this->arguments['evaluationType'];
4✔
160
        $evaluations = [];
4✔
161
        if ($this->arguments['anyFrontendUser'] ?? false) {
4✔
UNCOV
162
            $evaluations['anyFrontendUser'] = intval($this->assertFrontendUserLoggedIn());
×
163
        }
164
        if ($this->arguments['anyFrontendUserGroup'] ?? false) {
4✔
UNCOV
165
            $evaluations['anyFrontendUserGroup'] = intval($this->assertFrontendUserGroupLoggedIn());
×
166
        }
167
        if ($frontendUser) {
4✔
UNCOV
168
            $evaluations['frontendUser'] = intval($this->assertFrontendUserLoggedIn($frontendUser));
×
169
        }
170
        if ($frontendUsers) {
4✔
UNCOV
171
            $evaluations['frontendUsers'] = intval($this->assertFrontendUsersLoggedIn($frontendUsers));
×
172
        }
173
        if (isset($this->arguments['frontendUserGroup'])) {
4✔
UNCOV
174
            $evaluations['frontendUserGroup'] =
×
UNCOV
175
                intval($this->assertFrontendUserGroupLoggedIn($this->arguments['frontendUserGroup']));
×
176
        }
177
        if (isset($this->arguments['frontendUserGroups'])) {
4✔
UNCOV
178
            $evaluations['frontendUserGroups'] =
×
UNCOV
179
                intval($this->assertFrontendUserGroupLoggedIn($this->arguments['frontendUserGroups']));
×
180
        }
181
        if ($this->arguments['anyBackendUser'] ?? false) {
4✔
182
            $evaluations['anyBackendUser'] = intval($this->assertBackendUserLoggedIn());
4✔
183
        }
184
        if ($this->arguments['anyBackendUserGroup'] ?? false) {
4✔
UNCOV
185
            $evaluations['anyBackendUserGroup'] = intval($this->assertBackendUserGroupLoggedIn());
×
186
        }
187
        if (isset($this->arguments['backendUser'])) {
4✔
UNCOV
188
            $evaluations['backendUser'] = intval($this->assertBackendUserLoggedIn($backendUser));
×
189
        }
190
        if (isset($this->arguments['backendUsers'])) {
4✔
UNCOV
191
            $evaluations['backendUsers'] = intval($this->assertBackendUserLoggedIn($backendUser));
×
192
        }
193
        if (isset($this->arguments['backendUserGroup'])) {
4✔
UNCOV
194
            $evaluations['backendUserGroup'] =
×
UNCOV
195
                intval($this->assertBackendUserGroupLoggedIn($this->arguments['backendUserGroup']));
×
196
        }
197
        if (isset($this->arguments['backendUserGroups'])) {
4✔
UNCOV
198
            $evaluations['backendUserGroups'] =
×
UNCOV
199
                intval($this->assertBackendUserGroupLoggedIn($this->arguments['backendUserGroups']));
×
200
        }
201
        if ($this->arguments['admin'] ?? false) {
4✔
UNCOV
202
            $evaluations['admin'] = intval($this->assertAdminLoggedIn());
×
203
        }
204
        $sum = array_sum($evaluations);
4✔
205
        return 'AND' === $evaluationType ? count($evaluations) === $sum : $sum > 0;
4✔
206
    }
207

208
    /**
209
     * Returns TRUE only if a FrontendUser is currently logged in. Use argument
210
     * to return TRUE only if the FrontendUser logged in must be that specific user.
211
     *
212
     * @param int|FrontendUser|null $frontendUser
213
     */
214
    public function assertFrontendUserLoggedIn($frontendUser = null): bool
215
    {
UNCOV
216
        $currentFrontendUser = $this->getCurrentFrontendUser();
×
UNCOV
217
        if (!$currentFrontendUser instanceof FrontendUser) {
×
UNCOV
218
            return false;
×
219
        }
UNCOV
220
        if ($frontendUser instanceof FrontendUser) {
×
UNCOV
221
            if ($currentFrontendUser->getUid() === $frontendUser->getUid()) {
×
UNCOV
222
                return true;
×
223
            } else {
UNCOV
224
                return false;
×
225
            }
226
        }
UNCOV
227
        return is_object($currentFrontendUser);
×
228
    }
229

230
    /**
231
     * Returns TRUE only if currently logged in frontend user is in list.
232
     */
233
    public function assertFrontendUsersLoggedIn(?ObjectStorage $frontendUsers = null): bool
234
    {
UNCOV
235
        if ($frontendUsers === null) {
×
236
            return false;
×
237
        }
238
        /** @var FrontendUser[] $frontendUsers */
UNCOV
239
        foreach ($frontendUsers as $frontendUser) {
×
UNCOV
240
            if ($this->assertFrontendUserLoggedIn($frontendUser)) {
×
UNCOV
241
                return true;
×
242
            }
243
        }
UNCOV
244
        return false;
×
245
    }
246

247
    /**
248
     * Returns TRUE if a FrontendUserGroup (specific given argument, else not) is logged in
249
     *
250
     * @param mixed $groups One \TYPO3\CMS\Extbase\Domain\Model\FrontendUserGroup or ObjectStorage containing same
251
     */
252
    public function assertFrontendUserGroupLoggedIn($groups = null): bool
253
    {
UNCOV
254
        $currentFrontendUser = $this->getCurrentFrontendUser();
×
UNCOV
255
        if (!$currentFrontendUser instanceof FrontendUser) {
×
UNCOV
256
            return false;
×
257
        }
UNCOV
258
        $currentFrontendUserGroups = $currentFrontendUser->getUsergroup();
×
UNCOV
259
        if (!$groups) {
×
UNCOV
260
            return (0 < $currentFrontendUserGroups->count());
×
UNCOV
261
        } elseif ($groups instanceof FrontendUserGroup) {
×
UNCOV
262
            return $currentFrontendUserGroups->contains($groups);
×
UNCOV
263
        } elseif ($groups instanceof ObjectStorage) {
×
UNCOV
264
            $currentFrontendUserGroupsClone = clone $currentFrontendUserGroups;
×
UNCOV
265
            $currentFrontendUserGroupsClone->removeAll($groups);
×
UNCOV
266
            return ($currentFrontendUserGroups->count() !== $currentFrontendUserGroupsClone->count());
×
267
        }
UNCOV
268
        return false;
×
269
    }
270

271
    /**
272
     * Returns TRUE only if a backend user is currently logged in. If used,
273
     * argument specifies that the logged in user must be that specific user
274
     *
275
     * @param int|BackendUser|null $backendUser
276
     */
277
    public function assertBackendUserLoggedIn($backendUser = null): bool
278
    {
279
        if ($backendUser instanceof BackendUser) {
68✔
280
            $backendUser = $backendUser->getUid();
×
281
        }
282
        $currentBackendUser = $this->getCurrentBackendUser();
68✔
283
        if (null !== $backendUser) {
68✔
284
            return ((int) ($currentBackendUser['uid'] ?? 0) === $backendUser);
20✔
285
        }
286
        return is_array($currentBackendUser);
48✔
287
    }
288

289
    /**
290
     * Returns TRUE only if a backend user is logged in and either has any group
291
     * (if param left out) or is a member of the group $groups or a group in
292
     * the array/CSV $groups
293
     *
294
     * @param mixed $groups Array of group uids or CSV of group uids or one group uid
295
     */
296
    public function assertBackendUserGroupLoggedIn($groups = null): bool
297
    {
298
        if (!$this->assertBackendUserLoggedIn()) {
40✔
299
            return false;
4✔
300
        }
301
        $currentBackendUser = $this->getCurrentBackendUser();
36✔
302
        $currentUserGroups = trim($currentBackendUser['usergroup'] ?? '', ',');
36✔
303
        /** @var array $userGroups */
304
        $userGroups = !empty($currentUserGroups) ? explode(',', $currentUserGroups) : [];
36✔
305
        if (0 === count($userGroups)) {
36✔
306
            return false;
4✔
307
        }
308
        if (is_string($groups)) {
32✔
309
            $groups = trim($groups, ',');
8✔
310
            /** @var array $groups */
311
            $groups = !empty($groups) ? explode(',', $groups) : [];
8✔
312
        }
313
        /** @var array $groups */
314
        if (count($groups) > 0) {
32✔
315
            return count(array_intersect($userGroups, (array) $groups)) > 0;
28✔
316
        }
317
        return false;
4✔
318
    }
319

320
    /**
321
     * Returns TRUE only if there is a current user logged in and this user
322
     * is an admin class backend user.
323
     */
324
    public function assertAdminLoggedIn(): bool
325
    {
UNCOV
326
        if (version_compare(VersionNumberUtility::getCurrentTypo3Version(), '11.5', '<')) {
×
UNCOV
327
            if (!$this->assertBackendUserLoggedIn()) {
×
UNCOV
328
                return false;
×
329
            }
UNCOV
330
            $currentBackendUser = $this->getCurrentBackendUser();
×
UNCOV
331
            return is_array($currentBackendUser) && (bool) ($currentBackendUser['admin'] ?? false);
×
332
        }
333
        /** @var Context $context */
334
        $context = GeneralUtility::makeInstance(Context::class);
×
335
        try {
336
            return (bool) $context->getPropertyFromAspect('backend.user', 'isAdmin');
×
337
        } catch (AspectNotFoundException $e) {
×
338
            return false;
×
339
        }
340
    }
341

342
    /**
343
     * Gets the currently logged in Frontend User.
344
     */
345
    public function getCurrentFrontendUser(): ?FrontendUser
346
    {
347
        if (empty($GLOBALS['TSFE']->loginUser)) {
4✔
348
            return null;
4✔
349
        }
350

UNCOV
351
        $frontendUserAuthentication = null;
×
UNCOV
352
        if ($GLOBALS['TYPO3_REQUEST'] instanceof ServerRequestInterface) {
×
353
            /** @var FrontendUserAuthentication|null $frontendUserAuthentication */
UNCOV
354
            $frontendUserAuthentication = $GLOBALS['TYPO3_REQUEST']->getAttribute('frontend.user');
×
355
        }
356

UNCOV
357
        if ($frontendUserAuthentication === null) {
×
358
            /** @var TypoScriptFrontendController $tsfe */
UNCOV
359
            $tsfe = $GLOBALS['TSFE'];
×
360
            /** @var FrontendUserAuthentication $frontendUserAuthentication */
UNCOV
361
            $frontendUserAuthentication = $tsfe->fe_user;
×
362
        }
363

364
        /** @var FrontendUser|null $frontendUser */
UNCOV
365
        $frontendUser = $this->frontendUserRepository->findByUid($frontendUserAuthentication->user['uid'] ?? 0);
×
UNCOV
366
        return $frontendUser;
×
367
    }
368

369
    /**
370
     * Returns a be_user record as lowerCamelCase indexed array if a BE user is
371
     * currently logged in.
372
     */
373
    public function getCurrentBackendUser(): ?array
374
    {
375
        return $GLOBALS['BE_USER']->user;
28✔
376
    }
377

378
    /**
379
     * Override: forcibly disables page caching - a TRUE condition
380
     * in this ViewHelper means page content would be depending on
381
     * the current visitor's session/cookie/auth etc.
382
     *
383
     * Returns value of "then" attribute.
384
     * If then attribute is not set, iterates through child nodes and renders ThenViewHelper.
385
     * If then attribute is not set and no ThenViewHelper and no ElseViewHelper is found, all child nodes are rendered
386
     *
387
     * @return mixed rendered ThenViewHelper or contents of <f:if> if no ThenViewHelper was found
388
     */
389
    protected function renderThenChild()
390
    {
391
        if ($this->isFrontendContext()) {
4✔
392
            $GLOBALS['TSFE']->no_cache = 1;
4✔
393
        }
394
        return parent::renderThenChild();
4✔
395
    }
396

397
    /**
398
     * @codeCoverageIgnore
399
     */
400
    protected function isFrontendContext(): bool
401
    {
402
        return ContextUtility::isFrontend();
403
    }
404
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc