Quantcast
Channel: Security
Viewing all articles
Browse latest Browse all 4737

SignInManager.PasswordSignInAsynch calling ResetAccessFailedCountAsync

$
0
0

In my Login method in the account controller, I have the following code

        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
        {
            if (!ModelState.IsValid)
            {
                return View(model);
            }

            // This doen't count login failures towards lockout only two factor authentication
            // To enable password failures to trigger lockout, change to shouldLockout: true
            var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: true);
            switch (result)
            {
                case SignInStatus.Success:
                    return RedirectToLocal(returnUrl);
                case SignInStatus.LockedOut:
                    return View("Lockout");
                case SignInStatus.RequiresVerification:
                    return RedirectToAction("SendCode", new { ReturnUrl = returnUrl });
                case SignInStatus.Failure:
                default:
                    ModelState.AddModelError("", "Invalid login attempt.");
                    return View(model);
            }
        }

When I enter a valid Email but invalid Password, the following methods are called:

GetLockoutEnabledAsync - For now I just always return true, will worry about admin user later

GetLockoutEndDateAsync - if the user has locked his account previously, I return 1000 days from now, otherwise a day before today.

Then a call to The UserPassword Store GetPasswordHashAsync method is called.  Followed by a call to my PasswordHasher, VerifyHashedPassword

Everything up until here seems to work fine.  I can see if the password passes validation or not.  I use the following to return success or failure

class K3PasswordHasher : IPasswordHasher
    {
        private readonly K3PasswordHash _k3PasswordHash = new K3PasswordHash();

        public string HashPassword(string password)
        {
            return _k3PasswordHash.CreateHash(password);
        }

        public PasswordVerificationResult VerifyHashedPassword(string hashedPassword, string providedPassword)
        {
            if (_k3PasswordHash.ValidatePassword(providedPassword, hashedPassword))
                return PasswordVerificationResult.Success;

            return PasswordVerificationResult.Failed;
        }
    }

Now I get confused.  If the password validation fails, the following methods in the UserLockoutStore are called (after getting a fresh version of the User):

IncrementAccessFailedCountAsync - This makes sense.  I want to increase the failure count on the user in the database.

SetLockoutEndDateAsync- I have no idea why this method is being called.  There has been no lockout yet to the best best of my knowledge, so I return an offset.  For clarity, I don't care about lockout end dates.  If an account is locked, it will remain so until my reset process is used.

ResetAccessFailedCountAsync - This totally defeats what I just did by increasing the failed count.  I have no idea why this call is in the stack and can not figure out what is causing the reset. 

Here is the code from my UserStore.  Any ideas would be appreciated.

