SHA512 hashed credentials fail on validation - c#

I got this register form where i get the user email and password and hash the password using SHA512
public Boolean IsRegistered(String email, String pass)
{
SHA512 shaM = new SHA512Managed();
if (pass.Length > 0 && email.Length > 0)
{
byte[] data = Encoding.UTF8.GetBytes(pass);
String encryptedpass = Encoding.UTF8.GetString(shaM.ComputeHash(data));
using (ModelContainer db = new ModelContainer())
{
//User usr = db.UserSet.Where(u => u.PasswordDigest == encryptedpass && u.Email == email).First();
int matches = (from u in bd.UserSet
where u.PasswordDigest == encryptedpass&& u.Email == email
select new
{
Id = u.Id
}
).Count();
if (matches > 0)
{
return true;
}
}
}
return false;
}
I use this method each time the user logs in and it works like a charm (i guess),
thing is when i prompt the user to change his/her password i cannot seem to be able to validate the old one here is what i try
I do the following to retrive the user data on the MyAccount form's constructor
User user;.
public MyAccount()
{
InitializeComponent();
try
{
using (ModelContainer db = new ModelContainer())
{
user = (from u in db.UserSet where u.Id == 2 select u).First();
txtName.Text = user.Name;
txtEmail.Text = user.Email;
}
}
catch (Exception x)
{
ErrorAlert error = new ErrorAlert("Error: " + x.Message);
error.Owner = getParentWindow();
error.ShowDialog();
}
}
then I validate it on the forms button_click
using (ModelContainer db = new ModelContainer())
{
SHA512 shaM = new SHA512Managed();
string oldpass = Encoding.UTF8.GetString(shaM.ComputeHash(Encoding.UTF8.GetBytes(ptxtOldPassword.Password)));
shaM.Dispose();
db.UserSet.Attach(user);
Regex rgx = new Regex(#"\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z");
if (rgx.IsMatch(txtEmail.Text))
{
if (oldpass == user.PasswordDigest)
{
if (ptxtNewPassword.Password.Equals(ptxtNewPassword2.Password))
{
string newpass = Encoding.UTF8.GetString(shaM.ComputeHash(Encoding.UTF8.GetBytes(ptxtNewPassword.Password)));
user.Name = txtName.Text;
user.Email = txtEmail.Text;
user.PasswordDigest = newpass;
db.SaveChanges();
}
else
{
ErrorAlert error = new ErrorAlert("Passwords do not match");
error.Owner = getParentWindow();
error.ShowDialog();
}
When I comapare the old password in the database with the one the user enter they do not match since they are strings I've tried using equals with no luck I thought == would work but I was wrong, i looked into other answers and found this Sha512 not returning equal in c# hash validation sadly it didn't work for me, I need to understand why my first validation work and the second doesnt
so any help is apreciated Have a nice day

You don't really need to compare the final strings, test at the bytes-level. Check this previous question.
Also, if you already validated the existence of the user (by email or any other mechanism), why don't just change / update with the new password? You could validate with the email and re-use the working function for login / signin.

Related

ModelState.AddModelError is setup to display Canned message instead of real Error

In my website i had a group of people working on my site and i have this code that they put a canned message in for an error. When i debug the code it is actually a different error but displays this canned message. For instance when i put the information in the form i used an email address that already exists in the database but it is showing a message to check the password requirements. How can this be fixed to show the actual error. To me it also seems like there is a lot code going on in this that may not need to be or can be achieved cleaner Your thoughts?
Code of Post Action:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult CreateCompanyUser(ExpandedUserDTO ExpandedUserDTO)
{
try
{
if (ExpandedUserDTO == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var Email = ExpandedUserDTO.Email.Trim();
var UserName = ExpandedUserDTO.UserName.Trim();
var Password = ExpandedUserDTO.Password.Trim();
if (UserName == "")
{
throw new Exception("No Username");
}
if (Password == "")
{
throw new Exception("No Password");
}
// UserName is LowerCase of the Email
// UserName = Email.ToLower();
// Create user
var objNewAdminUser = new Models.ApplicationUser { UserName = UserName, Email = Email };
var AdminUserCreateResult = UserManager.Create(objNewAdminUser, Password);
if (AdminUserCreateResult.Succeeded == true)
{
string strNewRole = Convert.ToString(Request.Form["Roles"]);
if (strNewRole != "0")
{
// Put user in role
UserManager.AddToRole(objNewAdminUser.Id, strNewRole);
}
var viewModel = new Users();
{
viewModel.UsersId = Convert.ToString(Guid.NewGuid());
viewModel.Email = Email;
viewModel.FirstName = UserName;
viewModel.AspNetUsersId = objNewAdminUser.Id;
viewModel.CreatedDate = System.DateTime.Now;
viewModel.UpdatedDate = System.DateTime.Now;
};
UsersBusinessModels Login = new UsersBusinessModels();
var results = Login.insertUserWithougAsny(viewModel);
string[] roleRemove = new string[2] { "Administrator", "CompanyAdmin" };
ViewBag.Roles = GetAllRolesAsSelectList().Where(k => !roleRemove.Contains(k.Text)).ToList();
// return RedirectToAction();
Response.Redirect("/Customer/ManageUsers/" + User.Identity.GetUserId());
return PartialView();
}
else
{
ViewBag.Roles = GetAllRolesAsSelectList();
ModelState.AddModelError(string.Empty,
"Error: Failed to create the user. Check password requirements.");
return PartialView(ExpandedUserDTO);
}
}
catch (Exception ex)
{
ViewBag.Roles = GetAllRolesAsSelectList();
ModelState.AddModelError(string.Empty, "Error: " + ex);
string[] roleRemove = new string[2] { "Administrator", "CompanyAdmin" };
ViewBag.Roles = GetAllRolesAsSelectList().Where(k => !roleRemove.Contains(k.Text)).ToList();
return PartialView(ExpandedUserDTO);
}
}

how to check multipal value from mongodb using c#

The following C# code accepts two parameter username and password from API using ajax
public Login[] checkLogin(models.Login log)
{
Boolean flag = false;
connection obj = new connection();
IMongoDatabase server = obj.getConnection();
var collection = server.GetCollection<models.Login>("login");
string param = "{'username':'" + log.username + "','password':'"+ log.password +"'}";
List<Login> result = new List<Login>();
var check = collection.Find(param);
foreach(var emp in check.ToList())
{
result.Add(emp);
}
if(result == null)
flag = false;
else
flag = true;
return result.ToArray();
}
I want to check the username and password from my MongoDB database. I am trying to find method but don't know how to check the value if it is available or not.
In order to test whether provided credentials are valid, your method should simply return a boolean value.
You might do something like this.
public IMongoCollection<models.Login> GetLoginCollection()
{
var client = new MongoClient();
var database = client.GetDatabase("dbName");
var collection = database.GetCollection<models.Login>("login");
return collection;
}
public bool CheckLogin(models.Login log)
{
var collection = this.GetLoginCollection();
var authSuccessful = collection
.Count(login =>
login.username == log.username &&
login.password == log.password) > 0;
return authSuccessful;
}
As an alternative, CheckLogin() method might be implemented using explictly-defined filters.
public bool CheckLogin(models.Login log)
{
var collection = GetLoginCollection();
var filter = Builders<models.Login>.Filter
.And(
Builders<models.Login>.Filter.Eq(login => login.username, log.username),
Builders<models.Login>.Filter.Eq(login => login.password, log.password));
var authSuccessful = collection.Count(filter) > 0;
return authSuccessful;
}
Note that storing clear text password within the database is a bad practice. Nobody but the user should know the actual password. One solution is storing the hashed password in the database. On authentication you can compare the hash of the provided password with your stored value. One of the most common hash functions is md5.

How to get user's password expiration date from Active Directory?

I have implemented implemented Active Directory authentication in ASP.NET MVC 5 using LDAP. I want to know how to get a user's
Account Locked (boolean)
Password Expired (boolean)
Password Expiry Date (DateTime)
This is my current code:
using System.Web.Mvc;
using System.Web.Security;
using MvcApplication.Models;
[HttpPost]
public ActionResult Login(LoginModel model, string returnUrl)
{
if (!this.ModelState.IsValid)
{
return this.View(model);
}
if (Membership.ValidateUser(model.UserName, model.Password))
{
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
if (this.Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
&& !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
{
return this.Redirect(returnUrl);
}
return this.RedirectToAction("Index", "Home");
}
this.ModelState.AddModelError(string.Empty, "The user name or password provided is incorrect.");
return this.View(model);
}
public ActionResult LogOff()
{
FormsAuthentication.SignOut();
return this.RedirectToAction("Index", "Home");
}
The easiest way is to PInvoke LogonUser Win32 API.e.g
http://www.pinvoke.net/default.aspx/advapi32/LogonUser.html
Read also MSDN reference: https://msdn.microsoft.com/en-us/library/aa378184.aspx
The examples for your questions: https://www.codeproject.com/articles/18102/howto-almost-everything-in-active-directory-via-c
I manage to do it using a combination of System.Web.Security and System.DirectoryServices.
public bool IsExpired(MembershipUser user, LoginModel model)
{
bool result = false;
string ldap = ConfigurationManager.ConnectionStrings["ADConnectionString"].ConnectionString;
DirectoryEntry rootEntry = new DirectoryEntry(ldap, model.UserName, model.Password, AuthenticationTypes.Secure);
DirectorySearcher mySearcher = new DirectorySearcher(rootEntry);
SearchResultCollection results;
string filter = "maxPwdAge=*";
mySearcher.Filter = filter;
results = mySearcher.FindAll();
long maxDays = 0;
if (results.Count >= 1)
{
Int64 maxPwdAge = (Int64)results[0].Properties["maxPwdAge"][0];
maxDays = maxPwdAge / -864000000000;
}
long daysLeft = 0;
daysLeft = maxDays - DateTime.Today.Subtract(user.LastPasswordChangedDate).Days;
if (daysLeft <0)
{
result = true;
} else
{
if (daysLeft<=14)
{
this.Expiring = true;
this.ExpiringString = String.Format("You must change your password within" + " {0} days", daysLeft);
}
else
{
this.Expiring = false;
}
}
return result;
}
Here's another approach to getting the user's account password expiration date, and from the result you can easily calculate IsExpired:
public static DateTime GetPasswordExpirationDate(UserPrincipal user)
{
DirectoryEntry deUser = (DirectoryEntry)user.GetUnderlyingObject();
ActiveDs.IADsUser nativeDeUser = (ActiveDs.IADsUser)deUser.NativeObject;
return nativeDeUser.PasswordExpirationDate;
}
You'll need to add a reference to the ActiveDS COM library typically found at C:\Windows\System32\activeds.tlb.
I got here from Google search and I found the current answers to be outdated and/or cumbersome (I don't want to import COM dlls, and I would like to avoid complex arithmetics if possible). In addition, it seems that the accepted answer doesn't take into account more granular settings for maxPwdAge that could be in effect.
I found out that AD exposes the calculated property msDS-UserPasswordExpiryTimeComputed which can be used directly, instead of performing complex calculations:
public DateTime? GetPasswordExpirationTime()
{
var path = #"LDAP://yourserver";
// null uses the current user's credentials.
var user = "yourUserNameOrNull";
var password = "yourPasswordOrNull";
var idToSearch = "userNameToCheck";
using(var entry = new DirectoryEntry(path, user, password, AuthenticationTypes.Secure))
using(var ds = GetSearcher(entry, $"(sAMAccountName={idToSearch})"))
{
ds.PropertiesToLoad.Add("msDS-UserPasswordExpiryTimeComputed");
var user = ds.FindOne();
return DateTimePropertyFromLong(user, "msDS-UserPasswordExpiryTimeComputed")
}
}
public static DateTime? DateTimePropertyFromLong(SearchResult sr, string propName)
{
if (!sr.Properties.Contains(propName)) return null;
var value = (long) sr.Properties[propName][0];
return value == long.MaxValue ? (DateTime?)null : DateTime.FromFileTimeUtc(value);
}
The relevant bits are just PropertiesToLoad.Add("msDS-UserPasswordExpiryTimeComputed") and the conversion from the strange long format returned by AD via the DateTime.FromFileTimeUtc method.
Edit
As per #t3chb0t, GetSearcher is a simple helper method, responsible for opening a DirectorySearcher over the DirectoryEntry:
private static DirectorySearcher GetSearcher(DirectoryEntry entry, string filter = null)
{
if (filter == null)
return new DirectorySearcher(entry) {ClientTimeout = TimeSpan.FromSeconds(30)};
return new DirectorySearcher(entry, filter) {ClientTimeout = TimeSpan.FromSeconds(30)};
}

Byte conversion in Linq

please help me in Linq. i am completely new in linq. please see my code below.
public Entities.ServiceResult<Customer> CustomerChangePassword(string CustomerId, string OldPassword, string NewPassword)
{
long _customerId = Convert.ToInt32(CustomerId);
byte _oldPassword = Convert.ToByte(OldPassword);
var _result = (from c in context.customers where (c.CustomerId == _customerId && c.Password == _oldPassword) select c.Password.Single).SingleOrDefault();
if (_result != null)
{
string newpassword;
newpassword = Convert.ToString(_result.Password);
newpassword = NewPassword;
context.SaveChanges();
return new Entities.ServiceResult<Customer>
{
ErrorState = 0,
Message = "Password Changed Successfully."
};
}
else
{
return new Entities.ServiceResult<Customer>
{
ErrorState = 1,
Message = "Old Password Is Wrong."
};
}
}
the above code i am doing a change password functionality. in this code c.Password is byte column, and i am passing from mobile as string. in this case how to handle this. please help me to do this
there is no need to check the password in finding the customer. That's because your are dealing with an IQueriable and you can not do this kind od job easily there. Also you should change the password in place to tell the context to save it for you.
Consider the code for Converting string to byte array as well.
With SequenceEqual method you check the equality of two arrays.
I hope the following code helps :
public Entities.ServiceResult<Customer> CustomerChangePassword(string CustomerId, string OldPassword, string NewPassword)
{
long _customerId = Convert.ToInt32(CustomerId);
byte[] _oldPassword = Encoding.ASCII.GetBytes(OldPassword);
var _result = from c in context.customers where (c.CustomerId == _customerId) select c;
if (_result == null || _result.Count() == 0)
{
return new Entities.ServiceResult<Customer>
{
ErrorState = 1,
Message = "User does not exists."
};
}
var customer = _result.First();
if (!customer.Password.SequenceEqual(_oldPassword))
{
return new Entities.ServiceResult<Customer>
{
ErrorState = 1,
Message = "Old Password Is Wrong."
};
}
customer.Password = Encoding.ASCII.GetBytes(NewPassword);
context.SaveChanges();
return new Entities.ServiceResult<Customer>
{
ErrorState = 0,
Message = "Password Changed Successfully."
};
}
Good Luck.

Forget password form in asp.net mvc 4

I try to implement forget password form in my asp.net mvc 4 project, everything works fine, but when I try to login to system with new password it told me that I have wrong password.
[HttpPost]
public ActionResult ForgetPassword(UserViewModel userModel) {
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
var random = new Random();
var result = new string(
Enumerable.Repeat(chars, 8)
.Select(s => s[random.Next(s.Length)])
.ToArray());
User user = _userRepo.GetUserByEmail(userModel.Email);
if (user == null) {
ViewBag.Error = Resources.Account.userEmailNotExist;
return View(userModel);
}
String newHashedPassword = Crypto.HashPassword(result);
user.Password = newHashedPassword;
user.LastPasswordChangedDate = DateTime.UtcNow;
_userRepo.SaveChanges();
string enMessage = "Your new password: " + result;
var httpCookie = Request.Cookies["lang"];
if (httpCookie != null && httpCookie.Value == "en") {
_mailHelper.SendEmail(userModel.Email, "New password", enMessage);
}
return RedirectToAction("ConfirmPasswordChange", "Account");
}
Login form:
[HttpPost]
public ActionResult Login(UserViewModel user) {
var users = _userRepo.GetAllEntitiesWithParam("JobsDb_Users_GetByEmail", user.Email).FirstOrDefault();
...
try {
var tryLogin = WebSecurity.Login(users.Username, user.Password, true);
if (tryLogin == WebSecurity.MembershipLoginStatus.Failure)
{
var httpCookie = Request.Cookies["lang"];
if (httpCookie != null && httpCookie.Value == "en") {
ViewBag.Error = "Your password is incorrect.";
new SeoHelper().ReturnSeoTags(this, "Login");
}
return View(user);
}
...
} catch {
...
}
}
inside WebSecurity
public static MembershipLoginStatus Login(string username, string password, bool rememberMe) {
if (Membership.ValidateUser(username, password)) {
FormsAuthentication.SetAuthCookie(username, rememberMe);
return MembershipLoginStatus.Success;
} else {
return MembershipLoginStatus.Failure;
}
}
inside Membership
public override bool ValidateUser(string username, string password) {
if (string.IsNullOrEmpty(username)) {
return false;
}
if (string.IsNullOrEmpty(password)) {
return false;
}
User user = _userRepository.GetAll().FirstOrDefault(usr => usr.Username == username);
if (user == null) {
return false;
}
if (!user.IsApproved.Value) {
return false;
}
if (user.IsLockedOut.Value) {
return false;
}
String hashedPassword = user.Password;
Boolean verificationSucceeded = (hashedPassword != null && Crypto.VerifyHashedPassword(hashedPassword, password));
if (verificationSucceeded) { //here is I have false if try to login using password from forget form
user.PasswordFailuresSinceLastSuccess = 0;
user.LastLoginDate = DateTime.UtcNow;
user.LastActivityDate = DateTime.UtcNow;
} else {
int failures = user.PasswordFailuresSinceLastSuccess.Value;
if (failures < MaxInvalidPasswordAttempts) {
user.PasswordFailuresSinceLastSuccess += 1;
user.LastPasswordFailureDate = DateTime.UtcNow;
} else if (failures >= MaxInvalidPasswordAttempts) {
user.LastPasswordFailureDate = DateTime.UtcNow;
user.LastLockoutDate = DateTime.UtcNow;
user.IsLockedOut = true;
}
}
_userRepository.SaveChanges();
if (verificationSucceeded) {
return true;
}
return false;
}
First step is to open up your database and verify that the new password was actually persisted. If it has, the most likely cause is that your repository is working with stale (cached) data.
If you're using Entity Framework, this happens because the framework will, by default, cache the state of the database at the time the DbContext is created, so it is retaining your original password. You can verify this by logging in with the original password.
I am not sure but following code does not look right to me:
User user = _userRepo.GetUserByEmail(userModel.Email);
if (user == null) {
ViewBag.Error = Resources.Account.userEmailNotExist;
return View(userModel);
}
String newHashedPassword = Crypto.HashPassword(result);
user.Password = newHashedPassword;
user.LastPasswordChangedDate = DateTime.UtcNow;
_userRepo.SaveChanges();
You fetched the user from repository, make changes to user object in memory and then called SaveChanges() on the repository. Does that work in your world? How does _userRepo.SaveChanges(); knows which object has changed. Do you see correct hashed value in DB after the call? What value you see in ValidateUser() method for password? Is the hashing algorithm consistent both while generating hashed password and while verifying?
I could be wrong, if that's the case it will be good if you share little bit more of analysis around the question I asked above.

Categories

Resources