diff --git a/config/environment.php b/config/environment.php index f1744729af..0df592dfe0 100644 --- a/config/environment.php +++ b/config/environment.php @@ -52,4 +52,7 @@ /* Feed */ 'feed_limit' => 10, 'feed_email' => 'author', + + /* Session autostart */ + 'session_autostart' => false ]; \ No newline at end of file diff --git a/lib/libraries/cms/application/cms.php b/lib/libraries/cms/application/cms.php index bc6ab4b579..373c9517ce 100644 --- a/lib/libraries/cms/application/cms.php +++ b/lib/libraries/cms/application/cms.php @@ -128,7 +128,7 @@ public function __construct(JInput $input = null, JRegistry $config = null, JApp // Create the session if a session name is passed. if ($this->config->get('session') !== false) { - $this->loadSession(); + $this->loadSession(null, $this->config->get('session_autostart')); } } @@ -620,7 +620,7 @@ public function isSite() * * @since 3.2 */ - public function loadSession(JSession $session = null) + public function loadSession(JSession $session = null, $auto_start = true) { if ($session !== null) { @@ -664,35 +664,49 @@ public function loadSession(JSession $session = null) // There's an internal coupling to the session object being present in JFactory, need to deal with this at some point $session = JFactory::getSession($options); - $session->initialise($this->input, $this->dispatcher); - $session->start(); - - // TODO: At some point we need to get away from having session data always in the db. - $db = JFactory::getDbo(); - - // Remove expired sessions from the database. - $time = time(); - - if ($time % 2) - { - // The modulus introduces a little entropy, making the flushing less accurate - // but fires the query less than half the time. - $query = $db->getQuery(true) - ->delete($db->quoteName('#__users_sessions')) - ->where($db->quoteName('time') . ' < ' . $db->quote((int) ($time - $session->getExpire()))); - - $db->setQuery($query); - $db->execute(); - } - - // Get the session handler from the configuration. - $handler = $this->get('session_handler', 'none'); - - if (($handler != 'database' && ($time % 2 || $session->isNew())) - || ($handler == 'database' && $session->isNew())) - { - $this->checkSession(); - } + $session->initialise($this->input, $this->dispatcher); + + if ($session->getState() != 'active') + { + if ($auto_start || $this->input->cookie->get($session->getName())) { + $session->start(); + } + } + + // Only update the session table if the session is active + if ($session->getState() == 'active') + { + // TODO: At some point we need to get away from having session data always in the db. + $db = JFactory::getDbo(); + + // Remove expired sessions from the database. + $time = time(); + + if ($time % 2) { + // The modulus introduces a little entropy, making the flushing less accurate + // but fires the query less than half the time. + $query = $db->getQuery(true) + ->delete($db->quoteName('#__users_sessions')) + ->where($db->quoteName('time') . ' < ' . $db->quote((int)($time - $session->getExpire()))); + + $db->setQuery($query); + $db->execute(); + } + + // Get the session handler from the configuration. + $handler = $this->get('session_handler', 'none'); + + if (($handler != 'database' && ($time % 2 || $session->isNew())) + || ($handler == 'database' && $session->isNew()) + ) { + $this->checkSession(); + } + } + else + { + $session->set('registry', new JRegistry('session')); + $session->set('user', new JUser()); + } // Set the session object. $this->session = $session; @@ -732,10 +746,19 @@ public function login($credentials, $options = array()) if ($response->status === JAuthentication::STATUS_SUCCESS) { - /* - * Validate that the user should be able to login (different to being authenticated). - * This permits authentication plugins blocking the user. - */ + $session = JFactory::getSession($options); + + // Fork the session to prevent session fixation issues if it's active + if($session->getState() != 'active') { + $session->start(); + } else { + $session->fork(); + } + + /* + * Validate that the user should be able to login (different to being authenticated). + * This permits authentication plugins blocking the user. + */ $authorisations = $authenticate->authorise($response, $options); foreach ($authorisations as $authorisation) diff --git a/lib/libraries/joomla/application/web.php b/lib/libraries/joomla/application/web.php index e695ed3d81..2c544f4a57 100644 --- a/lib/libraries/joomla/application/web.php +++ b/lib/libraries/joomla/application/web.php @@ -133,6 +133,10 @@ public function __construct(JInput $input = null, JRegistry $config = null, JApp // Load the configuration object. $this->loadConfiguration($this->fetchConfigurationData()); + if (is_null($this->config->get('session_autostart'))) { + $this->config->set('session_autostart', true); + } + // Set the execution datetime and timestamp; $this->set('execution.datetime', gmdate('Y-m-d H:i:s')); $this->set('execution.timestamp', time()); @@ -213,7 +217,7 @@ public function initialise($session = null, $document = null, $language = null, // Create the session based on the application logic. if ($session !== false) { - $this->loadSession($session); + $this->loadSession($session, $this->config->get('session_autostart')); } // Create the document based on the application logic. @@ -1030,7 +1034,7 @@ public function loadLanguage(JLanguage $language = null) * * @since 11.3 */ - public function loadSession(JSession $session = null) + public function loadSession(JSession $session = null, $auto_start = true) { if ($session !== null) { @@ -1065,10 +1069,12 @@ public function loadSession(JSession $session = null) { $session->restart(); } - else - { - $session->start(); - } + elseif ($session->getState() != 'active') + { + if ($auto_start || $this->input->cookie->get($session->getName())) { + $session->start(); + } + } // Set the session object. $this->session = $session; diff --git a/lib/libraries/legacy/application/application.php b/lib/libraries/legacy/application/application.php index 3dd309d76c..4c4dc63d88 100644 --- a/lib/libraries/legacy/application/application.php +++ b/lib/libraries/legacy/application/application.php @@ -146,10 +146,15 @@ public function __construct($config = array()) $this->_createConfiguration(JPATH_CONFIGURATION . '/' . $config['config_file']); } + // Set the session autostart + if(!isset($config['session_autostart'])) { + $config['session_autostart'] = !is_null($this->getCfg('session_autostart')) ? $this->getCfg('session_autostart') : true; + } + // Create the session if a session name is passed. if ($config['session'] !== false) { - $this->_createSession(self::getHash($config['session_name'])); + $this->_createSession(self::getHash($config['session_name']), false, $config['session_autostart']); } $this->requestTime = gmdate('Y-m-d H:i'); @@ -962,7 +967,7 @@ protected function _createConfiguration($file) * @since 11.1 * @deprecated 4.0 */ - protected function _createSession($name) + protected function _createSession($name, $auto_start = true) { $options = array(); $options['name'] = $name; @@ -987,36 +992,50 @@ protected function _createSession($name) $this->registerEvent('onAfterSessionStart', array($this, 'afterSessionStart')); $session = JFactory::getSession($options); - $session->initialise($this->input, $this->dispatcher); - $session->start(); - - // TODO: At some point we need to get away from having session data always in the db. - - $db = JFactory::getDbo(); - - // Remove expired sessions from the database. - $time = time(); - - if ($time % 2) - { - // The modulus introduces a little entropy, making the flushing less accurate - // but fires the query less than half the time. - $query = $db->getQuery(true) - ->delete($db->quoteName('#__users_sessions')) - ->where($db->quoteName('time') . ' < ' . $db->quote((int) ($time - $session->getExpire()))); - - $db->setQuery($query); - $db->execute(); - } - - // Check to see the the session already exists. - $handler = $this->getCfg('session_handler'); - - if (($handler != 'database' && ($time % 2 || $session->isNew())) - || ($handler == 'database' && $session->isNew())) - { - $this->checkSession(); - } + $session->initialise($this->input, $this->dispatcher); + + if($session->getState() != 'active') + { + if ($auto_start || JRequest::getCmd($session->getName(), null, 'cookie')) { + $session->start(); + } + } + + // Only update the session table if the session is active + if($session->getState() == 'active') + { + // TODO: At some point we need to get away from having session data always in the db. + $db = JFactory::getDbo(); + + // Remove expired sessions from the database. + $time = time(); + + if ($time % 2) + { + // The modulus introduces a little entropy, making the flushing less accurate + // but fires the query less than half the time. + $query = $db->getQuery(true) + ->delete($db->quoteName('#__users_sessions')) + ->where($db->quoteName('time') . ' < ' . $db->quote((int) ($time - $session->getExpire()))); + + $db->setQuery($query); + $db->execute(); + } + + // Check to see the the session already exists. + $handler = $this->getCfg('session_handler'); + + if (($handler != 'database' && ($time % 2 || $session->isNew())) + || ($handler == 'database' && $session->isNew())) + { + $this->checkSession(); + } + } + else + { + $session->set('registry', new JRegistry('session')); + $session->set('user', new JUser()); + } return $session; }