IdentityServer4 Update Claim Value from API Project - .net-core

I've got a pretty simple simple question I'd appreciate if you can provide a solution.
I have two projects:
An IdentityServer4 project.
An API project.
The API project is being protected using IdentityServer4 like the following:
services.AddAuthentication("Bearer")
.AddIdentityServerAuthentication(options =>
{
options.Authority = "http://localhost:5000";
options.RequireHttpsMetadata = false;
options.ApiName = "TestAPI";
options.ApiSecret = "Password"
});
Up to this point everything is working as expected.
My question is from the API project how can I make update operations on IdentityServer4 like updating a users claim value ?

If I have understood your question correct - you want to change the claims, inside an API, that is protected by the IDS, that has issued the claims.
In general - this is not possible and not right.
Why not possible?
The ClaimsPrincipal class, and its Claims property is readonly (it has only getter, but no setter):
public virtual IEnumerable<Claim> Claims { get; }
Why it is not right?
Usually the claims are holding some authentication info (roles, username, some user profile information etc). This data is supposed to be issued by the authentication provider (in your case the IDS) and it is not supposed to be changed by someone/something, whose authorization depends on this authentication data.
PS: Out of curiosity - what claims exactly do you want to change, or this was just a general question?

Related

Asp.net core 2 AuthenticationProperties storing jwt tokens

I am trying to get a better understanding of how jwt tokens are stored (id, access, refresh). When you add OpenIdConnect, one of the options you can set is saving tokens. With below configuration, whenever the user logs in, the jwt tokens are generated (without having to have a separate call to the authorization endpoint to retrieve tokens).
.AddOpenIdConnect("Test", options => {
options.SaveTokens = true;
}
From what I have read, they are saved in the AuthenticationProperties collection returned along with the ClaimsPrincipal. You can retrieve them via HttpContext.GetTokenAsync.
Example below:
var accessToken = await HttpContext.GetTokenAsync("access_token");
I am trying to understand more about how these values are stored and retrieved. I know that the claimsprincial is a collection of identities / claims associated with a user. But how exactly are authentication properties set? How can I access the collection of authentication properties individually? Is there a class / interface I can use to get direct access to the class properties? I didn't see anything about authentication properties in the ClaimsPrincial class.
Also, as the access token is stored in the authentication properties, is the only way to update the value is to re-authenticate (i.e. challenge the user to login again)? How can I update the value? Or would it be better off extracting the value is storing it elsewhere to update?
I have been looking into this a bit myself as well. The OpenID Connect middleware seems to usually persist data into a signed cookie via a second cookie authentication scheme, specified by the SignInScheme option. Extending your example from before with an explicitly configured example:
.AddOpenIdConnect("Test", options => {
options.SignInScheme = "MyCookieScheme";
options.SaveTokens = true;
}
This example implies that a cookie authentication scheme has also been set up with a call like this:
.AddCookie("MyCookieScheme")
From the documentation comments on SignInScheme:
Gets or sets the authentication scheme corresponding to the middleware responsible of persisting user's identity after a successful authentication. This value typically corresponds to a cookie middleware registered in the Startup class. When omitted, Microsoft.AspNetCore.Authentication.AuthenticationOptions.DefaultSignInScheme is used as a fallback value.
(Note that this property actually comes from a RemoteAuthenticationOptions class that OpenIdConnectOptions extends)
Tracing what happens in default setup scenarios where you don't explicitly give a cookie authentication scheme is a bit tricky but I imagine it sets one up by default, or relies on one being there. Also, I guess that in theory, any other type of authentication scheme could be used for this persistence (e.g. your own JWT issuing and signing scheme), but I have not seen any examples of this.
As for what is actually stored in the cookie and how it gets put there by the OpenID Connect middleware, you would probably have to do a lot of digging through all of the code to work that out for sure - the specifics of all this low-level middleware doesn't seem to have been documented much yet. All I know for sure is that the DataProtection middleware is involved in encrypting the contents of the cookie.
You could look into decrypting the cookie itself to see what's there - see the answers here: How to manually decrypt an ASP.NET Core Authentication cookie?
(oh and for the record, all these examples are based off ASP.NET Core v2.0)
Another option is to use TokenValidationParameters.SaveSigninToken
From source code
if (validationParameters.SaveSigninToken)
identity.BootstrapContext = jwtToken.RawData;
It will store the original token in the BoostrapContext property of the current identity.
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication()
.AddJwtBearer(options =>
{
options.TokenValidationParameters.SaveSigninToken = true;
});
}
}
Then access the identity of the current user
((ClaimsIdentity)this.User.Identity).BoostrapContext // => original JWT token