using AutoMapper;
using K3LoginDomain;
using K3LoginRepo;
using Microsoft.AspNet.Identity;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace K3Identity
{
    public class K3UserStore :  IUserStore<K3IdentityUser, int>,
                                IUserRoleStore<K3IdentityUser, int>,
                                IUserPasswordStore<K3IdentityUser, int>,
                                IUserLockoutStore<K3IdentityUser, int>,
                                IUserTwoFactorStore<K3IdentityUser, int>
    {
        private LoginAccessor _loginAccessor = new LoginAccessor();
        private bool _disposed = false;

        public K3UserStore()
        {
            ConfigureAutoMapper();
            new K3UserStore(new K3DbContext());
        }

        public K3UserStore(K3DbContext k3DbContext)
        {
            ConfigureAutoMapper();
            _loginAccessor = new LoginAccessor();
        }

        private void ConfigureAutoMapper()
        {
            Mapper.CreateMap<K3IdentityUser, UserProfile>()
                .ForMember(d => d.Address, o => o.Ignore())
                .ForMember(d => d.Address, o => o.Ignore())
                .ForMember(d => d.ObjectState, o => o.Ignore())
                .ForMember(d => d.PasswordHistories, o => o.Ignore())
                .ForMember(d => d.Role, o => o.Ignore())
                .ForMember(d => d.SecQues1, o => o.Ignore())
                .ForMember(d => d.SecQues2, o => o.Ignore())
                .ForMember(d => d.SecQues3, o => o.Ignore())
                .ForMember(d => d.SecQues4, o => o.Ignore())
                .ForMember(d => d.SecQues5, o => o.Ignore())
                .ForMember(d => d.Theme, o => o.Ignore())
                .ForMember(d => d.UserPhones, o => o.Ignore());
            Mapper.CreateMap<UserProfile, K3IdentityUser>()
                .ForMember(d => d.PasswordHash, o => o.Ignore());
            Mapper.AssertConfigurationIsValid();
        }

        #region UserStore
        public Task CreateAsync(K3IdentityUser user)
        {
            if (user == null)
            {
                throw new ArgumentNullException("user");
            }

            UserProfile userProfile = Mapper.Map<K3IdentityUser, UserProfile>(user);
            if (!_loginAccessor.Repo.InsertUserProfile(userProfile, false))
            {
                throw new ApplicationException("Unable to insert user.");
            }
            _loginAccessor.Save();
            return Task.FromResult<object>(null);
        }

        public Task DeleteAsync(K3IdentityUser user)
        {
            if (user.Id > 0)
            {
                if (!_loginAccessor.Repo.DeleteUserProfile(user.Id))
                {
                    throw new Exception("Can not delete user.");
                }
            }
            return Task.FromResult<Object>(null);
        }

        public Task<K3IdentityUser> FindByIdAsync(int userId)
        {
            if (userId <= 0)
            {
                throw new ArgumentException("Null or empty argument: id");
            }

            UserProfile user = _loginAccessor.Repo.GetUserProfile(userId);
            if (user == null)
            {
                return Task.FromResult<K3IdentityUser>(null);
            }
            K3IdentityUser k3User = Mapper.Map<UserProfile, K3IdentityUser>(user);
            return Task.FromResult<K3IdentityUser>(k3User);
        }

        public Task<K3IdentityUser> FindByNameAsync(string userName)
        {
            if (string.IsNullOrEmpty(userName))
            {
                throw new ArgumentException("Null or empty argument: userName");
            }

            UserProfile user = _loginAccessor.Repo.GetUserProfileByUserName(userName);
            if (user == null)
            {
                return Task.FromResult<K3IdentityUser>(null);
            }
            K3IdentityUser k3User = Mapper.Map<UserProfile, K3IdentityUser>(user);
            return Task.FromResult<K3IdentityUser>(k3User);
        }

        public Task UpdateAsync(K3IdentityUser user)
        {
            UserProfile userProfile = _loginAccessor.Repo.GetUserProfile(user.Id);

            if (user == null)
            {
                throw new ArgumentNullException("user");
            }
            if (userProfile.Password != user.Password)
            {
                throw new Exception("Use Change Password Function");
            }

            UserProfile newUserProfile = Mapper.Map<K3IdentityUser,UserProfile>(user);
            _loginAccessor.Repo.UpdateUserProfile(newUserProfile, false, false);
            return Task.FromResult<object>(null);
        }
        #endregion

        #region UserLockoutStore
        public Task<int> GetAccessFailedCountAsync(K3IdentityUser user)
        {
            return Task.FromResult(user.PasswordFailures);
        }

        public Task<bool> GetLockoutEnabledAsync(K3IdentityUser user)
        {
           return Task.FromResult(true);
        }

        public Task<DateTimeOffset> GetLockoutEndDateAsync(K3IdentityUser user)
        {
            if (user == null)
            {
                throw new ArgumentNullException("user");
            }
            UserProfile userProfile = _loginAccessor.Repo.GetUserProfile(user.Id);
            PasswordRequirement passwordRequirement = _loginAccessor.Repo.GetPasswordRequirement();
            if (userProfile.PasswordFailures >= passwordRequirement.PasswordFailsAllowed)
                return Task.FromResult(DateTimeOffset.UtcNow.AddDays(1000));

            return Task.FromResult(DateTimeOffset.UtcNow.Subtract(new TimeSpan(1,0,0,0)));
        }

        public Task<int> IncrementAccessFailedCountAsync(K3IdentityUser user)
        {
            if (user == null)
            {
                throw new ArgumentNullException("user");
            }
            UserProfile userProfile = _loginAccessor.Repo.GetUserProfile(user.Id);

            userProfile.PasswordFailures++;
            if (_loginAccessor.Repo.UpdateUserProfile(userProfile, false, false));
                _loginAccessor.Save();

            return Task.FromResult(userProfile.PasswordFailures);
        }

        public Task ResetAccessFailedCountAsync(K3IdentityUser user)
        {
            if (user == null)
            {
                throw new ArgumentNullException("user");
            }
            UserProfile userProfile = _loginAccessor.Repo.GetUserProfile(user.Id);

            userProfile.PasswordFailures = 0;
            if (_loginAccessor.Repo.UpdateUserProfile(userProfile, false, false))
                _loginAccessor.Save();

            return Task.FromResult(0);
        }

        public Task SetLockoutEnabledAsync(K3IdentityUser user, bool enabled)
        {
            if (user == null)
            {
                throw new ArgumentNullException("user");
            }
            UserProfile userProfile = _loginAccessor.Repo.GetUserProfile(user.Id);
            PasswordRequirement passwordRequirement = _loginAccessor.Repo.GetPasswordRequirement();
            if (userProfile.PasswordFailures >= passwordRequirement.PasswordFailsAllowed)
                return Task.FromResult(DateTimeOffset.UtcNow.AddDays(1000));

            return Task.FromResult(0);
        }

        public Task SetLockoutEndDateAsync(K3IdentityUser user, DateTimeOffset lockoutEnd)
        {
            if (user == null)
            {
                throw new ArgumentNullException("user");
            }
            UserProfile userProfile = _loginAccessor.Repo.GetUserProfile(user.Id);
            PasswordRequirement passwordRequirement = _loginAccessor.Repo.GetPasswordRequirement();
            if (userProfile.PasswordFailures >= passwordRequirement.PasswordFailsAllowed)
                return Task.FromResult(DateTimeOffset.UtcNow.AddDays(1000));

            return Task.FromResult(DateTimeOffset.UtcNow.Subtract(new TimeSpan(1, 0, 0, 0)));
        }
        #endregion

        #region UserPasswordStore
        public Task<string> GetPasswordHashAsync(K3IdentityUser user)
        {
            if (user == null)
            {
                throw new ArgumentNullException("user");
            }

            string passwordHash = _loginAccessor.Repo.GetUserProfile(user.Id).Password;
            return Task.FromResult<string>(passwordHash);
        }

        public Task SetPasswordHashAsync(K3IdentityUser user, string passwordHash)
        {
            if (user == null)
            {
                throw new ArgumentNullException("user");
            }
            if (passwordHash == null)
            {
                throw new ArgumentNullException("user");
            }

            if (user.Id > 0)
            {
                UserProfile userProfile = _loginAccessor.Repo.GetUserProfile(user.Id);
                userProfile.Password = passwordHash;
                if (!_loginAccessor.Repo.UpdateUserProfile(userProfile, false, false))
                    throw new Exception("Can not update password.");
            }
            user.Password = passwordHash;
            user.PasswordHash = passwordHash;
            return Task.FromResult<Object>(null);
        }

        public Task<bool> HasPasswordAsync(K3IdentityUser user)
        {
            var hasPassword = !string.IsNullOrEmpty(_loginAccessor.Repo.GetUserProfile(user.Id).Password);

            return Task.FromResult<bool>(Boolean.Parse(hasPassword.ToString()));
        }
        #endregion

        #region UserRoleStore
        public Task AddToRoleAsync(K3IdentityUser user, string roleName)
        {
            if (user == null)
            {
                throw new ArgumentNullException("user");
            }
            if (string.IsNullOrEmpty(roleName))
            {
                throw new ArgumentException("Argument cannot be null or empty: roleName.");
            } 

            Role role = _loginAccessor.Repo.GetRoleByName(roleName);
            UserProfile userProfile = _loginAccessor.Repo.GetUserProfile(user.Id);
            userProfile.RoleId = role.Id;
            _loginAccessor.Repo.UpdateUserProfile(userProfile, false, false);
            _loginAccessor.Save();

            return Task.FromResult<object>(null);
        }

        public Task RemoveFromRoleAsync(K3IdentityUser user, string roleName)
        {
            throw new NotImplementedException();
        }

        public Task<IList<string>> GetRolesAsync(K3IdentityUser user)
        {
            if (user == null)
            {
                throw new ArgumentNullException("user");
            }

            UserProfile userProfile = _loginAccessor.Repo.GetUserProfile(user.Id);
            Role role = _loginAccessor.Repo.GetRole(userProfile.RoleId);
            List<string> roleList = new List<string>();
            roleList.Add(role.RoleDes);

            return Task.FromResult<IList<string>>(roleList);
        }

        public Task<bool> IsInRoleAsync(K3IdentityUser user, string roleName)
        {
            if (user == null)
            {
                throw new ArgumentNullException("user");
            }
            if (string.IsNullOrEmpty(roleName))
            {
                throw new ArgumentNullException("roleName");
            }

            UserProfile userProfile = _loginAccessor.Repo.GetUserProfile(user.Id);
            Role role = _loginAccessor.Repo.GetRole(userProfile.RoleId);
            if (role != null && role.RoleDes == roleName)
            {
                return Task.FromResult<bool>(true);
            }

            return Task.FromResult<bool>(false);
        }
        #endregion

        #region UserTwoFactor
        public Task SetTwoFactorEnabledAsync(K3IdentityUser user, bool enabled)
        {
            throw new NotImplementedException();
        }

        public Task<bool> GetTwoFactorEnabledAsync(K3IdentityUser user)
        {
            return Task.FromResult(false);
        }
        #endregion

        #region Dispose
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (_disposed)
                return;

            if (disposing)
            {
                if (_loginAccessor != null)
                {
                    _loginAccessor.Dispose();
                    _loginAccessor= null;
                }
            }

            _disposed = true;
        }
        #endregion
    }
}


Viewing all articles
Browse latest Browse all 4737

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>