ILIAS  release_5-1 Revision 5.0.0-5477-g43f3e3fab5f
class.ilSessionControl.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 1998-2009 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4
12{
17 const INTERNAL_DEBUG = false;
18
24 const DEFAULT_MIN_IDLE = 15;
25 const DEFAULT_MAX_IDLE = 30;
28
34 private static $setting_fields = array(
35 'session_max_count',
36 'session_min_idle',
37 'session_max_idle',
38 'session_max_idle_after_first_request',
39 'session_allow_client_maintenance',
40 'session_handling_type'
41 );
42
52
59 public static $session_types_controlled = array(
60 self::SESSION_TYPE_USER,
61 self::SESSION_TYPE_ANONYM
62 );
63
70 private static $session_types_not_controlled = array(
71 self::SESSION_TYPE_UNKNOWN,
72 self::SESSION_TYPE_SYSTEM,
73 self::SESSION_TYPE_ADMIN
74 );
75
85 public static function checkExpiredSession()
86 {
87 global $ilSetting;
88
89 // do not check session in fixed duration mode
90 if( $ilSetting->get('session_handling_type', 0) != 1 )
91 return;
92
93 // check for expired sessions makes sense
94 // only when public section is not enabled
95 // because it is not possible to determine
96 // wether the sid cookie relates to a session of an
97 // authenticated user or a anonymous user
98 // when the session dataset has allready been deleted
99
100 if(!$ilSetting->get("pub_section"))
101 {
102 global $lng;
103
104 $sid = null;
105
106 if( !isset($_COOKIE[session_name()]) || !strlen($_COOKIE[session_name()]) )
107 {
108 self::debug('Browser did not send a sid cookie');
109 }
110 else
111 {
112 $sid = $_COOKIE[session_name()];
113
114 self::debug('Browser sent sid cookie with value ('.$sid.')');
115
116 if(!self::isValidSession($sid))
117 {
118 self::debug('remove session cookie for ('.$sid.') and trigger event');
119
120 // raw data will be updated (later) with garbage collection [destroyExpired()]
121
123
124 // Trigger expiredSessionDetected Event
125 global $ilAppEventHandler;
126 $ilAppEventHandler->raise(
127 'Services/Authentication', 'expiredSessionDetected', array()
128 );
129
130 ilUtil::redirect('login.php?expired=true'.'&target='.$_GET['target']);
131 }
132 }
133 }
134 }
135
140 public static function initSession()
141 {
142 global $ilSetting;
143
144 // do not init session type in fixed duration mode
145 if( $ilSetting->get('session_handling_type', 0) != 1 )
146 return;
147
148 if( !isset($_SESSION['SessionType']) )
149 {
150 $_SESSION['SessionType'] = self::SESSION_TYPE_UNKNOWN;
151 self::debug(__METHOD__." --> init session with type (".$_SESSION['SessionType'].")");
152 }
153 else
154 {
155 self::debug(__METHOD__." --> keep sessions type on (".$_SESSION['SessionType'].")");
156 }
157 }
158
164 public static function handleLoginEvent($a_login, $a_auth)
165 {
166 global $ilSetting;
167
168 require_once 'Services/User/classes/class.ilObjUser.php';
169 $user_id = ilObjUser::_lookupId($a_login);
170
171 // we need the session type for the session statistics
172 // regardless of the current session handling type
173 switch(true)
174 {
175 case isset($_ENV['SHELL']):
177 break;
178
179 case $user_id == ANONYMOUS_USER_ID:
181 break;
182
185 break;
186
187 default:
189 break;
190 }
191
192 $_SESSION['SessionType'] = $type;
193 self::debug(__METHOD__." --> update sessions type to (".$type.")");
194
195 // do not handle login event in fixed duration mode
196 if( $ilSetting->get('session_handling_type', 0) != 1 )
197 return;
198
199 if(in_array($type, self::$session_types_controlled))
200 {
201 self::checkCurrentSessionIsAllowed($a_auth, $user_id);
202 }
203 }
204
208 public static function handleLogoutEvent()
209 {
210 global $ilSetting;
211
212 // do not handle logout event in fixed duration mode
213 if( $ilSetting->get('session_handling_type', 0) != 1 )
214 return;
215
216 $_SESSION['SessionType'] = self::SESSION_TYPE_UNKNOWN;
217 self::debug(__METHOD__." --> reset sessions type to (".$_SESSION['SessionType'].")");
218
219 // session_destroy() is called in auth, so raw data will be updated
220
222 }
223
234 private static function checkCurrentSessionIsAllowed(Auth $a_auth, $a_user_id)
235 {
236 global $ilSetting;
237
238 $max_sessions = (int)$ilSetting->get('session_max_count', DEFAULT_MAX_COUNT);
239
240 if($max_sessions > 0)
241 {
242 // get total number of sessions
243 $num_sessions = self::getExistingSessionCount(self::$session_types_controlled);
244
245 self::debug(__METHOD__."--> total existing sessions (".$num_sessions.")");
246
247 if(($num_sessions + 1) > $max_sessions)
248 {
249 self::debug(__METHOD__.' --> limit for session pool reached, but try kicking some first request abidencer');
250
251 self::kickFirstRequestAbidencer(self::$session_types_controlled);
252
253 // get total number of sessions again
254 $num_sessions = self::getExistingSessionCount(self::$session_types_controlled);
255
256 if(($num_sessions + 1) > $max_sessions)
257 {
258 self::debug(__METHOD__.' --> limit for session pool still reached so try kick one min idle session');
259
260 self::kickOneMinIdleSession(self::$session_types_controlled);
261
262 // get total number of sessions again
263 $num_sessions = self::getExistingSessionCount(self::$session_types_controlled);
264
265 if(($num_sessions + 1) > $max_sessions)
266 {
267 self::debug(__METHOD__.' --> limit for session pool still reached so logout session ('.session_id().') and trigger event');
268
270
271 // as the session is opened and closed in one request, there
272 // is no proper session yet and we have to do this ourselves
273 ilSessionStatistics::createRawEntry(session_id(), $_SESSION['SessionType'],
274 time(), $a_user_id);
275
276 $a_auth->logout();
277
278 // Trigger reachedSessionPoolLimit Event
279 global $ilAppEventHandler;
280 $ilAppEventHandler->raise(
281 'Services/Authentication', 'reachedSessionPoolLimit', array()
282 );
283
284 // auth won't do this, we need to close session properly
285 session_destroy();
286
287 ilUtil::redirect('login.php?reached_session_limit=true');
288 }
289 else
290 {
291 self::debug(__METHOD__.' --> limit of session pool not reached anymore after kicking one min idle session');
292 }
293 }
294 else
295 {
296 self::debug(__METHOD__.' --> limit of session pool not reached anymore after kicking some first request abidencer');
297 }
298 }
299 else
300 {
301 self::debug(__METHOD__.' --> limit for session pool not reached yet');
302 }
303 }
304 else
305 {
306 self::debug(__METHOD__.' --> limit for session pool not set so check is bypassed');
307 }
308 }
309
317 public static function getExistingSessionCount(array $a_types)
318 {
319 global $ilDB;
320
321 $ts = time();
322
323 $query = "SELECT count(session_id) AS num_sessions FROM usr_session ".
324 "WHERE expires > %s ".
325 "AND ".$ilDB->in('type', $a_types, false, 'integer');
326
327 $res = $ilDB->queryF($query, array('integer'), array($ts));
328 $row = $res->fetchRow(DB_FETCHMODE_OBJECT);
329
330 return $row->num_sessions;
331 }
332
343 private static function kickOneMinIdleSession(array $a_types)
344 {
345 global $ilDB, $ilSetting;
346
347 $ts = time();
348 $min_idle = (int)$ilSetting->get('session_min_idle', self::DEFAULT_MIN_IDLE) * 60;
349 $max_idle = (int)$ilSetting->get('session_max_idle', self::DEFAULT_MAX_IDLE) * 60;
350
351 $query = "SELECT session_id,expires FROM usr_session WHERE expires >= %s " .
352 "AND (expires - %s) < (%s - %s) " .
353 "AND ".$ilDB->in('type', $a_types, false, 'integer');
354 "ORDER BY expires";
355
356 $res = $ilDB->queryF(
357 $query,
358 array('integer', 'integer', 'integer', 'integer'),
359 array($ts, $ts, $max_idle, $min_idle)
360 );
361
362 while( $row = $res->fetchRow(DB_FETCHMODE_OBJECT) )
363 {
365
366 self::debug(__METHOD__.' --> successfully deleted one min idle session');
367
368 return true;
369 }
370
371 self::debug(__METHOD__.' --> no min idle session available for deletion');
372
373 return false;
374 }
375
384 private static function kickFirstRequestAbidencer(array $a_types)
385 {
386 global $ilDB, $ilSetting;
387
388 $max_idle_after_first_request = (int)$ilSetting->get('session_max_idle_after_first_request') * 60;
389
390 if((int)$max_idle_after_first_request == 0) return;
391
392 $query = "SELECT session_id,expires FROM usr_session WHERE " .
393 "(ctime - createtime) < %s " .
394 "AND (%s - createtime) > %s " .
395 "AND ".$ilDB->in('type', $a_types, false, 'integer');
396
397 $res = $ilDB->queryF( $query,
398 array('integer', 'integer', 'integer'),
399 array($max_idle_after_first_request, time(), $max_idle_after_first_request)
400 );
401
402 $session_ids = array();
403 while( $row = $res->fetchRow(DB_FETCHMODE_OBJECT) )
404 {
405 $session_ids[$row->session_id] = $row->expires;
406 }
408
409 self::debug(__METHOD__.' --> Finished kicking first request abidencer');
410 }
411
421 private static function isValidSession($a_sid)
422 {
423 global $ilDB, $ilSetting;
424
425 $query = "SELECT session_id, expires FROM usr_session ".
426 "WHERE session_id = %s";
427
428 $res = $ilDB->queryF($query, array('text'), array($a_sid));
429
430 $ts = time();
431
432 $sessions = array();
433
434 while( $row = $ilDB->fetchAssoc($res) )
435 {
436 if( $row['expires'] > $ts )
437 {
438 self::debug(__METHOD__.' --> Found a valid session with id ('.$a_sid.')');
439 $sessions[] = $row;
440 }
441 else
442 {
443 self::debug(__METHOD__.' --> Found an expired session with id ('.$a_sid.')');
444 }
445 }
446
447 if(count($sessions) == 1)
448 {
449 self::debug(__METHOD__.' --> Exact one valid session found for session id ('.$a_sid.')');
450
451 return true;
452 }
453 else
454 {
455 if(count($sessions) > 1)
456 self::debug(__METHOD__.' --> Strange!!! More than one sessions found for given session id! ('.$a_sid.')');
457 else self::debug(__METHOD__.' --> No valid session found for session id ('.$a_sid.')');
458
459 return false;
460 }
461 }
462
466 private static function removeSessionCookie()
467 {
468 ilUtil::setCookie(session_name(),'deleted',true,true);
469 self::debug('Session cookie has been removed');
470 }
471
480 private static function checkAdministrationPermission($a_user_id)
481 {
482 if( !(int)$a_user_id ) return false;
483
484 global $rbacsystem;
485
486 $access = $rbacsystem->checkAccessOfUser(
487 $a_user_id, 'read,visible', SYSTEM_FOLDER_ID
488 );
489
490 return $access;
491 }
492
499 private static function debug($a_debug_log_message)
500 {
501 global $ilLog;
502
503 if(DEVMODE) $ilLog->write($a_debug_log_message, 'message');
504
505 if(self::INTERNAL_DEBUG) error_log($a_debug_log_message."\n", 3, 'session.log');
506 }
507
513 public static function getSettingFields()
514 {
516 }
517
518}
519
520
521?>
$_GET["client_id"]
$_SESSION["AccountId"]
logout()
Logout function.
Definition: Auth.php:1077
const DB_FETCHMODE_OBJECT
Definition: class.ilDB.php:11
isValidSession($ext_uid, $soap_pw, $new_user)
isValidSession
static _lookupId($a_user_str)
Lookup id by login.
const INTERNAL_DEBUG
this controls the debuggin into a separate logfile (.
static handleLogoutEvent()
reset sessions type to unknown
static isValidSession($a_sid)
checks if session exists for given id and if it is still valid
static checkCurrentSessionIsAllowed(Auth $a_auth, $a_user_id)
checks wether the current session exhaust the limit of sessions when limit is reached it deletes "fir...
static $session_types_not_controlled
all session types that will be involved when count of sessions will be determined or when idleing ses...
static initSession()
mark session with type regarding to the context.
static $setting_fields
all fieldnames that are saved in settings table
const SESSION_TYPE_UNKNOWN
session types from which one is assigned to each session
static getSettingFields()
returns the array of setting fields
static checkExpiredSession()
checks for possibly expired session should be called from ilAuthUtils::__initAuth() so it's called be...
static debug($a_debug_log_message)
logs the given debug message in ilLog
static getExistingSessionCount(array $a_types)
returns number of valid sessions relating to given session types
static handleLoginEvent($a_login, $a_auth)
when current session is allowed to be created it marks it with type regarding to the sessions user co...
static removeSessionCookie()
removes a session cookie, so it is not sent by browser anymore
const DEFAULT_MAX_COUNT
default value for settings that have not been defined in setup or administration yet
static checkAdministrationPermission($a_user_id)
checks wether a given user login relates to an user with administrative permissions
static kickOneMinIdleSession(array $a_types)
if sessions exist that relates to given session types and idled longer than min idle parameter,...
static kickFirstRequestAbidencer(array $a_types)
kicks sessions of users that abidence after login so people could not login and go for coffe break ;-...
static createRawEntry($a_session_id, $a_session_type, $a_timestamp, $a_user_id)
Create raw data entry.
static setClosingContext($a_context)
set closing context (for statistics)
static _destroy($a_session_id, $a_closing_context=null, $a_expired_at=null)
Destroy session.
const SESSION_CLOSE_FIRST
const SESSION_CLOSE_IDLE
const SESSION_CLOSE_LIMIT
static setCookie($a_cookie_name, $a_cookie_value='', $a_also_set_super_global=true, $a_set_cookie_invalid=false)
static redirect($a_script)
http redirect to other script
$_COOKIE["ilClientId"]
Definition: cron.php:11
global $lng
Definition: privfeed.php:40
global $ilSetting
Definition: privfeed.php:40
global $ilDB