How to check password manually in Asp.Net identity 2? - asp.net

This might actually be more of a conceptual question. In Asp.Net Identity the PasswordHasher generates a different hash for the same string every time you do:
new PasswordHasher.HashPassword("myString");
Now if for some reason I need to manually compare a user's input to the password saved in the database, I will most probably get a different string when I hash the user's entered password, than the one that is stored in the database.
Can someone please explain this to me? Shouldn't hashing the same string result in the same hash and if not, how does Identity itself realize that two different hashes are in fact the same?

PasswordHasher generates different hashes each time because it uses salting technique. This technique secure the hashed password against dictionary attacks. By the way you could use following code to manually verify the password:
if(PasswordHasher.VerifyHashedPassword("hashedPassword", "password")
!= PasswordVerificationResult.Failed)
{
// password is correct
}

var user = _userManager.Users.SingleOrDefault(p => p.PhoneNumber == model.PhoneNumber);
if (user == null)
{
return RedirectToAction(nameof(Login));
}
var result1 = _userManager.PasswordHasher.VerifyHashedPassword(user, user.PasswordHash, model.Password);
if (result1 != PasswordVerificationResult.Success)
{
ModelState.AddModelError(string.Empty, "Invalid login attempt.");
return View(model);
}

Related

Why is Dictionary<TKey,TValue>.TryGetValue(TKey, TValue) always returning true?

I'm trying to use Dictionary.TryGetValue() to search a dictionary for a username and password hash, if it matches authenticate the user, if not do something else.
The problem I'm having is that anytime the hash value does not match what's in the dictionary it returns true anyways, maybe because it matched the username key?
Is it expected behavior to return true if only the key but not that value matches?
I've included my method and user output below. I'm printing the hashes for troubleshooting purposes.
Here's example user output where the hash matches and then it doesn't:
It does not change behavior if the hash doesn't match the first time
PASSWORD AUTHENTICATION SYSTEM
Please select one option:
Establish an account
Authenticate a user
Exit the system
Enter selection: 1
Enter your username: username
Enter password:
username, 5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8]
PASSWORD AUTHENTICATION SYSTEM
Please select one option:
Establish an account
Authenticate a user
Exit the system
Enter selection: 2
Enter username you would like to authenticate
Username: username
Enter password:
5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8
5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8
Successfully authenticated as username
PASSWORD AUTHENTICATION SYSTEM
Please select one option:
Establish an account
Authenticate a user
Exit the system
Enter selection: 2
Enter username you would like to authenticate
Username: username
Enter password:
152f66d0fe3a409590ec40fea1ee037cefb4549a1f511defd16824117a768b1d
5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8
Successfully authenticated as username
Below is the authentication method
static void authUser(string userName)
{
if (!passDB.ContainsKey(userName))
Console.WriteLine($"Username \"{userName}\" does not exist.");
else if (passDB.ContainsKey(userName))
{
string secret;
string testHash;
int tryCount = 4;
do
{
secret = HidePassInput();
SHA256 sha256Hash = SHA256.Create();
testHash = GetHash(sha256Hash, secret);
Console.WriteLine(testHash);
if (passDB.TryGetValue(userName, out testHash))
{
Console.WriteLine(testHash);
Console.WriteLine($"Successfully authenticated as {userName}\n");
tryCount = 0;
}
else
{
tryCount--;
Console.WriteLine($"Failed to autheticate as {userName}. {tryCount} more tries left.\n");
}
} while (tryCount > 0);
}
}
It appears that you are misunderstanding the use of the TryGetValue method.
The first parameter is the key for which you want to get its value. The second parameter is an out parameter. If the key exists, its value will be assigned to the variable that you've used as argument to the out parameter. Whatever value was held by testHash is overwritten.
TryGetValue does not receive a value that you are looking for. It only receives a key. It returns true if that key is found, otherwise false. The value of the found key is assigned to the out variable.

MVC Login password comparison case sensitive

