Asp.net Identity 2.0 temporary password - c#

In my MVC application user registration is implemented in two ways; the user register and then approved by the Administrator; or the Administrator can create a user. My question is: will it be possible to send a temporary password and then the user has to change it after first login, or can I flag this user to use external authentication first time.
I would appreciate your suggestions.

You can define a UserAccount class like this:
public class UserAccount
{
public int AccountId { get; set;}
public UserAccountState AccountState { get; set; }
public Guid ActivationCode { get; set; }
public string Password { get; set; }
}
Where UserAccountState is
public enum UserAccountState
{
PendingActivation = 0,
UsingTempPassword = 1
Normal = 2
}
When a new user just signed up. You can put his account to the PendingActivation state and send him a link to activate the account, something like this
www.MySite.com/Activate?code=F3D17EE
When user clicks on the link, you match the user account with the code, and do the following:
Generate a temp password for the account, e.g "TempPass12"
Change the account state to UsingTempPassword
Show the following message to user
"Your account is now activated. Click here to login with your temp password TempPass12"
After user login to your site with the temp password, your code should detect that the UserAccountState is in the UsingTempPassword state and subsequently redirect the user to the change password page.
After a new password is provided by the user, the account can be put to the Normal state.

Add a column in your password table, something like 'ForceToChangePassword'. Check that column every time an user logged in, if it was set to true, redirect user to the change password page.

My opinion is to use roles than using new columns, and checking things every time user logged in as it is not good when we thinking about performances.
Create three new roles it could be
Created - User created by admin
Registered - User registered by them self
Approved - Approved by admin
In your case if the user registered them self, then add them to ROLE 'Registered'. If the user created by admin then add them to ROLE 'Created'. Once admin approved or user change there password first time login, then you can add them to ROlE 'Approved'.
Then you can handle user self registration and admin creation controller actions to add users to correct ROlE.
There is a column called 'EmailConfirmed' already there, so that you can use that column for your purpose. Update that column when the user approved or successfully change the password on first login.
As you know that password field is nullable, so that you don't need to insert temporary passwords, (but you could if you want). You can keep password field as null and update it when the user first login. You need to change your views to support this scenario.
You can use asp.net identity framework supported methods in order to achieve this.
GenerateEmailConfirmationTokenAsync
GenerateEmailConfirmationToken
IsEmailConfirmedAsync
ConfirmEmailAsync
This role based scenario may help you to categorize users depending on there role and restrict access easily using [Authorize(Role = "RoleName")].
Let me know if you need anymore details.
Hope this helps.

Related

Multi-site, single code-base user registration using ASPNet.Identity

