Change from Roles authorization to Claims authorization - c#

I have a webforms application which was built with ASP.NET Membership. I migrated to Identities successfully.
I now want to use Claims authorization instead of Roles authorization, but the Role information for the old users has been migrated to the AspNetUserRoles table in the database but the AspNetUserClaims table is empty. New users registered after migration, I can add to AspNetUserClaims with the following code:
IdentityResult result1 = manager.AddClaim(user.Id, new Claim(ClaimTypes.Role, "role"));
But the old users are only registered in the AspNetUserRoles table not in the AspNetUserClaims table.
On login will the claim created include Role information from the AspNetUserRoles table also or only from the AspNetUserClaims table?
Will the User.IsInRole() check both the AspNetUserRoles table and the AspNetUserClaims table?
How can I migrate information from the AspNetUserRoles table to the AspNetUserClaims table?

Don't get hooked on "claims" term. Here this is a convenient way to add information into the cookie.
Here actually are 2 types of "claims" - one that is added into the cookie and one that is preserved in AspNetUserClaims table.
When user is logging in, a cookie with identity is created. Identity contains all the claims user has. Claim here is a key-value pair that is added in the cookie as a payload. Cookie claims contains things like User.Id, SecurityStamp, Username some other framework related stuff and... list of roles from AspNetUserRoles. Along with additional claims from AspNetUserClaims.
So what you are trying to add roles into claims - makes no sense. Roles will be in the cookie as claims anyway - added by the framework.
Probably I'm not explaining well - when you debug your application, analyse User property of a controller and look into ClaimsIdentity and see list of all the claims. All my jibbering will make more sense.
To answer your second question - User.IsInRole() does not go into the database. This method only checks information in the cookie, see the source code for yourself: it only checks if cookie contains claims of type ClaimTypes.Role with the name of the role you are trying to check.
Third question... do you still want to do that? You can do a SQL statement, something like insert into aspnetuserclaims (<columns>) select <columns> from aspnetUserRoles inner join aspnetroles on aspnetUserRoles.roleid = aspnetroles.id.
I wrote about what claims go into the cookie in my blog a while ago - you'll get a better understanding how it all comes together.

Related

.NET #claims == 0 on all users

I am working on adding a user manager module to an application. It has a database and this database has a table of users and a table of user claims so that each user can have mulotiple claims. However, when I use usermanager to get Users.ToList() each user has its claims collection set to 0 entries even if the user in question does have claims listed in the user claims table.
It appears obvious to me that for some reason just doing usermanager.Users.Tolist() does not cause the code to consult the user claims table to check what claims each user has.
So the question is where and how to insert code that does exactly that.
Some potential issues with the existing code:
1. They have made a subclass of the IdentityUser so the UserManager is defined to be a usermanager of that subclass. But there is no explicit subclass of the usermanager. I am contemplating creating a subclass of UserManager for that purpose and if so I could override the Users property so that reading the Users list caused it to populate each user entry with the claims for that user. Does that sound like a clean way of doing it?
In some other stack overflow question I saw a reference to a Startup.Auth.cs file. We have a Startup.cs file but no Startup.Auth.cs file, should we make one?
Thank you in advance for any input.
If you used the ASP.Net identity template when you created your project, you must have a Startup.Auth.cs, it could be hidden as a sub-file of Startup.cs, or in the App_Start folder etc.
If trying to bypass the UserManager, when you request your user from EF, make sure you .Include(...) the claims property. For example:
dbcontext.Users.Include(u => u.Claims).FirstOrDefault(...);
Better yet, you should be using UserManager:
var userManager = HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
var claims = userManager.GetClaims(userId);

common roles for all tenants in AspNetBoilerplate

I have a custom set of roles that is supposed to be used in a multi-tenant app.
AbpRoles table has a column titled "TenantId" (nullable).
Problem is that if I leave this field with a null value, a user per certain tenant cannot be recognized as being related to a certain role. But if an AbpRole record has tenant id value - all works pretty well.
The bottomline is:
my code has to be creating the same set of roles for each tenant, so I'm just wondering if it's possible to have common set of roles for all tenants.
If the TenantId value is null for AbpRole record and I wrap the code that checks if user belongs to a role
User.IsInRole("Employee")
into this block
using (_unitOfWorkManager.Current.DisableFilter(AbpDataFilters.MayHaveTenant))
the problem is still not solved.
Sorry for late answer. For the guys looking an answer for this question;
Roles should be created per tenant. If you are using single tenant then you have use the Default tenant's id. As a result you can not share a role. If you insist on sharing roles btw tenants you have to disable MayHaveTenant everytime you make operation on role.