I need to compare the username field and the password field with the one in database, my code does work but the problem is that the comparison is not case sensitive. below is part of my code, I know I must be missing something silly. any help will be appreciated, Thanks
var UserDetail = db.UserTbls.Where(x => x.UserName == UserModel.UserName &&
x.Password == UserModel.Password).FirstOrDefault();
if (UserDetail == null)
{
UserModel.loginErrorMessage = "Wrong Username or Password";
return View("Login", UserModel);
}
else
{
Session["UserId"] = UserDetail.UserId;
return RedirectToAction("Index", "Home");
}
EF to SQL Server will perform string comparisons case-insensitive. To perform a case-sensitive check like you describe:
var users = var UserDetail = db.UserTbls.Where(x => x.UserName == UserModel.UserName).ToList();
var matchingUser = users.SingleOrDefault(x => x.Password == password);
The .ToList() will mean the next expression will be evaluated against Objects, returning all user records with that name. If user names are unique then this should be a SingleOrDefault(). From there the == operation on the password will be case sensitive by default.
However, as mentioned by Stephen, Passwords should always be hashed with a salt and stored, where the HASHES are compared, not plain-text passwords.
I recommend reading up on SHA-1 hashes.
string.Compare method has and overload which you can use for comparing the username and passwords.
As Stephen mentioned, you certainly need to work on implementing proper security measures.
If you want to compare user names ignoring case, this is an option:
x.UserName.Equals(UserModel.UserName, StringComparison.OrdinalIgnoreCase)
If you want to compare user names case sensitive, this is an option:
x.UserName.Equals(UserModel.UserName, StringComparison.Ordinal)
Update:
For anyone coming to this post who see's my answer, I'd like to point to Steve Py's answer which I've upvoted. And, here is a nice related explanation.
(I figured that I might as well leave my answer here in case it's still helpful for people to see different approaches to comparing strings)

How to authencticate the encrypt password with input password value?

Here we call webapi service from mobile application to authenticate the userid and encrypted password in database.
So to authenticate I encrypt the input password and compare with database password?
Another question: Is it correct what I am doing?
Or is it a better way to decrypt the database password value and check with input value. If second way is better, how can I do that?
Below is my code:
using (LoginServiceEntities context = new LoginServiceEntities())
{
var crypto = new SimpleCrypto.PBKDF2();
var encrypass = crypto.Compute(Password);
var user = (from u in context.user_master
where String.Compare(u.UserID, UserID, StringComparison.OrdinalIgnoreCase) == 0
&& u.Password== encrypass
select u).FirstOrDefault();
return user != null;
}
Password in database should not be decrypted.
What you are doing is correct. Just compare the encrypted password in database with the encrypted input

WebSecurity.ChangePassword returning FALSE value

I can't figure out why my WebSecurity.ChangePassword is not working. Here's the piece of code I'm working on.
if (WebSecurity.ChangePassword(USER, oldpass, password)) {
Response.Redirect("~/SuperAdmin");
return;
}else {
ModelState.AddFormError(USER);
// I put the each WebSecurity.ChangePassword parameter to this parameter to check whether
//each parameter valid or not (print it out)
}
and for each parameter of WebSecurity.ChangePassword, I retrieve it from the database as follows
if(IsPost){
Validation.RequireField("email", "Masukkan email");
Validation.RequireField("password", "Masukkan Password");
Validation.RequireField("userid", "user ID tidak ada!");
email = Request.Form["email"];
password = Request.Form["password"];
userId = Request.Form["userId"];
if(Validation.IsValid()){
var db = Database.Open("StarterSite");
var updateCommand2 = "UPDATE UserProfile SET Email=#0 WHERE UserId=#1";
db.Execute(updateCommand2, email,userId);
var USER = db.QueryValue("SELECT a.Email FROM UserProfile a, webpages_Membership b WHERE a.UserId=b.UserId AND a.UserId= #0", userId);
var oldpass = db.QueryValue("SELECT Password FROM webpages_Membership WHERE UserId = #0", userId);
Can anyone tell me what seems to be the problem here? Thanks in advance
The WebPages Membership has everything built you do not need to get the users email address and password (I am guessing the email address is the username right?) The ChangePassword method takes 3 arguments. which is UserName, CurrentPassword, NewPassword.
The reason your getting false is because your getting the old password from the database based on the users current Id, but the old password does not match the users current password because old one is encrypted and you're not encrypting the one they submit (in fact you don't even have a field for them to enter their current password).
The WebPages Membership provider will do all the updating you do not need open the database and update the users password, the weird thing you're doing is telling the user to enter a new password but not asking for the current one! Here see this for more information:
http://www.thecodingguys.net/reference/asp/websecurity-changepassword
Make sure the user you are trying to change password for is not LockedOut. You can check it by this
select * from aspnet_membership
where
IsLockedOut = 1

Storing DotNetOpenAuth information and user info retrieval

This question is a bit of a structural/design question as I'm having trouble working out the best way to perform the task.
In my MVC app, I am using DotNetOpenAuth (3.4) as my login information provider and just using the standard FormsAuthentication for cookies etc.
The current user table in the DB has:
UserId (PK, uniqueidentifier)
OpenIdIdentifier (nvarchar(255))
OpenIdDisplay (nvarchar(255))
Displayname (nvarchar(50))
Email (nvarchar(50))
PhoneNumber (nvarchar(50))
As the UserId is the clear identifier for a user (they should be able to change their OpenId provider at a later date), it is the key that other tables link to (for a user).
This is the current code, that on a successfull authentication, creates a temporary user and redirects to Create Action.
switch (response.Status)
{
case AuthenticationStatus.Authenticated:
FormsAuthentication.SetAuthCookie(response.ClaimedIdentifier, false);
var users = new UserRepository();
if (!users.IsOpenIdAssociated(response.ClaimedIdentifier))
{
var newUser = new DueDate.Models.User();
newUser.OpenIdIdentifer = response.ClaimedIdentifier;
newUser.OpenIdDisplay = response.FriendlyIdentifierForDisplay;
TempData["newUser"] = newUser;
return this.RedirectToAction("Create");
}
And now for the crux of the question:
Is the response.ClaimedIdentifier the correct piece of information to be storing against a user?
Is FormAuthentication.SetAuthCookie the preferred way to forms authentication? Or is there a better way?
When I call SetAuthCookie, there is no data relating to the user except for the ClaimedIdentifier. If I'm consistently referring to their UserId, is a better idea to create the user, then store that UserId in the cookie instead of the ClaimedIdentifier?
If I'm using that UserId in a number of places, how do I either retrieve it from the cookie, or store it somewhere else more logical/useful?
A bit long winded but I've been having trouble trying to work out the best way to do this/
1.Is the response.ClaimedIdentifier the correct piece of information to be storing against a user?
Yes. And make sure the column you store it in the database with is case sensitive. Here is a table schema that demonstrates how to make sure it is case sensitive. This comes out of the DotNetOpenAuth project template's database schema. The "CS" bit of the specified collation stand for Case Sensitive.
CREATE TABLE [dbo].[AuthenticationToken] (
[AuthenticationTokenId] INT IDENTITY (1, 1) NOT NULL,
[UserId] INT NOT NULL,
[OpenIdClaimedIdentifier] NVARCHAR (250) COLLATE SQL_Latin1_General_CP1_CS_AS NOT NULL,
[OpenIdFriendlyIdentifier] NVARCHAR (250) NULL,
[CreatedOn] DATETIME NOT NULL,
[LastUsed] DATETIME NOT NULL,
[UsageCount] INT NOT NULL
);
2.Is FormAuthentication.SetAuthCookie the preferred way to forms authentication? Or is there a better way?
For MVC apps it definitely is, since you still can return your preferred ActionResult from the method.
3.When I call SetAuthCookie, there is no data relating to the user except for the ClaimedIdentifier. If I'm consistently referring to their UserId, is a better idea to create the user, then store that UserId in the cookie instead of the ClaimedIdentifier?
That sounds like personal preference. But I would typically go with user_id, since it might result in a faster database lookup every time an HTTP request comes in that requires you to look up any user information.
4.If I'm using that UserId in a number of places, how do I either retrieve it from the cookie, or store it somewhere else more logical/useful?
FormsAuthentication does provide a way to store more information in its encrypted cookie than just username, but it is harder than you'd expect to use it. This snippet comes out of DotNetOpenAuth's web SSO RP sample:
const int TimeoutInMinutes = 100; // TODO: look up the right value from the web.config file
var ticket = new FormsAuthenticationTicket(
2, // magic number used by FormsAuth
response.ClaimedIdentifier, // username
DateTime.Now,
DateTime.Now.AddMinutes(TimeoutInMinutes),
false, // "remember me"
"your extra data goes here");
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(ticket));
Response.SetCookie(cookie);
Response.Redirect(Request.QueryString["ReturnUrl"] ?? FormsAuthentication.DefaultUrl);
Then you can get at that extra data in a future HTTP request with this:
var cookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
if (cookie != null) {
var ticket = FormsAuthentication.Decrypt(cookie.Value);
if (!string.IsNullOrEmpty(ticket.UserData)) {
// do something cool with the extra data here
}
}

Resources