Faking authentication during development

In my current asp.net MVC core application we use OpenId Connect to authenticate with our corporation's identity provider.
However during local development we cannot reach the the provider.
Also we would like to easily change claim values for development and unit testing purposes.
I tried swapping my service binding for IHttpContextAccessor to a DevelopmentHttpContextAccessor that fills up the HttpContext's Identity with the desired claims.
This is a bit of a roundabout way and it also doesn't work as the claims are emptied when I check them in my Service.
What is the standard way of handling this during development and unit testing? What am I missing?
The answer was not faking IHttpContextAccessor, but setting a custom ClaimsPrincipal to the identity property.
In your Startup.Configure you can add a middleware step:
app.Use((httpContext, nextMiddleware) => {
var claims = new[] {
// Your claims here
};
var claimsIdentity = new ClaimsIdentity(claims);
var user = new ClaimsPrincipal(claimsIdentity);
httpContext.User = user;
return nextMiddleware();
});

How can I send authorization information back to my client app when using AngularJS, WebAPI 2 and Oauth 2?

I have a AngularJS client application that uses javascript (not coffeescript or typescript) Oauth2 to authenticate against a WebAPI 2 application using the latest Identity 2. All the software in my application is the very latest and is based on this example. My client browser targets are IE9 and above.
Note that I made some minor changes from the example above in that I do not urlencode all of the data sent to the server using the transform. Instead I urlencode only in the authenticate method below:
user.authenticate = function (userName, password, rememberMe, successCallback, errorCallback) {
var config = {
method: 'POST',
url: '/Token',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
data: 'grant_type=password&username=' + encodeURIComponent(userName) + '&password=' + encodeURIComponent(password),
};
I am developing with VS2013 Update 2 and on the server, I use C#, the latest Entity Framework and SQL Server 2012.
To login my client calls a /Token method to the WebAPI and passes the userid and password. The WebAPI then responds with a token to the client which I store. With each request to the WebAPI the token is sent back and authenticated:
$http.defaults.headers.common.Authorization = 'Bearer ' + user.data.bearerToken;
This works very well so far but as it stands the application is unable to tell the difference between users that have different roles assigned to them.
Some of the WebAPI methods can only be executed by users who have a certain role. I would like to adjust the menus of my front-end AngularJS application so that only if the user has this role then the appropriate links will appear visible. I do realize that this would not stop a user from checking the HTML and posting but I am not concerned about this as I will still have method decoration to limit the ability of users not in a role to perform actions.
Can someone give me an example of how I can do this using just the suite of products mentioned above that I mention in the question plus JavaScript Web Tokens if they help make bring the solution up to date. From what I understand roles are handled by claims but I do not understand how to add these and send them back to the client with tokens. I have done a lot of research on the internet but I've not been able to find any good examples as I think most of this is very new and not many people have had the chance to explore how a SPA can use these very latest software components.
When answering this question please note that I am not looking for an answer that can tell the community how to set up roles on the server or an answer that explains about how important it is to provide role checks on the server. I think almost everyone is aware of this. What I really think will be of use is some very detailed technical suggestions with sample code and an explanation. To keep the answer focused it would probably be of help to everyone if answers that do not meet this need are not posted as suggested answers.
Thank you in advance.
The short answer to your question is ApplicationOAuthProvider.CreateProperties method. Its created for you by default and is found under WebApi2/Provider/ApplicationOAuthProvider.cs, By default it only sends the userName
//WepApi2/Providers/ApplicationOAuthProvider.cs
public static AuthenticationProperties CreateProperties(string userName)
{
IDictionary<string, string> data = new Dictionary<string, string>
{
{ "userName", userName }
};
return new AuthenticationProperties(data);
}
I would make the following update (in case I need to send more user data later on):
public static AuthenticationProperties CreateProperties(string userName, ClaimsIdentity oAuthIdentity)
{
IDictionary<string, string> data = new Dictionary<string, string>
{
{ "userName", userName},
{ "roles",string.Join(",",oAuthIdentity.Claims.Where(c=> c.Type == ClaimTypes.Role).Select(c => c.Value).ToArray())}
};
return new AuthenticationProperties(data);
}
If you haven't made major changes to the WebApi project, ApplicationOAuthProvider.CreateProperties is only referenced in two places, just update the calling code to pass the oAuthIdentity along with user.UserName and you'll get the user roles sent along with the access token response:
{
"access_token": "ZpxAZyYuvCaWgShUz0c_XDLFqpbC0-DIeXl_tuFbr11G-5hzBzSUxFNwNPahsasBD9t6mDDJGHcuEqdvtBT4kDNQXFcjWYvFP7U2Y0EvLS3yejdSvUrh2v1N7Ntz80WKe5G_wy2t11eT0l48dgdyak8lYcl3Nx8D0cgwlQm-pePIanYZatdPFP9q5jzhD-_k9SF-ARTHgf0ePnbvhLBi1MCYQjvfgPKlbBHt0M5qjwGAeFg1IhSVj0gb4g9QTXoiPhRmxGBmjOpGgzxXixavmrpM7cCBFLoR3DCGnIJo6pwT-6VArxlB8-ZyyOZqh_6gGtptd0lIu8iJRUIGwO9HFNkROdoE9T4buwLnhPpWpy9geBjPVwsB1K3xnbch26YbklhxIHVybBxeIVXd17QTw_LjlQ5TJdqpAYfiZ5B9Nx2AFYYYe3--aemh4y1XOIvN",
"token_type": "bearer",
"expires_in": 1209599,
"userName": "MK",
"roles": "Admin,Public",
".issued": "Fri, 23 May 2014 17:36:54 GMT",
".expires": "Fri, 06 Jun 2014 17:36:54 GMT"
}
Now you have the roles available, you can use Angular conditional directives to show/hide actions according to user roles.
If you need more clarification, please let me know.
Edit:
Decorating your controller methods with Authorize attribute is valid, since the HttpContext.Current.User.Identity is actually a ClaimsIdentity. But as not to hard code security logic inside the application, I prefer using ClaimsAuthorizationManager
public ActionResult Secure()
{
if(!ClaimsPrincipalPermission.CheckAccess("resource", "action"))
return new HttpUnauthorizedResult();
ViewBag.Message = "You are allowed to perform action on resource.";
return View();
}
Roles creation using RoleManager:
RoleManager roleManger = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>());
roleManager.Create(new IdentityRole() { Name = "Admin" });
Roles assignment using UserManager:
userManager.AddToRole(user.Id, "Admin");
There are 2 ways I see you can approach your problem.
include the "Role" Information to the token by a hash or a simple string append as you are the one generating the token, then you can decipher it on the angular.
it seems you want to use ASP.NET Identity system and store and retrieve the role information there. If that is the case you can go through this post pay attention to "Initialize the database to create Admin Role and Admin User" section.
IMO, #1 will give you more flexibility on how you store and use your user data as #2 you are following Microsoft's IdentityUser , although it look magic sometimes and it tend to post limitation and you need to spend time to understand how it works behind the scene and make it work for your project.
To know more about the "Individual User Accounts" you pick during the WebAPI project you created, you can go to http://www.asp.net/visual-studio/overview/2013/creating-web-projects-in-visual-studio#indauth
I have a very similar scenario as yours, but instead of using tokens to authenticate, I use an Identity Server (Thinktecture) to handle my authentication. My app redirects to the Identity Server to authenticate and it comes back with some very basic claims (username and email). This happens as soon as someone tries to first browse to the page. Once the user is authenticated and redirected to my app I make another call to the server to get the user's permissions. These permissions are stored inside a Security service (AngularJS) which also exposes a "hasPermissions" method. I then use ng-if to decide if I am going to display certain parts of the page - including menu items. Something to this effect:
var service = {
currentUser: ...,
isAuthenticated: function() {
return ...;
},
checkAccess: function(permission) {
return service.isAuthenticated() ?
!!(service.currentUser.permissions.indexOf(permission) > -1) : false;
}
}
Remember that all all the permissions and html elements are visible to anyone who decides to hit the dev tools button and take a peek. You have to do the same checks on the server side before you perform any action. We have a custom Authorization attribute based off of this that checks if the user has the necessary permissions to execute the MVC/WebAPI action before it is executed for simple cases or actually check it within the Action or the HTTP resource before doing anything that needs elevated privileges.
If you want the client to not see any html elements or certain sections of your site you can either point your templates to a MVC action that will authenticate and then return the HTML template or redirect to another page (not the SPA realm) and have them authenticated on the server before the response is served back.
Here another answer:
In ApplicationOAuthProvider.cs
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
simply add a custom header!
context.OwinContext.Response.Headers.Add("Roles", userManager.GetRoles(user.Id).ToArray());

