Joomla 3 Session management

JSession - libraries/joomla/session/session.php

JSessionStorage (abstract) - libraries/joomla/session/storage.php

JSessionStorageDatabase - libraries/joomla/session/storage/database.php

Overview

Session handler - [ database | memcache | memcached | wincache | xcache | apc ]

Provides for the production of form tokens to prevent spoofing of variable names (JSession::getFormToken()).

getToken - form processing invalidate post request if token is not present or not correct.

hasToken

Psuedo code

Session lifecycle
Session instantiation
  1. JSession::getInstance() which entails –
    1. create session handler of the specified type using JSessionStorage::getInstance;
    2. call JSessionStorage::register() to register the open, close, read, write, destroy and garbage collection functions of the relevant JSessionStorage object with the PHP session persistence manager using the PHP function session_set_save_handler;
  2. JSession::initialise($input, $dispatcher);
  3. JSession::start() which –
    1. processes the cookie received from the user agent to determine the session name;
    2. registers the PHP function session_write_close() as the shutdown function;
    3. calls the PHP session management function session_start() which, in turn –
      1. makes a call to the 'open' session persistence function set, above; and
      2. makes a call to the 'read' session persistence function.
Session application
JView::display
JController::<action>
  1. JSession::has(), JSession::get(), JSession::set();
  2. JSession::getFormToken(), JSession::checkToken($type ['request'])
Session destruction

The JSession object is not formally destroyed at any point by the Joomla framework. Instead, the Joomla framework uses JSession as a form of shim layer for PHP session management provision wherein JSession::get and JSession::set operations access and update the global variable $_SESSION which is created, read, updated and deleted by PHP session management through the save handlers. Accordingly, any changes to the data associated with the session are written to the persistent store indirectly through a call to session_write_close(), itself invoked on a call to the PHP function exit() by virtue of the registration of session_write_close as the shutdown function. In turn, the session_write_close function executes the JStorageSession::write() and JStorageSession::close() functions by virtue of the call to session_set_save_handler() function made by the JSession constructor.

Psuedo code

 Accepts a session handler, and an array of options.

JSession

JSession::getInstance, JSession::__construct

Psuedo code

  1. if a PHP session has been identified automatically by the PHP environment according to the php.ini configuration parameter, session.auto_start, call session_unset() to unset the variables associated with the global session variable $_SESSION followed by session_destroy() to destroy the session data stored in the persistent store;
  2. disable PHP transparent session identifier support (session.use_trans_sid);
  3. require PHP session management to rely upon the use of cookies only (session.use_only_cookies);
  4. create a session handler of the specified type using JSessionStorage::getInstance($session_handler ['database'], $options) which, on instantiation, registers functions associated with the JSessionStorage object as PHP session save handlers;
  5. set certain global PHP variables and JSession members according to the values provided by $options using JSession::_setOptions($options) as follows –
    1. session_name : md5($options['name']);
    2. session_id : $options['id'];
    3. JSession::$_expire : $options['expire'];
    4. JSession::$_security : $options['security'];
    5. JSession::$_force_ssl : $options['force_ssl'];
    6. session.gc_maxlifetime : $options['expire'];
  6. JSession::_setCookieParams() as follows –
    1. session_get_cookie_params();
    2. if $JSession::_force_ssl is true, set $cookie['secure'] to true;
    3. $cookie['domain'] = <configuration>('cookie_domain')
    4. $cookie['path'] = <configuration>('cookie_path')
    5. session_set_cookie_params($cookie['lifetime'], $cookie['path'], $cookie['domain'], $cookie['secure'], true)
  7. mark JSession object as being in an 'inactive' state.

JSession::checkToken($method [post])

Psuedo code

  1. obtain the value associated with the form token given by JSession::getFormToken from the JInput object associated with the relevant JApplication object;
  2. if there is no associated value
  3. if the JSession object is 'new' in the sense the session activity counter is equal to 1, redirect the client browser to the index page with a message to the effect that the session has expired;
  4. otherwise, return false;
  5. if there is an associated value, return true.

