Completed
Push — master ( 01e78e...ee7667 )
by
unknown
35:38 queued 22:54
created

FrontendUserAuthentication   F

Complexity

Total Complexity 89

Size/Duplication

Total Lines 671
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 237
dl 0
loc 671
rs 2
c 1
b 0
f 0
wmc 89

21 Methods

Rating   Name   Duplication   Size   Complexity  
A setKey() 0 19 6
A getNewSessionRecord() 0 5 2
A updateOnlineTimestamp() 0 13 4
A createUserSession() 0 7 1
A regenerateSessionId() 0 12 3
F fetchGroupData() 0 74 16
B createUserAspect() 0 35 7
A hideActiveLogin() 0 4 1
A setSessionData() 0 8 2
A removeSessionData() 0 14 6
A getCookieName() 0 7 2
A gc() 0 3 1
A getLoginFormData() 0 21 6
A __construct() 0 15 4
A isSetSessionCookie() 0 4 5
A performLogoff() 0 21 4
A setAndSaveSessionData() 0 4 1
A isRefreshTimeBasedCookie() 0 3 3
A getUserTSconf() 0 12 2
B storeSessionData() 0 30 9
A getKey() 0 15 4

How to fix   Complexity   

Complex Class

Complex classes like FrontendUserAuthentication often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use FrontendUserAuthentication, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/*
4
 * This file is part of the TYPO3 CMS project.
5
 *
6
 * It is free software; you can redistribute it and/or modify it under
7
 * the terms of the GNU General Public License, either version 2
8
 * of the License, or any later version.
9
 *
10
 * For the full copyright and license information, please read the
11
 * LICENSE.txt file that was distributed with this source code.
12
 *
13
 * The TYPO3 project - inspiring people to share!
14
 */
15
16
namespace TYPO3\CMS\Frontend\Authentication;
17
18
use TYPO3\CMS\Core\Authentication\AbstractUserAuthentication;
19
use TYPO3\CMS\Core\Authentication\AuthenticationService;
20
use TYPO3\CMS\Core\Configuration\Features;
21
use TYPO3\CMS\Core\Context\UserAspect;
22
use TYPO3\CMS\Core\Database\ConnectionPool;
23
use TYPO3\CMS\Core\Session\Backend\Exception\SessionNotFoundException;
24
use TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser;
25
use TYPO3\CMS\Core\Utility\GeneralUtility;
26
27
/**
28
 * Extension class for Front End User Authentication.
29
 */
