Login issues: password not authenticating

My login page isn’t working. The error must be coming from the password encryption or authentication.

I modified the error code on the login page to tell me whether the username or the password generated the error.

It says username when I enter an invalid username and it tells me password when the password doesn’t authenticate.

Here is my code, if you could help me track down my problem.

UserIdentity:




class UserIdentity extends CUserIdentity

{

	private $_id;

    public function authenticate()

	{

		$user=User::model()->findByAttributes(array('username'=>$this->username));

		if($user===null)

		{

		$this->errorCode=self::ERROR_USERNAME_INVALID;

		}

		else	

		{

			if($user->password!==$user->encrypt($this->password))

			{

				$this->errorCode=self::ERROR_PASSWORD_INVALID;

			}

			else

			{

				$this->_id = $user->id;

				$this->errorCode=self::ERROR_NONE;

			}

		}

		return !$this->errorCode;

	}

 

    public function getId()

    {

        return $this->_id;

    }

}



LoginForm (the authenticate and login methods to keep length down):




	public function authenticate($attribute,$params)

	{

		if(!$this->hasErrors())

		{

			$this->_identity=new UserIdentity($this->username,$this->password);

			if(!$this->_identity->authenticate())

			{

				if($this->_identity->errorCode === UserIdentity::ERROR_USERNAME_INVALID){$error = "username";}

				if($this->_identity->errorCode === UserIdentity::ERROR_PASSWORD_INVALID){$error = "password";}

				$this->addError('password', "$error is invalid");

			}

		}

	}


        public function login()

	{

		if($this->_identity===null)

		{

			$this->_identity=new UserIdentity($this->username,$this->password);

			$this->_identity->authenticate();

		}

		if($this->_identity->errorCode===UserIdentity::ERROR_NONE)

		{

			$duration=$this->rememberMe ? 3600*24*30 : 0; // 30 days

			Yii::app()->user->login($this->_identity,$duration);

			return true;

		}

		else

			return false;

	}	



[b]

the login view:[/b]




<div class="form">

<?php $form=$this->beginWidget('CActiveForm', array(

	'id'=>'login-form',

	'enableClientValidation'=>true,

	'clientOptions'=>array(

		'validateOnSubmit'=>true,

	),

)); ?>


	<p class="note">Fields with <span class="required">*</span> are required.</p>


	<div class="row">

		<?php echo $form->labelEx($model,'email'); ?>

		<?php echo $form->textField($model,'username'); ?>

		<?php echo $form->error($model,'username'); ?>

	</div>


	<div class="row">

		<?php echo $form->labelEx($model,'password'); ?>

		<?php echo $form->passwordField($model,'password'); ?>

		<?php echo $form->error($model,'password'); ?>

		

	</div>


	<div class="row rememberMe">

		<?php echo $form->checkBox($model,'rememberMe'); ?>

		<?php echo $form->label($model,'rememberMe'); ?>

		<?php echo $form->error($model,'rememberMe'); ?>

	</div>


	<div class="row buttons">

		<?php echo CHtml::submitButton('Login'); ?>

	</div>


<?php $this->endWidget(); ?>

</div><!-- form -->



User model: (just the afterValidate and encrypt methods)




	protected function afterValidate()

	{

		parent::afterValidate();

		$this->password = $this->encrypt($this->password);              

	}

	public function encrypt($value)

	{

		return sha1($value);

	}



If there is code you need to see that I neglected to add please let me know.

This has me stumped right now.


ok so to track down the error, I made the encrypt method return the raw value.

The login works fine after that with a new user created that has a raw password stored.

This means the error is with the encryption. I have tried sha1 and md5 and neither have worked.

Have you tried dumping the two passwords in UserIdentity to see if the are the same?

They are not the same because the output tells me the password is the field that doesnt authenticate.

I dont know how exactly to dump the outputs. how can I dump the two values?

As my edit to the original post said, I can disable the actual encryption(by making encrypt() return the raw value) and everything works fine, so for some reason the md5 and sha1 commands are not doing what they are supposed to.




// UserIdentity

...

else

{

   // output here the passwords; be sure that at least one log route is enabled!

   Yii::log('encrypted db password: '.$user->password,'trace');

   Yii::log('input password: '.$this->password.' / encrypted: '.$user->encrypt($this->password),'trace');

   if($user->password!==$user->encrypt($this->password))

   {

	$this->errorCode=self::ERROR_PASSWORD_INVALID;

   }

   else

...



so here is the dump of the vars:

2011/06/10 02:34:40 encrypted db password: fb469d7ef430b0baf0cab6c436e70375

2011/06/10 02:34:40 input password: test / encrypted: 098f6bcd4621d373cade4e832627b4f6

in messing around with things, I changed the encrypt back to md5. (yes I created a new user to test after I changed the encrypt function);

Can anyone help me figure out why the encrypt method isn’t working properly?

I don’t think the encrypt method is not working properly instead it is sure that you don’t have the correct MD5 password for the password “test” in the db saved.

Maybe you misspelled the password or something like that.

How do you generate new users? Maybe there is the failure…

Maybe you are searching at the wrong place because in my opinion the authenticate()+encrypt() method’s are working correct.

When adding or editing a user… the validation can be called many times… especially if AJAX validation is enabled… so you are getting sha1 of sha1 of sha1 … of the entered password…

It’s better to put the call


$this->password=$this->encrypt($this->password)

in beforeSave()

Mdombo, thank you. That was definitely the problem.

However, when I placed the call within beforeSave() like so:




	public function beforeSave()

	{		

		$this->password = $this->encrypt($this->password);

		

	}




This was giving me foreign key constraint errors on the second model that uses the id of the primary model.

I then remembered that its best to call the parent::beforeSave() as well.

Changing the beforeSave() to this makes it work like a charm:




	public function beforeSave()

	{		

		$this->password = $this->encrypt($this->password);

		return parent::beforeSave();

	}



So the issue is solved. Thanks again mdomba and kokomo.

PS: If someone could explain why we return the parent::beforeSave(), that would be awesome. But Im sure I could just do a search and find it.

If you don’t call the parent::beforeSave() you are interrupting the possible chain of events…