[TASK] Trivial: bad phpDoc format in tslib_feUserAuth
[Packages/TYPO3.CMS.git] / typo3 / sysext / cms / tslib / class.tslib_feuserauth.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 1999-2011 Kasper Skårhøj (kasperYYYY@typo3.com)
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
18 *
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27 /**
28 * Front End session user. Login and session data
29 * Included from index_ts.php
30 *
31 * Revised for TYPO3 3.6 June/2003 by Kasper Skårhøj
32 *
33 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
34 * @author René Fritz <r.fritz@colorcube.de>
35 */
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50 /**
51 * Extension class for Front End User Authentication.
52 *
53 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
54 * @author René Fritz <r.fritz@colorcube.de>
55 * @package TYPO3
56 * @subpackage tslib
57 */
58 class tslib_feUserAuth extends t3lib_userAuth {
59 var $formfield_permanent = 'permalogin'; // formfield with 0 or 1 // 1 = permanent login enabled // 0 = session is valid for a browser session only
60
61 protected $sessionDataLifetime = 86400; // Lifetime of session data in seconds.
62
63 var $usergroup_column = 'usergroup';
64 var $usergroup_table = 'fe_groups';
65 var $groupData = Array(
66 'title' =>Array(),
67 'uid' =>Array(),
68 'pid' =>Array()
69 );
70 var $TSdataArray=array(); // Used to accumulate the TSconfig data of the user
71 var $userTS = array();
72 var $userTSUpdated=0;
73 var $showHiddenRecords=0;
74
75 // Session and user data:
76 /*
77 There are two types of data that can be stored: UserData and Session-Data. Userdata is for the login-user, and session-data for anyone viewing the pages.
78 'Keys' are keys in the internal dataarray of the data. When you get or set a key in one of the data-spaces (user or session) you decide the type of the variable (not object though)
79 'Reserved' keys are:
80 - 'recs': Array: Used to 'register' records, eg in a shopping basket. Structure: [recs][tablename][record_uid]=number
81 - sys: Reserved for TypoScript standard code.
82 */
83 var $sesData = Array();
84 var $sesData_change = 0;
85 var $userData_change = 0;
86 protected $sessionDataTimestamp = NULL;
87
88 /**
89 * Default constructor.
90 */
91 public function __construct() {
92 $this->session_table = 'fe_sessions';
93 $this->name = self::getCookieName();
94 $this->get_name = 'ftu';
95 $this->loginType = 'FE';
96
97 $this->user_table = 'fe_users';
98 $this->username_column = 'username';
99 $this->userident_column = 'password';
100 $this->userid_column = 'uid';
101 $this->lastLogin_column = 'lastlogin';
102
103 $this->enablecolumns = array(
104 'deleted' => 'deleted',
105 'disabled' => 'disable',
106 'starttime' => 'starttime',
107 'endtime' => 'endtime',
108 );
109
110 $this->formfield_uname = 'user';
111 $this->formfield_uident = 'pass';
112 $this->formfield_chalvalue = 'challenge';
113 $this->formfield_status = 'logintype';
114 $this->security_level = '';
115
116 $this->auth_timeout_field = 6000;
117 $this->sendNoCacheHeaders = FALSE;
118 $this->getFallBack = TRUE;
119 $this->getMethodEnabled = TRUE;
120 }
121
122
123 /**
124 * Returns the configured cookie name
125 *
126 * @static
127 * @return string
128 */
129 public static function getCookieName() {
130 $configuredCookieName = trim($GLOBALS['TYPO3_CONF_VARS']['FE']['cookieName']);
131 if (empty($configuredCookieName)) {
132 $configuredCookieName = 'fe_typo_user';
133 }
134 return $configuredCookieName;
135 }
136
137
138 /**
139 * Starts a user session
140 *
141 * @return void
142 * @see t3lib_userAuth::start()
143 */
144 function start() {
145 if (intval($this->auth_timeout_field)>0 && intval($this->auth_timeout_field) < $this->lifetime) {
146 // If server session timeout is non-zero but less than client session timeout: Copy this value instead.
147 $this->auth_timeout_field = $this->lifetime;
148 }
149
150 $this->sessionDataLifetime = intval($GLOBALS['TYPO3_CONF_VARS']['FE']['sessionDataLifetime']);
151 if ($this->sessionDataLifetime <= 0) {
152 $this->sessionDataLifetime = 86400;
153 }
154
155 parent::start();
156 }
157
158 /**
159 * Returns a new session record for the current user for insertion into the DB.
160 *
161 * @return array user session record
162 */
163 function getNewSessionRecord($tempuser) {
164 $insertFields = parent::getNewSessionRecord($tempuser);
165 $insertFields['ses_permanent'] = $this->is_permanent;
166
167 return $insertFields;
168 }
169
170 /**
171 * Determine whether a session cookie needs to be set (lifetime=0)
172 *
173 * @return boolean
174 * @internal
175 */
176 function isSetSessionCookie() {
177 $retVal = ($this->newSessionID || $this->forceSetCookie) && ($this->lifetime==0 || !$this->user['ses_permanent']);
178 return $retVal;
179 }
180
181 /**
182 * Determine whether a non-session cookie needs to be set (lifetime>0)
183 *
184 * @return boolean
185 * @internal
186 */
187 function isRefreshTimeBasedCookie() {
188 return $this->lifetime > 0 && $this->user['ses_permanent'];
189 }
190
191 /**
192 * Returns an info array with Login/Logout data submitted by a form or params
193 *
194 * @return array
195 * @see t3lib_userAuth::getLoginFormData()
196 */
197 function getLoginFormData() {
198 $loginData = parent::getLoginFormData();
199 if($GLOBALS['TYPO3_CONF_VARS']['FE']['permalogin'] == 0 || $GLOBALS['TYPO3_CONF_VARS']['FE']['permalogin'] == 1) {
200 if ($this->getMethodEnabled) {
201 $isPermanent = t3lib_div::_GP($this->formfield_permanent);
202 } else {
203 $isPermanent = t3lib_div::_POST($this->formfield_permanent);
204 }
205 if(strlen($isPermanent) != 1) {
206 $isPermanent = $GLOBALS['TYPO3_CONF_VARS']['FE']['permalogin'];
207 } elseif(!$isPermanent) {
208 $this->forceSetCookie = TRUE; // To make sure the user gets a session cookie and doesn't keep a possibly existing time based cookie, we need to force seeting the session cookie here
209 }
210 $isPermanent = $isPermanent?1:0;
211 } elseif($GLOBALS['TYPO3_CONF_VARS']['FE']['permalogin'] == 2) {
212 $isPermanent = 1;
213 } else {
214 $isPermanent = 0;
215 }
216 $loginData['permanent'] = $isPermanent;
217 $this->is_permanent = $isPermanent;
218
219 return $loginData;
220 }
221
222 /**
223 * Will select all fe_groups records that the current fe_user is member of - and which groups are also allowed in the current domain.
224 * It also accumulates the TSconfig for the fe_user/fe_groups in ->TSdataArray
225 *
226 * @return integer Returns the number of usergroups for the frontend users (if the internal user record exists and the usergroup field contains a value)
227 */
228 function fetchGroupData() {
229 $this->TSdataArray = array();
230 $this->userTS = array();
231 $this->userTSUpdated = 0;
232 $this->groupData = Array(
233 'title' => Array(),
234 'uid' => Array(),
235 'pid' => Array()
236 );
237
238 // Setting default configuration:
239 $this->TSdataArray[]=$GLOBALS['TYPO3_CONF_VARS']['FE']['defaultUserTSconfig'];
240
241 // get the info data for auth services
242 $authInfo = $this->getAuthInfoArray();
243
244 if ($this->writeDevLog) {
245 if (is_array($this->user)) {
246 t3lib_div::devLog('Get usergroups for user: '.t3lib_div::arrayToLogString($this->user, array($this->userid_column,$this->username_column)), 'tslib_feUserAuth');
247 } else {
248 t3lib_div::devLog('Get usergroups for "anonymous" user', 'tslib_feUserAuth');
249 }
250 }
251
252 $groupDataArr = array();
253
254 // use 'auth' service to find the groups for the user
255 $serviceChain='';
256 $subType = 'getGroups'.$this->loginType;
257 while (is_object($serviceObj = t3lib_div::makeInstanceService('auth', $subType, $serviceChain))) {
258 $serviceChain.=','.$serviceObj->getServiceKey();
259 $serviceObj->initAuth($subType, array(), $authInfo, $this);
260
261 $groupData = $serviceObj->getGroups($this->user, $groupDataArr);
262 if (is_array($groupData) && count($groupData)) {
263 $groupDataArr = t3lib_div::array_merge($groupDataArr, $groupData); // Keys in $groupData should be unique ids of the groups (like "uid") so this function will override groups.
264 }
265 unset($serviceObj);
266 }
267 if ($this->writeDevLog AND $serviceChain) t3lib_div::devLog($subType.' auth services called: '.$serviceChain, 'tslib_feUserAuth');
268 if ($this->writeDevLog AND !count($groupDataArr)) t3lib_div::devLog('No usergroups found by services', 'tslib_feUserAuth');
269 if ($this->writeDevLog AND count($groupDataArr)) t3lib_div::devLog(count($groupDataArr).' usergroup records found by services', 'tslib_feUserAuth');
270
271
272 // use 'auth' service to check the usergroups if they are really valid
273 foreach ($groupDataArr as $groupData) {
274 // by default a group is valid
275 $validGroup = TRUE;
276
277 $serviceChain='';
278 $subType = 'authGroups'.$this->loginType;
279 while (is_object($serviceObj = t3lib_div::makeInstanceService('auth', $subType, $serviceChain))) {
280 $serviceChain.=','.$serviceObj->getServiceKey();
281 $serviceObj->initAuth($subType, array(), $authInfo, $this);
282
283 if (!$serviceObj->authGroup($this->user, $groupData)) {
284 $validGroup = FALSE;
285 if ($this->writeDevLog) t3lib_div::devLog($subType.' auth service did not auth group: '.t3lib_div::arrayToLogString($groupData, 'uid,title'), 'tslib_feUserAuth', 2);
286
287 break;
288 }
289 unset($serviceObj);
290 }
291 unset($serviceObj);
292
293 if ($validGroup) {
294 $this->groupData['title'][$groupData['uid']]=$groupData['title'];
295 $this->groupData['uid'][$groupData['uid']]=$groupData['uid'];
296 $this->groupData['pid'][$groupData['uid']]=$groupData['pid'];
297 $this->groupData['TSconfig'][$groupData['uid']]=$groupData['TSconfig'];
298 }
299 }
300
301 if (count($this->groupData) && count($this->groupData['TSconfig'])) {
302 // TSconfig: collect it in the order it was collected
303 foreach($this->groupData['TSconfig'] as $TSdata) {
304 $this->TSdataArray[]=$TSdata;
305 }
306
307 $this->TSdataArray[]=$this->user['TSconfig'];
308
309 // Sort information
310 ksort($this->groupData['title']);
311 ksort($this->groupData['uid']);
312 ksort($this->groupData['pid']);
313 }
314
315 return count($this->groupData['uid']) ? count($this->groupData['uid']) : 0;
316 }
317
318 /**
319 * Returns the parsed TSconfig for the fe_user
320 * First time this function is called it will parse the TSconfig and store it in $this->userTS. Subsequent requests will not re-parse the TSconfig but simply return what is already in $this->userTS
321 *
322 * @return array TSconfig array for the fe_user
323 */
324 function getUserTSconf() {
325 if (!$this->userTSUpdated) {
326 // Parsing the user TS (or getting from cache)
327 $this->TSdataArray = t3lib_TSparser::checkIncludeLines_array($this->TSdataArray);
328 $userTS = implode(LF.'[GLOBAL]'.LF,$this->TSdataArray);
329 $parseObj = t3lib_div::makeInstance('t3lib_TSparser');
330 $parseObj->parse($userTS);
331 $this->userTS = $parseObj->setup;
332
333 $this->userTSUpdated=1;
334 }
335 return $this->userTS;
336 }
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354 /*****************************************
355 *
356 * Session data management functions
357 *
358 ****************************************/
359
360 /**
361 * Fetches the session data for the user (from the fe_session_data table) based on the ->id of the current user-session.
362 * The session data is restored to $this->sesData
363 * 1/100 calls will also do a garbage collection.
364 *
365 * @return void
366 * @access private
367 * @see storeSessionData()
368 */
369 function fetchSessionData() {
370 // Gets SesData if any AND if not already selected by session fixation check in ->isExistingSessionRecord()
371 if ($this->id && !count($this->sesData)) {
372 $statement = $GLOBALS['TYPO3_DB']->prepare_SELECTquery(
373 '*',
374 'fe_session_data',
375 'hash = :hash'
376 );
377 $statement->execute(array(':hash' => $this->id));
378 if (($sesDataRow = $statement->fetch()) !== FALSE) {
379 $this->sesData = unserialize($sesDataRow['content']);
380 $this->sessionDataTimestamp = $sesDataRow['tstamp'];
381 }
382 $statement->free();
383 }
384 }
385
386 /**
387 * Will write UC and session data.
388 * If the flag $this->userData_change has been set, the function ->writeUC is called (which will save persistent user session data)
389 * If the flag $this->sesData_change has been set, the fe_session_data table is updated with the content of $this->sesData
390 * If the $this->sessionDataTimestamp is NULL there was no session record yet, so we need to insert it into the database
391 *
392 * @return void
393 * @see fetchSessionData(), getKey(), setKey()
394 */
395 function storeSessionData() {
396 // Saves UC and SesData if changed.
397 if ($this->userData_change) {
398 $this->writeUC('');
399 }
400
401 if ($this->sesData_change && $this->id) {
402 if ($this->sessionDataTimestamp === NULL) {
403 // Write new session-data
404 $insertFields = array(
405 'hash' => $this->id,
406 'content' => serialize($this->sesData),
407 'tstamp' => $GLOBALS['EXEC_TIME']
408 );
409 $this->sessionDataTimestamp = $GLOBALS['EXEC_TIME'];
410 $GLOBALS['TYPO3_DB']->exec_INSERTquery('fe_session_data', $insertFields);
411 } else {
412 // Update session data
413 $updateFields = array(
414 'content' => serialize($this->sesData),
415 'tstamp' => $GLOBALS['EXEC_TIME'],
416 );
417 $this->sessionDataTimestamp = $GLOBALS['EXEC_TIME'];
418 $GLOBALS['TYPO3_DB']->exec_UPDATEquery('fe_session_data', 'hash=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($this->id, 'fe_session_data'), $updateFields);
419 }
420 }
421 }
422
423 /**
424 * Removes data of the current session.
425 *
426 * @return void
427 */
428 public function removeSessionData() {
429 $GLOBALS['TYPO3_DB']->exec_DELETEquery(
430 'fe_session_data',
431 'hash=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($this->id, 'fe_session_data')
432 );
433 }
434
435 /**
436 * Executes the garbage collection of session data and session.
437 * The lifetime of session data is defined by $TYPO3_CONF_VARS['FE']['sessionDataLifetime'].
438 *
439 * @return void
440 */
441 public function gc() {
442 $timeoutTimeStamp = intval($GLOBALS['EXEC_TIME'] - $this->sessionDataLifetime);
443 $GLOBALS['TYPO3_DB']->exec_DELETEquery('fe_session_data', 'tstamp < ' . $timeoutTimeStamp);
444
445 parent::gc();
446 }
447
448 /**
449 * Returns session data for the fe_user; Either persistent data following the fe_users uid/profile (requires login) or current-session based (not available when browse is closed, but does not require login)
450 *
451 * @param string Session data type; Either "user" (persistent, bound to fe_users profile) or "ses" (temporary, bound to current session cookie)
452 * @param string Key from the data array to return; The session data (in either case) is an array ($this->uc / $this->sesData) and this value determines which key to return the value for.
453 * @return mixed Returns whatever value there was in the array for the key, $key
454 * @see setKey()
455 */
456 function getKey($type,$key) {
457 if ($key) {
458 switch($type) {
459 case 'user':
460 return $this->uc[$key];
461 break;
462 case 'ses':
463 return $this->sesData[$key];
464 break;
465 }
466 }
467 }
468
469 /**
470 * Saves session data, either persistent or bound to current session cookie. Please see getKey() for more details.
471 * 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.
472 * Notice: The key "recs" is already used by the function record_registration() which stores table/uid=value pairs in that key. This is used for the shopping basket among other things.
473 * 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 index_ts.php. So if you exit before this point, nothing gets saved of course! And the solution is to call $GLOBALS['TSFE']->storeSessionData(); before you exit.
474 *
475 * @param string Session data type; Either "user" (persistent, bound to fe_users profile) or "ses" (temporary, bound to current session cookie)
476 * @param string Key from the data array to store incoming data in; The session data (in either case) is an array ($this->uc / $this->sesData) and this value determines in which key the $data value will be stored.
477 * @param mixed The data value to store in $key
478 * @return void
479 * @see setKey(), storeSessionData(), record_registration()
480 */
481 function setKey($type,$key,$data) {
482 if ($key) {
483 switch($type) {
484 case 'user':
485 if ($this->user['uid']) {
486 $this->uc[$key]=$data;
487 $this->userData_change=1;
488 }
489 break;
490 case 'ses':
491 $this->sesData[$key]=$data;
492 $this->sesData_change=1;
493 break;
494 }
495 }
496 }
497
498 /**
499 * Returns the session data stored for $key.
500 * The data will last only for this login session since it is stored in the session table.
501 *
502 * @param string $key
503 * @return mixed
504 */
505 public function getSessionData($key) {
506 return $this->getKey('ses', $key);
507 }
508
509 /**
510 * Saves the tokens so that they can be used by a later incarnation of this class.
511 *
512 * @param string $key
513 * @param mixed $data
514 * @return void
515 */
516 public function setAndSaveSessionData($key, $data) {
517 $this->setKey('ses', $key, $data);
518 $this->storeSessionData();
519 }
520
521
522
523 /**
524 * Registration of records/"shopping basket" in session data
525 * This will take the input array, $recs, and merge into the current "recs" array found in the session data.
526 * If a change in the recs storage happens (which it probably does) the function setKey() is called in order to store the array again.
527 *
528 * @param array The data array to merge into/override the current recs values. The $recs array is constructed as [table]][uid] = scalar-value (eg. string/integer).
529 * @param integer The maximum size of stored session data. If zero, no limit is applied and even confirmation of cookie session is discarded.
530 * @return void
531 */
532 function record_registration($recs,$maxSizeOfSessionData=0) {
533
534 // Storing value ONLY if there is a confirmed cookie set (->cookieID),
535 // otherwise a shellscript could easily be spamming the fe_sessions table
536 // with bogus content and thus bloat the database
537 if (!$maxSizeOfSessionData || $this->cookieId) {
538 if ($recs['clear_all']) {
539 $this->setKey('ses', 'recs', array());
540 }
541 $change=0;
542 $recs_array=$this->getKey('ses','recs');
543 foreach ($recs as $table => $data) {
544 if (is_array($data)) {
545 foreach ($data as $rec_id => $value) {
546 if ($value != $recs_array[$table][$rec_id]) {
547 $recs_array[$table][$rec_id] = $value;
548 $change=1;
549 }
550 }
551 }
552 }
553 if ($change && (!$maxSizeOfSessionData || strlen(serialize($recs_array))<$maxSizeOfSessionData)) {
554 $this->setKey('ses','recs',$recs_array);
555 }
556 }
557 }
558
559 /**
560 * Determine whether there's an according session record to a given session_id
561 * in the database. Don't care if session record is still valid or not.
562 *
563 * This calls the parent function but additionally tries to look up the session ID in the "fe_session_data" table.
564 *
565 * @param integer Claimed Session ID
566 * @return boolean Returns TRUE if a corresponding session was found in the database
567 */
568 function isExistingSessionRecord($id) {
569 // Perform check in parent function
570 $count = parent::isExistingSessionRecord($id);
571
572 // Check if there are any fe_session_data records for the session ID the client claims to have
573 if ($count == FALSE) {
574 $statement = $GLOBALS['TYPO3_DB']->prepare_SELECTquery(
575 'content,tstamp',
576 'fe_session_data',
577 'hash = :hash'
578 );
579 $res = $statement->execute(array(':hash' => $id));
580 if ($res !== FALSE) {
581 if ($sesDataRow = $statement->fetch()) {
582 $count = TRUE;
583 $this->sesData = unserialize($sesDataRow['content']);
584 $this->sessionDataTimestamp = $sesDataRow['tstamp'];
585 }
586 $statement->free();
587 }
588 }
589
590 return $count;
591 }
592 }
593
594
595 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['tslib/class.tslib_feuserauth.php'])) {
596 include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['tslib/class.tslib_feuserauth.php']);
597 }
598
599 ?>