[TASK] Change "true" into "TRUE"
[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 * [CLASS/FUNCTION INDEX of SCRIPT]
38 *
39 *
40 *
41 * 79: class tslib_feUserAuth extends t3lib_userAuth
42 * 143: function fetchGroupData()
43 * 233: function getUserTSconf()
44 *
45 * SECTION: Session data management functions
46 * 278: function fetchSessionData()
47 * 300: function storeSessionData()
48 * 326: function getKey($type,$key)
49 * 351: function setKey($type,$key,$data)
50 * 377: function record_registration($recs,$maxSizeOfSessionData=0)
51 *
52 * TOTAL FUNCTIONS: 7
53 * (This index is automatically created/updated by the extension "extdeveval")
54 *
55 */
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70 /**
71 * Extension class for Front End User Authentication.
72 *
73 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
74 * @author René Fritz <r.fritz@colorcube.de>
75 * @package TYPO3
76 * @subpackage tslib
77 */
78 class tslib_feUserAuth extends t3lib_userAuth {
79 var $session_table = 'fe_sessions'; // Table to use for session data.
80 var $name = 'fe_typo_user'; // Session/Cookie name
81 var $get_name = 'ftu'; // Session/GET-var name
82
83 var $user_table = 'fe_users'; // Table in database with userdata
84 var $username_column = 'username'; // Column for login-name
85 var $userident_column = 'password'; // Column for password
86 var $userid_column = 'uid'; // Column for user-id
87 var $lastLogin_column = 'lastlogin';
88
89 var $enablecolumns = Array (
90 'deleted' => 'deleted',
91 'disabled' => 'disable',
92 'starttime' => 'starttime',
93 'endtime' => 'endtime'
94 );
95 var $formfield_uname = 'user'; // formfield with login-name
96 var $formfield_uident = 'pass'; // formfield with password
97 var $formfield_chalvalue = 'challenge'; // formfield with a unique value which is used to encrypt the password and username
98 var $formfield_status = 'logintype'; // formfield with status: *'login', 'logout'
99 var $formfield_permanent = 'permalogin'; // formfield with 0 or 1 // 1 = permanent login enabled // 0 = session is valid for a browser session only
100 var $security_level = ''; // sets the level of security. *'normal' = clear-text. 'challenged' = hashed password/username from form in $formfield_uident. 'superchallenged' = hashed password hashed again with username.
101
102 var $auth_timeout_field = 6000; // Server session lifetime. If > 0: session-timeout in seconds. If false or <0: no timeout. If string: The string is a fieldname from the usertable where the timeout can be found.
103
104 var $lifetime = 0; // Client session lifetime. 0 = Session-cookies. If session-cookies, the browser will stop the session when the browser is closed. Otherwise this specifies the lifetime of a cookie that keeps the session.
105 protected $sessionDataLifetime = 86400; // Lifetime of session data in seconds.
106 var $sendNoCacheHeaders = 0;
107 var $getFallBack = 1; // If this is set, authentication is also accepted by the _GET. Notice that the identification is NOT 128bit MD5 hash but reduced. This is done in order to minimize the size for mobile-devices, such as WAP-phones
108 var $getMethodEnabled = 1; // Login may be supplied by url.
109
110 var $usergroup_column = 'usergroup';
111 var $usergroup_table = 'fe_groups';
112 var $groupData = Array(
113 'title' =>Array(),
114 'uid' =>Array(),
115 'pid' =>Array()
116 );
117 var $TSdataArray=array(); // Used to accumulate the TSconfig data of the user
118 var $userTS = array();
119 var $userTSUpdated=0;
120 var $showHiddenRecords=0;
121
122 // Session and user data:
123 /*
124 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.
125 '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)
126 'Reserved' keys are:
127 - 'recs': Array: Used to 'register' records, eg in a shopping basket. Structure: [recs][tablename][record_uid]=number
128 - sys: Reserved for TypoScript standard code.
129 */
130 var $sesData = Array();
131 var $sesData_change = 0;
132 var $userData_change = 0;
133 protected $sessionDataTimestamp;
134
135
136 /**
137 * Starts a user session
138 *
139 * @return void
140 * @see t3lib_userAuth::start()
141 */
142 function start() {
143 if (intval($this->auth_timeout_field)>0 && intval($this->auth_timeout_field) < $this->lifetime) {
144 // If server session timeout is non-zero but less than client session timeout: Copy this value instead.
145 $this->auth_timeout_field = $this->lifetime;
146 }
147
148 $this->sessionDataLifetime = intval($GLOBALS['TYPO3_CONF_VARS']['FE']['sessionDataLifetime']);
149 if ($this->sessionDataLifetime <= 0) {
150 $this->sessionDataLifetime = 86400;
151 }
152
153 parent::start();
154 }
155
156 /**
157 * Returns a new session record for the current user for insertion into the DB.
158 *
159 * @return array user session record
160 */
161 function getNewSessionRecord($tempuser) {
162 $insertFields = parent::getNewSessionRecord($tempuser);
163 $insertFields['ses_permanent'] = $this->is_permanent;
164
165 return $insertFields;
166 }
167
168 /**
169 * Determine whether a session cookie needs to be set (lifetime=0)
170 *
171 * @return boolean
172 * @internal
173 */
174 function isSetSessionCookie() {
175 $retVal = ($this->newSessionID || $this->forceSetCookie) && ($this->lifetime==0 || !$this->user['ses_permanent']);
176 return $retVal;
177 }
178
179 /**
180 * Determine whether a non-session cookie needs to be set (lifetime>0)
181 *
182 * @return boolean
183 * @internal
184 */
185 function isRefreshTimeBasedCookie() {
186 return $this->lifetime > 0 && $this->user['ses_permanent'];
187 }
188
189 /**
190 * Returns an info array with Login/Logout data submitted by a form or params
191 *
192 * @return array
193 * @see t3lib_userAuth::getLoginFormData()
194 */
195 function getLoginFormData() {
196 $loginData = parent::getLoginFormData();
197 if($GLOBALS['TYPO3_CONF_VARS']['FE']['permalogin'] == 0 || $GLOBALS['TYPO3_CONF_VARS']['FE']['permalogin'] == 1) {
198 if ($this->getMethodEnabled) {
199 $isPermanent = t3lib_div::_GP($this->formfield_permanent);
200 } else {
201 $isPermanent = t3lib_div::_POST($this->formfield_permanent);
202 }
203 if(strlen($isPermanent) != 1) {
204 $isPermanent = $GLOBALS['TYPO3_CONF_VARS']['FE']['permalogin'];
205 } elseif(!$isPermanent) {
206 $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
207 }
208 $isPermanent = $isPermanent?1:0;
209 } elseif($GLOBALS['TYPO3_CONF_VARS']['FE']['permalogin'] == 2) {
210 $isPermanent = 1;
211 } else {
212 $isPermanent = 0;
213 }
214 $loginData['permanent'] = $isPermanent;
215 $this->is_permanent = $isPermanent;
216
217 return $loginData;
218 }
219
220 /**
221 * Will select all fe_groups records that the current fe_user is member of - and which groups are also allowed in the current domain.
222 * It also accumulates the TSconfig for the fe_user/fe_groups in ->TSdataArray
223 *
224 * @return integer Returns the number of usergroups for the frontend users (if the internal user record exists and the usergroup field contains a value)
225 */
226 function fetchGroupData() {
227 $this->TSdataArray = array();
228 $this->userTS = array();
229 $this->userTSUpdated = 0;
230 $this->groupData = Array(
231 'title' => Array(),
232 'uid' => Array(),
233 'pid' => Array()
234 );
235
236 // Setting default configuration:
237 $this->TSdataArray[]=$GLOBALS['TYPO3_CONF_VARS']['FE']['defaultUserTSconfig'];
238
239 // get the info data for auth services
240 $authInfo = $this->getAuthInfoArray();
241
242 if ($this->writeDevLog) {
243 if (is_array($this->user)) {
244 t3lib_div::devLog('Get usergroups for user: '.t3lib_div::arrayToLogString($this->user, array($this->userid_column,$this->username_column)), 'tslib_feUserAuth');
245 } else {
246 t3lib_div::devLog('Get usergroups for "anonymous" user', 'tslib_feUserAuth');
247 }
248 }
249
250 $groupDataArr = array();
251
252 // use 'auth' service to find the groups for the user
253 $serviceChain='';
254 $subType = 'getGroups'.$this->loginType;
255 while (is_object($serviceObj = t3lib_div::makeInstanceService('auth', $subType, $serviceChain))) {
256 $serviceChain.=','.$serviceObj->getServiceKey();
257 $serviceObj->initAuth($subType, array(), $authInfo, $this);
258
259 $groupData = $serviceObj->getGroups($this->user, $groupDataArr);
260 if (is_array($groupData) && count($groupData)) {
261 $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.
262 }
263 unset($serviceObj);
264 }
265 if ($this->writeDevLog AND $serviceChain) t3lib_div::devLog($subType.' auth services called: '.$serviceChain, 'tslib_feUserAuth');
266 if ($this->writeDevLog AND !count($groupDataArr)) t3lib_div::devLog('No usergroups found by services', 'tslib_feUserAuth');
267 if ($this->writeDevLog AND count($groupDataArr)) t3lib_div::devLog(count($groupDataArr).' usergroup records found by services', 'tslib_feUserAuth');
268
269
270 // use 'auth' service to check the usergroups if they are really valid
271 foreach ($groupDataArr as $groupData) {
272 // by default a group is valid
273 $validGroup = TRUE;
274
275 $serviceChain='';
276 $subType = 'authGroups'.$this->loginType;
277 while (is_object($serviceObj = t3lib_div::makeInstanceService('auth', $subType, $serviceChain))) {
278 $serviceChain.=','.$serviceObj->getServiceKey();
279 $serviceObj->initAuth($subType, array(), $authInfo, $this);
280
281 if (!$serviceObj->authGroup($this->user, $groupData)) {
282 $validGroup = FALSE;
283 if ($this->writeDevLog) t3lib_div::devLog($subType.' auth service did not auth group: '.t3lib_div::arrayToLogString($groupData, 'uid,title'), 'tslib_feUserAuth', 2);
284
285 break;
286 }
287 unset($serviceObj);
288 }
289 unset($serviceObj);
290
291 if ($validGroup) {
292 $this->groupData['title'][$groupData['uid']]=$groupData['title'];
293 $this->groupData['uid'][$groupData['uid']]=$groupData['uid'];
294 $this->groupData['pid'][$groupData['uid']]=$groupData['pid'];
295 $this->groupData['TSconfig'][$groupData['uid']]=$groupData['TSconfig'];
296 }
297 }
298
299 if (count($this->groupData) && count($this->groupData['TSconfig'])) {
300 // TSconfig: collect it in the order it was collected
301 foreach($this->groupData['TSconfig'] as $TSdata) {
302 $this->TSdataArray[]=$TSdata;
303 }
304
305 $this->TSdataArray[]=$this->user['TSconfig'];
306
307 // Sort information
308 ksort($this->groupData['title']);
309 ksort($this->groupData['uid']);
310 ksort($this->groupData['pid']);
311 }
312
313 return count($this->groupData['uid']) ? count($this->groupData['uid']) : 0;
314 }
315
316 /**
317 * Returns the parsed TSconfig for the fe_user
318 * 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
319 *
320 * @return array TSconfig array for the fe_user
321 */
322 function getUserTSconf() {
323 if (!$this->userTSUpdated) {
324 // Parsing the user TS (or getting from cache)
325 $this->TSdataArray = t3lib_TSparser::checkIncludeLines_array($this->TSdataArray);
326 $userTS = implode(LF.'[GLOBAL]'.LF,$this->TSdataArray);
327 $parseObj = t3lib_div::makeInstance('t3lib_TSparser');
328 $parseObj->parse($userTS);
329 $this->userTS = $parseObj->setup;
330
331 $this->userTSUpdated=1;
332 }
333 return $this->userTS;
334 }
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352 /*****************************************
353 *
354 * Session data management functions
355 *
356 ****************************************/
357
358 /**
359 * Fetches the session data for the user (from the fe_session_data table) based on the ->id of the current user-session.
360 * The session data is restored to $this->sesData
361 * 1/100 calls will also do a garbage collection.
362 *
363 * @return void
364 * @access private
365 * @see storeSessionData()
366 */
367 function fetchSessionData() {
368 // Gets SesData if any AND if not already selected by session fixation check in ->isExistingSessionRecord()
369 if ($this->id && !count($this->sesData)) {
370 $statement = $GLOBALS['TYPO3_DB']->prepare_SELECTquery(
371 '*',
372 'fe_session_data',
373 'hash = :hash'
374 );
375 $statement->execute(array(':hash' => $this->id));
376 if (($sesDataRow = $statement->fetch()) !== FALSE) {
377 $this->sesData = unserialize($sesDataRow['content']);
378 $this->sessionDataTimestamp = $sesDataRow['tstamp'];
379 }
380 $statement->free();
381 }
382 }
383
384 /**
385 * Will write UC and session data.
386 * If the flag $this->userData_change has been set, the function ->writeUC is called (which will save persistent user session data)
387 * If the flag $this->sesData_change has been set, the fe_session_data table is updated with the content of $this->sesData (deleting any old record, inserting new)
388 *
389 * @return void
390 * @see fetchSessionData(), getKey(), setKey()
391 */
392 function storeSessionData() {
393 // Saves UC and SesData if changed.
394 if ($this->userData_change) {
395 $this->writeUC('');
396 }
397 if ($this->sesData_change) {
398 if ($this->id) {
399 $insertFields = array (
400 'hash' => $this->id,
401 'content' => serialize($this->sesData),
402 'tstamp' => $GLOBALS['EXEC_TIME'],
403 );
404 $this->removeSessionData();
405 $GLOBALS['TYPO3_DB']->exec_INSERTquery('fe_session_data', $insertFields);
406 }
407 }
408 }
409
410 /**
411 * Removes data of the current session.
412 *
413 * @return void
414 */
415 public function removeSessionData() {
416 $GLOBALS['TYPO3_DB']->exec_DELETEquery(
417 'fe_session_data',
418 'hash=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($this->id, 'fe_session_data')
419 );
420 }
421
422 /**
423 * Executes the garbage collection of session data and session.
424 * The lifetime of session data is defined by $TYPO3_CONF_VARS['FE']['sessionDataLifetime'].
425 *
426 * @return void
427 */
428 public function gc() {
429 $timeoutTimeStamp = intval($GLOBALS['EXEC_TIME'] - $this->sessionDataLifetime);
430 $GLOBALS['TYPO3_DB']->exec_DELETEquery('fe_session_data', 'tstamp < ' . $timeoutTimeStamp);
431
432 parent::gc();
433 }
434
435 /**
436 * 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)
437 *
438 * @param string Session data type; Either "user" (persistent, bound to fe_users profile) or "ses" (temporary, bound to current session cookie)
439 * @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.
440 * @return mixed Returns whatever value there was in the array for the key, $key
441 * @see setKey()
442 */
443 function getKey($type,$key) {
444 if ($key) {
445 switch($type) {
446 case 'user':
447 return $this->uc[$key];
448 break;
449 case 'ses':
450 return $this->sesData[$key];
451 break;
452 }
453 }
454 }
455
456 /**
457 * Saves session data, either persistent or bound to current session cookie. Please see getKey() for more details.
458 * 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.
459 * 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.
460 * 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.
461 *
462 * @param string Session data type; Either "user" (persistent, bound to fe_users profile) or "ses" (temporary, bound to current session cookie)
463 * @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.
464 * @param mixed The data value to store in $key
465 * @return void
466 * @see setKey(), storeSessionData(), record_registration()
467 */
468 function setKey($type,$key,$data) {
469 if ($key) {
470 switch($type) {
471 case 'user':
472 if ($this->user['uid']) {
473 $this->uc[$key]=$data;
474 $this->userData_change=1;
475 }
476 break;
477 case 'ses':
478 $this->sesData[$key]=$data;
479 $this->sesData_change=1;
480 break;
481 }
482 }
483 }
484
485 /**
486 * Returns the session data stored for $key.
487 * The data will last only for this login session since it is stored in the session table.
488 *
489 * @param string $key
490 * @return mixed
491 */
492 public function getSessionData($key) {
493 return $this->getKey('ses', $key);
494 }
495
496 /**
497 * Saves the tokens so that they can be used by a later incarnation of this class.
498 *
499 * @param string $key
500 * @param mixed $data
501 * @return void
502 */
503 public function setAndSaveSessionData($key, $data) {
504 $this->setKey('ses', $key, $data);
505 $this->storeSessionData();
506 }
507
508
509
510 /**
511 * Registration of records/"shopping basket" in session data
512 * This will take the input array, $recs, and merge into the current "recs" array found in the session data.
513 * If a change in the recs storage happens (which it probably does) the function setKey() is called in order to store the array again.
514 *
515 * @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).
516 * @param integer The maximum size of stored session data. If zero, no limit is applied and even confirmation of cookie session is discarded.
517 * @return void
518 */
519 function record_registration($recs,$maxSizeOfSessionData=0) {
520
521 // Storing value ONLY if there is a confirmed cookie set (->cookieID),
522 // otherwise a shellscript could easily be spamming the fe_sessions table
523 // with bogus content and thus bloat the database
524 if (!$maxSizeOfSessionData || $this->cookieId) {
525 if ($recs['clear_all']) {
526 $this->setKey('ses', 'recs', array());
527 }
528 $change=0;
529 $recs_array=$this->getKey('ses','recs');
530 foreach ($recs as $table => $data) {
531 if (is_array($data)) {
532 foreach ($data as $rec_id => $value) {
533 if ($value != $recs_array[$table][$rec_id]) {
534 $recs_array[$table][$rec_id] = $value;
535 $change=1;
536 }
537 }
538 }
539 }
540 if ($change && (!$maxSizeOfSessionData || strlen(serialize($recs_array))<$maxSizeOfSessionData)) {
541 $this->setKey('ses','recs',$recs_array);
542 }
543 }
544 }
545
546 /**
547 * Determine whether there's an according session record to a given session_id
548 * in the database. Don't care if session record is still valid or not.
549 *
550 * This calls the parent function but additionally tries to look up the session ID in the "fe_session_data" table.
551 *
552 * @param integer Claimed Session ID
553 * @return boolean Returns TRUE if a corresponding session was found in the database
554 */
555 function isExistingSessionRecord($id) {
556 // Perform check in parent function
557 $count = parent::isExistingSessionRecord($id);
558
559 // Check if there are any fe_session_data records for the session ID the client claims to have
560 if ($count == false) {
561 $statement = $GLOBALS['TYPO3_DB']->prepare_SELECTquery(
562 'content',
563 'fe_session_data',
564 'hash = :hash'
565 );
566 $res = $statement->execute(array(':hash' => $id));
567 if ($res !== FALSE) {
568 if ($sesDataRow = $statement->fetch()) {
569 $count = TRUE;
570 $this->sesData = unserialize($sesDataRow['content']);
571 }
572 $statement->free();
573 }
574 }
575
576 // @deprecated: Check for commerce basket records. The following lines should be removed once a fixed commerce version is released.
577 // Extensions like commerce which have their own session table should just put some small bit of data into fe_session_data using $GLOBALS['TSFE']->fe_user->setKey('ses', ...) to make the session stable.
578 if ($count == false && t3lib_extMgm::isLoaded('commerce')) {
579 t3lib_div::deprecationLog("EXT:commerce specific code in tslib_feuserauth::isExistingSessionRecord() is deprecated. Will be removed in 4.6");
580
581 $dbres = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
582 '*',
583 'tx_commerce_baskets',
584 'sid=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($id, 'tx_commerce_baskets')
585 );
586 if ($dbres !== false) {
587 if ($sesDataRow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($dbres)) {
588 $count = TRUE;
589 }
590 $GLOBALS['TYPO3_DB']->sql_free_result($dbres);
591 }
592 }
593
594 return $count;
595 }
596 }
597
598
599 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['tslib/class.tslib_feuserauth.php'])) {
600 include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['tslib/class.tslib_feuserauth.php']);
601 }
602
603 ?>