30
class FrontendUserAuthentication extends AbstractUserAuthentication
31
{
32
    /**
33
     * Login type, used for services.
34
     * @var string
35
     */
36
    public $loginType = 'FE';
37
38
    /**
39
     * Form field with login-name
40
     * @var string
41
     */
42
    public $formfield_uname = 'user';
43
44
    /**
45
     * Form field with password
46
     * @var string
47
     */
48
    public $formfield_uident = 'pass';
49
50
    /**
51
     * Form field with status: *'login', 'logout'. If empty login is not verified.
52
     * @var string
53
     */
54
    public $formfield_status = 'logintype';
55
56
    /**
57
     * form field with 0 or 1
58
     * 1 = permanent login enabled
59
     * 0 = session is valid for a browser session only
60
     * @var string
61
     */
62
    public $formfield_permanent = 'permalogin';
63
64
    /**
65
     * Lifetime of anonymous session data in seconds.
66
     * @var int
67
     */
68
    protected $sessionDataLifetime = 86400;
69
70
    /**
71
     * Session timeout (on the server)
72
     *
73
     * If >0: session-timeout in seconds.
74
     * If <=0: Instant logout after login.
75
     *
76
     * @var int
77
     */
78
    public $sessionTimeout = 6000;
79
80
    /**
81
     * Table in database with user data
82
     * @var string
83
     */
84
    public $user_table = 'fe_users';
85
86
    /**
87
     * Column for login-name
88
     * @var string
89
     */
90
    public $username_column = 'username';
91
92
    /**
93
     * Column for password
94
     * @var string
95
     */
96
    public $userident_column = 'password';
97
98
    /**
99
     * Column for user-id
100
     * @var string
101
     */
102
    public $userid_column = 'uid';
103
104
    /**
105
     * Column name for last login timestamp
106
     * @var string
107
     */
108
    public $lastLogin_column = 'lastlogin';
109
110
    /**
111
     * @var string
112
     */
113
    public $usergroup_column = 'usergroup';
114
115
    /**
116
     * @var string
117
     */
118
    public $usergroup_table = 'fe_groups';
119
120
    /**
121
     * Enable field columns of user table
122
     * @var array
123
     */
124
    public $enablecolumns = [
125
        'deleted' => 'deleted',
126
        'disabled' => 'disable',
127
        'starttime' => 'starttime',
128
        'endtime' => 'endtime'
129
    ];
130
131
    /**
132
     * @var array
133
     */
134
    public $groupData = [
135
        'title' => [],
136
        'uid' => [],
137
        'pid' => []
138
    ];
139
140
    /**
141
     * Used to accumulate the TSconfig data of the user
142
     * @var array
143
     */
144
    public $TSdataArray = [];
145
146
    /**
147
     * @var array
148
     */
149
    public $userTS = [];
150
151
    /**
152
     * @var bool
153
     */
154
    public $userTSUpdated = false;
155
156
    /**
157
     * @var bool
158
     */
159
    public $sesData_change = false;
160
161
    /**
162
     * @var bool
163
     */
164
    public $userData_change = false;
165
166
    /**
167
     * @var bool
168
     */
169
    public $is_permanent = false;
170
171
    /**
172
     * @var bool
173
     */
174
    protected $loginHidden = false;
175
176
    /**
177
     * Will prevent the setting of the session cookie (takes precedence over forceSetCookie)
178
     * Disable cookie by default, will be activated if saveSessionData() is called,
179
     * a user is logging-in or an existing session is found
180
     * @var bool
181
     */
182
    public $dontSetCookie = true;
183
184
    /**
185
     * Send no-cache headers (disabled by default, if no fixed session is there)
186
     * @var bool
187
     */
188
    public $sendNoCacheHeaders = false;
189
190
    public function __construct()
191
    {
192
        $this->name = self::getCookieName();
193
        $this->checkPid = $GLOBALS['TYPO3_CONF_VARS']['FE']['checkFeUserPid'];
194
        $this->lifetime = (int)$GLOBALS['TYPO3_CONF_VARS']['FE']['lifetime'];
195
        $this->sessionTimeout = (int)$GLOBALS['TYPO3_CONF_VARS']['FE']['sessionTimeout'];
196
        if ($this->sessionTimeout > 0 && $this->sessionTimeout < $this->lifetime) {
197
            // If server session timeout is non-zero but less than client session timeout: Copy this value instead.
198
            $this->sessionTimeout = $this->lifetime;
199
        }
200
        $this->sessionDataLifetime = (int)$GLOBALS['TYPO3_CONF_VARS']['FE']['sessionDataLifetime'];
201
        if ($this->sessionDataLifetime <= 0) {
202
            $this->sessionDataLifetime = 86400;
203
        }
204
        parent::__construct();
205
    }
206
207
    /**
208
     * Returns the configured cookie name
209
     *
210
     * @return string
211
     */
212
    public static function getCookieName()
213
    {
214
        $configuredCookieName = trim($GLOBALS['TYPO3_CONF_VARS']['FE']['cookieName']);
215
        if (empty($configuredCookieName)) {
216
            $configuredCookieName = 'fe_typo_user';
217
        }
218
        return $configuredCookieName;
219
    }
220
221
    /**
222
     * Returns a new session record for the current user for insertion into the DB.
223
     *
224
     * @param array $tempuser
225
     * @return array User session record
226
     */
227
    public function getNewSessionRecord($tempuser)
228
    {
229
        $insertFields = parent::getNewSessionRecord($tempuser);
230
        $insertFields['ses_permanent'] = $this->is_permanent ? 1 : 0;
231
        return $insertFields;
232
    }
233
234
    /**
235
     * Determine whether a session cookie needs to be set (lifetime=0)
236
     *
237
     * @return bool
238
     * @internal
239
     */
240
    public function isSetSessionCookie()
241
    {
242
        return ($this->newSessionID || $this->forceSetCookie)
243
            && ((int)$this->lifetime === 0 || !isset($this->user['ses_permanent']) || !$this->user['ses_permanent']);
244
    }
245
246
    /**
247
     * Determine whether a non-session cookie needs to be set (lifetime>0)
248
     *
249
     * @return bool
250
     * @internal
251
     */
252
    public function isRefreshTimeBasedCookie()
253
    {
254
        return $this->lifetime > 0 && isset($this->user['ses_permanent']) && $this->user['ses_permanent'];
255
    }
256
257
    /**
258
     * Returns an info array with Login/Logout data submitted by a form or params
259
     *
260
     * @return array
261
     * @see AbstractUserAuthentication::getLoginFormData()
262
     */
263
    public function getLoginFormData()
264
    {
265
        $loginData = parent::getLoginFormData();
266
        if ($GLOBALS['TYPO3_CONF_VARS']['FE']['permalogin'] == 0 || $GLOBALS['TYPO3_CONF_VARS']['FE']['permalogin'] == 1) {
267
            $isPermanent = GeneralUtility::_POST($this->formfield_permanent);
268
            if (strlen($isPermanent) != 1) {
269
                $isPermanent = $GLOBALS['TYPO3_CONF_VARS']['FE']['permalogin'];
270
            } elseif (!$isPermanent) {
271
                // To make sure the user gets a session cookie and doesn't keep a possibly existing time based cookie,
272
                // we need to force setting the session cookie here
273
                $this->forceSetCookie = true;
274
            }
275
            $isPermanent = (bool)$isPermanent;
276
        } elseif ($GLOBALS['TYPO3_CONF_VARS']['FE']['permalogin'] == 2) {
277
            $isPermanent = true;
278
        } else {
279
            $isPermanent = false;
280
        }
281
        $loginData['permanent'] = $isPermanent;
282
        $this->is_permanent = $isPermanent;
283
        return $loginData;
284
    }
285
286
    /**
287
     * Creates a user session record and returns its values.
288
     * However, as the FE user cookie is normally not set, this has to be done
289
     * before the parent class is doing the rest.
290
     *
291
     * @param array $tempuser User data array
292
     * @return array The session data for the newly created session.
293
     */
294
    public function createUserSession($tempuser)
295
    {
296
        // At this point we do not know if we need to set a session or a permanent cookie
297
        // So we force the cookie to be set after authentication took place, which will
298
        // then call setSessionCookie(), which will set a cookie with correct settings.
299
        $this->dontSetCookie = false;
300
        return parent::createUserSession($tempuser);
301
    }
302
303
    /**
304
     * Will select all fe_groups records that the current fe_user is member of
305
     * and which groups are also allowed in the current domain.
306
     * It also accumulates the TSconfig for the fe_user/fe_groups in ->TSdataArray
307
     *
308
     * @return int Returns the number of usergroups for the frontend users (if the internal user record exists and the usergroup field contains a value)
309
     */
310
    public function fetchGroupData()
311
    {
312
        $this->TSdataArray = [];
313
        $this->userTS = [];
314
        $this->userTSUpdated = false;
315
        $this->groupData = [
316
            'title' => [],
317
            'uid' => [],
318
            'pid' => []
319
        ];
320
        // Setting default configuration:
321
        $this->TSdataArray[] = $GLOBALS['TYPO3_CONF_VARS']['FE']['defaultUserTSconfig'];
322
        // Get the info data for auth services
323
        $authInfo = $this->getAuthInfoArray();
324
        if (is_array($this->user)) {
325
            $this->logger->debug('Get usergroups for user', [
326
                $this->userid_column => $this->user[$this->userid_column],
327
                $this->username_column => $this->user[$this->username_column]
328
            ]);
329
        } else {
330
            $this->logger->debug('Get usergroups for "anonymous" user');
331
        }
332
        $groupDataArr = [];
333
        // Use 'auth' service to find the groups for the user
334
        $subType = 'getGroups' . $this->loginType;
335
        /** @var AuthenticationService $serviceObj */
336
        foreach ($this->getAuthServices($subType, [], $authInfo) as $serviceObj) {
337
            $groupData = $serviceObj->getGroups($this->user, $groupDataArr);
338
            if (is_array($groupData) && !empty($groupData)) {
339
                // Keys in $groupData should be unique ids of the groups (like "uid") so this function will override groups.
340
                $groupDataArr = $groupData + $groupDataArr;
341
            }
342
        }
343
        if (empty($groupDataArr)) {
344
            $this->logger->debug('No usergroups found by services');
345
        }
346
        if (!empty($groupDataArr)) {
347
            $this->logger->debug(count($groupDataArr) . ' usergroup records found by services');
348
        }
349
        // Use 'auth' service to check the usergroups if they are really valid
350
        foreach ($groupDataArr as $groupData) {
351
            // By default a group is valid
352
            $validGroup = true;
353
            $subType = 'authGroups' . $this->loginType;
354
            foreach ($this->getAuthServices($subType, [], $authInfo) as $serviceObj) {
355
                // we assume that the service defines the authGroup function
356
                if (!$serviceObj->authGroup($this->user, $groupData)) {
357
                    $validGroup = false;
358
                    $this->logger->debug($subType . ' auth service did not auth group', [
359
                        'uid ' => $groupData['uid'],
360
                        'title' => $groupData['title'],
361
                    ]);
362
                    break;
363
                }
364
            }
365
            if ($validGroup && (string)$groupData['uid'] !== '') {
366
                $this->groupData['title'][$groupData['uid']] = $groupData['title'];
367
                $this->groupData['uid'][$groupData['uid']] = $groupData['uid'];
368
                $this->groupData['pid'][$groupData['uid']] = $groupData['pid'];
369
                $this->groupData['TSconfig'][$groupData['uid']] = $groupData['TSconfig'];
370
            }
371
        }
372
        if (!empty($this->groupData) && !empty($this->groupData['TSconfig'])) {
373
            // TSconfig: collect it in the order it was collected
374
            foreach ($this->groupData['TSconfig'] as $TSdata) {
375
                $this->TSdataArray[] = $TSdata;
376
            }
377
            $this->TSdataArray[] = $this->user['TSconfig'];
378
            // Sort information
379
            ksort($this->groupData['title']);
380
            ksort($this->groupData['uid']);
381
            ksort($this->groupData['pid']);
382
        }
383
        return !empty($this->groupData['uid']) ? count($this->groupData['uid']) : 0;
384
    }
385
386
    /**
387
     * Initializes the front-end user groups for the context API,
388
     * based on the user groups and the logged-in state.
389
     *
390
     * @param bool $respectUserGroups used with the $TSFE->loginAllowedInBranch flag to disable the inclusion of the users' groups
391
     * @return UserAspect
392
     */
393
    public function createUserAspect(bool $respectUserGroups = true): UserAspect
394
    {
395
        $userGroups = [0];
396
        $isUserAndGroupSet = is_array($this->user) && !empty($this->groupData['uid']);
397
        if ($isUserAndGroupSet) {
398
            // group -2 is not an existing group, but denotes a 'default' group when a user IS logged in.
399
            // This is used to let elements be shown for all logged in users!
400
            $userGroups[] = -2;
401
            $groupsFromUserRecord = $this->groupData['uid'];
402
        } else {
403
            // group -1 is not an existing group, but denotes a 'default' group when not logged in.
404
            // This is used to let elements be hidden, when a user is logged in!
405
            $userGroups[] = -1;
406
            if ($respectUserGroups) {
407
                // For cases where logins are not banned from a branch usergroups can be set based on IP masks so we should add the usergroups uids.
408
                $groupsFromUserRecord = $this->groupData['uid'];
409
            } else {
410
                // Set to blank since we will NOT risk any groups being set when no logins are allowed!
411
                $groupsFromUserRecord = [];
412
            }
413
        }
414
        // Make unique and sort the groups
415
        $groupsFromUserRecord = array_unique($groupsFromUserRecord);
416
        if ($respectUserGroups && !empty($groupsFromUserRecord)) {
417
            sort($groupsFromUserRecord);
418
            $userGroups = array_merge($userGroups, array_map('intval', $groupsFromUserRecord));
419
        }
420
421
        // For every 60 seconds the is_online timestamp for a logged-in user is updated
422
        if ($isUserAndGroupSet) {
423
            $this->updateOnlineTimestamp();
424
        }
425
426
        $this->logger->debug('Valid frontend usergroups: ' . implode(',', $userGroups));
427
        return GeneralUtility::makeInstance(UserAspect::class, $this, $userGroups);
428
    }
429
    /**
430
     * Returns the parsed TSconfig for the fe_user
431
     * The TSconfig will be cached in $this->userTS.
432
     *
433
     * @return array TSconfig array for the fe_user
434
     */
435
    public function getUserTSconf()
436
    {
437
        if (!$this->userTSUpdated) {
438
            // Parsing the user TS (or getting from cache)
439
            $this->TSdataArray = TypoScriptParser::checkIncludeLines_array($this->TSdataArray);
440
            $userTS = implode(LF . '[GLOBAL]' . LF, $this->TSdataArray);
441
            $parseObj = GeneralUtility::makeInstance(TypoScriptParser::class);
442
            $parseObj->parse($userTS);
443
            $this->userTS = $parseObj->setup;
444
            $this->userTSUpdated = true;
445
        }
446
        return $this->userTS;
447
    }
448
449
    /*****************************************
450
     *
451
     * Session data management functions
452
     *
453
     ****************************************/
454
    /**
455
     * Will write UC and session data.
456
     * If the flag $this->userData_change has been set, the function ->writeUC is called (which will save persistent user session data)
457
     * If the flag $this->sesData_change has been set, the current session record is updated with the content of $this->sessionData
458
     *
459
     * @see getKey()
460
     * @see setKey()
461
     */
462
    public function storeSessionData()
463
    {
464
        // Saves UC and SesData if changed.
465
        if ($this->userData_change) {
466
            $this->writeUC();
467
        }
468
469
        if ($this->sesData_change && $this->id) {
470
            if (empty($this->sessionData)) {
471
                // Remove session-data
472
                $this->removeSessionData();
473
                // Remove cookie if not logged in as the session data is removed as well
474
                if (empty($this->user['uid']) && !$this->loginHidden && $this->isCookieSet()) {
475
                    $this->removeCookie($this->name);
476
                }
477
            } elseif (!$this->isExistingSessionRecord($this->id)) {
478
                $sessionRecord = $this->getNewSessionRecord([]);
479
                $sessionRecord['ses_anonymous'] = 1;
480
                $sessionRecord['ses_data'] = serialize($this->sessionData);
481
                $updatedSession = $this->getSessionBackend()->set($this->id, $sessionRecord);
482
                $this->user = array_merge($this->user ?? [], $updatedSession);
483
                // Now set the cookie (= fix the session)
484
                $this->setSessionCookie();
485
            } else {
486
                // Update session data
487
                $insertFields = [
488
                    'ses_data' => serialize($this->sessionData)
489
                ];
490
                $updatedSession = $this->getSessionBackend()->update($this->id, $insertFields);
491
                $this->user = array_merge($this->user ?? [], $updatedSession);
492
            }
493
        }
494
    }
495
496
    /**
497
     * Removes data of the current session.
498
     */
499
    public function removeSessionData()
500
    {
501
        if (!empty($this->sessionData)) {
502
            $this->sesData_change = true;
503
        }
504
        $this->sessionData = [];
505
506
        if ($this->isExistingSessionRecord($this->id)) {
507
            // Remove session record if $this->user is empty is if session is anonymous
508
            if ((empty($this->user) && !$this->loginHidden) || $this->user['ses_anonymous']) {
509
                $this->getSessionBackend()->remove($this->id);
510
            } else {
511
                $this->getSessionBackend()->update($this->id, [
512
                    'ses_data' => ''
513
                ]);
514
            }
515
        }
516
    }
517
518
    /**
519
     * Removes the current session record, sets the internal ->user array to null,
520
     * Thereby the current user (if any) is effectively logged out!
521
     * Additionally the cookie is removed, but only if there is no session data.
522
     * If session data exists, only the user information is removed and the session
523
     * gets converted into an anonymous session if the feature toggle
524
     * "security.frontend.keepSessionDataOnLogout" is set to true (default: false).
525
     */
526
    protected function performLogoff()
527
    {
528
        $oldSession = [];
0 ignored issues
show
Unused Code introduced by
The assignment to $oldSession is dead and can be removed.
Loading history...
529
        $sessionData = [];
530
        try {
531
            // Session might not be loaded at this point, so fetch it
532
            $oldSession = $this->getSessionBackend()->get($this->id);
533
            $sessionData = unserialize($oldSession['ses_data']);
534
        } catch (SessionNotFoundException $e) {
535
            // Leave uncaught, will unset cookie later in this method
536
        }
537
538
        $keepSessionDataOnLogout = GeneralUtility::makeInstance(Features::class)
539
            ->isFeatureEnabled('security.frontend.keepSessionDataOnLogout');
540
541
        if ($keepSessionDataOnLogout && !empty($sessionData)) {
542
            // Regenerate session as anonymous
543
            $this->regenerateSessionId($oldSession, true);
544
            $this->user = null;
545
        } else {
546
            parent::performLogoff();
547
        }
548
    }
549
550
    /**
551
     * Regenerate the session ID and transfer the session to new ID
552
     * Call this method whenever a user proceeds to a higher authorization level
553
     * e.g. when an anonymous session is now authenticated.
554
     * Forces cookie to be set
555
     *
556
     * @param array $existingSessionRecord If given, this session record will be used instead of fetching again'
557
     * @param bool $anonymous If true session will be regenerated as anonymous session
558
     */
559
    protected function regenerateSessionId(array $existingSessionRecord = [], bool $anonymous = false)
560
    {
561
        if (empty($existingSessionRecord)) {
562
            $existingSessionRecord = $this->getSessionBackend()->get($this->id);
563
        }
564
        $existingSessionRecord['ses_anonymous'] = (int)$anonymous;
565
        if ($anonymous) {
566
            $existingSessionRecord['ses_userid'] = 0;
567
        }
568
        parent::regenerateSessionId($existingSessionRecord, $anonymous);
569
        // We force the cookie to be set later in the authentication process
570
        $this->dontSetCookie = false;
571
    }
572
573
    /**
574
     * Returns session data for the fe_user; Either persistent data following the fe_users uid/profile (requires login)
575
     * or current-session based (not available when browse is closed, but does not require login)
576
     *
577
     * @param string $type Session data type; Either "user" (persistent, bound to fe_users profile) or "ses" (temporary, bound to current session cookie)
578
     * @param string $key Key from the data array to return; The session data (in either case) is an array ($this->uc / $this->sessionData) and this value determines which key to return the value for.
579
     * @return mixed Returns whatever value there was in the array for the key, $key
580
     * @see setKey()
581
     */
582
    public function getKey($type, $key)
583
    {
584
        if (!$key) {
585
            return null;
586
        }
587
        $value = null;
588
        switch ($type) {
589
            case 'user':
590
                $value = $this->uc[$key];
591
                break;
592
            case 'ses':
593
                $value = $this->getSessionData($key);
594
                break;
595
        }
596
        return $value;
597
    }
598
599
    /**
600
     * Saves session data, either persistent or bound to current session cookie. Please see getKey() for more details.
601
     * When a value is set the flags $this->userData_change or $this->sesData_change will be set so that the final call to ->storeSessionData() will know if a change has occurred and needs to be saved to the database.
602
     * Notice: Simply calling this function will not save the data to the database! The actual saving is done in storeSessionData() which is called as some of the last things in \TYPO3\CMS\Frontend\Http\RequestHandler. So if you exit before this point, nothing gets saved of course! And the solution is to call $GLOBALS['TSFE']->storeSessionData(); before you exit.
603
     *
604
     * @param string $type Session data type; Either "user" (persistent, bound to fe_users profile) or "ses" (temporary, bound to current session cookie)
605
     * @param string $key Key from the data array to store incoming data in; The session data (in either case) is an array ($this->uc / $this->sessionData) and this value determines in which key the $data value will be stored.
606
     * @param mixed $data The data value to store in $key
607
     * @see setKey()
608
     * @see storeSessionData()
609
     */
610
    public function setKey($type, $key, $data)
611
    {
612
        if (!$key) {
613
            return;
614
        }
615
        switch ($type) {
616
            case 'user':
617
                if ($this->user['uid']) {
618
                    if ($data === null) {
619
                        unset($this->uc[$key]);
620
                    } else {
621
                        $this->uc[$key] = $data;
622
                    }
623
                    $this->userData_change = true;
624
                }
625
                break;
626
            case 'ses':
627
                $this->setSessionData($key, $data);
628
                break;
629
        }
630
    }
631
632
    /**
633
     * Set session data by key.
634
     * The data will last only for this login session since it is stored in the user session.
635
     *
636
     * @param string $key A non empty string to store the data under
637
     * @param mixed $data Data store store in session
638
     */
639
    public function setSessionData($key, $data)
640
    {
641
        $this->sesData_change = true;
642
        if ($data === null) {
643
            unset($this->sessionData[$key]);
644
            return;
645
        }
646
        parent::setSessionData($key, $data);
647
    }
648
649
    /**
650
     * Saves the tokens so that they can be used by a later incarnation of this class.
651
     *
652
     * @param string $key
653
     * @param mixed $data
654
     */
655
    public function setAndSaveSessionData($key, $data)
656
    {
657
        $this->setSessionData($key, $data);
658
        $this->storeSessionData();
659
    }
660
661
    /**
662
     * Garbage collector, removing old expired sessions.
663
     *
664
     * @internal
665
     */
666
    public function gc()
667
    {
668
        $this->getSessionBackend()->collectGarbage($this->gc_time, $this->sessionDataLifetime);
669
    }
670
671
    /**
672
     * Hide the current login
673
     *
674
     * This is used by the fe_login_mode feature for pages.
675
     * A current login is unset, but we remember that there has been one.
676
     */
677
    public function hideActiveLogin()
678
    {
679
        $this->user = null;
680
        $this->loginHidden = true;
681
    }
682
683
    /**
684
     * Update the field "is_online" every 60 seconds of a logged-in user
685
     *
686
     * @internal
687
     */
688
    public function updateOnlineTimestamp()
689
    {
690
        if (!is_array($this->user) || !$this->user['uid']
691
            || $this->user['is_online'] >= $GLOBALS['EXEC_TIME'] - 60) {
692
            return;
693
        }
694
        $dbConnection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($this->user_table);
695
        $dbConnection->update(
696
            $this->user_table,
697
            ['is_online' => $GLOBALS['EXEC_TIME']],
698
            ['uid' => (int)$this->user['uid']]
699
        );
700
        $this->user['is_online'] = $GLOBALS['EXEC_TIME'];
701
    }
702
}
703