Manage the session timeout automatically
authorTim Düsterhus <duesterhus@woltlab.com>
Mon, 5 Oct 2020 10:11:05 +0000 (12:11 +0200)
committerTim Düsterhus <duesterhus@woltlab.com>
Thu, 15 Oct 2020 14:13:52 +0000 (16:13 +0200)
com.woltlab.wcf/option.xml
constants.php
wcfsetup/install/files/lib/data/acp/session/ACPSessionEditor.class.php
wcfsetup/install/files/lib/data/acp/session/log/ACPSessionLog.class.php
wcfsetup/install/files/lib/system/WCF.class.php
wcfsetup/install/files/lib/system/cronjob/SessionCleanUpCronjob.class.php
wcfsetup/install/files/lib/system/event/listener/SessionAccessLogListener.class.php
wcfsetup/install/files/lib/system/session/SessionHandler.class.php
wcfsetup/install/files/options.inc.php
wcfsetup/install/lang/de.xml
wcfsetup/install/lang/en.xml

index 333f11291991979081608b22ae595f1e945fe5c8..cdac9ddef222cd8790916a7ca5e1e57616e5434e 100644 (file)
@@ -623,19 +623,12 @@ private:wcf.acp.option.exception_privacy.private</selectoptions>
                        </option>
                        <!-- /general.system.proxy -->
                        <!-- security.general.session -->
-                       <option name="session_timeout">
-                               <categoryname>security.general.session</categoryname>
-                               <optiontype>integer</optiontype>
-                               <defaultvalue>1800</defaultvalue>
-                               <minvalue>600</minvalue>
-                               <maxvalue>86400</maxvalue>
-                               <suffix>seconds</suffix>
-                       </option>
                        <option name="user_online_timeout">
                                <categoryname>security.general.session</categoryname>
                                <optiontype>integer</optiontype>
                                <defaultvalue>900</defaultvalue>
                                <minvalue>1</minvalue>
+                               <maxvalue>7200</maxvalue>
                                <suffix>seconds</suffix>
                        </option>
                        <!-- /security.general.session -->
index 0f82d8020c3e53ed403cccac6baae42cc44efb13..58157cb8c4bbf9aacea904efa7c3663f241879bd 100644 (file)
@@ -71,7 +71,6 @@ define('HTTP_SEND_X_FRAME_OPTIONS', 1);
 define('HTTP_ENABLE_GZIP', 1);
 define('PACKAGE_SERVER_AUTH_CODE', '');
 define('PROXY_SERVER_HTTP', '');
-define('SESSION_TIMEOUT', 1800);
 define('IP_ADDRESS_SEARCH_ENGINE', '');
 define('USER_ONLINE_TIMEOUT', 900);
 define('ENABLE_USER_AUTHENTICATION_FAILURE', 1);
index 72122872724f5009aa382d15e7b5db110d087911..e8b7eb76f6482f2fbf09ff0bb0e3f26d37d0e8ec 100644 (file)
@@ -2,6 +2,7 @@
 namespace wcf\data\acp\session;
 use wcf\data\DatabaseObjectEditor;
 use wcf\system\database\util\PreparedStatementConditionBuilder;
+use wcf\system\session\SessionHandler;
 use wcf\system\WCF;
 
 /**
@@ -46,9 +47,7 @@ class ACPSessionEditor extends DatabaseObjectEditor {
        }
        
        /**
-        * Deletes active sessions of the given users.
-        * 
-        * @param       integer[]       $userIDs
+        * @deprecated 5.4 - Sessions are managed via the SessionHandler.
         */
        public static function deleteUserSessions(array $userIDs = []) {
                $conditionBuilder = new PreparedStatementConditionBuilder();
@@ -63,14 +62,9 @@ class ACPSessionEditor extends DatabaseObjectEditor {
        }
        
        /**
-        * Deletes the expired sessions.
-        * 
-        * @param       integer         $timestamp
+        * @deprecated 5.4 - Sessions are managed via the SessionHandler.
         */
        public static function deleteExpiredSessions($timestamp) {
-               $sql = "DELETE FROM     ".call_user_func([static::$baseClass, 'getDatabaseTableName'])."
-                       WHERE           lastActivityTime < ?";
-               $statement = WCF::getDB()->prepareStatement($sql);
-               $statement->execute([$timestamp]);
+               SessionHandler::getInstance()->prune();
        }
 }
