Skip to content

Commit

Permalink
Avoid session invalidation when changing session lifetime.
Browse files Browse the repository at this point in the history
  • Loading branch information
colinmollenhour committed May 22, 2019
1 parent 9f9a99b commit 17b744d
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 34 deletions.
52 changes: 27 additions & 25 deletions app/code/core/Mage/Core/Model/Session/Abstract/Varien.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ class Mage_Core_Model_Session_Abstract_Varien extends Varien_Object
const VALIDATOR_HTTP_X_FORVARDED_FOR_KEY = 'http_x_forwarded_for';
const VALIDATOR_HTTP_VIA_KEY = 'http_via';
const VALIDATOR_REMOTE_ADDR_KEY = 'remote_addr';
const VALIDATOR_SESSION_EXPIRE_TIMESTAMP = 'session_expire_timestamp';
const VALIDATOR_SESSION_RENEW_TIMESTAMP = 'session_renew_timestamp';
const VALIDATOR_SESSION_LIFETIME = 'session_lifetime';
const VALIDATOR_PASSWORD_CREATE_TIMESTAMP = 'password_create_timestamp';
const SECURE_COOKIE_CHECK_KEY = '_secure_cookie_check';

Expand Down Expand Up @@ -136,33 +137,34 @@ public function start($sessionName=null)

session_start();

Mage::dispatchEvent('session_before_renew_cookie', ['cookie' => $cookie]);

