Validate Values before Apply PATCH in REST - asp.net

I'm looking for a way to validate and check the values of the model that is sent to my PATCH method for updating. I haven't found my answer yet.
I've read the JsonPatch Documentation but I didn't find what I want.
Scenario: I have a RESTful Web API, and say I have a resource named "users". Say a client wants to partially update a "user" resource: (PATCH api/users/{id}), when the client sends a JsonPatch Document, for example, I have to check if the email is sent for updating and if yes, I have to check if the email wasn't duplicate. So, how could I do this in a method like below: (I use ASP.NET Web API)
[HttpPatch]
[Route("{userId}")]
public HttpResponseMessage UpdateUser(int userId, JsonPatch.JsonPatchDocument<User> patchDocument)
{
// I could do this but before that I wanna validate the proeprties:
patchDocument.ApplyUpdatesTo(dbContext.Users.Single(u => u.Id == userId));
}

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

C#/OWIN/ASP.NET: can I *manually* generate and get a valid bearer token string in my API code?

I am using the OWIN OAuthAuthorizationServer library in an OWIN ASP.NET C# web API to generate and process bearer tokens.
Right now, I have a single endpoint (which you set in the OAuthAuthorizationServerOptions struct) that accepts the grant_type, username and password fields from the frontend. I created a provider class that performs the validation, and then calls context.Validated() or context.SetError() accordingly. The middleware then handles generating the token and returning it to the user, and also "takes over" the login endpoint, doing all the work internally.
Now, I am adding a new feature to my API where the user can change their "role" (e.g. an admin can set themselves as a regular user to view the results of their work, a user can select among multiple roles, etc.) Since I already handle this through the bearer token (I store the user's role there and all my endpoints use the bearer token to determine the current role), I now have a reason to update the contents of the bearer token from the API backend.
What I'm looking to do is to allow the frontend to call an endpoint (e.g. api/set_role) that will accept a parameter. The user requests a certain role, and their current bearer token would accompany the request. The server then would check if the user in question is allowed to use that specific role and, if so, would generate a new token and return it to the user in the response body. The frontend would then update its token in local storage. Or, of course, if the user is not permitted to switch to that role, the backend would return an appropriate error and the frontend would react accordingly.
To do this I basically want to be able to manually generate a token. Similar to how I use identity.AddClaim() in my login provider, I'd like to be able to do that at any arbitrary position within the API's code. The method would take responsibility for transferring over any necessary existing information (e.g. the user's username) into the new token, since it already has the existing one.
Pseudocode for what I want:
if (!userCanUseRole(requestedRoleId)) return Request.CreateErrorResponse(...);
// we have a struct containing parsed information for the current token in the variable cToken
bearerToken newToken = new bearerToken();
newToken.AddClaim(new Claim("user", cToken.user));
newToken.AddClaim(new Claim("role", requestedRoleId));
string tokenToReturnToFrontend = newToken.getTokenString(); // string suitable for using in Authorization Bearer header
return Request.CreateResponse(new StringContent(tokenToReturnToFrontend));
I am not too familiar with "refresh" tokens, but the only way I am using them right now is extending token expiration. To that end the frontend explicitly requests a refresh token and provides its own, which the backend simply copies to a new token and edits the expiry time. The problem with this is that there's a single method for getting a refresh token, and since I have now at least one other reason to refresh a token (and possibly, future developments could add even more reasons to change token contents at various times), I'd then have to deal with storing transient data somewhere (E.g. "when requesting a refresh token, what is the thing the user wanted to do? has it been too long since they requested to do that? etc.) It'd be much easier if I could simply generate a bearer token on demand in the same way that the OAuthAuthorizationServer itself does. (I know it uses the MachineKey to do this, but I don't know exactly how it does it, nor how I would go about doing what I'm trying to do.)
Of note: In another project I provided internal access to the OAuthBearerAuthenticationOptions class that is passed to the authorization server instance, and was able to use that to decode a bearer token inside of a test. I haven't seen anything obvious thought that would let me encode a bearer token this way.
EDIT: I explored the (extremely tersely, almost uselessly documented) OWIN namespace and found the AccessTokenFormat class which appears that it should do what I want. I wrote this code:
Microsoft.Owin.Security.AuthenticationTicket at = new Microsoft.Owin.Security.AuthenticationTicket(new ClaimsIdentity
{
Label="claims"
}
, new Microsoft.Owin.Security.AuthenticationProperties
{
AllowRefresh=true,
IsPersistent=true,
IssuedUtc=DateTime.UtcNow,
ExpiresUtc=DateTime.UtcNow.AddMinutes(5),
});
at.Identity.AddClaim(new Claim("hello", "world"));
string token = Startup.oabao.AccessTokenFormat.Protect(at);
return Request.CreateResponse(HttpStatusCode.OK, new StringContent(token, System.Text.Encoding.ASCII, "text/plain"));
which seems like it should work. (I again allow access to the OAuthBearerAuthenticationOptions class passed to the OAuthAuthorizationServer instance.) However, this code throws an ArgumentNull exception. The stacktrace indicates that it is writing to a BinaryWriter but the OWIN code is passing a null value to the Write method on the BinaryWriter.
Still have no solution.
I did figure out the code to make this work. One could argue I'm "not using OAuth right", but strictly, this code WILL accomplish what I want - to generate a token in code at any arbitrary point and get the string.
First, as I said, I have to provide access to the OAuthBearerAuthenticationOptions class instance. When the OAuth server initializes I'm guessing it populates this class with all of the various objects used for tokens. The key is that we do have access to Protect and Unprotect which can both encode and decode bearer tokens directly.
This code will generate a token assuming that oabao is the OAuthBearerAuthenticationOptions class that has been passed to the OAuthAuthorizationServer instance:
Microsoft.Owin.Security.AuthenticationTicket at = new Microsoft.Owin.Security.AuthenticationTicket(new ClaimsIdentity("Bearer", "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", "http://schemas.microsoft.com/ws/2008/06/identity/claims/role"),
new Microsoft.Owin.Security.AuthenticationProperties
{
AllowRefresh = true,
IsPersistent = true,
IssuedUtc = DateTime.UtcNow,
ExpiresUtc = DateTime.UtcNow.AddDays(1) // whenever you want your new token's expiration to happen
});
// add any claims you want here like this:
at.Identity.AddClaim(new Claim("userRole", role));
// and so on
string token = oabao.AccessTokenFormat.Protect(at);
// You now have the token string in the token variable.

Authorization by Role/Group in ASP.NET using Auth0

Thanks in advance for your help in this matter!
I was hoping someone could help me figure out how to authorize API access by Group assigned in the Auth0 Authorization extension.
I currently am using the [Authorize] attribute in the web api perfectly - it allows an api call if they have signed in successfully and blocks it if not.
However, if I try [Authorize(Roles = "myGroupName")] authorization fails. Same occurs if I add it to the users app_metadata manually in the Users dashboard on the Auth0 website instead of assigning through the extension.
My project is set up by following the Angular Quick Start and Asp.Net Quick Start. My webapiconfig where I validate the token server side is:
class WebApiConfig
{
public static void Register(HttpConfiguration configuration)
{
var clientID = WebConfigurationManager.AppSettings["auth0:ClientId"];
var clientSecret = WebConfigurationManager.AppSettings["auth0:ClientSecret"];
configuration.MessageHandlers.Add(new JsonWebTokenValidationHandler()
{
Audience = clientID,
SymmetricKey = clientSecret
});
configuration.Routes.MapHttpRoute("API Default", "api/{controller}/{id}",
new { id = RouteParameter.Optional });
}
}
The Auth0 Authorization extension currently supports authorization decisions through the concept of groups. You can create a group, assign users to that group and that configure an application to only be accessible to user within a specific group. All of this would be handled automatically and any user outside of the application expected groups would be denied complete access.
Your use case is a bit different, but valid nonetheless. You want the groups configured with the extension to be sent along the generated token so that the application itself makes authorization decisions based on those values.
In order for the groups configured within the extension to be sent along in the token, the first thing you need to do is request them. For this, you need to include the groups scope when performing the authentication requests.
Add the user's group membership to the outgoing token (which can be requested via the OpenID groups scope);
(emphasis is mine, source: Authorization Extension Docs, section Rule Behavior)
If you request a token using that scope and then decode it in jwt.io, you would get something similar to this (the actual groups would vary by user):
{
"groups": [
"GROUP-1",
"GROUP-2"
],
"iss": "https://[tenant].auth0.com/"
}
Now, for the validation of this information on the ASP .NET API side. Assuming the sample you're using is this one (ASP.NET Web API), the group information contained within the token would be mapped to the following claims:
Type: groups | Value: GROUP-1
Type: groups | Value: GROUP-2
This happens because of the logic that exists in the JsonWebToken class which handles arrays coming from the JWT payload by creating per-value claim that share the same type.
The final part is making sure the AuthorizeAttribute checks these claims of type groups instead of trying to lookup role claims. You should be able to accomplish this, by changing the RoleClaimType constant in the JsonWebToken class to have the value "groups" instead of "http://schemas.microsoft.com/ws/2008/06/identity/claims/role".
Like you certrainly know, the Authorize attribute works using what is in the principal: something that inherits IPrincipal.
In web api, it is even more specific; it is something that inherits ClaimsPrincipal (this implements himself IPrincipal).
As you certainly know already, a claim is like a key-value pair.
The ClaimsPrincipal contains a serie of key-value pairs that are directly taken from the authentication token. This authentication token is issued by the authentication server most of time as JWT (Json Web Token). Most of time as well, the authentication server is using OAuth, like is your case.
If the user group, that you expect to be the role in your application doesn't work by using the out-of-the-box Authorize attribute, it's because it is not mapped correctly: Auhtorize checks the claim with claim type: http://schemas.microsoft.com/ws/2008/06/identity/claims/role (the "claim type" is the "key" of the key-value pair). That means that if you want your Authorize to work, this claim must be valued with the group.
You can do several things to have a clean authorization in your application.
Make a custom Authorize attribute. This Authorize attribute would check the role using a different claim type. The claim type that refers to the user group depends on your authentication server. If you don't find what claim type is used for groups in the doc of your authentication server, run your application in debug, and check every claim that is contained in the property User of your controller. You will certainly find what the claim type you are interested in.
Change the setup of your authorization server by redefining the mapping between user information and claims of the token that is produced (in your case, map groups of the user to the claim that has the type http://schemas.microsoft.com/ws/2008/06/identity/claims/role). Generally, this can be setup per client application or even globally. For example this is the way that must be done if you use an ADFS authentication, AzureAD or WSO2 authentication server (http://wso2.com/products/identity-server/)
Add an owin middleware to modify the current principal. It will change the current principal by copying the value of the claim that contains groups into the claim type http://schemas.microsoft.com/ws/2008/06/identity/claims/role. This middleware must be inserted in the flow after the authentication middleware
I have no rights to comment so I'm going to inquire from here. Why are you doing this
[Authorize(Roles = "myGroupName")]
as far as I remember when I was implementing group based authorization I was still typing
[Authorize(Roles = "myRoleName")]
Not other way around.

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());

RESTful Verify Password service

I'm writing a Verify Password service using the ASP.NET Web Api.
The service accepts a password for the currently signed in user, verifies it, and returns an encoded value. This all happens over SSL.
Calling this method causes no changes to state.
Initially this looks like it should be a GET request however on further inspection I'm concerned about the web server logging plain text passwords.
We could implement this as a POST but that seems like the wrong verb given the action.
Is this simply a case of pragmatism over procedure or is there more we can do to fulfil both the pragmatic and RESTful cases?
You should use Basic Authentication where you pass the username/password as headers. This also fits better as the standard already defined.
There is already a javascript code for doing base64 encoding - if you need to do this on the browser.
If you are doing this to authenticate and the encoded value is the access token (cookie), it is better to use OAuth 2.0.
If the API call sends a response that is not a resource per se (does not involve a resource returned from a data store), you should use verbs not nouns.
You can have a UserPasswordsController controller that exposes an action method like this:
[HttpPost()]
public HttpResponseMessage Validate()
{
if (!this.Request.Content.IsFormUrlEncodedContent())
{
return this.Request.CreateErrorResponse(
HttpStatusCode.BadRequest,
"Body of request must be form URL encoded."
);
}
var parameters = this.Request.Content.ReadAsFormDataAsync().Result;
var userName = parameters["userName"];
var password = parameters["password"];
// TODO: Validate user name and password
var isValid = true;
if(!isValid)
{
return this.Request.CreateErrorResponse(
HttpStatusCode.Forbidden,
String.Format(null, "The password provided for {0} is not valid.", userName)
);
}
return this.Request.CreateResponse(HttpStatusCode.OK);
}
And have a registered route like this:
routes.MapHttpRoute(
name: "UserPasswords",
routeTemplate: "api/v1/validate",
defaults: new { controller = "userpasswords" }
);
You would POST forms data to the validation endpoint that contains the user name and password you wish to validate. A status of Forbidden status indicates the password is invalid, while a status of OK is returned if the password is valid.
If you are new to working on REST interfaces and want to take a pragmatic approach, I highly recommend you take a look at Web API Design - Crafting Interfaces that Developers Love.

Resources