User is logged in and wants to do something major and I want them to re-enter their password so I can make sure that they are the user that is logged in.
How can I confirm that this password is for the account holder?
Would be happy to know how to do it via ASP.NET Identity or how to set up a stored proc to go against the AspNetUsers table or how to do it via Entity Framework.
How can I confirm that this password is for the account holder?
how to do it via ASP.NET Identity
To reverify the password of currently logged in user, provide the user VerifyView to enter password and use the following method to check if the user exists.
var user = await UserManager.FindAsync(User.Identity.Name,VerifyViewModel.Password)
If the user is found, the current request is the same from the account holder.
Membership.ValidateUser is from earlier version of Membership framework, not from ASP.NET Identity.
You can also use UserManager.CheckPassword() extension function:
UserManagerExtensions.CheckPassword Method
string id = User.Identity.GetUserId();
var user = UserManager.FindById(id);
if(!UserManager.CheckPassword(user, model.Password))
{
ModelState.AddModelError("Password", "Incorrect password.");
}
With Identity framework you never want to hit the database directly. Always use the API provided. The database structure has changed several times in the past few years, so introducing dependencies (e.g. on a data context) is adding work for no reason.
For async usage, see the answer already provided by jd4u.
For synchronously identifying that the password matches the current user, you need to first include:
using Microsoft.AspNet.Identity;
as this brings in a number of synchronous extension methods for identity framework.
You can then check with Find on the UserManager like this:
var user = UserManager.Find(User.Identity.Name, password);
if (user != null)
{
// It is them!
}
If the user is not null, then you have a match of password and current username.
You can use UserManager to do that:
if(UserManager.PasswordHasher.VerifyHashedPassword("hashedPassword", "password")
!= PasswordVerificationResult.Failed)
{
// password is correct
}
For more information see the link:
How to check password manually in Asp.Net identity 2?
Related
I'm trying to add 2-factor authentication using pin codes sent in email. The 2FA step is only required by users 30 days after they last completed the 2FA step.
Project's tech is ASP.NET MVC 5 using EntityFramework 6 with NuGet package version 2.2.2 of the Microsoft.AspNet.Identity packages(.Core, .EntityFramework, .Owin).
I've been following the advice in this tutorial, but integrating it in my company's already existing solution: https://learn.microsoft.com/en-us/aspnet/identity/overview/features-api/two-factor-authentication-using-sms-and-email-with-aspnet-identity
My problems
SignInManager never returns RequiresVerification when using the PasswordSignIn
I assumed that I should expect this login status, when the "TwoFactorEnabled" flag is set to true in the database for each user. I'm not sure if I should use this, if I only want users to go through the 2FA verification every 2 weeks, as it's my impression that it will require users to go through this every time. Either that, or I should use a timestamp set on the user to determine, if it's time to reenable the "TwoFactorEnabled" flag?
I can't retrieve the verified user's ID, when verifying code
I thought that after performing a normal PasswordSignIn, the server would be able to retrieve the user's ID, for example when verifying that the entered pin code is correct:
[HttpPost]
[AllowAnonymous]
public async Task<ActionResult> VerifyCode(string pin)
{
string userId = await SignInManager.GetVerifiedUserIdAsync().WithCurrentCulture();
if (userId == null || String.IsNullOrEmpty(pin))
{
return View("Error");
}
var user = await UserManager.FindByIdAsync(userId);
if (await UserManager.VerifyTwoFactorTokenAsync(user.Id, "EmailCode", pin))
{
await SignInManager.SignInAsync(user, false, false);
return RedirectToAction("Index", "Dashboards");
}
else
{
ModelState.AddModelError("", "Invalid code");
}
return View();
}
It's a little bit confusing, since most tutorials are very old, and use the AuthenticationManager, which I have never seen before.
How do I prevent users from simply skipping to other pages from the verification screen, if they're already "successfully logged in with username and password"
Won't they be able to bypass the Authorization attribute at this point?
What already works
I can get the UserManager to send an email with a token(pin code), and it will be successfully verified, if I enter the correct user ID
What I have done
I have the standard/default Identity setup, so we're using the standard configuration pretty much that comes with new MVC 5 projects.
Startup.Auth:
// Enables the application to temporarily store user information when they are verifying the second factor in the two-factor authentication process.
app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(10));
// Enables the application to remember the second login verification factor such as phone or email.
// Once you check this option, your second step of verification during the login process will be remembered on the device where you logged in from.
// This is similar to the RememberMe option when you log in.
app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
2FA provider setup in ApplicationUserManager:
manager.RegisterTwoFactorProvider("EmailCode", new EmailTokenProvider<ApplicationUser>
{
Subject = "Security Code",
BodyFormat = "Your security code is {0}"
});
manager.EmailService = new EmailService();
//manager.SmsService = new SmsService();
var dataProtectionProvider = options.DataProtectionProvider;
if (dataProtectionProvider != null)
{
manager.UserTokenProvider =
new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity"));
}
return manager;
Thank you very much in advance for any help.
I think I may have figured out what the problem is.
The UserManager returned 0 for GetValidTwoFactorProvidersAsync. It seems that this occurs, when the email isn't confirmed for the user. I tried settings email as confirmed for the user, and now RequiresVerification is returned.
When RequiresVerification is returned, it seems the user isn't completely signed in, but I'm still able to fetch the user ID in subsequent code verification calls using the SignInManager's GetVerifiedUserId method.
So now, when a user logs in, before performing the password sign-in, I simply perform a check to see, when the user last completed 2FA authentication. If it's been more than 30 days, I reenable the 2FA flag in the database. Then when the password signin is performed, I'll get RequiresVerification as expected, and I can continue the rest of the flow as any standard 2FA verification would otherwise require.
I have a question, I have Web Application on Asp Net Core 1.1.0 with the implemented classical Identity model, and OpenIddict for Authorization.
In the classical implementation when registering the user using email / password, I need to realize the possibility of registering also with CodeNumber (numerical sequence length of 15 characters) as login name, and pin code (numeric combination of 4 characters) as a password.
CodeNumber and PinCode will be stored in separate from User Indentity table.
So that users can use two methods to log on to the system
Tell me please how can this be achieved in Asp .Net Core?
Thank you in advance.
Simplistically, the way Identity works out of the box is that the user is queried by username and then signed in automatically by comparing the password. To handle things a different way, you just need to take more manual control over that process. Instead of using something like UserManager.FindByNameAsync, you'd simply fallback to your context and do something like:
var user = db.Users.Where(m => m.CodeNumber == model.CodeNumber && m.PinCode == model.PinCode);
if (user == null)
{
ModelState.AddModelError("", "Incorrect code number and/or pin code");
}
Then, just sign the user in manually, if they exist:
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
I am using OAuth to sing the user up with Facebook.
I am doing successful signup using the following method:-
Request.GetOwinContext().Authentication.SignIn(id);
This Autheticates the user. I can check this using User.Identity.IsAuthenticated
But I am not able to get the name of the User or any of his details using User.Identity.Name.
How can I get the name of the User who has just been authenticated without going back to the database?
The reason you can't get anything from User.Identity.Name is because there's no actual user record to pull that info from, which means hitting the database wouldn't help you anyways. Sign-in provider logins are handled separately from system user logins, in a separate table in fact. They can and often are tied to an actual user account, but they don't have to be. The provider login is enough to authenticate, and sometimes that may be all that's needed. If you do actually need the user information, then you'll need to create a user record after successful provider login and associate that with the provider login.
The best response that thing I came up with is adding claims and adding the Name claim to the answer.
var newClaims = new Claim[]
{
new Claim(ClaimTypes.NameIdentifier, PersonId.ToString()),
new Claim(ClaimTypes.GivenName, FirstName),
new Claim(ClaimTypes.Surname, LastName),
new Claim(ClaimTypes.Name, FirstName + LastName),
new Claim(ClaimTypes.Email, Email)
};
The Name claim that I added would fill the User.Identity.Name field.
I hope this helps someone.
To reset a password we need to know a UserId and pass it to the UserManager.ResetPasswordAsync method. In the Identity 1.0 it was possible to obtain UserId from the UserManager.PasswordResetTokens.Validate method ((UserManager.PasswordResetTokens.Validate(token)).UserId). Now it's gone and all existing examples telling me that I need to ask an user for username or email. This is not user friendly, I don't want my users enter username again if token is valid.
This is already established tradition in ASP.NET Identity - something that worked before is broken in the new release. Of course I can create my own combined token with embedded UserId, but why I need to do extra work? New releases should improve things, not make them worse.
Asp.Net Identity 2.x do not provide a way to find a user by a token created from GeneratePasswordResetTokenAsync method.
You have two options:
1) Add the user id at the url you will send to the user. Ex:
var token = await _userManager.GeneratePasswordResetTokenAsync(applicationUser);
var callbackUrl = $"/reset-password/?user={WebUtility.UrlEncode(applicationUser.Id)}&code={WebUtility.UrlEncode(token)}";
This approach is more user friendly. But I know people that says this is a security issue because anyone with the link could reset the user password.
2) Ask for the user name at the reset password page, as you did. Ex:
public async Task<YourResultModel> ResetPassword(ResetPasswordViewModel vm)
{
// Your password validations...
var user = await _userManager.FindByNameAsync(vm.UserName);
// could be FindByEmailAsync if your app uses the user e-mail to login.
IdentityResult result = await _userManager.ResetPasswordAsync(user, vm.Token, vm.NewPassword);
return YourResultModelFromIdentityResult(result);
}
Before choose between this two approaches you need to think about your specific scenario. For example: If your app uses the user e-mail as username and to intercept the token the "interceptor" needs to access the user e-mail box, remove the user id from reset password link will not improve the security of your app. Because who has the link already knows the e-mail of the user.
I developed a web application. It has a login form using ASP.NET membership. Now I need to add a form allowing to change the password. Before a new password can be set, the old password must be entered by the user.
How can I check if the old password is valid?
// checking if the old password is correct
if (Membership.ValidateUser(username, oldPassword))
{
// setting a new password
string newPassword = MembershipUser.ResetPassword();
}
Membership.ValidateUser
Membership.ResetPassword
if The User logged In then you have the User Id
so retrieve all user Information like user name password using It.
now you Can just ask User to enter his old password now match this two if both matched then change the password with new One.
Use the ChangePassword control.
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.changepassword.aspx