if (Mage::app()->getFrontController()->getRequest()->isSecure() && empty($cookieParams['secure'])) {
// secure cookie check to prevent MITM attack
$secureCookieName = $sessionName . '_cid';
if (isset($_SESSION[self::SECURE_COOKIE_CHECK_KEY])) {
if ($_SESSION[self::SECURE_COOKIE_CHECK_KEY] !== md5($cookie->get($secureCookieName))) {
session_regenerate_id(false);
$sessionHosts = $this->getSessionHosts();
$currentCookieDomain = $cookie->getDomain();
foreach (array_keys($sessionHosts) as $host) {
// Delete cookies with the same name for parent domains
if (strpos($currentCookieDomain, $host) > 0) {
$cookie->delete($this->getSessionName(), null, $host);
}
$secureCookieName = session_name() . '_cid';
if (isset($_SESSION[self::SECURE_COOKIE_CHECK_KEY])
&& $_SESSION[self::SECURE_COOKIE_CHECK_KEY] !== md5($cookie->get($secureCookieName))
) {
session_regenerate_id(false);
$sessionHosts = $this->getSessionHosts();
$currentCookieDomain = $cookie->getDomain();
foreach (array_keys($sessionHosts) as $host) {
// Delete cookies with the same name for parent domains
if (strpos($currentCookieDomain, $host) > 0) {
$cookie->delete($this->getSessionName(), null, $host);
}
$_SESSION = array();
} else {
/**
* Renew secure cookie expiration time if secure id did not change
*/
$cookie->renew($secureCookieName, null, null, null, true, true);
}
$_SESSION = array();
}
if (!isset($_SESSION[self::SECURE_COOKIE_CHECK_KEY])) {
$checkId = Mage::helper('core')->getRandomString(16);
$cookie->set($secureCookieName, $checkId, null, null, null, true, true);
$_SESSION[self::SECURE_COOKIE_CHECK_KEY] = md5($checkId);
}
// renew secure cookie
else if ($cookie->get($secureCookieName)) {
$cookie->renew($secureCookieName, null, null, null, true, true);
}
}

/**
Expand Down Expand Up @@ -441,7 +443,8 @@ public function validate()

// Refresh expire timestamp
if ($this->useValidateSessionExpire()) {
$_SESSION[self::VALIDATOR_KEY][self::VALIDATOR_SESSION_EXPIRE_TIMESTAMP] = time() + $this->getCookie()->getLifetime();
$_SESSION[self::VALIDATOR_KEY][self::VALIDATOR_SESSION_RENEW_TIMESTAMP] = time();
$_SESSION[self::VALIDATOR_KEY][self::VALIDATOR_SESSION_LIFETIME] = $this->getCookie()->getLifetime();
}
}

Expand Down Expand Up @@ -485,15 +488,16 @@ protected function _validate()
}

if ($this->useValidateSessionExpire()
&& isset($sessionData[self::VALIDATOR_SESSION_EXPIRE_TIMESTAMP])
&& $sessionData[self::VALIDATOR_SESSION_EXPIRE_TIMESTAMP] < time() ) {
&& isset($sessionData[self::VALIDATOR_SESSION_RENEW_TIMESTAMP])
&& isset($sessionData[self::VALIDATOR_SESSION_LIFETIME])
&& $sessionData[self::VALIDATOR_SESSION_RENEW_TIMESTAMP] + $sessionData[self::VALIDATOR_SESSION_LIFETIME] < time() ) {
return false;
}
if ($this->useValidateSessionPasswordTimestamp()
&& isset($validatorData[self::VALIDATOR_PASSWORD_CREATE_TIMESTAMP])
&& isset($sessionData[self::VALIDATOR_SESSION_EXPIRE_TIMESTAMP])
&& isset($sessionData[self::VALIDATOR_SESSION_RENEW_TIMESTAMP])
&& $validatorData[self::VALIDATOR_PASSWORD_CREATE_TIMESTAMP]
> $sessionData[self::VALIDATOR_SESSION_EXPIRE_TIMESTAMP] - $this->getCookie()->getLifetime()
> $sessionData[self::VALIDATOR_SESSION_RENEW_TIMESTAMP]
) {
return false;
}
Expand Down Expand Up @@ -531,8 +535,6 @@ public function getValidatorData()
$parts[self::VALIDATOR_HTTP_USER_AGENT_KEY] = (string)$_SERVER['HTTP_USER_AGENT'];
}

$parts[self::VALIDATOR_SESSION_EXPIRE_TIMESTAMP] = time() + $this->getCookie()->getLifetime();

if (isset($this->_data['visitor_data']['customer_id'])) {
$parts[self::VALIDATOR_PASSWORD_CREATE_TIMESTAMP] =
Mage::helper('customer')->getPasswordTimestamp($this->_data['visitor_data']['customer_id']);
Expand Down
8 changes: 1 addition & 7 deletions app/code/core/Mage/Customer/Helper/Data.php
Original file line number Diff line number Diff line change
Expand Up @@ -741,13 +741,7 @@ public function getVatValidationUserMessage($customerAddress, $customerGroupAuto
*/
public function getPasswordTimestamp($customerId)
{
/** @var $customer Mage_Customer_Model_Customer */
$customer = Mage::getModel('customer/customer')
->setWebsiteId(Mage::app()->getStore()->getWebsiteId())
->load((int)$customerId);
$passwordCreatedAt = $customer->getPasswordCreatedAt();

return is_null($passwordCreatedAt) ? $customer->getCreatedAtTimestamp() : $passwordCreatedAt;
return Mage::getResourceModel('customer/customer')->getPasswordTimestamp($customerId);
}

/**
Expand Down
22 changes: 21 additions & 1 deletion app/code/core/Mage/Customer/Model/Resource/Customer.php
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,8 @@ public function setNewIncrementId(Varien_Object $object)
* @param string $newResetPasswordLinkToken
* @return $this
*/
public function changeResetPasswordLinkToken(Mage_Customer_Model_Customer $customer, $newResetPasswordLinkToken) {
public function changeResetPasswordLinkToken(Mage_Customer_Model_Customer $customer, $newResetPasswordLinkToken)
{
if (is_string($newResetPasswordLinkToken) && !empty($newResetPasswordLinkToken)) {
$customer->setRpToken($newResetPasswordLinkToken);
$currentDate = Varien_Date::now();
Expand Down Expand Up @@ -354,4 +355,23 @@ public function changeResetPasswordLinkCustomerId(
}
return $this;
}

/**
* Get password created at timestamp for a customer by id
*
* @param int $customerId
* @return string
*/
public function getPasswordTimestamp($customerId)
{
$field = $this->_getReadAdapter()->getIfNullSql('password_created_at', 'created_at');
$select = $this->_getReadAdapter()->select()
->from($this->getEntityTable(), ['password_created_at' => $field])
->where($this->getEntityIdField() . ' =?', $customerId);
$value = $this->_getReadAdapter()->fetchOne($select);
if ($value && ! is_numeric($value)) { // Convert created_at string to unix timestamp
$value = Varien_Date::toTimestamp($value);
}
return $value;
}
}
2 changes: 1 addition & 1 deletion lib/Varien/Date.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ protected static function _convert($value, $dictionary)
public static function toTimestamp($date)
{
if ($date instanceof Zend_Date) {
return $date->getUnixTimestamp();
return $date->getTimestamp();
}

if ($date === true) {
Expand Down

0 comments on commit 17b744d

Please sign in to comment.