Asp.NET Core Claim based Authorization - c#

I was using Role-based authorization for asp since now. I wanted to learn Policy-based and claim-based authorizations. Then I realized I can turn claims into something like "Permission based api authorization" which I am using for NodeJs. I have 2 questions to understand the fundamentals, thank you.
Question 1: The scenario in my mind is this: Users have roles, and roles have claims. Then I will add Authorization policies which require claims. Is this a correct approach? Basically users won't have claims. (I have seen many approaches on net, that's why I am asking)
Question 2: To do that I created tables with switches. I will add a photo to so you can picture the scenario easily.
But when I use:
var role = await roleManager.FindByIdAsync(RoleId);
await roleManager.AddClaimAsync(role,new Claim("Permission 1", "perm explanation"));
List<IdentityRoleClaim<string>> allClaims = _db.RoleClaims.ToList();
this block of code doesn't check duplication check for Claim which will be added to database. We can use RoleManager and UserManager, but is there a Manager for claims? Thank you again.

There's many way to solve authorization problem, what you are asking tended to optionality, best solution would be difference based on various usecases and the developer, who implement them themself. Since I was use all role, claim and policy, I'll giving my answers as advises.
The scenario in my mind is this: Users have roles, and roles have claims. Then I will add Authorization policies which require claims. Is this a correct approach? Basically users won't have claims. (I have seen many approaches on net, that's why I am asking)
Think of role as A BIG CLAIM. Whenever you saw a role, you grant them permission to do some stuffs. Like a when you entering a building, the security would have the permisions to check your basic personal information. It doesn't matter who the security is, they have the permisions to ask for your paper as long as they performed in security role.
To do that I created tables with switches. I will add a photo to so you can picture the scenario easily.
Have you saw something in jwt token like
"someCustomClaim": ["ClaimOne", "ClaimTwo", "ClaimThree"],
Think of how this claim will be preserve in a relational database like sql, that's why there is not an unique index there.
But, you can always add one, and enforce each claim are unique, or each role+claim is unique,... all is up to your use cases.
We can use RoleManager and UserManager, but is there a Manager for claims?
Claims doesn't make any senses if they stand alone, it has to be attached with Role or User to be meaningful right ?
So UserManager(which have claims via UserClaims) and RoleManager(which have claims via RoleClaims) are good enough, even if you in a very-complex scenerio that require both Multiple Role - Claims and Claims that directly assign to an user.
And about Policy, that's the mixin way to solve complex authorization scenerios, like UserAuthenticated + Must have Internal Role + Must have Maintaination Claim + does not have fresher claim. If you need to authorize an endpoint kind of complex like this... you might consider to register those as policies.

Related

.Net Core Identity Framework Get Users By Claim

In our .NET Core Web API, we have configured claim based authorization and it works perfectly. We have created role-claims and assign roles to users. We do not use user-claims.
Now I have a requirement to get users having a specific claim. In UserManager there is a method GetUsersByClaimAsync(Claim), which seems only considering user-claims. Not role claims. So in my case, it is not usable.
So I was thinking of getting roles by claim and then get the users by roles (not very efficient as it has to make several DB calls to get the users of each role separately). But even to do that, there is no straight forward method to get roles by claims in UserManager or RoleManager.
So to me, it seems there is no clean way of achieving this other than custom querying.
I'm not sure I'm missing something here. Has anyone achieved this, using a better way?
Thanks
Now I have a requirement to get users having a specific claim. In UserManager there is a method GetUsersByClaimAsync(Claim), which seems only considering user-claims. Not role claims. So in my case, it is not usable.
I think you could try the UserManager<TUser>.GetUsersInRoleAsync(roleName) api:
var users = await _userManager.GetUsersInRoleAsync("Role1");
By the way, to use the above api, you need enable the Role related services by :
AddDefaultIdentity<IdentityUser>(options => { /*...*/ })
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<AppIdentityDbContext>();

does Authorize attribute with Roles take Claims into account

I tried searching everywhere on the web, but I can't seem to figure out this important part.
Basically, if we do a DB call each time when checking if a user belongs to a role - this will have negative effect on performance.
I saw code examples listing all user roles, e.g.
var roles = ((ClaimsIdentity)User.Identity).Claims
.Where(c => c.Type == ClaimTypes.Role)
.Select(c => c.Value);
the code can be used in controller action, it is also possible to fetch claims the same way in an Attribute Filter.
From this example I infer that Claims come into play (seems to be most performant solution).
I tried to find out if Authorize attribute with Roles verifies user's claims, but the official Microsoft documentation doesn't cover this bit.
AuthorizeAttribute class
Specifies that access to a controller or action method is restricted to users who meet the authorization requirement.
Properties:
Roles - Gets or sets the user roles that are authorized to access the controller or action method.
And that's the extent of what we have.
Both the Authorize attribute as e.g. User.IsInRole look at the User.Identity roles claims.
By default the Authority (where the user logs in) will add the roles from the AspNetUserRoles table as claims of type 'http://schemas.microsoft.com/ws/2008/06/identity/claims/role'. See WIF claimtypes members.
The client app will automatically take the information from the token / cookie and convert this as User.Identity. As the claim type matches, the role type claims are mapped as roles.
This means that the app doesn't need access to the user store. In most cases this is also not possible. So it is actually not about performance, but about accessibility. Usually apps don't have access to the Identity context. So UserManager is not an option.
There is however a drawback when using claims. The information is dated. When the user logs in a snapshot of the claims at that time are added to the Identity. If in the meantime claims (or roles) are updated in the database, then these changes are not noted. Only after the user logs in again, the changes become effective.
This means that claims are only suitable for pieces of information that do not (frequently) change unless you find a way to invalidate claims. But that would probably mean to access the database or call the authority.
That's why I wouldn't recommend the use of roles. As roles tend to be used for authorization, but you can't revoke access in the meantime. So until you solve that, you may want to consider an alternative.
Sticking to UserManager is not an alternative, because the context may not be available for all apps.
That's why resource-based authorization may be a solution for you. Please read my answer here for additional thoughts.
Open your Startup file and change this:
services.AddDefaultIdentity<IdentityUser>()
.AddEntityFrameworkStores<ApplicationDbContext>();
to this:
services.AddIdentity<IdentityUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultUI()
.AddDefaultTokenProviders();
Then the Roles should start working.

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).

