/// <summary>
        /// Resets a user's password to a new, automatically generated password.
        /// </summary>
        /// <returns>
        /// The new password for the specified user.
        /// </returns>
        /// <param name="username">The user to reset the password for. </param><param name="answer">The password answer for the specified user. </param>
        public override string ResetPassword(string username, string answer)
        {
            if (!PasswordPolicy.IsPasswordResetEnabled)
            {
                throw new NotSupportedException("Password reset is not supported.");
            }

            var user = AccountRepository.Get(username);

            if (PasswordPolicy.IsPasswordQuestionRequired && answer == null)
            {
                throw new MembershipPasswordException("Password answer is empty and question/answer is required.");
            }

            if (PasswordPolicy.IsPasswordQuestionRequired &&
                !user.PasswordAnswer.Equals(answer, StringComparison.OrdinalIgnoreCase))
            {
                return(null);
            }

            var newPassword = PasswordStrategy.GeneratePassword(PasswordPolicy);

            ValidatePassword(username, newPassword);

            var info = new AccountPasswordInfo(username, newPassword);

            user.Password     = PasswordStrategy.Encrypt(info);
            user.PasswordSalt = info.PasswordSalt;
            AccountRepository.Update(user);
            return(newPassword);
        }
        /// <summary>
        /// Processes a request to update the password question and answer for a membership user.
        /// </summary>
        /// <returns>
        /// true if the password question and answer are updated successfully; otherwise, false.
        /// </returns>
        /// <param name="username">The user to change the password question and answer for. </param><param name="password">The password for the specified user. </param><param name="newPasswordQuestion">The new password question for the specified user. </param><param name="newPasswordAnswer">The new password answer for the specified user. </param>
        public override bool ChangePasswordQuestionAndAnswer(string username, string password,
                                                             string newPasswordQuestion, string newPasswordAnswer)
        {
            var account = AccountRepository.Get(username);

            if (account == null)
            {
                return(false);
            }

            var info = new AccountPasswordInfo(username, account.Password)
            {
                PasswordSalt = account.PasswordSalt
            };

            if (PasswordStrategy.Compare(info, password))
            {
                return(false);
            }

            account.PasswordQuestion = newPasswordAnswer;
            account.PasswordAnswer   = newPasswordAnswer;
            AccountRepository.Update(account);
            return(true);
        }
        /// <summary>
        /// Adds a new membership user to the data source.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.Web.Security.MembershipUser"/> object populated with the information for the newly created user.
        /// </returns>
        /// <param name="username">The user name for the new user. </param><param name="password">The password for the new user. </param><param name="email">The e-mail address for the new user.</param><param name="passwordQuestion">The password question for the new user.</param><param name="passwordAnswer">The password answer for the new user</param><param name="isApproved">Whether or not the new user is approved to be validated.</param><param name="providerUserKey">The unique identifier from the membership data source for the user.</param><param name="status">A <see cref="T:System.Web.Security.MembershipCreateStatus"/> enumeration value indicating whether the user was created successfully.</param>
        public override MembershipUser CreateUser(string username, string password, string email,
                                                  string passwordQuestion, string passwordAnswer, bool isApproved,
                                                  object providerUserKey, out MembershipCreateStatus status)
        {
            if (AccountRepository.IsUniqueEmailRequired && AccountRepository.GetUserNameByEmail(email) != null)
            {
                status = MembershipCreateStatus.DuplicateEmail;
                return(null);
            }

            if (AccountRepository.Get(username) != null)
            {
                status = MembershipCreateStatus.DuplicateUserName;
                return(null);
            }

            try
            {
                ValidatePassword(username, password);
            }
            catch
            {
                // not the smoothest approach, but the best
                // considering the inconsistent password failure handling.
                status = MembershipCreateStatus.InvalidPassword;
                return(null);
            }

            var account      = AccountRepository.Create(providerUserKey, ApplicationName, username, email);
            var passwordInfo = new AccountPasswordInfo(username, password);

            account.Password     = PasswordStrategy.Encrypt(passwordInfo);
            account.PasswordSalt = passwordInfo.PasswordSalt;

            account.PasswordAnswer   = passwordAnswer;
            account.PasswordQuestion = passwordQuestion;

            status = AccountRepository.Register(account);
            if (status == MembershipCreateStatus.Success)
            {
                return(CloneUser(account));
            }

            return(null);
        }
        /// <summary>
        /// Resets a user's password to a new, automatically generated password.
        /// </summary>
        /// <returns>
        /// The new password for the specified user.
        /// </returns>
        /// <param name="username">The user to reset the password for. </param><param name="answer">The password answer for the specified user. </param>
        public override string ResetPassword(string username, string answer)
        {
            if (!PasswordPolicy.IsPasswordResetEnabled)
                throw new NotSupportedException("Password reset is not supported.");

            var user = AccountRepository.Get(username);
            if (PasswordPolicy.IsPasswordQuestionRequired && answer == null)
                throw new MembershipPasswordException("Password answer is empty and question/answer is required.");

            if (PasswordPolicy.IsPasswordQuestionRequired && 
                !user.PasswordAnswer.Equals(answer, StringComparison.OrdinalIgnoreCase))
                return null;

            var newPassword = PasswordStrategy.GeneratePassword(PasswordPolicy);

            ValidatePassword(username, newPassword);

            var info = new AccountPasswordInfo(username, newPassword);
            user.Password = PasswordStrategy.Encrypt(info);
            user.PasswordSalt = info.PasswordSalt;
            AccountRepository.Update(user);
            return newPassword;
        }
        /// <summary>
        /// Processes a request to update the password question and answer for a membership user.
        /// </summary>
        /// <returns>
        /// true if the password question and answer are updated successfully; otherwise, false.
        /// </returns>
        /// <param name="username">The user to change the password question and answer for. </param><param name="password">The password for the specified user. </param><param name="newPasswordQuestion">The new password question for the specified user. </param><param name="newPasswordAnswer">The new password answer for the specified user. </param>
        public override bool ChangePasswordQuestionAndAnswer(string username, string password,
                                                             string newPasswordQuestion, string newPasswordAnswer)
        {
            var account = AccountRepository.Get(username);
            if (account == null)
                return false;

            var info = new AccountPasswordInfo(username, account.Password)
                           {
                               PasswordSalt = account.PasswordSalt
                           };
            if (PasswordStrategy.Compare(info, password))
                return false;

            account.PasswordQuestion = newPasswordAnswer;
            account.PasswordAnswer = newPasswordAnswer;
            AccountRepository.Update(account);
            return true;
        }
        /// <summary>
        /// Adds a new membership user to the data source.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.Web.Security.MembershipUser"/> object populated with the information for the newly created user.
        /// </returns>
        /// <param name="username">The user name for the new user. </param><param name="password">The password for the new user. </param><param name="email">The e-mail address for the new user.</param><param name="passwordQuestion">The password question for the new user.</param><param name="passwordAnswer">The password answer for the new user</param><param name="isApproved">Whether or not the new user is approved to be validated.</param><param name="providerUserKey">The unique identifier from the membership data source for the user.</param><param name="status">A <see cref="T:System.Web.Security.MembershipCreateStatus"/> enumeration value indicating whether the user was created successfully.</param>
        public override MembershipUser CreateUser(string username, string password, string email,
                                                  string passwordQuestion, string passwordAnswer, bool isApproved,
                                                  object providerUserKey, out MembershipCreateStatus status)
        {
            if (AccountRepository.IsUniqueEmailRequired && AccountRepository.GetUserNameByEmail(email) != null)
            {
                status = MembershipCreateStatus.DuplicateEmail;
                return null;
            }

            if (AccountRepository.Get(username) != null)
            {
                status = MembershipCreateStatus.DuplicateUserName;
                return null;
            }

            try
            {
                ValidatePassword(username, password);
            }
            catch
            {
                // not the smoothest approach, but the best 
                // considering the inconsistent password failure handling.
                status = MembershipCreateStatus.InvalidPassword;
                return null;
            }

            var account = AccountRepository.Create(providerUserKey, ApplicationName, username, email);
            var passwordInfo = new AccountPasswordInfo(username, password);
            account.Password = PasswordStrategy.Encrypt(passwordInfo);
            account.PasswordSalt = passwordInfo.PasswordSalt;
            
            account.PasswordAnswer = passwordAnswer;
            account.PasswordQuestion = passwordQuestion;

            status = AccountRepository.Register(account);
            if (status == MembershipCreateStatus.Success)
                return CloneUser(account);

            return null;
        }
        /// <summary>
        /// Adds a new membership user to the data source.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.Web.Security.MembershipUser"/> object populated with the information for the newly created user.
        /// </returns>
        /// <param name="username">The user name for the new user. </param><param name="password">The password for the new user. </param><param name="email">The e-mail address for the new user.</param><param name="passwordQuestion">The password question for the new user.</param><param name="passwordAnswer">The password answer for the new user</param><param name="isApproved">Whether or not the new user is approved to be validated.</param><param name="providerUserKey">The unique identifier from the membership data source for the user.</param><param name="status">A <see cref="T:System.Web.Security.MembershipCreateStatus"/> enumeration value indicating whether the user was created successfully.</param>
        public override MembershipUser CreateUser(string username, string password, string email,
                                                  string passwordQuestion, string passwordAnswer, bool isApproved,
                                                  object providerUserKey, out MembershipCreateStatus status)
        {
            if (AccountRepository.IsUniqueEmailRequired && AccountRepository.GetUserNameByEmail(email) != null)
            {
                status = MembershipCreateStatus.DuplicateEmail;
                return null;
            }

            if (AccountRepository.Get(username) != null)
            {
                status = MembershipCreateStatus.DuplicateUserName;
                return null;
            }

            ValidatePassword(username, password);


            var account = AccountRepository.Create(providerUserKey, ApplicationName, username, email);
            var passwordInfo = new AccountPasswordInfo(username, password);
            account.Password = PasswordStrategy.Encrypt(passwordInfo);
            account.PasswordSalt = passwordInfo.PasswordSalt;

            status = AccountRepository.Register(account);
            if (status == MembershipCreateStatus.Success)
                return CloneUser(account);

            return null;
        }