Creating ready-made users with claims with ASP.NET - c#

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

Related

Asp.NET Core Claim based Authorization

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.

Fetch permissions from identity server during authorization

I am using identity server 4 for authentication and authorization, and user permissions are saved in JWT and then used on API-s to check if users has required permission.
But the problem is that JWT got too big and I would like to remove permissions from it, and make custom authorization on API-s so that its fetches permissions from identity server instead of getting it from JWT.
API would get only userId from JWT and then based on that fetch additional information from identity server. Is it possible to do something like that?
We basically have a similar problem in our application.
The way to solve this problem is using an event which is raised at the level of the API resource (the API which you are protecting by using JWT bearer tokens authentication) once the JWT token has been read from the incoming request and validated.
This event is called OnTokenValidated, see here for more details.
This is the top level plan:
keep your JWT bearer token minimal. At the very minimum it contains the subject id, which is the unique identifier of the user at the identity provider level. You can put other claims there, but the idea is that the JWT bearer token must be small
implement a way to get the user permissions given the user unique identifier (you can use the subject id as an identifier or any other id which makes sense in your system)
make the user permissions fetch mechanism of the previous point accessible via api call. Caching this API is a good idea, because usually permissions are stable. Defining a smart way to evict this cache is beyond the scope of this answer, but it's something you should definitely think about.
once you have fetched the user permissions (via an API call) you need to make them available to the ASP.NET core authorization framework. The simplest way to do so is create a custom claim type (for instance: "app_permission") and create one user claim per each user permission. Each of these permission claims has the custom claim type ("app_permission") and the permission name as the claim value. For instance a user having the two permissions "read-content" and "write-content" will have two claims both having "app_permission" as the claim type, the first one having "read-content" as the claim value and the second one having "write-content" as the claim value.
the permissions claims defined at the previous point can be injected in the user identity (at the API resource level) by defining an additional ClaimsIdentity for the user and by adding it to the current user identity. The process depicted here is quite similar to a claims transformation done by an MVC application using cookie authentication.
In the Startup class of your API resource, in the point where you register the authentication services, you can do something like this:
services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Authority = "https://localhost:8080";
options.Audience = "sample-api";
options.RequireHttpsMetadata = false;
// register callbacks for events
options.Events = new JwtBearerEvents
{
OnTokenValidated = context =>
{
if (!context.Principal.Identity.IsAuthenticated)
{
return;
}
var subjectId = context.Principal.FindFirst(JwtClaimTypes.Subject)?.Value;
if (string.IsNullOrWhiteSpace(subjectId))
{
return;
}
// do whatever you want with the user subjectId in order to get user permissions.
//You can resolve services by using context.HttpContext.RequestServices which is an instance of IServiceProvider
//Usually you will perform an API call to fetch user permissions by using the subject id as the user unique identifier
// User permissions are usually transformed in additional user claims, so that they are accessible from ASP.NET core authorization handlers
var identity = new ClaimsIdentity(userPermissionsClaims);
context.Principal.AddIdentity(identity);
}
};
});
+1 for the accepted answer but I would just like to offer an alternative solution to this problem. If your permissions are pretty simple like readResource or writeResource then you could define all your permissions as enum and use integers instead of strings in JWT, that would reduce JWT size.
If permission list is still huge then you could also group permissions together so that the permission list is smaller for some customers e.g. merge readResource, writeResource, updateResource, deleteResource into one permission called crudResource.

Editing asp.net core identity claims instead of adding them

I'm using external logins for my asp.net core mvc website, and when the login completes I want to store the social info they used to login (such as username, profile image, etc.) as claims in the user's identity...
So I run code like this in my account controller after a successful login:
var authClaim = user.Claims.FirstOrDefault(c => c.ClaimType == authToken.Name);
if (authClaim == null)
externalClaims.Add(new Claim(authToken.Name, authToken.Value));
else
authClaim.ClaimValue = authToken.Value;
if (externalClaims.Any())
await _userManager.AddClaimsAsync(user, externalClaims);
await _userManager.UpdateAsync(user);
however when I attempt to do this, the claims table is duplicating the claims rather than updating them as I expected, so every time the user logs in I get another collection of records in the table for that user that are identical to the last.
do I have to delete them and re-add them instead on every login? if not, how do I update existing claims without duplicating them?
I'm doing it on every login in case the user has changed their profile or other info (and to make sure I have the most up to date token).
I'm also curious why I add the claims to the main Identity of the user. The User has a property called ExternalClaims, but it is empty and there doesn't appear to be any way to update it. It seems to me this is a better place to put these third-party Claims, but I can't for the life of me find any way to modify it...
either way, I'm sure I'd have the same problem if I use this code, so is the proper course to delete the claim on login and always add it new, or should I be doing something differently?

Update user's membership role

I am using asp.net MVC 5 identity 2.0
The administrator is able to change user’s role but used must re-log to see the changes. First thought was to re-log user manually but I failed. After that I thought of dynamically changing user’s role or something else. Could you provide me the right way?
I set user’s role using UserManager.AddToRolesAsync
I have tried a lot of things like:
var memberUser = Membership.GetUser(user.UserName.ToString());
if (memberUser.IsOnline)
{
FormsAuthentication.SignOut();
}
or also try to clean up my cookies.
I dunno how I can sign out another user.
Also I have read articles like these
http://w3facility.org/question/mvc-5-addtorole-requires-logout-before-it-works/
How do I forcefully propagate role changes to users with ASP.NET Identity 2.0.1?
How to force logout user when his/her username is changed by another user?
ASP.net Identity 2.0 Sign-out another user
Have a look at the answer provided by Hao Kung on this post he describes exactly how to solve this using the SecurityStamp .
https://stackoverflow.com/a/19505060/1454538
So the primary purpose of the SecurityStamp is to enable sign out
everywhere. The basic idea is that whenever something security related
is changed on the user, like a password, it is a good idea to
automatically invalidate any existing sign in cookies, so if your
password/account was previously compromised, the attacker no longer
has access.
In 2.0.0 we added the following configuration to hook the
OnValidateIdentity method in the CookieMiddleware to look at the
SecurityStamp and reject cookies when it has changed. It also
automatically refreshes the user's claims from the database every
refreshInterval if the stamp is unchanged (which takes care of things
like changing roles etc)
This should get you going.

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.

Categories