[SOLVED]The identity cookie

I have a domain, say www.domain.com and a module for it’s forum pointing to forum.domain.com

I need to share the cookies for domain.com so that they are availabe for *.domain.com and in order to do this, i had to do it in 3 base classes (so far).

The components who will accept cookie params are:

  • CDbHttpSession - this is responsable with the session cookie.

  • CWebUser - this sets the identity cookie

  • CHttpRequest - this sets the CSRF Token

I decided to set the cookie params inside the classes just because i had them extended already, so instead of passing the params in the main.php configuration file, i did it in the init() method of the classes as follows:




class CmsCDbHttpSession extends CDbHttpSession{

    [...]

    public function init()

    {

        $this->setCookieParams(Yii::app()->settings->get('system', 'cookieSettings'));

        parent::init();

    }

    [...]

}




class CmsCWebUser extends CWebUser{

    [...]

    public function init()

    {

        $this->identityCookie=Yii::app()->settings->get('system', 'cookieSettings');

        parent::init();

    }

    [...]

}




class CmsCHttpRequest extends CHttpRequest{


    [...]

    public function init()

    {

        $this->csrfCookie=Yii::app()->settings->get('system', 'cookieSettings');

        parent::init();

    }

    [...]

}



The Yii::app()->settings->get(‘system’, ‘cookieSettings’); call returns an array like:




array(

  'domain'   => '.domain.com',

  'expire'   => 0,

  'path'     => '/',

);



Everything works perfectly till this moment, auto-login is enabled, the users have same cookies on all subdomains of the domain.com, when they close the browser and come back, they are logged in automatically etc.

The problem arise when they edit their profile.

Because they can change their username, which is also stored in the cookie, i need to update the identity cookie as well but i fail everytime.

I looked over the forums to see a solution but nothing.

Here is what i tried, please follow the comments:





Yii::app()->user->setName($model->username);

//Everything went okay, update the identity cookie:

if(Yii::app()->user->allowAutoLogin)

{

    //identity cookie update.

    $cookie=Yii::app()->request->getCookies()->itemAt(Yii::app()->user->getStateKeyPrefix());

    if($cookie && !empty($cookie->value) && ($data=Yii::app()->securityManager->validateData($cookie->value))!==false)

    {

        $data=@unserialize($data);

        if(is_array($data) && isset($data[0],$data[1],$data[2],$data[3]))

        {

            list($id,$name,$duration,$states)=$data;

            $data[1]=$model->username;//the __name atribute[@link CWebUser::restoreFromCookie()]

            $cookie->value=Yii::app()->securityManager->hashData(serialize($data));

            //In this moment, if i call getCookies()->add() it will put the cookie but with the class default options, like domain=>'', etc.

            //So i have to get the cookie settings again and set them manually, like follows: 

            $cookieSettings=Yii::app()->settings->get('system', 'cookieSettings');

            if(is_array($cookieSettings))

            {

                foreach($cookieSettings AS $key=>$value)

                    $cookie->$key=$value;

            }

            Yii::app()->request->getCookies()->add($cookie->name,$cookie);

        }

    }

}



As you see, the problem is that when i get the identity cookie, it doesn’t have my settings in it, which i set in the init() method of the CWebUser class, so i have to get() and add() the settings once again.

If i do like in the above example, everything works fine, with ONE exception, if i close the browser and come back again, the auto-login process is DEAD, i believe somehow the cookie data becomes tampered.

[b]So, the big question IS:

How we suppose to update that darn identity cookie ?

Also very important:

Is there a better approach to use same cookie settings for all the components like in my case ? [/b]

Interesting enough, after i am logged in and try to get the details for the identity cookie like:




$cookie=Yii::app()->request->getCookies()->itemAt(Yii::app()->user->getStateKeyPrefix());

            if($cookie && !empty($cookie->value) && ($data=Yii::app()->securityManager->validateData($cookie->value))!==false)

            {

                echo $cookie->name.'<br />';//prints okay

                echo $cookie->domain.'<br />';// prints nothing

            }	



But if i do a




print_r(Yii::app()->user->identityCookie);



I get




Array ( [domain] => .domain.com [path] => / [expire] => 0 )



This happens even if i set the cookie params from the init() method or from the configuration file, same result.

So, what am i missing here ?

Okay, i deserve a big slap over my head for not being careful enough.

This is the correct approach:




Yii::app()->user->setName($model->username);

            

if(Yii::app()->user->allowAutoLogin)

{

	//identity cookie update.

	$cookie=Yii::app()->request->getCookies()->itemAt(Yii::app()->user->getStateKeyPrefix());

	if($cookie && !empty($cookie->value) && ($data=Yii::app()->securityManager->validateData($cookie->value))!==false)

	{

		$data=@unserialize($data);

		if(is_array($data) && isset($data[0],$data[1],$data[2],$data[3]))

		{

			//list($id,$name,$duration,$states)=$data;

			$data[1]=$model->username;//the __name atribute[@link CWebUser::restoreFromCookie()]

			$cookie->value=Yii::app()->securityManager->hashData(serialize($data));

			$cookieSettings=Yii::app()->settings->get('system', 'cookieSettings');

			if(is_array($cookieSettings))

			{

				$cookieSettings['expire']=time() + 3600*24*30; // i was missing this.

				foreach($cookieSettings AS $key=>$value)

					$cookie->$key=$value;

			}

			Yii::app()->request->getCookies()->add($cookie->name,$cookie);

		}

	}

}



Works like a charm :)