index 27dfbb5f85f87c907386ece42bbe1790a7661189..d47fb97ba4e715cbe80e62d9adebc7fe0fc2bc8f 100644 (file)
@@ -58,11 +58,7 @@ class ACPSessionLog extends DatabaseObject {
         * @return      boolean
         */
        public function isActive() {
-               if ($this->active && $this->lastActivityTime > TIME_NOW - SESSION_TIMEOUT) {
-                       return 1;
-               }
-               
-               return 0;
+               return $this->active ? true : false;
        }
        
        /**
index 6f412d7e544008833be61e0095226100e659d342..6c04c86fea3f136aed209e26fea75074a706a902 100644 (file)
@@ -396,6 +396,9 @@ class WCF {
                // Virtual sessions no longer exist since 5.4.
                define('SESSION_ENABLE_VIRTUALIZATION', 1);
                
+               // The session timeout is fully managed since 5.4.
+               define('SESSION_TIMEOUT', 3600);
+               
                $filename = WCF_DIR.'options.inc.php';
                
                // create options file if doesn't exist
@@ -590,8 +593,8 @@ class WCF {
                                $application->__run();
                        }
                        
-                       // refresh the session 1 minute before it expires
-                       self::getTPL()->assign('__sessionKeepAlive', SESSION_TIMEOUT - 60);
+                       // TODO: Check this
+                       self::getTPL()->assign('__sessionKeepAlive', 60 * 50);
                }
        }
        
index dcca6020154f17bc43bffd23a34e9fa2c0cdc9c3..3de3118da7601f7285e55d77686bd2a8ed249132 100644 (file)
@@ -1,14 +1,13 @@
 <?php
 namespace wcf\system\cronjob;
-use wcf\data\acp\session\ACPSessionEditor;
 use wcf\data\cronjob\Cronjob;
-use wcf\data\session\SessionEditor;
+use wcf\system\session\SessionHandler;
 
 /**
  * Deletes expired sessions.
  * 
- * @author     Marcel Werk
- * @copyright  2001-2019 WoltLab GmbH
+ * @author     Tim Duesterhus Marcel Werk
+ * @copyright  2001-2020 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\System\Cronjob
  */
@@ -19,11 +18,6 @@ class SessionCleanUpCronjob extends AbstractCronjob {
        public function execute(Cronjob $cronjob) {
                parent::execute($cronjob);
                
-               // Prevent the sessions from expiring while the development mode is active.
-               if (!ENABLE_DEBUG_MODE || !ENABLE_DEVELOPER_TOOLS) {
-                       ACPSessionEditor::deleteExpiredSessions(TIME_NOW - SESSION_TIMEOUT);
-               }
-               
-               SessionEditor::deleteExpiredSessions(TIME_NOW - SESSION_TIMEOUT);
+               SessionHandler::getInstance()->prune();
        }
 }
index 0668f1dcda8276fcf57fbd8337775c3f3849c7ed..775b1c5fd50ab64057dfae5b00d32984b6bd76fd 100644 (file)
@@ -23,12 +23,10 @@ class SessionAccessLogListener implements IParameterizedEventListener {
                        // try to find existing session log
                        $sql = "SELECT  sessionLogID
                                FROM    wcf".WCF_N."_acp_session_log
-                               WHERE   sessionID = ?
-                                       AND lastActivityTime >= ?";
+                               WHERE   sessionID = ?";
                        $statement = WCF::getDB()->prepareStatement($sql);
                        $statement->execute([
                                WCF::getSession()->sessionID,
-                               TIME_NOW - SESSION_TIMEOUT
                        ]);
                        $row = $statement->fetchArray();
                        if (!empty($row['sessionLogID'])) {
index afbb1582b808abdcdbb65cd901c03570ff965f9b..b725329c307ec4c4132e74cb66734628e070ef3d 100644 (file)
@@ -153,6 +153,10 @@ final class SessionHandler extends SingletonFactory {
         */
        protected $usersOnlyPermissions = [];
        
+       private const ACP_SESSION_LIFETIME = 7200;
+       private const GUEST_SESSION_LIFETIME = 7200;
+       private const USER_SESSION_LIFETIME = 86400 * 14;
+       
        /**
         * Provides access to session data.
         * 
@@ -384,6 +388,15 @@ final class SessionHandler extends SingletonFactory {
                        return false;
                }
                
+               // Check whether the session technically already expired.
+               $lifetime =
+                       ($this->isACP   ? self::ACP_SESSION_LIFETIME  :
+                       ($row['userID'] ? self::USER_SESSION_LIFETIME :
+                       (                 self::GUEST_SESSION_LIFETIME)));
+               if ($row['lastActivityTime'] < (TIME_NOW - $lifetime)) {
+                       return false;
+               }
+               
                $variables = @unserialize($row['sessionVariables']);
                // Check whether the session variables became corrupted.
                if (!is_array($variables)) {
@@ -776,6 +789,38 @@ final class SessionHandler extends SingletonFactory {
                }
        }
        
+       /**
+        * Prunes expired sessions.
+        */
+       public function prune() {
+               // Prevent the sessions from expiring while the development mode is active.
+               if (!ENABLE_DEBUG_MODE || !ENABLE_DEVELOPER_TOOLS) {
+                       $sql = "DELETE FROM     wcf".WCF_N."_user_session
+                               WHERE           lastActivityTime < ?";
+                       $statement = WCF::getDB()->prepareStatement($sql);
+                       $statement->execute([
+                               TIME_NOW - self::ACP_SESSION_LIFETIME,
+                       ]);
+               }
+               
+               $sql = "DELETE FROM     wcf".WCF_N."_user_session
+                       WHERE           (lastActivityTime < ? AND userID IS NULL)
+                               OR      (lastActivityTime < ? AND userID IS NOT NULL)";
+               $statement = WCF::getDB()->prepareStatement($sql);
+               $statement->execute([
+                       TIME_NOW - self::GUEST_SESSION_LIFETIME,
+                       TIME_NOW - self::USER_SESSION_LIFETIME,
+               ]);
+               
+               // Legacy sessions live 120 minutes, they will be re-created on demand.
+               $sql = "DELETE FROM     wcf".WCF_N."_session
+                       WHERE           lastActivityTime < ?";
+               $statement = WCF::getDB()->prepareStatement($sql);
+               $statement->execute([
+                       TIME_NOW - (3600 * 2),
+               ]);
+       }
+       
        /**
         * Deletes this session if:
         * - it is newly created in this request, and
index 66492065e2b6895da6ed838354ce127ea5f8f119..43dd6014a60db690c677616cb29fd9c544e919a4 100644 (file)
@@ -26,8 +26,6 @@ define('BLACKLIST_IP_ADDRESSES', '');
 define('BLACKLIST_USER_AGENTS', '');
 define('BLACKLIST_HOSTNAMES', '');
 
-define('SESSION_TIMEOUT', 3600);
-
 define('CACHE_SOURCE_TYPE', 'disk');
 define('IMAGE_ADAPTER_TYPE', 'gd');
 define('MODULE_MASTER_PASSWORD', 0);
index 82634fd71533d282b4f99e2b99779aaf05de8d44..1000600437815b6a871f9d2f4a4cafbacdcea324 100644 (file)
@@ -1366,8 +1366,6 @@ ACHTUNG: Die oben genannten Meldungen sind stark gekürzt. Sie können Details z
                <item name="wcf.acp.option.page_description"><![CDATA[Seitenbeschreibung]]></item>
                <item name="wcf.acp.option.page_title"><![CDATA[Titel der Seite]]></item>
                <item name="wcf.acp.option.proxy_server_http"><![CDATA[Proxy-Server (HTTP)]]></item>
-               <item name="wcf.acp.option.session_timeout"><![CDATA[Gültigkeitslänge einer Sitzung]]></item>
-               <item name="wcf.acp.option.session_timeout.description"/>
                <item name="wcf.acp.option.timezone"><![CDATA[Zeitzone]]></item>
                <item name="wcf.acp.option.timezone.description"><![CDATA[Standard-Zeitzone {if LANGUAGE_USE_INFORMAL_VARIANT}deiner{else}Ihrer{/if} Seite]]></item>
                <item name="wcf.acp.option.ip_address_search_engine"><![CDATA[Suchmaschine für IP-Adressen]]></item>
index b25e06dbbe80440871b073f3e95d202929977a6a..614b8c385cc0e074da3f26b69f55d3b31eda53e5 100644 (file)
@@ -1343,8 +1343,6 @@ ATTENTION: The messages listed above are greatly shortened. You can view details
                <item name="wcf.acp.option.page_description"><![CDATA[Page Description]]></item>
                <item name="wcf.acp.option.page_title"><![CDATA[Page Title]]></item>
                <item name="wcf.acp.option.proxy_server_http"><![CDATA[Proxy-Server (HTTP)]]></item>
-               <item name="wcf.acp.option.session_timeout"><![CDATA[User Session Timeout]]></item>
-               <item name="wcf.acp.option.session_timeout.description"><![CDATA[User sessions expire after the following seconds.]]></item>
                <item name="wcf.acp.option.timezone"><![CDATA[Timezone]]></item>
                <item name="wcf.acp.option.timezone.description"><![CDATA[The default timezone of your page.]]></item>
                <item name="wcf.acp.option.ip_address_search_engine"><![CDATA[Search Engine for IP Addresses]]></item>