Bcrypt Verify always returning false - asp.net

[HttpPost("signUp")]
public async Task<ActionResult<Users>> PostUserRegister(Users user)
{
if (userEmailExists(user.Email))
{
return BadRequest();
}
string salt = BC.GenerateSalt(12);
// hash password
user.Password = BC.HashPassword(user.Password, salt);
_context.Database.ExecuteSqlRaw("EXECUTE dbo.UserRegister #userName, #firstName, #lastName, #Password, #userEmail, #gender, #dob",
new SqlParameter("#userName", user.UserName.ToString()),
new SqlParameter("#firstName", user.FirstName.ToString()),
new SqlParameter("#lastName", user.LastName.ToString()),
new SqlParameter("#Password", user.Password.ToString()),
new SqlParameter("#userEmail", user.Email.ToString()),
new SqlParameter("#gender", user.Gender.ToString()),
new SqlParameter("#dob", user.Dob));
/* var format = "dd/MM/yyyy";
var date = DateTime.ParseExact(user.Dob, format);*/
return Ok(user);
//_context.Users.Add(users);
//await _context.SaveChangesAsync();
//return CreatedAtAction("GetUsers", new { id = users.UserId }, users);
}
Im siging a new user up like this. Hashing the password using Bcrypt.
using BC = BCrypt.Net.BCrypt;
[HttpPost("login")]
public async Task<ActionResult<Users>> PostUserLogin(Users user)
{
// get account from database
var account = _context.Users.SingleOrDefault(x => x.Email == user.Email);
// check account found and verify password
if (account == null || !BC.Verify(user.Password, account.Password))
{
// authentication failed
return Unauthorized(user);
}
else
{
// authentication successful
return Ok(user);
}
Then I try to verify the password in the login function. When i debug to see the values of user.Password and account.Password they are correct. the user.Password is equal to the password the user entered to register and the account.Password is the Hashed password stored in the database. I was trying to follow this tutorial ASP.NET Core 3.1 - Hash and Verify Passwords with BCrypt

I have read the blog you provided. And I think we should double check below points.
The format of Password in your db,if the orginal password is 11, then the value stored should like :
$2a$12$NTuJLk9/xZnlxP.oFj1mu.1ZypqYP4YuS1QbTBy7ofJwzKLSEEVBq
In this line BC.Verify(user.Password, account.Password),
The value of user.Password
user.Password == 11
And the value of account.Password
account.Password == $2a$12$NTuJLk9/xZnlxP.oFj1mu.1ZypqYP4YuS1QbTBy7ofJwzKLSEEVBq
Please double check it, if you still have some issue, you can add the picture with debugging result.

i have same problem with bCrypt like you.
The main problem was much simpler than I thought. The main reason for this was that I used uppercase and lowercase letters when I received and saved the password.
I Fixed this problem with make my password input to lower and save it to db
And When i want to verify it , i make the password lowercase again .
user.Password = BC.HashPassword(user.Password.ToLower(), salt);
and when you want to Verify , use it like this:
if (account == null || !BC.Verify(user.Password.ToLower(),account.Password))
I Think This is your question Answer.

Related

Check if a password is valid using ASP.NET Identity 2

On my website, I give the administrators the possibility to change someone's password without entering the old one. I do the following:
userManager.RemovePassword(oldUser.Id);
userManager.AddPassword(oldUser.Id, newPassword);
However, this changes the password only if the newPassword string complies with the password policy set in the configuration files. AddPassword seems to fail silently when the new password does not fulfil the requirements.
Is there some simple way to check if a password is valid according to the current policy, apart from the obvious "manual procedure" (check how many upper/lowercase chars there are, how many digits, etc.). I'm looking for something like
bool valid = IsPasswordValid("pass");
You may be able to use the PasswordValidator.ValidateAsync() method to determine if a password meets the criteria defined in your UserManager :
var valid = (await UserManager.PasswordValidator.ValidateAsync("pass")).Succeeded;
You can simply use PasswordValidator to check for password validity and errors as shown below:
var passwordValidator = new PasswordValidator<IdentityUser>();
var result = await passwordValidator.ValidateAsync(_userManager, null, "your password here");
if (result.Succeeded)
{
// Valid Password
}
else
{
// Check the error messages in result.Errors
}
Above solution works for Asp.Net Core 2.2
In Net.Core 2.2, I did this. I collect the errors into a string list as I send them back via JSON using a mechanism that standard throughout my application. Thanks to cularbytes
List<string> passwordErrors = new List<string>();
var validators = _userManager.PasswordValidators;
foreach(var validator in validators)
{
var result = await validator.ValidateAsync(_userManager, null, newPassword);
if (!result.Succeeded)
{
foreach (var error in result.Errors)
{
passwordErrors.Add(error.Description);
}
}
}

Web app protected by single password for all clients

I was wondering if there is a standard way of protecting a ASP.Net web application with just a single password? In other words no username needed and all clients use the same password for authentication.
Or does anyone have their own solution?
You simply could use Identity framework to aim this propose. Actually you don't need any user or password to authenticate.
[HttpPost]
public ActionResult Login(string password)
{
if (password=="MyVerySecretPassword")
{
var ident = new ClaimsIdentity(
new[] {
// adding following 2 claim just for supporting default antiforgery provider
new Claim(ClaimTypes.NameIdentifier, "JustAnuniqueName"),
new Claim("http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider", "ASP.NET Identity", "http://www.w3.org/2001/XMLSchema#string"),
new Claim(ClaimTypes.Name,"JustAnuniqueName"),
},
DefaultAuthenticationTypes.ApplicationCookie);
HttpContext.GetOwinContext().Authentication.SignIn(
new AuthenticationProperties { IsPersistent = false }, ident);
return RedirectToAction("MyAction"); // auth succeed
}
// invalid password
ModelState.AddModelError("", "invalid username or password");
return View();
}
But it would be much better if you hash the password and check the hashed password instead of above simple if statement. To aim this you could use PasswordHasher class to hash and verify the password.
First hash your desired password and save it in preferred storage (DB, file, hard coded in code or everywhere else):
string hashedPassword = new PasswordHasher().HashPassword("MyVerySecretPassword");
Now since you have the hashed one. You could use VerifyHashedPassword() method to verify it.
if(new PasswordHasher()
.VerifyHashedPassword("myHashedPassword",password)==PasswordVerificationResult.Success)
{
// the password is correct do whatever you want
}
Also you could see my simple working example which I made to demonstrate it.

Creating users with no password using ASP.NET Identity

I have been given the requirement to provide the ability to create users through the UI with no password. I am trying to accomplish this using ASP.NET Identity.
I am able to successfully create a user without a password using the UserManager's Create method:
if (vm.ShouldHavePassword)
{
userManager.Create(userToInsert, vm.Password);
}
else
{
userManager.Create(userToInsert);
}
After the call to the Create method, the test user gets successfully saved into our AspNetUsers table. And when I do not provide a password, the PasswordHash column in our AspNetUsers table is set to NULL.
My issue is, I cannot login as the test user that does not have a password. The following is the method call that we use to validate a user's credentials:
result = await SignInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, shouldLockout: false);
I attempted to login as a test user that has a NULL PasswordHash multiple times. To do this, I do not provide a password in our login form. As a result, a NULL password is passed into the PasswordSignInAsync method. The return value of this method call is always SignInStatus.Failure.
Using ASP.NET Identity, how can I configure my code to correctly authenticate user credentials when the credentials contain a NULL password, and the user in the database contains a NULL PasswordHash? Is such a thing even possible?
Yes you can. ASP.NET Identity Framework is fully customizable. Just override PasswordValidator.ValidateAsync and PasswordHasher.VerifyHashedPassword methods like this:
internal class CustomPasswordValidator: PasswordValidator
{
public override async Task<IdentityResult> ValidateAsync(string item)
{
if (string.IsNullOrEmpty(item)) return IdentityResult.Success;
return await base.ValidateAsync(item);
}
}
internal class CustomPasswordHasher : PasswordHasher
{
public override PasswordVerificationResult VerifyHashedPassword(string hashedPassword, string providedPassword)
{
if (hashedPassword == null && string.IsNullOrEmpty(providedPassword))
return PasswordVerificationResult.Success;
return base.VerifyHashedPassword(hashedPassword, providedPassword);
}
}
And set them like this:
var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));
manager.PasswordValidator = new CustomPasswordValidator();
manager.PasswordHasher = new CustomPasswordHasher();
Okay, what you need to do is find the user (AspNetUsers user) using your db context. After you have the user, you can check if their PasswordHash is null.
If yes, then just sign them in using SignInManager.SignIn.
If not, use SignInManager.PasswordSignIn.
example..
//alternatively, you can find the user using Email, Id or some other unique field
var user = db.AspNetUsers.FirstOrDefault(p => p.UserName);
if (user != null)
{
if (user.PasswordHash == null)
await SignInManager.SignInAsync(user, true, true);
else
await SignInManager.PasswordSignInAsync(model.UserName, model.Password,
model.RememberMe, shouldLockout: false);
}
Hope it helps.
I don't think you can validate user without password. As a workaround: Instead of blank password, I'll recommend to use some Dummy/Common password from C# code, both while creating User and while validating credential
When creating user
if (vm.ShouldHavePassword)
{
userManager.Create(userToInsert, vm.Password);
}
else
{
userManager.Create(userToInsert, "someDummy123$");
}
When validating
result = await SignInManager.PasswordSignInAsync(model.UserName, "someDummy123$", model.RememberMe, shouldLockout: false);

