Search code examples
c#asp.net-mvcpassword-hash

Verify hashed password & edit event after it's created


I'm working on a project that will let an employee clock in and out for their day, including their lunch. The employee would enter their username and password and click the clock in button. It would then check to make sure that the username and password match in the database.

I got the username verification to work, but I'm having a hard time with the password. It always returns null.

Then, after username and password are verified, it creates an event that will show when you clocked in. I need to now figure out how to check if that event doesn't have an end time listed, to edit that event and add an end time for when they clock out for lunch. If there is a start and an end time, it needs to create a new event.

model:

    [Key]
    public Guid EventID { get; set; }
    public DateTime Start { get; set; }
    public DateTime? End { get; set; }
    public string Note { get; set; }       
    [Timestamp]
    public byte[] Timestamp { get; set; }
    public string Title { get; set; }
    public bool ActiveSchedule { get; set; }
    [Column("UserId")]
    public string Id { get; set; }
    [ForeignKey("Id")]
    public virtual ApplicationUser User { get; set; }
}

controller:

public ActionResult Create(LoginViewModel workTimeEvent)
    {
        PasswordHasher ph = new PasswordHasher();
        ApplicationUser user = new ApplicationUser
        {
            Email = workTimeEvent.Email
        }; 

        if (db.Users.Where(x => x.Email == workTimeEvent.Email).Count() == 1)
        {
            var result = ph.VerifyHashedPassword(user.PasswordHash, workTimeEvent.Password);
            if (result == PasswordVerificationResult.Success)

            WorkTimeEvent work = new WorkTimeEvent() { };

            if (work.Start==null)
            {
                WorkTimeEvent clockIn = new WorkTimeEvent()
                {
                    User = db.Users.Where(e => e.Email == workTimeEvent.Email).First(),
                    Start = DateTime.Now,
                    EventID = Guid.NewGuid()
                };

                db.WorkTimeEvents.Add(clockIn);
                db.SaveChanges();
                return View();
            }
            else if (work.End == null)
            {

            }

                db.WorkTimeEvents.Add(work);
                db.SaveChanges();
                return View();
        }
        else
        {
            return View("inValid");
        }
    }

Solution

  • Your user.PasswordHash is always NULL : )

            // query db to check if user does exist but you do not retrieve it
            if (db.Users.Where(x => x.Email == workTimeEvent.Email).Count() == 1)
            {
                var result = ph.VerifyHashedPassword(user.PasswordHash, workTimeEvent.Password);
                if (result == PasswordVerificationResult.Success)
    

    Please try the following:

            ApplicationUser user = new ApplicationUser
            {
                Email = workTimeEvent.Email
            }; 
    
            // query db to check if user does exist but you do not retrieve it
            var dbUser = db.Users.FirstOrDefault(x => x.Email == workTimeEvent.Email);
    
            if (dbUser == null)
            {
                ModelState.AddModelError("", "Login failed!");
                return View("inValid");
            }
            var result = ph.VerifyHashedPassword(dbUser.PasswordHash, workTimeEvent.Password);
    

    FirstOrDefault does return null if nothing is found.

    Further I would change your authentication check like following:

        if (result != PasswordVerificationResult.Success)
    {
                 ModelState.AddModelError("", "Login failed!");
                 return View("inValid");
    }
    

    About your second question, it is sadly not really clear to me what you are trying to achieve. Do you want to get the latest event? And then check if there is an EndTime set?

    EDIT

    Based on your comment response you want to check if there is a created Event (Event does describe the database table/information not a c# event) with no end time set. If so, it needs to be updated with an end time. Due to End beeing a nullable DateTime we check with EntityFramework and the HasValue property:

    var notFinishedEvent = db.WorkTimeEvents.FirstOrDefault(x=>x.Id == dbUser.Id && !x.End.HasValue);
    if(notFinishedEvent != null)
    {
        notFinishedEvent.End = DateTime.Now;
        db.SaveChanges();
    }
    else
    {
       // create new one to save...
    }
    

    This code does rely on that there is only one event with no end date set. I do not know your default value for Start but you could easily add it as a check or query for the latest one (using OrderByDescending and taking the first).