MVC 5 and use of claims default authentication

I have a question regarding the claims in MVC 5.
So basically imagine I have a registered user in DB, now the user is going to log in, like so:
private async Task SignInAsync(ApplicationUser user, bool isPersistent)
{
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
// Add more custom claims here if you want. Eg HomeTown can be a claim for the User
var homeclaim = new Claim(ClaimTypes.Country, user.HomeTown);
identity.AddClaim(homeclaim);
AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
}
So in this case i add a new claim to the identity and then i sign in this identity.
Now my questions are:
What is the use of setting this claim? (because i can also get this from the db if i need it, what is the point in this case of claim)
And how do i use it later on in the code?
Setting the Claim against the identity makes your application security more efficient and saves hitting your database each time.
The method above can be known as a Claims Transformation which often involves reading in data that is transformed into claims after authentication succeeds.
In order to read it later you can do this:
//Get the current claims principal
var identity = (ClaimsPrincipal)Thread.CurrentPrincipal;
//Get the country from the claims
var country = identity.Claims.Where(c => c.Type == ClaimTypes.Country).Select(c => c.Value);
Update
Just to provide some further information to the answer as discussed in the comments below.
With a Claims based approach you also benefit from being able to use a claims authorization manager which can provide a centralized/finely grained access control to resources and actions. 
If you've not used claims before it's best to think of actions against resources rather than role based permissions. That way you can drill right down and control access to each resource/action individually rather than having a multitude of roles for each one. 
I personally like to use a mixture but store the roles as claims too. 
That way I can use the standard authorization tags in mvc with roles, which read the claims and use thinktecture's attributes/ClaimsAuthorization to make the claims authorization manager pickup the more complicated rules.
A good link on implementing claims based authentication in MVC 4 is available here:
http://dotnetcodr.com/2013/02/25/claims-based-authentication-in-mvc4-with-net4-5-c-part-1-claims-transformation/