How to login with "UserName" instead of "Email" in MVC Identity?

I need to set my login to use username instead of email address, how can I change it?
It's actually using the e-mail address as the username, so in the ASPNetUsers table, you'll see both the username and email fields with the email address.
Go into the AccountController, look for Register method (POST).
Change this:
var user = new ApplicationUser { UserName = model.Email, Email = model.Email};
to this:
var user = new ApplicationUser
{
UserName = model.UserName,
Email = model.Email
};
Then go into the Login.cshtml and change all corresponding e-mail model fields to username instead.
Finally, go into the Login method (POST) in the AccountController and change model.Email to model.UserName.
var result = await SignInManager.PasswordSignInAsync(model.UserName, model.Password,
model.RememberMe, shouldLockout: false);
You also have to make changes in AccountViewModels.cs in order to introduce your new UserName property.
Here is how you do it
var user = await _userManager.Users
.FirstOrDefaultAsync(u => u.UserName == username || u.Email == username);
if (user != null){
var result = await _signInManager
.PasswordSignInAsync(/*email*/user.Email, password, false, false);
/*removed for brevity*/
}
Think you have a user having username=test and email=myemail#example.com then you would like to allow users to authenticate using test instead of myemail#... `
PS. While the answer from #Jason works, sometimes you'd like to authenticate a user with real username and password, not using the email.
In this case use my answer

