Posted by: knuzich - Wednesday, 21 October 2009 11:08:58
It is not possible to recover forgotten password if user changed his password manually once before. I see error: "Your answer could not be verified. Please try again." every time when i want to recover my password through "recoverpassword" page. Username is correct and answer to password question is correct too and problem does not disappear when i set correct value (for example password answer: "knuzich") instead of variable "answer " in code [code] protected void PasswordRecovery1_VerifyingAnswer(object sender, LoginCancelEventArgs e) { e.Cancel = true; MembershipUser user = Membership.GetUser(PasswordRecovery1.UserName); string answer = PasswordRecovery1.Answer; if (user != null) { if (user.PasswordQuestion.Equals(answer)) { e.Cancel = false; } } } [/code] Every time AnswerLookupError event occures [code] protected void PasswordRecovery1_AnswerLookupError(object sender, EventArgs e) { PageContext.AddLoadMessageSession(GetText("QUESTION_FAILURE")); } [/code] Any help is greatly appreciated

Posted by: knuzich - Thursday, 22 October 2009 07:54:44
I have found solution to this problem myself :) The reason of permanent error is in method "ChangePassword" of class "YafMembershipProvider" [code] public override bool ChangePassword(string username, string oldPassword, string newPassword) { string salt = string.Empty; string str2 = string.Empty; if (!this.IsPasswordCompliant(newPassword)) { return false; } UserPasswordInfo info = UserPasswordInfo.CreateInstanceFromDB(this.ApplicationName, username, false, this.UseSalt, this.HashHex, this.HashCase, this.HashRemoveChars, this.MSCompliant); if (info == null) { return false; } if (!info.IsCorrectPassword(oldPassword)) { return false; } //here begin if (this.UseSalt) { salt = GenerateSalt(); } //here end str2 = EncodeString(newPassword, (int) this.PasswordFormat, salt, this.UseSalt, this.HashHex, this.HashCase, this.HashRemoveChars, this.MSCompliant); DB.ChangePassword(this.ApplicationName, username, str2, salt, (int) this.PasswordFormat, info.PasswordAnswer); return true; } [/code] Every time in changing user password we generate new value in field "PasswordSalt" but our password question was encoded with previous salt. That is reason why entered "PasswordAnswer" is not equal to saved one in database. As we can see "DB.ChangePasswordvariable" method saves new value "salt" for current user but does not change encoded password question!! [code] public static void ChangePassword(string appName, string username, string newPassword, string newSalt, int passwordFormat, string newPasswordAnswer) { using (SqlCommand command = new SqlCommand(DBAccess.GetObjectName("prov_changepassword"))) { command.CommandType = CommandType.StoredProcedure; command.Parameters.AddWithValue("@ApplicationName", appName); command.Parameters.AddWithValue("@Username", username); command.Parameters.AddWithValue("@Password", newPassword); command.Parameters.AddWithValue("@PasswordSalt", newSalt); command.Parameters.AddWithValue("@PasswordFormat", passwordFormat); command.Parameters.AddWithValue("@PasswordAnswer", newPasswordAnswer); DBAccess.ExecuteNonQuery(command); } } [/code] One should input [code] if (this.UseSalt && String.IsNullOrEmpty(info.PasswordSalt)) { salt = GenerateSalt(); } else { salt = info.PasswordSalt; } [/code] instead of marked part (by 'begin here' and 'end here') in code "ChangePassword" method and recopile dll.

Posted by: Jaben - Thursday, 22 October 2009 15:43:26
Confirmed bug -- thank you -- this bug has been bugging many, many users. Fix committed to SVN.