Commit 3b5ada5f authored by Carsten  Rose's avatar Carsten Rose
Browse files

F4906 Php Session Timeout: can be specified globally in configuration and per...

F4906 Php Session Timeout: can be specified globally in configuration and per form. Affects only logged in FE User.
parent abd28839
Pipeline #1083 passed with stage
in 1 minute and 34 seconds
......@@ -286,6 +286,65 @@ Install Check List
Configuration
-------------
.. _config-qfq-php:
config.qfq.php
^^^^^^^^^^^^^^
+-------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+
| Keyword | Example | Description |
+===============================+=======================================================+============================================================================+
| DB_<n>_USER | DB_1_USER=qfqUser | Credentials configured in MySQL |
+-------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+
| DB_<n>_PASSWORD | DB_1_PASSWORD=1234567890 | Credentials configured in MySQL |
+-------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+
| DB_<n>_SERVER | DB_1_SERVER=localhost | Hostname of MySQL Server |
+-------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+
| DB_<n>_NAME | DB_1_NAME=qfq_db | Database name |
+-------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+
| LDAP_1_RDN | LDAP_1_RDN='ou=Admin,ou=example,dc=com' | Credentials for non-anonymous LDAP access. At the moment only one set of |
| LDAP_1_PASSWORD | LDAP_1_PASSWORD=mySecurePassword | |
+-------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+
| T3_DB_NAME | T3_DB_NAME=specialt3dbname | Only necessary for inline report editing if the t3 database is not |
| | | anologous to the Data db name (but ending in _t3) - see `inline-report`_. |
+-------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+
Example: *typo3conf/config.qfq.php*: ::
<?php
// QFQ configuration
//
// Save this file as: <site path>/typo3conf/config.qfq.php
return [
'DB_1_USER' => '<DBUSER>',
'DB_1_SERVER' => '<DBSERVER>',
'DB_1_PASSWORD' => '<DBPW>',
'DB_1_NAME' => '<DB>',
//DB_2_USER = <DBUSER>
//DB_2_SERVER = <DBSERVER>
//DB_2_PASSWORD = <DBPW>
//DB_2_NAME = <DB>
// DB_n ...
// ...
// LDAP_1_RDN =
// LDAP_1_PASSWORD =
];
After parsing the configuration, the following variables will be set automatically in STORE_SYSTEM:
+----------------+------------------------------------------------------------------------------------+
| _dbNameData | Can be used to dynamically access the current selected database: {{_dbNameData:Y}} |
+----------------+------------------------------------------------------------------------------------+
| _dbNameQfq | Can be used to dynamically access the current selected database: {{_dbNameQfq:Y}} |
+----------------+------------------------------------------------------------------------------------+
.. _extension-manager-qfq-configuration:
Extension Manager: QFQ Configuration
......@@ -376,6 +435,8 @@ Extension Manager: QFQ Configuration
+-------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+
| recordLockTimeoutSeconds | 900 | Timeout for record locking. After this time, a record will be replaced. |
+-------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+
| sessionTimeoutSeconds | 1800 | Timeout for FE User session. See sessionTimeoutSeconds_ |
+-------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+
| enterAsSubmit | enterAsSubmit = 1 | 0: off, 1: Pressing *enter* in a form means *save* and *close*. |
+-------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+
| editFormPage | form | T3 Pagealias to edit a form. |
......@@ -461,64 +522,6 @@ Extension Manager: QFQ Configuration
+-------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+
.. _config-qfq-php:
config.qfq.php
--------------
+-------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+
| Keyword | Example | Description |
+===============================+=======================================================+============================================================================+
| DB_<n>_USER | DB_1_USER=qfqUser | Credentials configured in MySQL |
+-------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+
| DB_<n>_PASSWORD | DB_1_PASSWORD=1234567890 | Credentials configured in MySQL |
+-------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+
| DB_<n>_SERVER | DB_1_SERVER=localhost | Hostname of MySQL Server |
+-------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+
| DB_<n>_NAME | DB_1_NAME=qfq_db | Database name |
+-------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+
| LDAP_1_RDN | LDAP_1_RDN='ou=Admin,ou=example,dc=com' | Credentials for non-anonymous LDAP access. At the moment only one set of |
| LDAP_1_PASSWORD | LDAP_1_PASSWORD=mySecurePassword | |
+-------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+
| T3_DB_NAME | T3_DB_NAME=specialt3dbname | Only necessary for inline report editing if the t3 database is not |
| | | anologous to the Data db name (but ending in _t3) - see `inline-report`_. |
+-------------------------------+-------------------------------------------------------+----------------------------------------------------------------------------+
Example: *typo3conf/config.qfq.php*: ::
<?php
// QFQ configuration
//
// Save this file as: <site path>/typo3conf/config.qfq.php
return [
'DB_1_USER' => '<DBUSER>',
'DB_1_SERVER' => '<DBSERVER>',
'DB_1_PASSWORD' => '<DBPW>',
'DB_1_NAME' => '<DB>',
//DB_2_USER = <DBUSER>
//DB_2_SERVER = <DBSERVER>
//DB_2_PASSWORD = <DBPW>
//DB_2_NAME = <DB>
// DB_n ...
// ...
// LDAP_1_RDN =
// LDAP_1_PASSWORD =
];
After parsing the configuration, the following variables will be set automatically in STORE_SYSTEM:
+----------------+------------------------------------------------------------------------------------+
| _dbNameData | Can be used to dynamically access the current selected database: {{_dbNameData:Y}} |
+----------------+------------------------------------------------------------------------------------+
| _dbNameQfq | Can be used to dynamically access the current selected database: {{_dbNameQfq:Y}} |
+----------------+------------------------------------------------------------------------------------+
.. _`CustomVariables`:
......@@ -613,6 +616,23 @@ the end. E.g. `my_long_variable_130`. Such a variable has an allowed length of 1
usual with the variable name: `{{my_long_variable_130:C:...}}`.
.. _`sessionTimeoutSeconds`:
FE-User: Session timeout seconds
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
There is no timeout for website users who are not logged in (but typically those users don't have access to protected content).
For logged in users, the default timeout is 1800 seconds. These timeout only affects QFQ related content and can be
specified a) globally (QFQ configuration) and b) specific per Form.
The maximum timeout depends on the minimal value of php.ini `session.cookie_lifetime` and `session.gc_maxlifetime`.
Specifying a higher value produces an error in the front end.
Every access to QFQ related content resets the timeout.
After FE login, the next access to QFQ related content starts the timeout counter.
.. _local-documentation:
Local Documentation
......@@ -2350,6 +2370,8 @@ Parameter
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| formSubmitLogMode | string | Overwrite default from configuration_ |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
| sessionTimeoutSeconds | int | Overwrite default from configuration_ . See sessionTimeoutSeconds_. |
+-----------------------------+--------+----------------------------------------------------------------------------------------------------------+
* Example:
......
......@@ -99,7 +99,8 @@ securityShowMessage = true
# cat=security/security; type=string; label='GET'-Parameter max length:Default is '50'. GET vars longer than 'x' character triggers an `attack-detected`.
securityGetMaxLength = 50
# cat=security/security; type=string; label=Session Timeout in seconds:Default is '1800'. After inactivity of 'x' seconds, the user has to relogin.
sessionTimeoutSeconds = 1800
......
......@@ -541,6 +541,11 @@ const SYSTEM_DB_UPDATE_AUTO = 'auto';
const SYSTEM_RECORD_LOCK_TIMEOUT_SECONDS = 'recordLockTimeoutSeconds';
const SYSTEM_RECORD_LOCK_TIMEOUT_SECONDS_DEFAULT = 900; // 15 mins
const SYSTEM_SESSION_TIMEOUT_SECONDS = 'sessionTimeoutSeconds';
const SYSTEM_SESSION_TIMEOUT_SECONDS_DEFAULT = 1800; // 30 mins
const SYSTEM_COOKIE_LIFETIME = 259200; // 3 days. Should be more than SYSTEM_SESSION_TIMEOUT_SECONDS_DEFAULT, in case the user setup's a higher value.
// Deprecated, replaced by SYSTEM_FILL_STORE_SYSTEM_BY_SQ
const SYSTEM_VAR_ADD_BY_SQL = 'VAR_ADD_BY_SQL'; // since 1.12.17
......@@ -856,7 +861,8 @@ const F_FORWARD_MODE_URL_SKIP_HISTORY = API_ANSWER_REDIRECT_URL_SKIP_HISTORY;
const F_FORWARD_MODE_URL_SIP = 'url-sip';
// client', 'no', 'url', 'url-skip-history'
const F_RECORD_LOCK_TIMEOUT_SECONDS = 'recordLockTimeoutSeconds';
const F_RECORD_LOCK_TIMEOUT_SECONDS = SYSTEM_RECORD_LOCK_TIMEOUT_SECONDS;
const F_SESSION_TIMEOUT_SECONDS = SYSTEM_SESSION_TIMEOUT_SECONDS;
const F_FE_DATA_PATTERN_ERROR = 'data-pattern-error';
const F_FE_DATA_REQUIRED_ERROR = 'data-required-error';
......@@ -1459,6 +1465,8 @@ const HTML2PDF_PARAM_GET = 'paramGet';
const HTML2PDF_URL_PRINT = 'urlPrint';
const SESSION_COOKIE_PREFEIX = 'qfq.cookie.'; // temporary 'cookie file' to forward `fe_user` and `qfq` session.
const SESSION_LAST_ACTIVITY = 'lastActivity';
const SESSION_LAST_FE_COOKIE = 'lastFeCookie';
// Class: LINK
const PARAM_DELIMITER = '|';
......
......@@ -143,7 +143,7 @@ class QuickFormQuery {
$this->session = Session::getInstance($phpUnit);
// Refresh the session even if no new data saved.
Session::set('LAST_ACTIVITY', time());
Session::set(SESSION_LAST_ACTIVITY, time());
set_error_handler("\\qfq\\ErrorHandler::exception_error_handler");
// PHPExcel
......@@ -360,6 +360,8 @@ class QuickFormQuery {
}
}
Session::checkSessionExpired($this->formSpec[F_SESSION_TIMEOUT_SECONDS]);
if ($formName !== false) {
// Validate only if there is a 'real' form (not a FORM_DELETE with only a tablename).
$sipFound = $this->validateForm($foundInStore, $formMode);
......@@ -1210,6 +1212,7 @@ class QuickFormQuery {
Support::setIfNotSet($formSpec, F_MODE, '');
Support::setIfNotSet($formSpec, F_DB_INDEX, $this->store->getVar(F_DB_INDEX, STORE_SYSTEM));
Support::setIfNotSet($formSpec, F_ENTER_AS_SUBMIT, $this->store->getVar(SYSTEM_ENTER_AS_SUBMIT, STORE_SYSTEM));
Support::setIfNotSet($formSpec, F_SESSION_TIMEOUT_SECONDS, $this->store->getVar(SYSTEM_SESSION_TIMEOUT_SECONDS, STORE_SYSTEM));
// In case there is no F_MODE defined on the form, check if there is one in STORE_SIP.
if ($formSpec[F_MODE] == '') {
......@@ -1374,6 +1377,8 @@ class QuickFormQuery {
*/
private function doReport() {
Session::checkSessionExpired($this->store->getVar(SYSTEM_SESSION_TIMEOUT_SECONDS, STORE_SYSTEM));
$report = new Report($this->t3data, $this->eval, $this->phpUnit);
$html = '';
......
......@@ -1442,8 +1442,7 @@ class Support {
* @param $size_str
* @return float|int|string
*/
public
static function returnBytes($size_str) {
public static function returnBytes($size_str) {
$size_str = trim($size_str);
switch (substr($size_str, -1)) {
......
......@@ -84,6 +84,7 @@ class Config {
*/
public static function readConfig($configIni = '') {
$configT3qfq = array();
$configPhp = '';
// Production Path to CONFIG_INI
$pathTypo3Conf = __DIR__ . '/../../../../..';
......@@ -99,12 +100,12 @@ class Config {
$configT3qfq = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf'][EXT_KEY]);
} else {
$all = include($pathTypo3Conf . '/' . CONFIG_T3);
if(empty($all) || $all===true){
if (empty($all) || $all === true) {
throw new qfq\UserFormException ("Error read file: " . $pathTypo3Conf . '/' . CONFIG_T3, ERROR_IO_READ_FILE);
}
$configT3qfq = unserialize($all['EXT']['extConf'][EXT_KEY]);
if(!is_array($configT3qfq)){
if (!is_array($configT3qfq)) {
throw new qfq\UserFormException ("Error read file: " . $pathTypo3Conf . '/' . CONFIG_T3, ERROR_IO_READ_FILE);
}
unset($all);
......@@ -318,6 +319,8 @@ class Config {
SYSTEM_DB_UPDATE => SYSTEM_DB_UPDATE_AUTO,
SYSTEM_RECORD_LOCK_TIMEOUT_SECONDS => SYSTEM_RECORD_LOCK_TIMEOUT_SECONDS_DEFAULT,
SYSTEM_SESSION_TIMEOUT_SECONDS => SYSTEM_SESSION_TIMEOUT_SECONDS_DEFAULT,
DOCUMENTATION_QFQ => DOCUMENTATION_QFQ_URL,
SYSTEM_ENTER_AS_SUBMIT => 1,
......@@ -382,4 +385,22 @@ class Config {
return $config;
}
/**
* @param $timeout
* @throws UserFormException
*/
public static function checkSessionTimeout($timeout) {
if (ini_get('session.gc_maxlifetime') < $timeout ||
ini_get('session.cookie_lifetime') < $timeout
) {
throw new qfq\UserFormException ("The specified timeout of $timeout seconds is higher than the PHP config 'session.gc_maxlifetime' and/or 'session.cookie_lifetime'");
}
if ($timeout > SYSTEM_COOKIE_LIFETIME) {
throw new qfq\UserFormException ("The specified timeout of $timeout seconds is higher than the hardcoded cookie lifetime.");
}
}
}
\ No newline at end of file
......@@ -20,6 +20,7 @@ class Session {
private static $sessionLocal = array();
private static $sessionId = null;
private static $sessionOpen = false;
private static $lastActivity = false;
/**
* @param bool|false $phpUnit
......@@ -39,7 +40,7 @@ class Session {
} else {
ini_set('session.cookie_httponly', 1);
$lifetime = 86400; // one day
$lifetime = SYSTEM_COOKIE_LIFETIME;
$path = $this->getSitePath();
......@@ -155,12 +156,26 @@ class Session {
$feUserSession = Session::get(SESSION_FE_USER);
$feUserGroup = false;
self::$lastActivity = false; // Session Timeout only exists for logged in FE users - the default is no user logged in, so set to false to switch of session expiration.
if (isset($GLOBALS["TSFE"])) {
// if noone is logged in: 0
// if no one is logged in: 0
$feUidLoggedIn = isset($GLOBALS["TSFE"]->fe_user->user["uid"]) ? $GLOBALS["TSFE"]->fe_user->user["uid"] : false;
$feUserSession = isset($GLOBALS["TSFE"]->fe_user->user["username"]) ? $GLOBALS["TSFE"]->fe_user->user["username"] : false;
$feUserGroup = isset($GLOBALS["TSFE"]->fe_user->user["usergroup"]) ? $GLOBALS["TSFE"]->fe_user->user["usergroup"] : false;
$beUser = isset($GLOBALS["BE_USER"]->user["username"]) ? $GLOBALS["BE_USER"]->user["username"] : false;
if (isset($GLOBALS["TSFE"]->fe_user->user["username"]) && isset($_COOKIE['fe_typo_user'])) {
if ($_COOKIE['fe_typo_user'] == self::get(SESSION_LAST_FE_COOKIE)) {
self::$lastActivity = self::get(SESSION_LAST_ACTIVITY); // ok, still the same user is logged in: get the last activity timestamp.
} else {
// New user: remember user
self::set(SESSION_LAST_FE_COOKIE, $_COOKIE['fe_typo_user']);
self::$lastActivity = time();
}
}
} else {
// If we are called through API there is no T3 environment. Assume nothing has changed, and fake the following check to always 'no change'.
$feUidLoggedIn = $feUserUidSession;
......@@ -196,16 +211,9 @@ class Session {
}
if (self::$phpUnit) {
if (isset(self::$sessionLocal[$key]))
$value = self::$sessionLocal[$key];
else
$value = false;
$value = isset(self::$sessionLocal[$key]) ? self::$sessionLocal[$key] : false;
} else {
if (isset($_SESSION[SESSION_NAME][$key]))
$value = $_SESSION[SESSION_NAME][$key];
else
$value = false;
$value = isset($_SESSION[SESSION_NAME][$key]) ? $_SESSION[SESSION_NAME][$key] : false;
}
return $value;
......@@ -281,4 +289,23 @@ class Session {
return self::$instance;
}
/**
* Checks if the QFQ session is expired.
*
* @param $timeout
* @throws UserFormException
*/
public static function checkSessionExpired($timeout) {
// Just to be sure that the given $timeout is supported by the current php.ini setup
config::checkSessionTimeout($timeout);
if (self::$lastActivity === false || $timeout === false || $timeout == 0) {
return;
}
if (time() - self::$lastActivity > $timeout) {
throw new UserFormException("Your session is expired. Please logout and login again.");
}
}
}
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment