Migrating plain-text password to asp.net Identity 2.1 - c#

I am moving an existing site to mvc and one of the thing that puzzles me is the migration of user data, particularly passwords, these passwords are stored as plain text (yes i know). Now moving the rest of the account information to aspnet identity tables is easy but I need to now hash these passwords and I am not sure how to properly hash them before storage (using tsql), if i must use a .net app to hash, what class do i need to call by feeding it plain password and it will give me a hash?
thank you

It seems like your application isn't set up right for a complete migration, so I have an idea for an easy solution to get the full use out of the Identity 2.0 database and features.
Create New Web Application, then create a method that gets the plain text login credientials for your old users. Next:
When you create a new application look at the code in the account/register files.
Here is what you see:
var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
var signInManager = Context.GetOwinContext().Get<ApplicationSignInManager>();
var user = new ApplicationUser() { UserName = Email.Text, Email = Email.Text };
IdentityResult result = manager.Create(user, Password.Text);
if (result.Succeeded)
{
}
Now create a class to hold all the properties from your existing user, or you could use a SQLDataReader["columnName"] if you wanted to go the rout of looping a reader.
So copy that code run your new Method:
var ListOfUsers = MyMethodThatRetunsAllOldMembers();
foreach member in ListOfUsers{
var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
var signInManager = Context.GetOwinContext().Get<ApplicationSignInManager>();
var user = new ApplicationUser() { UserName = Member.UserName, Email = Member.Email };
IdentityResult result = manager.Create(member.LoginName, Member.Password);
//Example: You can even add roles at the same time.
var ra = new RoleActions();
ra.AddUserToRoll(member.LoginName, Member.Email, userRole);
}
This will create the new hashed passwords as well as settings roles and userid's for each of your old users, effectively migrating your database.

Related

Asp.Net Core Identity, updating existing plain text passwords

We have customized Asp.Net Core to use our table of students rather than the AspNetUser table. Everything works fine for new students. But we need to update the existing students' passwords. I would like to do something like this (in AccountController Login method) when a student logins or this could be done on a one-time basis…
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
{
ViewData["ReturnUrl"] = returnUrl;
if (ModelState.IsValid)
{
// Require the user to have a confirmed email before they can log on.
var user = await _userManager.FindByEmailAsync(model.Email);
if (user != null)
{
if (user.PasswordHash == null)
{
user.EmailConfirmed = true;
user.UserName = model.Email;
user.NormalizedEmail = model.Email.ToUpper();
user.NormalizedUserName = user.NormalizedEmail;
//user.PasswordHash = ?;
//user.SecurityStamp = ?;
//update user in database.
}
//continue on with login process
}
}
}
The below code (from the Register method) creates a new user and adds him to the database. This is not what we want.
var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
var result = await _userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
// …
You’ll find the UserManager has anything you need to set the password for a user. While you could use the internal password hasher directly, going through the user manager makes sure that the user entity is updated properly in respect to the password. So you can just rely on the user manager to “do the right thing”.
If a user does not have a password, you can use AddPasswordAsync to set it:
var user = await _userManager.FindByEmailAsync(model.Email);
if (user != null && !(await _userManager.HasPasswordAsync(user)))
{
// retrieve plaintext password
var originalPassword = GetPlainTextPassword(user);
var result = await _userManager.AddPasswordAsync(user, originalPassword);
if (!result.Succeeded)
{
// handle error
}
}
Otherwise, you could also make use of the password reset flow and generate a token you then immediately use to reset the user’s password (without actually involving the user). So you would basically chain GeneratePasswordResetTokenAsync and ResetPasswordAsync. Of course, this should only be done for maintenance reasons:
var user = await _userManager.FindByEmailAsync(model.Email);
if (user != null)
{
// retrieve plaintext password
var originalPassword = GetPlainTextPassword(user);
// retrieve token
var resetToken = await _userManager.GeneratePasswordResetTokenAsync(user);
// reset password
var result = await _userManager.ResetPasswordAsync(user, resetToken, originalPassword);
if (!result.Succeeded)
{
// handle error
}
}
Regardless of this, I would still suggest you to actively require users to reset their passwords themselves. Just remove the plain text passwords from the database, and keep the empty password. That way, users will have to reset their password first (you should add a note to explain that they will have to do that before their first login), and nobody will ever be able to see their new password in plain text. – The old passwords are exposed in the database and likely (hopefully?!) a large number of backups, and even if you believe your system is secure, it likely isn’t perfect. And there are still people involved that have access to the database and could directly or indirectly expose those passwords to others (with or without good intentions). You shouldn’t trust your system enough that nothing will go wrong. And users shouldn’t have to trust you with keeping their passwords safe. You should tell them to make a new password and get rid of their old ones—better sooner than later.

