/// <summary>
        /// Gets the password of a user given the provided password answer
        /// </summary>
        public override string GetPassword(string username, string answer)
        {
            if (!this.EnablePasswordRetrieval)
            {
                throw new NotSupportedException("Membership provider is configured to reject password retrieval.");
            }

            SecUtility.CheckParameter(ref username, true, true, true, Constants.MaxTableUsernameLength, "username");

            try
            {
                if (answer != null)
                {
                    answer = answer.Trim();
                }

                string encodedPasswordAnswer;
                DataServiceContext svc = this.CreateDataServiceContext();
                MembershipRow member = this.GetUserFromTable(svc, username);
                if (member == null)
                {
                    throw new ProviderException("Couldn't find a unique user with that name.");
                }

                if (member.IsLockedOut)
                {
                    throw new MembershipPasswordException("User is locked out.");
                }

                if (string.IsNullOrEmpty(answer))
                {
                    encodedPasswordAnswer = answer;
                }
                else
                {
                    encodedPasswordAnswer = this.EncodePassword(answer.ToLowerInvariant(), member.PasswordFormat, member.PasswordSalt);
                }

                SecUtility.CheckParameter(ref encodedPasswordAnswer, this.RequiresQuestionAndAnswer, this.RequiresQuestionAndAnswer, false, MaxTablePasswordAnswerLength, "passwordAnswer");

                Exception ex = null;
                if (this.RequiresQuestionAndAnswer)
                {
                    DateTime now = DateTime.UtcNow;
                    if (string.IsNullOrEmpty(member.PasswordAnswer) || encodedPasswordAnswer != member.PasswordAnswer)
                    {
                        ex = new MembershipPasswordException("Password answer is invalid.");
                        if (now > member.FailedPasswordAnswerAttemptWindowStartUtc.Add(TimeSpan.FromMinutes(this.PasswordAttemptWindow)))
                        {
                            member.FailedPasswordAnswerAttemptWindowStartUtc = now;
                            member.FailedPasswordAnswerAttemptCount = 1;
                        }
                        else
                        {
                            member.FailedPasswordAnswerAttemptWindowStartUtc = now;
                            member.FailedPasswordAnswerAttemptCount++;
                        }

                        if (member.FailedPasswordAnswerAttemptCount >= this.MaxInvalidPasswordAttempts)
                        {
                            member.IsLockedOut = true;
                            member.LastLockoutDateUtc = now;
                        }
                    }
                    else
                    {
                        if (member.FailedPasswordAnswerAttemptCount > 0)
                        {
                            member.FailedPasswordAnswerAttemptCount = 0;
                            member.FailedPasswordAnswerAttemptWindowStartUtc = ProvidersConfiguration.MinSupportedDateTime;
                        }
                    }
                }

                svc.UpdateObject(member);
                svc.SaveChanges();
                if (ex != null)
                {
                    throw ex;
                }

                return this.UnEncodePassword(member.Password, member.PasswordFormat);
            }
            catch (Exception e)
            {
                if (e.InnerException is DataServiceClientException)
                {
                    throw new ProviderException("Error accessing the data source.", e);
                }
                else
                {
                    throw;
                }
            }
        }
        /// <summary>
        /// Processes a request to update the password for a membership user.
        /// </summary>
        /// <param name="username">The user to update the password for.</param>
        /// <param name="oldPassword">The current password for the specified user.</param>
        /// <param name="newPassword">The new password for the specified user.</param>
        /// <returns>
        /// true if the password was updated successfully; otherwise, false.
        /// </returns>
        public override bool ChangePassword(string username, string oldPassword, string newPassword)
        {
            // Validate new password
            if (IsPasswordValid(newPassword) == false)
            {
                var e = new MembershipPasswordException("Change password canceled due to new password validation failure.");
                LogHelper.WarnWithException<MembersMembershipProvider>(e.Message, e);
                throw e;
            }

            var member = MemberService.GetByUsername(username);
            if (member == null) return false;
            
            var encodedPassword = EncryptOrHashPassword(oldPassword);

            if (member.Password == encodedPassword)
            {

                member.Password = EncryptOrHashPassword(newPassword);
                MemberService.Save(member);

                return true;
            }

            LogHelper.Warn<MembersMembershipProvider>("Can't change password as old password was incorrect");
            return false;
        }
        /// <summary>
        /// Reset the password of a user. No retry policies are used in this function.
        /// </summary>
        public override string ResetPassword(string username, string answer)
        {
            if (!this.EnablePasswordReset)
            {
                throw new NotSupportedException("Membership provider is configured to not allow password resets!");
            }

            SecUtility.CheckParameter(ref username, true, true, true, Constants.MaxTableUsernameLength, "username");

            try
            {
                TableServiceContext svc = this.CreateDataServiceContext();
                MembershipRow member = this.GetUserFromTable(svc, username);
                if (member == null)
                {
                    throw new ProviderException(string.Format(CultureInfo.InstalledUICulture, "Couldn't find a unique user with the name {0}.", username));
                }

                if (member.IsLockedOut)
                {
                    throw new MembershipPasswordException(string.Format(CultureInfo.InstalledUICulture, "The user {0} is currently locked out!", username));
                }

                int format = member.PasswordFormat;
                string salt = member.PasswordSalt;
                string encodedPasswordAnswer;

                if (answer != null)
                {
                    answer = answer.Trim();
                }

                if (!string.IsNullOrEmpty(answer))
                {
                    encodedPasswordAnswer = this.EncodePassword(answer.ToLowerInvariant(), format, salt);
                }
                else
                {
                    encodedPasswordAnswer = answer;
                }

                SecUtility.CheckParameter(ref encodedPasswordAnswer, this.RequiresQuestionAndAnswer, this.RequiresQuestionAndAnswer, false, MaxTablePasswordSize, "passwordAnswer");

                string newPassword = this.GeneratePassword();
                var e = new ValidatePasswordEventArgs(username, newPassword, false);
                OnValidatingPassword(e);
                if (e.Cancel)
                {
                    if (e.FailureInformation != null)
                    {
                        throw e.FailureInformation;
                    }
                    else
                    {
                        throw new ProviderException("Password validation failed.");
                    }
                }

                DateTime now = DateTime.UtcNow;
                Exception ex = null;
                if (encodedPasswordAnswer == null || encodedPasswordAnswer == member.PasswordAnswer)
                {
                    member.Password = this.EncodePassword(newPassword, (int)format, salt);
                    member.LastPasswordChangedDateUtc = now;
                    if (member.FailedPasswordAnswerAttemptCount > 0 && encodedPasswordAnswer != null)
                    {
                        member.FailedPasswordAnswerAttemptCount = 0;
                        member.FailedPasswordAnswerAttemptWindowStartUtc = ProvidersConfiguration.MinSupportedDateTime;
                    }
                }
                else
                {
                    if (now > member.FailedPasswordAnswerAttemptWindowStartUtc.Add(TimeSpan.FromMinutes(this.PasswordAttemptWindow)))
                    {
                        member.FailedPasswordAnswerAttemptWindowStartUtc = now;
                        member.FailedPasswordAnswerAttemptCount = 1;
                    }
                    else
                    {
                        member.FailedPasswordAnswerAttemptWindowStartUtc = now;
                        member.FailedPasswordAnswerAttemptCount++;
                    }

                    if (member.FailedPasswordAnswerAttemptCount >= this.MaxInvalidPasswordAttempts)
                    {
                        member.IsLockedOut = true;
                        member.LastLockoutDateUtc = now;
                    }

                    ex = new MembershipPasswordException("Wrong password answer.");
                }

                svc.UpdateObject(member);
                svc.SaveChanges();

                if (ex != null)
                {
                    throw ex;
                }

                return newPassword;
            }
            catch (Exception e)
            {
                if (e.InnerException is DataServiceClientException)
                {
                    throw new ProviderException("Error accessing the data source.", e);
                }
                else
                {
                    throw;
                }
            }
        }