What is ASP.NET Identity's IUserSecurityStampStore<TUser> interface?

Looking at ASP.NET Identity (new membership implementation in ASP.NET), I came across this interface when implementing my own UserStore:
//Microsoft.AspNet.Identity.Core.dll
namespace Microsoft.AspNet.Identity
{
public interface IUserSecurityStampStore<TUser> :
{
// Methods
Task<string> GetSecurityStampAsync(TUser user);
Task SetSecurityStampAsync(TUser user, string stamp);
}
}
IUserSecurityStampStore is implemented by the default EntityFramework.UserStore<TUser> which essentially get and set the TUser.SecurityStamp property.
After some more digging, it appears that a SecurityStamp is a Guid that is newly generated at key points in the UserManager (for example, changing passwords).
I can't really decipher much beyond this since I'm examining this code in Reflector. Almost all the symbol and async information has been optimized out.
Also, Google hasn't been much help.
Questions are:
What is a SecurityStamp in ASP.NET Identity and what is it used for?
Does the SecurityStamp play any role when authentication cookies are created?
Are there any security ramifications or precautions that need to be taken with this? For example, don't send this value downstream to clients?
Update (9/16/2014)
Source code available here:
https://github.com/aspnet/Identity/
https://github.com/aspnet/Security/
This is meant to represent the current snapshot of your user's credentials. So if nothing changes, the stamp will stay the same. But if the user's password is changed, or a login is removed (unlink your google/fb account), the stamp will change. This is needed for things like automatically signing users/rejecting old cookies when this occurs, which is a feature that's coming in 2.0.
Identity is not open source yet, its currently in the pipeline still.
Edit: Updated for 2.0.0. 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)
app.UseCookieAuthentication(new CookieAuthenticationOptions {
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider {
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
}
});
If your app wants to trigger this behavior explicitly, it can call:
UserManager.UpdateSecurityStampAsync(userId);
The UseCookieAuthentication is deprecated by now. I managed to configure it using
services.Configure<SecurityStampValidatorOptions>(o =>
o.ValidationInterval = TimeSpan.FromSeconds(10));
Moved from reply to answer per request.
I observed the SecurityStamp to be required for token verification.
To repo:
Set SecurityStamp to null in the databsae
Generate a token (works ok)
Verify token (fails)

Resources