How to run code within Seed method during deployment?

I have a Web Api solution that makes use of ASP.NET Identity (v2.1) and Entity Framework v6.1. Inside the Seed() method of the Configuration.cs file I have code that creates my first Identity user. This code makes use of the Identity framework to hash the password, create the security stamp, etc. These are all things I cannot do via SQL so adding to the Up() method does not seem like an option.
protected override void Seed(ApplicationDbContext context)
{
// Create the admin user
var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
var roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(new ApplicationDbContext()));
var user = new ApplicationUser()
{
UserName = "adminuser",
Email = "adminuser#mycompany.com",
EmailConfirmed = true,
FirstName = "John",
LastName = "Does",
JoinDate = DateTime.Now.AddYears(-1)
};
manager.Create(user, "SuperSecurePassword321!");
if (roleManager.Roles.Count() == 0)
{
roleManager.Create(new IdentityRole { Name = "Admin" });
roleManager.Create(new IdentityRole { Name = "Employee" });
roleManager.Create(new IdentityRole { Name = "Customer" });
}
var adminUser = manager.FindByName("adminuser");
manager.AddToRoles(adminUser.Id, new string[] { "Admin" });
}
I need to use FTP to publish this (no control over this). Any suggestions on how to run this code once it is deployed and the database is schema is setup?
Options I have considered:
I have thought about creating an API endpoint that when called can
kick off this code, however, this endpoint would have to allow
anonymous access since it would be creating this first user and
the roles used in the system. I would then need to somehow disable
or remove this endpoint later.
Script the database and include the data and then restore that to
the database server targeted for deployment.
Seed() gets called when the database is accessed the first time. What's wrong with that automatic behavior?
If you want to call it manually, try something like this in protected void Application_Start():
Database.SetInitializer(new YourInititalizer());
var dbContext = new TheContextYouAreUsing();
dbContext.Database.Initialize(force: true);

ASP.NET Identity, Register manual added user without deleting him

I have an issue with ASP.NET Identity. In my application, I want to add users to the table dbo.AspNetUsers, as soon as someone adds them to a poll with their mail adress, like this:
var user = new ApplicationUser
{
UserName = model.Email,
Email = model.Email,
TwoFactorEnabled = false,
EmailConfirmed = false,
Registered = true
};
_dbContext.ApplicationUsers.Add(user);
_dbContext.SaveChanges();
If someone who was added like this to the database earlier, wants to register himself with his mailadress, I don't want to delete the manually added user and register him as a new one, because other relations are already related to his ID and constraints would not allow that. I also can not delete the connected relations, because other users are also related to them.
I tried to manually add a hashedPassword to him in the database like this:
_dbContext.ApplicationUsers.FirstOrDefault(u => u.Email == model.Email).PasswordHash =
this.HashPassword(user, model.Password);
_dbContext.SaveChanges();
But then the login failed, because of an internal server error, because of a NULL value in
"System.Security.Claims.Claim..ctor(String type, String value, String valueType, String issuer, String originalIssuer, ClaimsIdentity subject, String propertyKey, String propertyValue)".
Does someone know a solution to register a user, who was already added manually, without deleting him?
Thanks for answers!
EDIT/SOLUTION
Here is the solution:
In a first step, just create the user with a default password, then if he wants to register, remove the Password and add the Password from the RegisterModel, like this:
var result = await _userManager.CreateAsync(user, "DefaultPassword1.");
await _userManager.RemovePasswordAsync(user);
var result = await _userManager.AddPasswordAsync(user, model.Password);
If you look in the Manage Controller you'll see all the methods to manage user accounts. For example to add a password you'd use
var result = await UserManager.AddPasswordAsync(User.Identity.GetUserId(), model.NewPassword);

