I am trying to move away from WebForms and learn MVC, specifically using the new ASP.NET Identity model. However, I cant seem to find any formal documentation from Microsoft, that demonstrates how to create a claims object, and store it in a database for a authenticated user.
My site, needs to do the following:
Authentication a user - TICK
Create a Claim, and store user information in it, so that I can use it throughout the session - NO TICK
Pull back the users roles from the new ASP.NET Roles table - NOT TICK
Can anyone shed any light on how this can be achieve?
Honestly, I'm still learning the ropes with Identity, myself. Admittedly, the Microsoft provided documentation could be better, but I've never found any of their documentation all that helpful. The best stuff always comes from the community, and unfortunately, Identity is still so new that the community has had time to really flesh it out yet.
That said, here's what I know, with the understanding that there may be better ways that I'm simply not aware of, yet.
Claims
Your UserManager has three methods of significance: GetClaimsAsync, AddClaimAsync and RemoveClaimAsync.
To get all claims for a user:
var claims = await UserManager.GetClaimsAsync(userId);
You can get the current user's id with:
var userId = User.Identity.GetUserId();
Once you have the claims, to pull out a specific one:
var someClaim = claims.FirstOrDefault(c => c.Type == "SomeClaimType");
Where "SomeClaimType" is the name of the claim as it was added. In some scenarios this might be a fully qualified URN, or it may just be a simple string. If it's not something you personally added, the best thing to do is just inspect the claims variable during a debug session to see what you actually have there.
Also, since the list of claims is a queryable, you can pretty much do whatever LINQ query you want on it, Where, Count, etc.
To add a new claim:
await UserManager.AddClaimAsync(userId, new Claim("SomeClaimType", claimValue));
And to remove a claim:
await UserManager.RemoveClaimAsync(userId, someClaim);
Roles
Roles work in a similar way. To get all roles for a user:
var roles = await UserManager.GetRolesAsync(userId);
To see if a user is in a particular role:
var hasRole = await UserManager.IsInRoleAsync(userId, "SomeRole");
To add a user to a particular role:
await UserManager.AddToRoleAsync(userId, "SomeRole");
And to remove:
await UserManager.RemoveFromRoleAsync(userId, "SomeRole");
Adding the roles in the first place is a bit different; you have to create an instance of RoleStore.
var roleStore = new RoleStore<IdentityRole>(context);
Then, you can use that to manage all roles. For example, to create a new role:
await roleStore.CreateAsync(new IdentityRole("RoleName"));
To remove:
var identityRole = await roleStore.FindByNameAsync("RoleName");
await roleStore.DeleteAsync(identityRole);
Getting all roles, is not possible with the Identity-specific API at this time, but you can always fall back to querying with Entity Framework directly:
var allRoles = context.Roles.OrderBy(o => o.Name);
Regarding Asp.Net Identity, I would strongly recommend Brock Allen's implementation, called 'Identity Reboot'. Identity Reboot basically is a set of extensions to the ASP.NET Identity. It was inspired due to frustrations with the ASP.NET Identity implementation.
You can read an introductory article here. You can download source code and samples from github here.
You can install it using nuget:
www.nuget.org/packages/BrockAllen.IdentityReboot/
www.nuget.org/packages/BrockAllen.IdentityReboot.Ef/ (for entity framework)
Related
I am completely new to the use of claims in ASP.NETIdentity and want to get an idea of best practices in the use of Roles and/or Claims.
After all this reading, I still have questions like...
Q: Do we no longer use Roles?
Q: If so, why are Roles still offered?
Q: Should we only use Claims?
Q: Should we use Roles & Claims together?
My initial thought is that we "should" use them together. I see Claims as sub-categories to the Roles they support.
FOR EXAMPLE:
Role: Accounting
Claims: CanUpdateLedger, CanOnlyReadLedger, CanDeleteFromLedger
Q: Are they intended to be mutually exclusive?
Q: Or is it better to go Claims ONLY and "fully-qualify" you claims?
Q: So what are the best practices here?
EXAMPLE: Using Roles & Claims Together
Of course, you would have to write your own Attribute logic for this...
[Authorize(Roles="Accounting")]
[ClaimAuthorize(Permission="CanUpdateLedger")]
public ActionResult CreateAsset(Asset entity)
{
// Do stuff here
return View();
}
EXAMPLE: Fully-Qualifying Your Claims
[ClaimAuthorize(Permission="Accounting.Ledger.CanUpdate")]
public ActionResult CreateAsset(Asset entity)
{
// Do stuff here
return View();
}
A role is a symbolic category that collects together users who share the same levels of security privileges. Role-based authorization requires first identifying the user, then ascertaining the roles to which the user is assigned, and finally comparing those roles to the roles that are authorized to access a resource.
In contrast, a claim is not group based, rather it is identity based.
from Microsoft documentation:
When an identity is created it may be assigned one or more claims issued by a trusted party. A claim is a name value pair that represents what the subject is, not what the subject can do.
A security check can later determine the right to access a resource based on the value of one or more claims.
You can use both in concert, or use one type in some situations and the other in other situations. It mostly depends on the inter-operation with other systems and your management strategy. For example, it might be easier for a manager to manage a list of users assigned to a role than it is to manage who has a specific Claim assigned. Claims can be very useful in a RESTful scenario where you can assign a claim to a client, and the client can then present the claim for authorization rather than passing the Username and Password for every request.
As #Claies perfectly explained, claims could be a more descriptive and is a deep kind of role. I think about them as your role's ids. I have a gym Id, so I belong to the members role. I am also in the kickboxing lessons, so I have a kickboxing Id claim for them. My application would need the declaration of a new role to fit my membership rights. Instead, I have ids for each group class that I belong to, instead of lots of new membership types. That is why claims fit better for me.
There is a a great explanation video of Barry Dorrans, talking about the advantage of using claims over roles. He also states that roles, are still in .NET for backward compatibility. The video is very informative about the way claims, roles, policies, authorization and authentication works.
Or check a related session shared by Lafi
Having used various authentication and authorisation techniques over decades, my current MVC application uses the following methodology.
Claims are used for all authorisation. Users are assigned one role (multiple roles are possible but I do not need this) - more below.
As is common practice, A ClaimsAuthorize attribute class is used. Since most controller actions are CRUD, I have a routine in the code-first database generation that iterates all controller actions and creates claim types for each controller action attribute of Read/Edit/Create/Delete. E.g. from,
[ClaimsAuthorize("SomeController", "Edit")]
[HttpPost]
For use at in an MVC View, a base controller class presents view bag items
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
// get user claims
var user = filterContext.HttpContext.User as System.Security.Claims.ClaimsPrincipal;
if (user != null)
{
// Get all user claims on this controller. In this controler base class, [this] still gets the descendant instance type, hence name
List<Claim> claims = user.Claims.Where(c => c.Type == this.GetType().Name).ToList();
// set Viewbag with default authorisations on this controller
ViewBag.ClaimRead = claims.Any(c => c.Value == "Read");
ViewBag.ClaimEdit = claims.Any(c => c.Value == "Edit");
ViewBag.ClaimCreate = claims.Any(c => c.Value == "Create");
ViewBag.ClaimDelete = claims.Any(c => c.Value == "Delete");
}
base.OnActionExecuting(filterContext);
}
For website menus and other non-controller actions, I have other claims. E.g. whether a user can view a particular monetary field.
bool UserHasSpecificClaim(string claimType, string claimValue)
{
// get user claims
var user = this.HttpContext.User as System.Security.Claims.ClaimsPrincipal;
if (user != null)
{
// Get the specific claim if any
return user.Claims.Any(c => c.Type == claimType && c.Value == claimValue);
}
return false;
}
public bool UserHasTradePricesReadClaim
{
get
{
return UserHasSpecificClaim("TradePrices", "Read");
}
}
So where do Roles fit in?
I have a table that links a Role to a (default) set of claims. When setting user authorisation, the default is to give the user the claims of their role. Each user can have more or less claims than the default. To make editing simple, the claims list is show by controller and actions (in a row), with other claims then listed. Buttons are used with a bit of Javascript to select a set of actions to minimise the "clicking" required to select claims. On Save, the users claims are deleted and all of the selected claims are added. The web application loads claims only once, so any changes must prompt a reload within this static data.
Managers can therefore select which claims are in each role and which claims a user has after setting them to a role and those default claims. The system has only a small number of users so managing this data is straightforward
To understand the difference between Roles and Claims you must face the limitation of roles and feel how claims come over these issues, so let me give you 2 scenarios to recognize the power of claims where role can't resolve these issues :
1- Your site has two modules (pages, service ..etc) the first module for children (under 18 years old) the other for adults (over 18 years old)
your user identity has a birthday claim
You need to create a policy on this claim so the authorization for each module will be given on this value and if the age of the user is over 18 years then he can go to the adult module and not before this age.
Role is Boolean data type you can have or not have the role, it doesn't have multi values.
2- Your site has role user and you want to prevent access of users to make some maintenance without changing the code.
In claims, you can create an UnderConstrain policy that if true the user can't view the page give property authorize for role user.
At the time of writing this answer we were at '.NET 5.0' with '.NET 6.0' just around the corner. And this is my understanding of what I've seen:
Q: Do we no longer use Roles?
Yep, you're not supposed to use Roles any longer (at least not the way you did it in the previous frameworks.
Q: If so, why are Roles still offered?
To make upgrading projects easier/faster?
Q: Should we only use Claims?
yes. But be sure to check out the video posted here in the answer by #Jonathan Ramos.
Q: Should we use Roles & Claims together?
No, but you can put a role into a claim ofcourse, but be sure to upgrade your project to use Claims only.
And you should not have to write you're own attributes, you should use policy for that, as it's the way of the newer framework. If you need you're own attributes you're "doing it wrong", just create your own Requirement(handler) that's what the whole 'new' policy is all about.
In the current framework the attribute ClaimAuthorize is not even available anymore.
I'm not a web developer by trade, but every couple of years I play one on TV or hang with them to look cool. The last time I raved with ASP.NET was back in the webform days. Back then, having a web-based UX to manage the users on your site was straightforward. I understand ASP.NET Identity 1.0/2.0 and Federation are designed to give developers all kinds of new glow-sticks and pacifiers to party with but it's amazingly frustrating to me to crack open VS 2013, fire up a new MVC/SPA web app and not be able to easily do something everybody else should need and likely be doing, which is manage their users via some admin UX on the site itself.
So, if you're DTC (down-to-code), I would appreciate any, simple examples of how to do the following (#1 is by far the most important. I can extrapolate to #2 and #3...I hope.). Assume nothing fancy (a local machine project using the embedded SQL DB. You know, project template defaults.):
Display all users registered on a website AND THE ROLES THEY ARE PART OF. I've already got everything I could ever want to directly know about a user down with Entity Frameworks. But why are roles so non-obvious here? Snippets for the M, the V and the C much appreciated.
Add or remove roles for a user.
Add or remove available roles for users.
I see the tables, much like the ones that have been around forever, in new MVC projects. The basic user stuff is exposed very easily, but an old, trusted and necessary friend (roles) seems to require some voodoo, mojo or secret sauce to expose in a similarly easy fashion. I'm not far from just mucking with the tables via SQL directly. I know that's bad in the new world order and will likely tip the bouncers off that they shouldn't let me into the party behind the velvet rope.
p.s. I've even seen some posts here and elsewhere suggesting roles be done with claims. While that seems logical, I would prefer ASP.NET Identity 2.0 stuff based on the vestigial of roles (.NET types, SQL tables, etc.) that still exist.
I find the issue quite straightforward (much more than it was before, at least with the membership system). The default installation uses Entity Framework as its backend and creates three tables (among others): one for users, one for roles and one for the many-to-many relationship. It also provides us with two classes that help us with managing users and roles: IdentityUserManager and IdentityRoleManager. With the default template we get classes inherited from these (ApplicationUserManager and ApplicationRoleManager). With these classes we get the basic functionality to manage users and roles.
A last comment about your last p.s.: When you login, the framework stores your roles (which were stored in the database) as claims (which are stored in the authentication cookie). You can access these claims via the ClaimsIdentity of the ApplicationUser.Identity so you don't have to access the database every time you want to know a role of the current user. This is also used in the Authorize action filters.
For 1. Create new controller with read/write actions using EntityFramework(right click on controllers folder) and select model ApplicationUser.
2 and 3. You can paste this code into Seed method in Migrations/Configuration.cs
if (!context.Users.Any()) {
System.Diagnostics.Debug.WriteLine("INSIDE USER SEED");
try {
var store = new UserStore<ApplicationUser>(context);
var userManager = new ApplicationUserManager(store);
var roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(context));
string roleName = "Admin";
if (!roleManager.RoleExists(roleName)) {
roleManager.Create(new IdentityRole(roleName));
}
roleName = "TeleMarketer";
if (!roleManager.RoleExists(roleName)) {
roleManager.Create(new IdentityRole(roleName));
}
roleName = "Marketer";
if (!roleManager.RoleExists(roleName)) {
roleManager.Create(new IdentityRole(roleName));
}
var user = new ApplicationUser() { Email = "informatyka4444#wp.pl", UserName = "informatyka4444#wp.pl" };
userManager.Create(user, "TestPass44!");
userManager.AddToRole(user.Id, "Admin");
user = new ApplicationUser() { Email = "s8359#pjwstk.edu.pl", UserName = "s8359#pjwstk.edu.pl" };
userManager.Create(user, "TestPass44!");
userManager.AddToRole(user.Id, "Admin");
user = new ApplicationUser() { Email = "marketer#wp.pl", UserName = "marketer#wp.pl" };
userManager.Create(user, "TestPass44!");
userManager.AddToRole(user.Id, "Marketer");
user = new ApplicationUser() { Email = "telemarketer#wp.pl", UserName = "telemarketer#wp.pl" };
userManager.Create(user, "TestPass44!");
userManager.AddToRole(user.Id, "TeleMarketer");
} catch (DbEntityValidationException e) {
System.Diagnostics.Debug.WriteLine("EXC: ");
foreach (DbEntityValidationResult result in e.EntityValidationErrors) {
foreach (DbValidationError error in result.ValidationErrors) {
System.Diagnostics.Debug.WriteLine(error.ErrorMessage);
}
}
}
}
I've found tons of examples online that explain how to create roles in MVC 5 using the RoleManager etc, but what I cannot find an answer to, is if it's at all possible to dynamically apply roles created on a user level (through the UI) to parts of the application?
I don't understand the purpose of creating new roles only for them to be stored in the DB with no other function?
Any comments are appreciated.
Here is an example of my role creation code:
public bool CreateRole(string name)
{
var rm = new RoleManager<IdentityRole>(
new RoleStore<IdentityRole>(new ApplicationDbContext()));
var idResult = rm.Create(new IdentityRole(name));
return idResult.Succeeded;
}
Are you looking to apply fine-grained authorization using more than just a role attribute? For instance:
a relationship between the user and the targeted document / resource?
Time of the day?
In that case you need to move from RBAC to ABAC (attribute-based access control).
NIST has a great page on the topic: csrc.nist.gov/projects/abac/
While I'm well used to using the standard ASP.Net Membership Provider for new MVC web applications, I've been getting a kick out of using RavenDb lately but I still don't believe I have a grasp on the best practice for implementing user authentication and role authorisation.
The code I have replaced my Register and Logon methods with in the AccountController looks like the following:
[HttpPost]
public ActionResult Register(RegisterModel model)
{
if (ModelState.IsValid)
{
using (IDocumentSession Session = DataDocumentStore.Instance.OpenSession())
{
Session.Store(new AuthenticationUser
{
Name = Email,
Id = String.Format("Raven/Users/{0}", Name),
AllowedDatabases = new[] { "*" }
}.SetPassword(Password));
Session.SaveChanges();
FormsAuthentication.SetAuthCookie(model.UserName, createPersistentCookie: false);
// ...etc. etc.
[HttpPost]
public JsonResult JsonLogOn(LogOnModel model, string returnUrl)
{
if (ModelState.IsValid)
{
using (IDocumentSession Session = DataDocumentStore.Instance.OpenSession())
{
book Ok = Session.Load<AuthenticationUser>(String.Format("Raven/Users/{0}", Username)).ValidatePassword(Password);
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
// etc...
I've seen the RavenDb Membership Provider code that a number of people have referenced in similar posts or questions, but there also seems to be a number of people who consider this to be over the top and leveraging an inefficient API for a data store that doesn't need most of what's provided within it.
So what is the best architectural / design strategy for RavenDb authentication (not for OAuth, but Forms Authentication) and am I barking up the right tree?
I think there are a few parts to this problem. First, from the MVC project's perspective, you really want to use something that will work with the AuthorizationAttribute. This actually does not require using a MembershipProvider per se, but rather stuffing an appropriate IPrincipal into HttpContext.Current.User as that is what those attributes look at to authorize things.
From a HTTP perspective, taking advantage of the existing forms authentication infrastructure also makes a ton of sense -- it solves most of the sticky security issues you really should not solve yourself and it is very flexible in terms of working with what you provide.
From there you get to the gist of the question -- how you want to back your authentication system from a data perspective. I think that is a very tactical call -- some apps it might make sense to just use a MembershipProvider style model. But if I had an app that was very user centric where I was storing lots of user data I would probably consider rolling a custom user store based around my requirements. If you are using the Authentication bundle you could glom onto that to some extent as well. But I don't think there is a hard and fast rule at this point -- do what makes sense for your app.
One thing you should not do is use the AuthenticationUser like above -- that is meant for database system users. In SQL Server terms that would be like making every user in your app a SQL user and then authenticating against that. Which is how some old intranet products used to work but the world has moved past that now.
This may be a slightly ignorant question but Im new to mvc so Im sorry!
I studied the nerd dinner auth model but In my app I have a complicated role based authentication. So What I do is this:
void MvcApplication_PostAuthenticateRequest(object sender, EventArgs e)
{
HttpCookie authCookie = HttpContext.Current.Request
.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null)
{
string encTicket = authCookie.Value;
if (!String.IsNullOrEmpty(encTicket))
{
FormsAuthenticationTicket ticket =
FormsAuthentication.Decrypt(encTicket);
CustomIdentity id = new CustomIdentity(ticket.Name);
GenericPrincipal prin = new GenericPrincipal(id, id.Roles);
HttpContext.Current.User = prin;
}
}
}
On LogOn I authentication the username/pass with FormsAuth and then I create the cookie.
The problem here is every time I create the custom identity, I have to query the database for the users roles. Is there a correct way around this or am I doing the right thing to query the DB on every incoming request? Should I save the roles list in a cookie or something?
I also don't really understand the whole life cycle of how forms auth takes care of the authentication? I use the same IFormsAuthentication design pattern that nerd dinner users and during a sign-in I call FormsAuth.SignIn() which in turn calls FormsAuthentication.SetAuthCookie, When does it manage to call the membershipservice.validateuser() method ?? Also if the auth cookie has been set why would nerd dinner create a ticket, then add it into the request, and then read it during PostAuthenticationRequest to check which user it was. Does the ticket operation like a session?
Thanks! Merry Christmas!
Update : This link gave me a slightly better understanding about forms authentication ticket.
"Correct?" Its a matter of opinion.
I'd say, if you aren't experiencing issues with the database performance caused by this query, then don't worry about it.
If you are, you can centralize your authentication code into some sort of auth provider or type, and cache authentication information in memory until a write updates the database, which should invalidate the cache at the same time.
(Your second question would do well on its own; I don't have enough info to answer it.)
An alternative approach is to store your user's roles in the authentication ticket when your user is authenticated. Then for every request (Application_AuthenticateRequest method of the global.asax file) you can extract the roles from the authentication ticket and create a GenericPrincipal.
See this answer for more details.