How to restrict the access to DB resources in WebAPI

I am making a WebAPI service. I just used the ASP.NET WebAPI template with authentication. I was wondering how can we restrict DB entity access for those users who are already logged in. With [Authorize] we can restrict unauthorized users, which I have done. After login, they can access anything right now. Eg: I have a table Bill. With BillId, users who are authorized can access any entry in Bill table. How to restrict this? Currently Bill table has no relation with UserIdentity tables!!.
After thinking about the scenario, I have a solution [Not sure the best]. In all my controllers I can get the Userid [Authenticated user's id]. When a user adds data to any entity, I will add userid as a column to that entity and store userid. When any user looks for a resource, he will get only those resources which are of his Userid. I am not giving any relation to any user table but just adding the userid to all entities as a new column.

Recreating a deleted user in ASP.Net Membership

I'm using an ASP.Net Membership provider to handle user accounts on my website and I've set the DeleteUser() function to only delete data from the aspnet_Membership table as I'd like to keep the user ID and details in aspnet_Users for auditing.
I've encountered a problem whereby if I delete a user "bob", when someone creates a new user with the same username, then instead of creating a new aspnet_Users record with a new UserId (it's a GUID by default) it will instead link the new aspnet_Membership table record to the previously created "bob" account.
This means rather than creating a new user that happens to have the same username, it's re-activating the old user and linking their activity history together.
Is there a way to force ASP.Net membership to create a new aspnet_users record instead of hijacking the old one?
Thanks!
Unfortunately it seems that the ASP.Net Membership SQL Provider generates the User ID GUID using the username as a seed. This means that without deleting the user (which you wouldn't want to do if you were keeping an audit history) there is no clean way of creating another user with the same User ID.
To resolve my issue I have done the following:
Allowed ASP.Net Membership to assign a membership record to the asp_user record as it does by default
Added an audit record to my audit table explicitly specifying that a user has been re-created
This will allow me to check when writing audit queries whether the user performing an action was once removed, and hence whether they're likely to be the same person or not.

Creating ready-made users with claims with ASP.NET

The application I'm working on is an MVC 5 web application, using ASP.NET Identity.
We're trying to allow certain users to create other users (i.e. pre-register them). On creation, we'd like to pass in some meta-data, that we want stored as claims against that user such as email address, age etc.
The example I've seen where claims are created, call a SignIn method to persist the claims in the database. We obviously don't want these accounts to sign in, just save the claims.
var user = new ApplicationUser { UserName = "joe#bloggington.com" };
var pwd = "password123"
var result = await _identityService.CreateAsync(user, pwd);
if (!result.Succeeded)
return null;
var identity = await _identityService.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
identity.AddClaim(new Claim(ClaimTypes.Email, "joe#bloggington.com"));
// PERSIST THIS CLAIM
Of course I could be very confused about the way claims work, but this seems like quite a common scenario to me. Appreciate any help or feedback.
Claims are pretty confusing when you first approach them. First, you'll want some resources about what Claims and Identity really are:
https://msdn.microsoft.com/en-us/library/ff359101.aspx does a decent job of explaining it.
Explain "claims-based authentication" to a 5-year-old was asked a few years ago and goes well with the MSDN link.
Distilled, Claims are basically attributes. The username is a Claim. The email address is a Claim. Each role the user has is a Claim. Combined they make up the Identity. Claims are meant to be used by the application's authorization system but how they are persisted/stored is completely arbitrary.
What you actually want to do here is store the email address, age, etc. in the database like you would any other user data. How you do that is up to you. The only time that information would become a "claim" would be if you wanted that information to be available as part of the logged in user's Identity, at which point you'd pull the information (like email address) from the database and add it to the user's Claims (which is probably a separate question/discussion).

Categories