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

FluidTYPO3 / vhs / 13566190336

27 Feb 2025 12:18PM UTC coverage: 72.127% (-0.6%) from 72.746%
13566190336

push

github

NamelessCoder
[TER] 7.1.0

5649 of 7832 relevant lines covered (72.13%)

20.01 hits per line

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

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

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

135
    public static function verdict(array $arguments, RenderingContextInterface $renderingContext): bool
136
    {
137
        /** @var static $proxy */
138
        $proxy = GeneralUtility::makeInstance(static::class);
7✔
139
        $proxy->setArguments((array) $arguments);
7✔
140
        return $proxy->evaluateArguments();
7✔
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;
52✔
152

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

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

159
        $evaluationType = $this->arguments['evaluationType'];
52✔
160
        $evaluations = [];
52✔
161
        if ($this->arguments['anyFrontendUser'] ?? false) {
52✔
162
            $evaluations['anyFrontendUser'] = intval($this->assertFrontendUserLoggedIn());
9✔
163
        }
164
        if ($this->arguments['anyFrontendUserGroup'] ?? false) {
52✔
165
            $evaluations['anyFrontendUserGroup'] = intval($this->assertFrontendUserGroupLoggedIn());
3✔
166
        }
167
        if ($frontendUser) {
52✔
168
            $evaluations['frontendUser'] = intval($this->assertFrontendUserLoggedIn($frontendUser));
3✔
169
        }
170
        if ($frontendUsers) {
52✔
171
            $evaluations['frontendUsers'] = intval($this->assertFrontendUsersLoggedIn($frontendUsers));
3✔
172
        }
173
        if (isset($this->arguments['frontendUserGroup'])) {
52✔
174
            $evaluations['frontendUserGroup'] =
3✔
175
                intval($this->assertFrontendUserGroupLoggedIn($this->arguments['frontendUserGroup']));
3✔
176
        }
177
        if (isset($this->arguments['frontendUserGroups'])) {
52✔
178
            $evaluations['frontendUserGroups'] =
3✔
179
                intval($this->assertFrontendUserGroupLoggedIn($this->arguments['frontendUserGroups']));
3✔
180
        }
181
        if ($this->arguments['anyBackendUser'] ?? false) {
52✔
182
            $evaluations['anyBackendUser'] = intval($this->assertBackendUserLoggedIn());
10✔
183
        }
184
        if ($this->arguments['anyBackendUserGroup'] ?? false) {
52✔
185
            $evaluations['anyBackendUserGroup'] = intval($this->assertBackendUserGroupLoggedIn());
3✔
186
        }
187
        if (isset($this->arguments['backendUser'])) {
52✔
188
            $evaluations['backendUser'] = intval($this->assertBackendUserLoggedIn($backendUser));
3✔
189
        }
190
        if (isset($this->arguments['backendUsers'])) {
52✔
191
            $evaluations['backendUsers'] = intval($this->assertBackendUserLoggedIn($backendUser));
3✔
192
        }
193
        if (isset($this->arguments['backendUserGroup'])) {
52✔
194
            $evaluations['backendUserGroup'] =
3✔
195
                intval($this->assertBackendUserGroupLoggedIn($this->arguments['backendUserGroup']));
3✔
196
        }
197
        if (isset($this->arguments['backendUserGroups'])) {
52✔
198
            $evaluations['backendUserGroups'] =
3✔
199
                intval($this->assertBackendUserGroupLoggedIn($this->arguments['backendUserGroups']));
3✔
200
        }
201
        if ($this->arguments['admin'] ?? false) {
52✔
202
            $evaluations['admin'] = intval($this->assertAdminLoggedIn());
9✔
203
        }
204
        $sum = array_sum($evaluations);
52✔
205
        return 'AND' === $evaluationType ? count($evaluations) === $sum : $sum > 0;
52✔
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
    {
216
        $currentFrontendUser = $this->getCurrentFrontendUser();
21✔
217
        if (!$currentFrontendUser instanceof FrontendUser) {
21✔
218
            return false;
6✔
219
        }
220
        if ($frontendUser instanceof FrontendUser) {
15✔
221
            if ($currentFrontendUser->getUid() === $frontendUser->getUid()) {
12✔
222
                return true;
6✔
223
            } else {
224
                return false;
9✔
225
            }
226
        }
227
        return is_object($currentFrontendUser);
3✔
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
    {
235
        if ($frontendUsers === null) {
6✔
236
            return false;
×
237
        }
238
        /** @var FrontendUser[] $frontendUsers */
239
        foreach ($frontendUsers as $frontendUser) {
6✔
240
            if ($this->assertFrontendUserLoggedIn($frontendUser)) {
6✔
241
                return true;
3✔
242
            }
243
        }
244
        return false;
3✔
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
    {
254
        $currentFrontendUser = $this->getCurrentFrontendUser();
24✔
255
        if (!$currentFrontendUser instanceof FrontendUser) {
24✔
256
            return false;
3✔
257
        }
258
        $currentFrontendUserGroups = $currentFrontendUser->getUsergroup();
21✔
259
        if (!$groups) {
21✔
260
            return (0 < $currentFrontendUserGroups->count());
6✔
261
        } elseif ($groups instanceof FrontendUserGroup) {
15✔
262
            return $currentFrontendUserGroups->contains($groups);
6✔
263
        } elseif ($groups instanceof ObjectStorage) {
9✔
264
            $currentFrontendUserGroupsClone = clone $currentFrontendUserGroups;
6✔
265
            $currentFrontendUserGroupsClone->removeAll($groups);
6✔
266
            return ($currentFrontendUserGroups->count() !== $currentFrontendUserGroupsClone->count());
6✔
267
        }
268
        return false;
3✔
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) {
122✔
280
            $backendUser = $backendUser->getUid();
×
281
        }
282
        $currentBackendUser = $this->getCurrentBackendUser();
122✔
283
        if (null !== $backendUser) {
122✔
284
            return ((integer) ($currentBackendUser['uid'] ?? 0) === $backendUser);
35✔
285
        }
286
        return is_array($currentBackendUser);
87✔
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()) {
70✔
299
            return false;
7✔
300
        }
301
        $currentBackendUser = $this->getCurrentBackendUser();
63✔
302
        $currentUserGroups = trim($currentBackendUser['usergroup'] ?? '', ',');
63✔
303
        /** @var array $userGroups */
304
        $userGroups = !empty($currentUserGroups) ? explode(',', $currentUserGroups) : [];
63✔
305
        if (0 === count($userGroups)) {
63✔
306
            return false;
7✔
307
        }
308
        if (is_string($groups)) {
56✔
309
            $groups = trim($groups, ',');
14✔
310
            /** @var array $groups */
311
            $groups = !empty($groups) ? explode(',', $groups) : [];
14✔
312
        }
313
        /** @var array $groups */
314
        if (count($groups) > 0) {
56✔
315
            return count(array_intersect($userGroups, (array) $groups)) > 0;
49✔
316
        }
317
        return false;
7✔
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
    {
326
        if (version_compare(VersionNumberUtility::getCurrentTypo3Version(), '11.5', '<')) {
3✔
327
            if (!$this->assertBackendUserLoggedIn()) {
3✔
328
                return false;
1✔
329
            }
330
            $currentBackendUser = $this->getCurrentBackendUser();
2✔
331
            return is_array($currentBackendUser) && (boolean) ($currentBackendUser['admin'] ?? false);
2✔
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)) {
10✔
348
            return null;
7✔
349
        }
350

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

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

364
        /** @var FrontendUser|null $frontendUser */
365
        $frontendUser = $this->frontendUserRepository->findByUid($frontendUserAuthentication->user['uid'] ?? 0);
3✔
366
        return $frontendUser;
3✔
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;
49✔
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()) {
7✔
392
            $GLOBALS['TSFE']->no_cache = 1;
7✔
393
        }
394
        return parent::renderThenChild();
7✔
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