diff --git a/NEWS.md b/NEWS.md index 70b85b100ff73e7c9e069220e2521bf36db832e0..a36b97df33328b527ee84a51f29c1ef9262ff9d9 100644 --- a/NEWS.md +++ b/NEWS.md @@ -146,6 +146,18 @@ The extension works with the same options as before. Previously $row['cache_data'] was a serialized array. To avoid double serializing and unserializing, from now on $row['cache_data'] is just reconstituted as array when fetching from cache. +* Frontend Cookie now only set when needed, not set by default anymore + +The cookie "fe_typo_user" set in the frontend by each request, is now only +being set if the session data is used via $TSFE->fe_user->setKey('ses') +so it can be used for shopping baskets for non-logged-in users +out-of-the-box without hacking the default behaviour of setting the +cookie. +The previous behaviour always set the "fe_typo_user" cookie, but changed +the session ID on each request, until it was fixated by a user login. +The superfluous option "dontSetCookie" is now ineffective as the cookie +is not set anymore by default. + ### Administration / Customization * Content-length header (TypoScript setting config.enableContentLengthHeader) @@ -191,4 +203,4 @@ Pages and content elements are now categorizable by default. * New menu types The "Special Menus" content element type now offers the possibility to display -a list of categorized pages or content elements. \ No newline at end of file +a list of categorized pages or content elements. diff --git a/typo3/sysext/core/Classes/Authentication/AbstractUserAuthentication.php b/typo3/sysext/core/Classes/Authentication/AbstractUserAuthentication.php index 3ec45b9b79063bf683b0b1c6d7540c051ff4f99a..b97cc41614e8eb05e1c7bf029e02b14ae73d020f 100644 --- a/typo3/sysext/core/Classes/Authentication/AbstractUserAuthentication.php +++ b/typo3/sysext/core/Classes/Authentication/AbstractUserAuthentication.php @@ -274,6 +274,7 @@ abstract class AbstractUserAuthentication { // to come from $_COOKIE). /** * @todo Define visibility + * @deprecated since TYPO3 CMS 6.2, remove two versions later, use $this->isCookieSet() instead */ public $cookieId; @@ -315,12 +316,19 @@ abstract class AbstractUserAuthentication { */ public $forceSetCookie = FALSE; - // Will prevent the setting of the session cookie (takes precedence over forceSetCookie) /** + * Will prevent the setting of the session cookie (takes precedence over forceSetCookie) + * @var bool * @todo Define visibility */ public $dontSetCookie = FALSE; + /** + * is set to know on this current request if a cookie was set + * @var bool + */ + protected $cookieWasSetOnCurrentRequest = FALSE; + // If set, the challenge value will be stored in a session as well so the // server can check that is was not forged. /** @@ -390,10 +398,7 @@ abstract class AbstractUserAuthentication { // $id is set to ses_id if cookie is present. Else set to FALSE, which will start a new session $id = $this->getCookie($this->name); $this->svConfig = $GLOBALS['TYPO3_CONF_VARS']['SVCONF']['auth']; - // If we have a flash client, take the ID from the GP - if (!$id && $GLOBALS['CLIENT']['BROWSER'] == 'flash') { - $id = GeneralUtility::_GP($this->name); - } + // If fallback to get mode.... if (!$id && $this->getFallBack && $this->get_name) { $id = isset($_GET[$this->get_name]) ? GeneralUtility::_GET($this->get_name) : ''; @@ -402,7 +407,7 @@ abstract class AbstractUserAuthentication { } $mode = 'get'; } - $this->cookieId = $id; + // If new session or client tries to fix session... if (!$id || !$this->isExistingSessionRecord($id)) { // New random session-$id is made @@ -470,6 +475,7 @@ abstract class AbstractUserAuthentication { * Sets the session cookie for the current disposal. * * @return void + * @throws \TYPO3\CMS\Core\Exception */ protected function setSessionCookie() { $isSetSessionCookie = $this->isSetSessionCookie(); @@ -489,6 +495,7 @@ abstract class AbstractUserAuthentication { // Do not set cookie if cookieSecure is set to "1" (force HTTPS) and no secure channel is used: if ((int)$settings['cookieSecure'] !== 1 || GeneralUtility::getIndpEnv('TYPO3_SSL')) { setcookie($this->name, $this->id, $cookieExpire, $cookiePath, $cookieDomain, $cookieSecure, $cookieHttpOnly); + $this->cookieWasSetOnCurrentRequest = TRUE; } else { throw new \TYPO3\CMS\Core\Exception('Cookie was not set since HTTPS was forced in $TYPO3_CONF_VARS[SYS][cookieSecure].', 1254325546); } @@ -543,6 +550,7 @@ abstract class AbstractUserAuthentication { * @return string The value stored in the cookie */ protected function getCookie($cookieName) { + $cookieValue = ''; if (isset($_SERVER['HTTP_COOKIE'])) { $cookies = GeneralUtility::trimExplode(';', $_SERVER['HTTP_COOKIE']); foreach ($cookies as $cookie) { @@ -980,6 +988,19 @@ abstract class AbstractUserAuthentication { } } + /** + * Empty / unset the cookie + * + * @param string $cookieName usually, this is $this->name + * @return void + */ + public function removeCookie($cookieName) { + $cookieDomain = $this->getCookieDomain(); + // If no cookie domain is set, use the base path + $cookiePath = $cookieDomain ? '/' : GeneralUtility::getIndpEnv('TYPO3_SITE_PATH'); + setcookie($cookieName, NULL, -1, $cookiePath, $cookieDomain); + } + /** * Determine whether there's an according session record to a given session_id * in the database. Don't care if session record is still valid or not. @@ -996,6 +1017,17 @@ abstract class AbstractUserAuthentication { return $row[0] ? TRUE : FALSE; } + /** + * Returns whether this request is going to set a cookie + * or a cookie was already found in the system + * replaces the old functionality for "$this->cookieId" + * + * @return boolean Returns TRUE if a cookie is set + */ + public function isCookieSet() { + return $this->cookieWasSetOnCurrentRequest || $this->getCookie($this->name); + } + /************************* * * SQL Functions diff --git a/typo3/sysext/core/Configuration/DefaultConfiguration.php b/typo3/sysext/core/Configuration/DefaultConfiguration.php index dea48e1b270898d5f9da6097f71ecde2e37769ad..a9b829dabb67e207f1c32ea036186e11d342eade 100644 --- a/typo3/sysext/core/Configuration/DefaultConfiguration.php +++ b/typo3/sysext/core/Configuration/DefaultConfiguration.php @@ -686,7 +686,6 @@ return array( 'defaultTypoScript_constants.' => array(), // Lines of TS to include after a static template with the uid = the index in the array (Constants) 'defaultTypoScript_setup' => '', // String (textarea). Enter lines of default TypoScript, setup-field. 'defaultTypoScript_setup.' => array(), // Lines of TS to include after a static template with the uid = the index in the array (Setup) - 'dontSetCookie' => FALSE, // Boolean: If set, the no cookies is attempted to be set in the front end. Of course no userlogins are possible either... 'additionalAbsRefPrefixDirectories' => '', // Enter additional directories to be prepended with absRefPrefix. Directories must be comma-separated. TYPO3 already prepends the following directories: media/, typo3conf/ext/, fileadmin/ 'IPmaskMountGroups' => array( // This allows you to specify an array of IPmaskLists/fe_group-uids. If the REMOTE_ADDR of the user matches an IPmaskList, then the given fe_group is add to the gr_list. So this is an automatic mounting of a user-group. But no fe_user is logged in though! This feature is implemented for the default frontend user authentication and might not be implemented for alternative authentication services. // array('IPmaskList_1','fe_group uid'), array('IPmaskList_2','fe_group uid') diff --git a/typo3/sysext/felogin/Classes/Controller/FrontendLoginController.php b/typo3/sysext/felogin/Classes/Controller/FrontendLoginController.php index 17ef8892b1710f8f8266c30fe5d94feb68b447f8..d39a72ca6700fe29d8cee5ad0ee7f75d7d357a27 100644 --- a/typo3/sysext/felogin/Classes/Controller/FrontendLoginController.php +++ b/typo3/sysext/felogin/Classes/Controller/FrontendLoginController.php @@ -180,7 +180,7 @@ class FrontendLoginController extends \TYPO3\CMS\Frontend\Plugin\AbstractPlugin } // Process the redirect if (($this->logintype === 'login' || $this->logintype === 'logout') && $this->redirectUrl && !$this->noRedirect) { - if (!$GLOBALS['TSFE']->fe_user->cookieId) { + if (!$GLOBALS['TSFE']->fe_user->isCookieSet()) { $content .= $this->cObj->stdWrap($this->pi_getLL('cookie_warning', '', TRUE), $this->conf['cookieWarning_stdWrap.']); } else { // Add hook for extra processing before redirect diff --git a/typo3/sysext/frontend/Classes/Authentication/FrontendUserAuthentication.php b/typo3/sysext/frontend/Classes/Authentication/FrontendUserAuthentication.php index 8fa3b2538a54ff74f6f470ada830f8bf597be4ea..95614355ef5c3466c4e63e40493f8340dfaa84b7 100644 --- a/typo3/sysext/frontend/Classes/Authentication/FrontendUserAuthentication.php +++ b/typo3/sysext/frontend/Classes/Authentication/FrontendUserAuthentication.php @@ -113,6 +113,10 @@ class FrontendUserAuthentication extends \TYPO3\CMS\Core\Authentication\Abstract * Default constructor. */ public function __construct() { + // Disable cookie by default, will be activated if saveSessionData() is called, + // a user is logging-in or an existing session is found + $this->dontSetCookie = TRUE; + $this->session_table = 'fe_sessions'; $this->name = self::getCookieName(); $this->get_name = 'ftu'; @@ -239,6 +243,19 @@ class FrontendUserAuthentication extends \TYPO3\CMS\Core\Authentication\Abstract return $loginData; } + /** + * Creates a user session record and returns its values. + * However, as the FE user cookie is normally not set, this has to be done + * before the parent class is doing the rest. + * + * @param array $tempuser User data array + * @return array The session data for the newly created session. + */ + public function createUserSession($tempuser) { + $this->setSessionCookie(); + return parent::createUserSession($tempuser); + } + /** * Will select all fe_groups records that the current fe_user is member of - and which groups are also allowed in the current domain. * It also accumulates the TSconfig for the fe_user/fe_groups in ->TSdataArray @@ -396,6 +413,10 @@ class FrontendUserAuthentication extends \TYPO3\CMS\Core\Authentication\Abstract if (empty($this->sesData)) { // Remove session-data $this->removeSessionData(); + // Remove cookie if not logged in as the session data is removed as well + if (!empty($this->user['uid'])) { + $this->removeCookie($this->name); + } } elseif ($this->sessionDataTimestamp === NULL) { // Write new session-data $insertFields = array( @@ -405,6 +426,8 @@ class FrontendUserAuthentication extends \TYPO3\CMS\Core\Authentication\Abstract ); $this->sessionDataTimestamp = $GLOBALS['EXEC_TIME']; $GLOBALS['TYPO3_DB']->exec_INSERTquery('fe_session_data', $insertFields); + // Now set the cookie (= fix the session) + $this->setSessionCookie(); } else { // Update session data $updateFields = array( @@ -426,6 +449,20 @@ class FrontendUserAuthentication extends \TYPO3\CMS\Core\Authentication\Abstract $GLOBALS['TYPO3_DB']->exec_DELETEquery('fe_session_data', 'hash=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($this->id, 'fe_session_data')); } + /** + * Log out current user! + * Removes the current session record, sets the internal ->user array to a blank string + * Thereby the current user (if any) is effectively logged out! + * Additionally the cookie is removed + * + * @return void + */ + public function logoff() { + parent::logoff(); + // Remove the cookie on log-off + $this->removeCookie($this->name); + } + /** * Executes the garbage collection of session data and session. * The lifetime of session data is defined by $TYPO3_CONF_VARS['FE']['sessionDataLifetime']. @@ -532,10 +569,10 @@ class FrontendUserAuthentication extends \TYPO3\CMS\Core\Authentication\Abstract * @todo Define visibility */ public function record_registration($recs, $maxSizeOfSessionData = 0) { - // Storing value ONLY if there is a confirmed cookie set (->cookieID), + // Storing value ONLY if there is a confirmed cookie set, // otherwise a shellscript could easily be spamming the fe_sessions table // with bogus content and thus bloat the database - if (!$maxSizeOfSessionData || $this->cookieId) { + if (!$maxSizeOfSessionData || $this->isCookieSet()) { if ($recs['clear_all']) { $this->setKey('ses', 'recs', array()); } diff --git a/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php b/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php index 2ce01170f332a2bbb09e21966767b6ebdcb52d14..6b6d3c66c552d7651057af9a0bde50747f013dfe 100644 --- a/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php +++ b/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php @@ -929,9 +929,6 @@ class TypoScriptFrontendController { unset($cookieName); } } - if ($this->TYPO3_CONF_VARS['FE']['dontSetCookie']) { - $this->fe_user->dontSetCookie = 1; - } $this->fe_user->start(); $this->fe_user->unpack_uc(''); // Gets session data diff --git a/typo3/sysext/install/Classes/Service/SilentConfigurationUpgradeService.php b/typo3/sysext/install/Classes/Service/SilentConfigurationUpgradeService.php index f62e39810b73ae012fe43a6462d8e11a25327b79..1c34c57d8d566fef6b0ffcedc9b37e4ed28c4fda 100644 --- a/typo3/sysext/install/Classes/Service/SilentConfigurationUpgradeService.php +++ b/typo3/sysext/install/Classes/Service/SilentConfigurationUpgradeService.php @@ -86,6 +86,8 @@ class SilentConfigurationUpgradeService { 'FE/simulateStaticDocuments', // #52786 'FE/logfile_dir', + // #55549 + 'FE/dontSetCookie', // #52011 'GFX/im_combine_filename', // #52088