JSession::getFormToken($forceNew [false]) [static]

Psuedo code

  1. if JApplication::getHash method exists, call JApplication::getHash on the catenated user identifier, and session token provided by JSession::getToken($forceNew);
  2. otherwise, generate an MD5 hash value from the catenated values of the application 'secret value', the user identifier and the session token provided by JSession::getToken($forceNew).

JSession::initialise($input, $dispatcher)

Psuedo code

  1. assign the object reference of $input to JSession::$_input;
  2. assign the object reference of $dispatcher to JSession::$_dispatcher.

JSession::start()

Psuedo code

  1. if the JSession object is not 'active' –
  2. activate the JSession object using JSession::_start() which –
  3. mark the JSession object as 'active';
  4. increment the session activity counter using JSession::_setCounter();
  5. update the session timers to reflect the time the session was created, when it was last used and the time now using JSession::_setTimers() to enable JSession to detect a lapsed or expired session;
  6. perform security checks on the session information recovered using JSession::_validate() as follows –
    1. check if the session has expired;
    2. record the identity of the intermediate proxy provided by HTTP_X_FORWARDED_FOR;
    3. record or check the client address is the same as that previously used for the session;
    4. record or check the client browser provided by HTTP_USER_AGENT;
  7. trigger the 'onAfterSessionStart' event.

JSessionStorage

JSessionStorage is an abstract class that provides a framework for a variety of approaches to session state management.

JSessionStorage::close()

Purpose

JSessionStorage::close is responsible for closing the persistent store.

JSessionStorage::open($save_path, $session_name)

Purpose

JSessionStorage::open is responsible for opening the persistent store ready for the relevant read, write, destroy and garbage collection operations.

JSessionStorage::read($id)

Purpose

JSessionStorage::read is responsible for reading the serialized session data from the persistent store.

JSessionStorage::write($id, $session_data)

Purpose

JSessionStorage::write is responsible for writing the serialized session data to the persistent store.

JSessionStorage::destroy($id)

Purpose

JSessionStorage::destroy is responsible for deleting the relevant session from the persistent store.

JSessionStorage::gc($maxlifetime [null])

Purpose

JSessionStorage::gc is responsible for identifying [and deleting / destroying] sessions that have expired.

JSessionStorageDatabase

JSessionStorageDatabase::read($id)

Psuedo code

  1. obtain the global database object using JFactory::getDbo();
  2. construct SQL statement of the form 'SELECT data FROM #__session WHERE session_id = $id';
  3. execute SQL statement against the global database object; and
  4. post-process the returned result.

JSessionStorageDatabase::write($id, $data)

Psuedo code

  1. obtain the global database object using JFactory::getDbo();
  2. construct SQL statement of the form 'UPDATE #__session SET data = $data, time = <current time> WHERE session_id = $id';
  3. execute the SQL statement against the global database object;
  4. return true if the update was successful, or false if an exception was raised or the execute operation failed to update any rows of the #__session table.

JSessionStorageDatabase::destroy($id)

Psuedo code

  1. obtain the global database object using JFactory::getDbo();
  2. construct SQL statement of the form 'DELETE FROM #__session WHERE session_id = $id;
  3. execute the SQL statement against the global database object;
  4. return true if the delete operation was successful, or false if the operation resulted in an exception being raised or the operation failed to delete any of the rows of the #__session table.

JSessionStorageDatabase::gc($lifetime [1440])

Psuedo code

  1. obtain the global database object using JFactory::getDbo();
  2. determine the timestamp threshold before which the relevant sessions ought to be deleted;
  3. construct SQL statement of the form 'DELETE FROM #__session WHERE time < <timestamp threshold>';
  4. execute the SQL statement against the global database object;
  5. return true if the delete operation was successful, or false if the operation resulted in an exception being raised or the operation failed to delete any of the rows of the #__session table.