asp.net membership change password without knowing old one

Evaluting the method signature, it is required to know old password while changing it.
membershipUser.ChangePassword(userWrapper.OldPassword, userWrapper.Password)
Is there any way to change password without knowing old one.
string username = "username";
string password = "newpassword";
MembershipUser mu = Membership.GetUser(username);
mu.ChangePassword(mu.ResetPassword(), password);
The other answers here are correct, but can leave the password in an unknown state.
ChangePassword will throw exceptions if the password doesn't meet the requirements laid out in Web.Config (minimum length, etc.). But it only fails after ResetPassword has been called, so the password will not be known to the original user or to the person who's tried to change it. Check for complexity requirements before changing the password to avoid this:
var user = Membership.GetUser(userName, false);
if ((newPassword.Length >= Membership.MinRequiredPasswordLength) &&
(newPassword.ToCharArray().Count(c => !Char.IsLetterOrDigit(c)) >=
Membership.MinRequiredNonAlphanumericCharacters) &&
((Membership.PasswordStrengthRegularExpression.Length == 0) ||
Regex.IsMatch(newPassword, Membership.PasswordStrengthRegularExpression))) {
user.ChangePassword(user.ResetPassword(), newPassword);
} else {
// Tell user new password isn't strong enough
}
You need to reset the user's password before changing it, and pass in the generated password to ChangePassword.
string randompassword = membershipUser.ResetPassword();
membershipUser.ChangePassword(randompassword , userWrapper.Password)
or inline:
membershipUser.ChangePassword(membershipUser.ResetPassword(), userWrapper.Password)
Try to use SimpleMembershipProvider it's easier:
var token = WebSecurity.GeneratePasswordResetToken("LoginOfUserToChange");
WebSecurity.ResetPassword(token, "YourNewPassword");
Please note, all these mentioned solutions will only work if the RequiresQuestionAndAnswer property is set to false in Membership system configuration. If RequiresQuestionAndAnswer is true then the ResetPassword method needs to be passed the security answer, otherwise it will throw an exception.
In case you need RequiresQuestionAndAnswer set to true, you can use this workaround
This code mentioned on posts above is working:
string username = "username";
string password = "newpassword";
MembershipUser mu = Membership.GetUser(username);
mu.ChangePassword(mu.ResetPassword(), password);
But you have to set requiresQuestionAndAnswer="false" in web.config in membership provider tag. If it is true, resetpassword method generate an error "Value can not be null".
In this case you must supply question answer as parameter to ResetPassword.
Use the password you want to set from textbox in place of 123456.
MembershipUser user;
user = Membership.GetUser(userName,false);
user.ChangePassword(user.ResetPassword(),"123456");
#Rob Church is right:
The other answers here are correct but can leave the password in an
unknown state.
However, instead of his solution to do the validation by hand, I would try to change the password using the ResetPassword from token method and catch and show the error:
var user = UserManager.FindByName(User.Identity.Name);
string token = UserManager.GeneratePasswordResetToken(user.Id);
var result = UserManager.ResetPassword(user.Id, token, model.Password);
if (!result.Succeeded){
// show error
}
string username = "UserName";
string userpassword = "NewPassword";
string resetpassword;
MembershipUser mu = Membership.GetUser(username, false);
if (mu == null){
Response.Write("<script>alert('Invalid Username!')</script>");
}
else{
resetpassword = mu.ResetPassword(username);
if (resetpassword != null){
if (mu.ChangePassword(resetpassword, userpassword)){
Response.Write("<script>alert('Password changed successfully!')</script>");
}
}
else{
Response.Write("<script>alert('Oh some error occurred!')</script>");
}
}
string username = "UserName";
string userpassword = "NewPassword";
MembershipUser mu = Membership.GetUser(username, false);
mu.ChangePassword(mu.ResetPassword(username), userpassword);

Resources