So I have multiple websites running off one code base (asp.net standard MVC). I'm using the built in ASPNet.Identity methods for users to register/log in (using ApplicationSignInManager, ApplicationUserManager).
Currently, all websites are using a single database to store user information. This is causing a couple of issues:
When user A registers on website A, they are now able to log into website B with the same details. As far as they are aware, they did not register on website B. Not good!
If I constrain user A to only access website A, if that user then tried to register on website B, they get the 'email address already in use' error. Also not good!
I've tried separating the databases, one per site, to get around this issue but I don't know how to dynamically change the DBContext assigned to the ApplicationSignInManager and ApplicationUserManager in my controller.
For example, when a user comes to website A, I grab the connection string for website A and perform login/register actions. I need the domain name to work out which connection string to load, which I can't access until after startup.cs code has run, configuring my manager instances.
I figure other people must have done this. Ideally I need to dynamically change the DBContext AFTER Startup.cs has run. Failing that, I need a nice approach to storing multiple identical email addresses in the same DB
Thanks
If you have a flag somewhere which website the current context is for, i'd say easiest to achieve that is to do two things:
extend the IdentityUser with a Website property, something simple either just an int WebsiteId or a String.
extend the AccountController to use that property wherever needed, I think you'd need to modify "Register" and all "Login" functions to verify the website the account is for.
I managed to find a solution. It's not the most elegant but it solves the issue until I can figure out how to dynamically change the DB Context used during login/register
In IdentityConfig.cs I switched 'RequireUniqueEmail' to false:
manager.UserValidator = new UserValidator<ApplicationUser>(manager)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = false
};
Then when a user registers, I take the email address, make it unique to the website they registered on, and store it in the UserName field (I don't use the UserName for anything). When they log in, I make the same alteration to the entered email address before attempting login.
If this user registers on a different website, the username will be different even though the email is identical. Not perfect, but it works.
E.g.
string uniqueCode = "Website_Specific_String";
var user = new ApplicationUser { uniqueCode + model.Email, Email = model.Email};
var result = await UserManager.CreateAsync(user, model.Password);
and the login
var user = await UserManager.FindByNameAsync(uniqueCode + model.Email);
Still open to better ideas. Thanks

Table Storage design for Identity

I am creating an ASP.NET MVC application with Identity and I decided to go with Azure Table Storage since it's very cheap and fast for my needs. The application will have two types of accounts: single user and multi-users with one owner. So I modeled this:
public class User : TableEntity, IUser
{
/// <summary>
/// The Email of the owner of the account
/// </summary>
public string Id { get { return PartitionKey; } set { PartitionKey = value; } }
/// <summary>
/// The Email of the user of the account
/// </summary>
public string UserName { get { return RowKey; } set { RowKey = value; } }
//other fields not relevant
}
I am wondering how to make this effective for logging in and searching for a user, however. The Store for Identity has this:
public async Task<User> FindByIdAsync(string userId)
{
try
{
TableResult operation = await UsersTable.ExecuteAsync(TableOperation.Retrieve<User>(userId, userId));
return operation.Result as User;
}
catch (Exception)
{
return null;
}
}
If the user trying to log in is the owner of the account, this will be a Single Point query and, according to the docs, have the best performance.
However, if the user is not the owner, that would result in a full table scan since a PartitionKey would not be available to filter on it, so the query would have the worst performance.
The other idea I have would be to make the user the PartitionKey and the owner the RowKey, but that would make it every single search a Range Query and have less performance than the Single Point queries.
How could I best design this? This is a new app, so there is no existing user base.
A few recommendations I would like to make (based on the app we've built which also uses Table Storage exclusively).
Introduce a new entity called Account or Subscription. You can use a GUID to uniquely identify an account.
Along with user information (user id, password etc.) in the user's table, store the account information as well. So at all times when you're authenticating a user, you're making point queries. Also store the user's role (Member or Owner) in the user's table. Doing this way, you would know if the user is an individual user or part of a team. If the user is part of a team, then what the role of that user in that team (Owner or Member).
Store 2 copies of user data. First copy is what you're using now. Second copy essentially associate a user with an account where the PartitionKey of the second copy is the account id and row key is the PartitionKey of the first copy. This will help you find the users in a particular team.
Individual User Login Scenario
So an individual user logs in using their username/password. You retrieve the information about the user and there you find out that the user is an individual user based on the account type.
Team Owner Login Scenario
So when a team owner logs in, based on the login you will find out that the user is a team owner. If the team owner needs to find the list of all the users in the team, you do another query (it will be the PartitionKey query only) which will give you information about all the users in the team.
Team User Login Scenario
So when a team user logs in, based on the login you will find out that the user is a team user. Since the user is a team user, he/she need not query the table to find out about other users in the team. Even if they do, you will do another query (same as team owner query) to get the list of users in a team.

How to give user access in MVC C#?

I want to give the user access according to the user role.
I have two user roles. they are Admin and user.
I write my controller like this.
[Authorize(Roles = "Admin")] // my Problem is here. I don't know how to set the current user role
public ActionResult Index()
{
var query = from company in db.tblCompanies
select company;
return View(query.ToList());
}
But I don't know how to set the Roles = "Admin" after cutomer login.
In my user tale I have Roles coloum and it can save Admin or user.
But I don't know how to set and where should I set Roles = "Admin".
Based on your question what I get is you want to set the currently logged user to some role. So here is my answer to that.
To Add a User to a Role:
Roles.AddUserToRole(userName, roleName);
To Remove a User from a Role:
Roles.RemoveUserFromRole(userName, roleName);
Reference Links:
SO - How to Assign roles to User while creating their account
MSDN - Implementing a Custom Role Provider
MSDN - Roles.AddUserToRole Method
MSDN - Roles.RemoveUserFromRole Method
Take a look at this :
http://www.asp.net/mvc/tutorials/mvc-music-store/mvc-music-store-part-7
You basically assign roles to your users via the ASP.NET Configuration website. Once done the user - role mapping is handled by default.

How to force logout user when his/her username is changed by another user?

In my application I am using Forms-Authentication to sign in and sign out users.
One functionality is admin can change the username of other users. In that case, I need to sign out the user whose username is changed.
If I do not, due to their cookies set before, they gain access to application and receive error messages (since their username does not exist and there are parts where I use their username for some functionality).
How can I force these users to log out using Forms-Authentication ?
UPDATE :
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
string controller = filterContext.RouteData.Values["controller"].ToString();
string action = filterContext.RouteData.Values["action"].ToString(); ;
// Below returns the previous username, which does not exist anymore in db.
string userName = HttpContext.Current.User.Identity.Name;
UnitOfWork unitOfWork = new UnitOfWork();
if (!unitOfWork.UserRepository.UserExists(userName))
{
FormsAuthentication.SignOut();
filterContext.HttpContext.Session.Clear();
filterContext.HttpContext.Session.Abandon();
// I am not using Roles.
}
unitOfWork.Dispose();
base.OnActionExecuting(filterContext);
}
In my customer global filter, I check whether user exist or not, if not I sign them out. However, it is not working. By working I mean they pass the authentication and gain access to application.
Thanks in advance.
Here's what you do to force user to sign out:
public void UserPasswordChangedHandler()
{
FormsAuthentication.SignOut();
Roles.DeleteCookie();
Session.Clear();
}
I don't think line by line explanation required, its self explanatory enough.
Please let me know if I am mistaken.
Update
Straightforward answer to your additional question is to keep per user boolean tracking if his data was updated by admin and if yes - just redirect him to login page.
Please see following articles for forced logout using forms authentication information:
How can I force a user to log out
How can I force a log out of all users for a website,
ASP.NET forms authentication forced logout
How to log off multiple MembershipUsers that are not the current user
Update 2
Clearing cookies
HowTo: create and remove Cookies with ASP.NET MVC
How do you clear cookies in ASP NET MVC 3 and C#
How do I invalidate a bad authentication cookie
Hope this help you.
When a user needs to become invalidated you must add their details to some kind of internal static list.
Then on every page request (possibly using Application_BeginRequest) see if that current user is in that list, and if so to call FormsAuthentication.SignOut there-and-then.
It seems like a bit of a hack, but it's the best I can think of right now.
Note that removing a user-in-absentia's session state is another issue entirely.

users in one role cannot remove users from another (C#)

I am developing a site and have 3 basic user roles. The roles are "admin", "manager", and "user". I have blocked basic users from certain pages, but allow admin and managers access to others. I have created a seperate page to delete users, however, I do not want to allow someone from the role of "manager" to be able to delete someone from the role of "admin". "user" roles do not have access to this page so I'm not worried about that. I have a drop down list that shows all the users and a button to remove the selected user and it is working. I would just like to add the security of not allowing "manager" roles to delete someone from an "admin" role.
Here is the code that I have so far for the onClick event:
string adminuser;
usertodelete = usersddl.SelectedItem.ToString();
if (Roles.GetRolesForUser(usertodelete) = "admin")
adminuser = "admin";
if (Roles.IsUserInRole("admin") && User.IsInRole("manager"))
statuslbl.Text = "You do not have sufficient privileges to remove this user. Only Administrator's can remove administrators from the system.";
else
{
System.Web.Security.Membership.DeleteUser(usertodelete);
Response.Redirect("~/Account/DeleteAccount.aspx");
}
I know my if statements are wrong at this point in finding and assigning a certain user and checking their role.
I would just like to add the security of not allowing "manager" roles to delete someone from an "admin" role.
if (Roles.GetRolesForUser(userToDelete).Contains("admin") && !User.IsInRole("admin"))
{ // only allow admins to remove other admins.
statuslbl.Text = "You do not have sufficient privileges to remove this user. Only Administrator's can remove administrators from the system.";
} else {
}

Categories

Resources