How to delete users that were created with UserManager.CreateAsync

Using asp.net mvc5, my user management systems seems to work. I can login with google or with name/password..
but now I am working on a user management interface in which I need to be able to delete existing users. And this is starting to expose to me just how confusing the user management system is. There's so many different ways to deal with users.. and some of them don't work.
Most everywhere I read, it is talking about using the Membership.DeleteUser().
But that isn't working...
The users were created with.
var user = new ApplicationUser()
{
UserName = model.UserName,
Email = model.Email,
ConfirmationToken = confirmationToken,
IsConfirmed = false
};
var result = await UserManager.CreateAsync(user, model.Password);
Now later on.. how do I delete such a user? (given its name or userid)
I have tried what comes up most on various searches.. comes up with Membership as the solution. But this surely isn't right for MVC5?
For example
var allusers = Membership.GetAllUsers(); // allusers is empty
bool success = Membership.DeleteUser(model.name); // <-- success = false
I can get all the users using this method..
ApplicationDbContext db = new ApplicationDbContext();
foreach (var user in db.Users) { ... }
And I can find an individual user with..
ApplicationDbContext db = new ApplicationDbContext();
var um = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(db));
ApplicationUser user = um.FindById(model.userId);
Now how do I delete one though? ....
Update
As of Microsoft.AspNet.Identity Version 2.0.0.0, you can now delete users with Identity using UserManager.Delete(user);.
For Posterity
You are referring to two different things, Identity and Membership. Newer versions of ASP.NET support Identity and Membership with Identity being the default, while older versions support only Membership (out of those two authentication systems).
When you create a user with UserManager.CreateAsync, you are doing so within the Microsoft.AspNet.Identity namespace. When you are attempting to delete a user with Membership.DeleteUser, you are doing so within the System.Web.Security namespace. They are living in two different worlds.
As another comment mentions, deleting users is not yet supported out of the box by Identity, but it is the first item on their roadmap for a Spring of 2014 release.
But why wait? Add another property to the ApplicationUser model like this:
public class ApplicationUser : IdentityUser
{
public string IsActive { get; set; }
}
Then, in your controller for deleting a user:
user.IsActive = false;
Do a check when the user logs in:
if (user.IsActive == false)
{
ModelState.AddModelError(String.Empty, "That user has been deleted.");
return View(model);
}
When an deleted user attempts to re-register, instead of UserManager.Create, use UserManager.Update with their new information on the registration page.
These steps will effectively delete the user. If you truly must clear their information from your database, you can use Entity Framework to do that more directly.
added to the previous response. If you have
public class ApplicationUser : IdentityUser
{
public string IsActive { get; set; }
}
Then, in your controller for deleting a user:
user.IsActive = false.ToString();
because your data type is a string and n ot a boolean

Authorization in mongodb

The readonly users have only read permissions. Thus, a user having readonly true is not authorized to add new user or any write capabilities.
I am building a utility which manages the data in MongoDB. When i log in as readonly user it should not allow me to add new user. When I implement it, it does not actually add a user but it is not throwing any exception.
Here is my commands for adding a readonly user
var credentials = new MongoCredentials(username, password,false);
var addUser = new MongoUser(credentials, readOnly);
var database = server.GetDatabase(databaseName);
database.AddUser(addUser);
Did you start mongod with the --auth command line argument?
Did you use safe=true on your connection string?
Also, you need to use admin credentials to add a user to a database:
var adminCredentials = new MongoCredentials("adminuser", "adminpassword", true);
var userCredentials = new MongoCredentials("username", "password");
var user = new MongoUser(userCredentials, true);
var fooDatabase = server.GetDatabase("foo", adminCredentials);
fooDatabase.AddUser(user);
Notice that there are two sets of credentials: one for the user being added, and another set of admin credentials for your code to be able to add the user.

Categories

Resources