Simple Membership Admin Accout

I am working on my first ASP.Net MVC 4 application and now stuck with one simple use case.
I need to authenticate one single user (Admin) so that he/she can log in to admin area to perform certain tasks. Though the ASP.Net internet project template has Account controller using simple membership but that seems to have much more than what I actually need. For instance, I don't really need the user registration functionality and user roles. My requirements are fairly simple, just to store one single user in database, give him the options to update his info like password, email etc and grant him access to admin area (admin controller and actions).
What I can't figure out is
Are simple membership or other asp.net membership provider my only options for this simple scenario.
If not what other option do I have in order to use [Authorize] to secure admin actions
You can build a custom method to grab the user and their stored role, then evaluate it in your controller. So, for instance:
public ActionResult GetAdminPage()
{
var loggedInUserName = HttpContext.User.Identity.Name;
var user = somesortofproviderlookupmethod(loggedInUserName);
// Assume user is a bool and is true
if (user)
{
return view("AdminPage");
}
}
The only thing I'm not sure of is whether or not HttpContext.User requires membership. Perhaps someone can shed some light. If so, perhaps you could send the username from the view, but then of course you're trusting the client. So how you are doing user authentication would change this answer somewhat.
Personally, I like membership. It's clean, easy, fast and can be scaled nicely if you end up having additional requirements. Doing something like this would be even easier with membership, since then you can actually use Roles.GetRolesForUser(); and only return the admin view if they contain the role you are looking for.

Custom User and Roles with ASP.NET MVC3

I have a ASP.NET MVC site with a CAS server set up as the authentication type. I also have a separate database with a Users table and a Roles table (with a User being related to one or more roles). A User is only able to log into the system if the Username is both in the User table and on the CAS system. I have this solution working.
My problem is i now need some form of trigger on User.IsAuthenticated so i can track the current User (from my database), without the possibility that i am trying to allow tracking of a User that has logged out. What I've been thinking is i need to add the User to the HttpContext but i am not sure how to trigger the clearing of the User if the CAS session times out or if the User Logs out.
I also wish to have some functionality such as User.IsInRole (again using my database, not ASP.NET) but am not sure how to go about implementing this. I suppose if i can successfully add the User to the HttpContext then a IsInRole method would simply be a User.Roles.Contains(string role) method but how can that then be used if i wish, for example, to use a method with the DataAnnotation [Authorize(role = "ExampleRole")].
I have looked at questions such as How do I create a custom membership provider for ASP.NET MVC 2? but this doesn't work for me (possibly to do with me using the CAS authentication?)
Any guidance or background reading would be appreciated as i'm really not sure where i should even start. I have read up on GenericPrinciple, IPrinciple and IIdentity but I'm struggling to see how i can apply them to my current project.
Ended up with a custom Authorise Attribute that uses the CAS logon to check the user exists in my database. It also checks the roles of that user. I also used a static class to save the current user in the session with a logout method that abandons the session when the user logs out.
I have kind of a two parter for you. This link does a really good job of explaining how to replace the HttpContext User with your own object: http://bradygaster.com/custom-authentication-with-mvc-3.0
His approach uses MVC filters, but you can also catch the Authentication event in the Global.asax file. Using the forms system with your own implementation can be trivial or not depending on what you're doing, but it boils down to calling FormsAuthentication.SetAuthCookie and .SignOut, amidst your own logic.
public static void FormsLogin(this User user, bool persist)
{
FormsAuthentication.SetAuthCookie(user.DisplayName, persist);
user.AddHistory("Login event.", HistoryType.Login, "SYSTEM");
Users.OnUserLogin(user);
SetLastActivity(user);
}
public static void FormsLogout(this User user)
{
FormsAuthentication.SignOut();
}
Lastly, once you've got the login stuff working out, you can use your own more complex permission system by making a custom Auth Attribute. I remember piecing this together from some other answers and articles but I can't seem to find the sources at the moment, I will try and edit with sources for credit where it's due, if I find them. For now, all I can offer is this gist which offers up one of the attributes I use: https://gist.github.com/1959509
Keep in mind the only really relevant part there is the override of OnAuthorization, which does the actual work.

Categories