I have this code for changing a user\'s password when they click the password reset button (with extra code to log to ELMAH so I can try to figure out what is going wrong).
Could your main catch block be throwing an exception itself that you haven't noticed?
catch (Exception ex)
{
ErrorSignal.FromCurrentContext().Raise(new Exception("ResetPassword: " + ex));
return Json(new { Error = ex.Message + " -> "
+ ex.InnerException.Message }, JsonRequestBehavior.AllowGet);
}
The ex.InnerException.Message statement is not safe because it could throw a NullReferenceException.
Which MemberShipProvider are you using? Is it the same for every user? For instance, if you use SqlMembershipProvider and set enablePasswordReset to false, it will quietly fail to update the password. ChangePassword, in this case, returns true as if everything went fine.
If you are using the built-in SQLServer based providers take a look at your SQL Stored procs. This is what my default proc looks like:
ALTER PROCEDURE dbo.aspnet_Membership_SetPassword
@ApplicationName nvarchar(256),
@UserName nvarchar(256),
@NewPassword nvarchar(128),
@PasswordSalt nvarchar(128),
@CurrentTimeUtc datetime,
@PasswordFormat int = 0
AS
BEGIN
DECLARE @UserId uniqueidentifier
SELECT @UserId = NULL
SELECT @UserId = u.UserId
FROM dbo.aspnet_Users u, dbo.aspnet_Applications a, dbo.aspnet_Membership m
WHERE LoweredUserName = LOWER(@UserName) AND
u.ApplicationId = a.ApplicationId AND
LOWER(@ApplicationName) = a.LoweredApplicationName AND
u.UserId = m.UserId
IF (@UserId IS NULL)
RETURN(1)
UPDATE dbo.aspnet_Membership
SET Password = @NewPassword, PasswordFormat = @PasswordFormat, PasswordSalt = @PasswordSalt,
LastPasswordChangedDate = @CurrentTimeUtc
WHERE @UserId = UserId
RETURN(0)
END
As you can see the update statement could totally fail and the stored proc could return true. I think this is where your errors are probably coming from. Could be locking issues...
I wonder if the problem is that you are resetting the password right before you change it. Without getting into all of the internals of the Membership class, could you try putting in some kind of delay between those two commands?
Well this is certainly an interesting one. The "it works for some, not for others" part is really bizarre.
Is this an intermittent problem, or does it always occur for certain users, and always not occur for other users?
One of the other people here suggested running ValidateUser(username, newPassword)
to confirm that the user could properly authenticate before assuming success.
Have you tried this? You could continuously loop, resetting + changing the password until ValidateUser is successful, perhaps exiting after N failures.
bool success = false;
int numAttempts = 0;
do
{
string pwd = user.ResetPassword();
if (user.ChangePassword(pwd, confirmPassword))
{
success = Membership.ValidateUser(user.UserName, pwd);
}
numAttempts++;
} while(numAttempts < 5 && !success);
Note: This is not for use in production, just for testing to see if this resolves the problem.
Are you using 1 webserver or multiple webservers? With multiple servers it could be that the machinekey used for encrypting the password is not the same on al servers.