this will be a long one...
I've got a bad case of erratic login failure, due to wrong cookie management. First of all, I'm managing a closed store (B2B) in which customers have to login before they can see the catalog. Every unregistered access gets redirected to the login page, but once in a while the customer can't login even if username and password are correct. I say 'username' because I use Diglin_Username extension and StoreRestricition plugin to achieve the desired behavior. What happens is that sometimes I found two different sets of cookie left by Magento, and they refer to two different domains (.www.abc.com and .abc.com for instance).
After reading this article from the great Alan Storm on early session instantiation, and finding the dreaded PHPSESSID cookie in my browser I investigated in some depth the issue.
What I found is two-faced. First I put a Mage::Log() call in the function start() in Mage_Core_Model_Session_Abstract_Varien class to log the various attempt made by Magento to start a new session and noticed that following the first Mage::run() invocation the preDispatch(), dispatch() and postDispatch() methods of Mage_Core_Controller_Front_Action class get called in the usual sequence but it seems that when postDispatch() executes it can't find the session started by preDispatch() and proceeds to create a new session. To this regard I found a difference in the code between Magento 1.7.x and 1.8.x version and I think that could maybe take care of the issue:
Magento 1.7.x - Mage_Core_Model_Session_Abstract_Varien class:
public function start($sessionName=null)
{
if (isset($_SESSION)) {
return $this;
}
.
.
}
Magento 1.8.x - Mage_Core_Model_Session_Abstract_Varien class:
public function start($sessionName=null)
{
if (isset($_SESSION) && !$this->getSkipEmptySessionCheck()) {
return $this;
}
.
.
}
I just can't find where to set SkipEmptySessionCheck property though, so I ended up patching Mage_Core_Controller_Front_Action class in this way:
public function postDispatch()
{
parent::postDispatch();
if (!$this->getFlag('', self::FLAG_NO_START_SESSION )) {
if (session_id()) {
Mage::getSingleton('core/session')->setLastUrl(Mage::getUrl('*/*/*', array('_current'=>true)));
}
}
return $this;
}
to have postDispatch() not calling Mage::getSingleton('core/session') (that would have created a new session) if it can't find a session already started. So long to the PHPSESSID cookie and all done, I thought...
But not so. Now I got rid of PHPSESSID cookie but still goto two different set of cookies (erratically) saved in the browser. Only deleting the wrong cookies I can successfully login, or I get redirected to the login page without even a message. I tried to state the cookie domain explicitly in the system config but this didn't resolve the issue.
Deep in the codebase again, and I found that in the various places when Magento sets a cookie it takes the domain to use from the function getDomain() in the Mage_Core_Model_Cookie class:
public function getDomain()
{
$domain = $this->getConfigDomain();
if (empty($domain)) {
$domain = $this->_getRequest()->getHttpHost();
}
return $domain;
}
Now, if you look at the page you get from Magento in your browser you can find in the 'head' section something like this:
<script type="text/javascript">
//<![CDATA[
Mage.Cookies.path = '/';
Mage.Cookies.domain = '.www.abc.com';
//]]>
</script>
These lines come from app/design/frontend/base/default/template/page/js/cookie.phtml:
<script type="text/javascript">
//<![CDATA[
Mage.Cookies.path = '<?php echo $this->getPath()?>';
Mage.Cookies.domain = '<?php echo $this->getDomain()?>';
//]]>
</script>
and in turn this code references the getDomain() function in Mage_Page_Block_Js_Cookie class:
public function getDomain()
{
$domain = $this->getCookie()->getDomain();
if (!empty($domain[0]) && ($domain[0] !== '.')) {
$domain = '.'.$domain;
}
return $domain;
}
So if I sets the cookie domain in system config as, for instance, 'www.abc.com' I end up with:
Mage.Cookies.domain = '.www.abc.com'
and finding in my browser both 'www.abc.com' and '.www.abc.com' cookies I thought, "ok, I'll set '.abc.com' in the system config and will always end up with '.abc.com' cookies!!"...
But no way. Now in my HTML page I always get '.abc.com' but nonetheless I still erratically got a 'www.abc.com' cookie and no login.
I'm puzzled, and my customer is starting to think I'm not so good as he thought I was (I'm starting to think that, too...) :(
Do some of you guys (and gals) have some hint?
UPDATE: I've seen someone relating issues with sessions and cookies to the use of Varnish as a cache for Magento. As I'm using Varnish too I'll try if disabling it the issue can be solved.