Managing permissions on RESTful service - c#

I am working on an SPA application using angularjs and Web API. I've been working on setting up user permissions for the resources on the api.
Since the api is a RESTful service, I'm not sure the best practice to store/retrieving the permissions. The permissions in my application can change somewhat frequently, as users have different permissions for different companies they belong to. The user can change their company on the fly in the application.
The way I have is solved currently, is when the user logs in, the application stores a claim for every permission the user has, for all companies. The claim is stored with permission name and company id concatenated together. Then I have an attribute that accepts a permission name. Then I concatenate that name with the selected company id in the app and see if it exists in the claims. If so, they have access.
Another option I see is to only store only pertinent user info in claims (user id, name). Then do a lookup every time I need roles or permissions. A drawback here is there will be a lot of traffic since I need that information on almost every api request. Also, since I have the authentication and resource server separated, it's not a simple lookup. I'd have to go over http to get the data.
Are these my only options or is there a better way to handle this?

You want to use Bearer Tokens to solve this problem. A bearer token is essentially an encrypted JSON string, that can contain all of the claims for a user. In your case, I recommend a having separate claim for every company/permission combination.
Bearer tokens are created on the server, and the exact technique you would use to generate one depends on the server technology/framework you are using.
Your SPA will send the bearer token with every request (take a look at $HttpInterceptor service to accomplish this). At the server, your service will decrypt the token, and use the claims information therein to verify whether or not the user has permissions for the given endpoint.

Related

Asp Net Core authentication with JWT

I'm currently planning on making an online scheduler in Blazor Webassembly (NET Core 3.1). As I've written intranet applications most of the time, I'm kind of concerned about the security aspects of the web api that the client will consume.
Currently, we're issuing JWT Tokens from the Backend with the username and the validity of the token in hours to the client and store the said token in the local storage of the browser. Since the token can be accessed by the user and the claims can be extracted from it, is there anything I have to be aware of? The token then is set as the DefaultRequestHeader of the HttpClient after the user has logged in. A cusotm Middleware then validates the token and sets the username in a scoped service if the user is authenticated.
The users (customers and employees) are stored in a database which is not publicly accessible. There is no option to register a user via the website. Users can create appointments in multiple locations of the company (not at the same time/day) but how do you restrict a user from consuming an api endpoint for one location but not for the other? Since claims can be manipulated I'm really not that confident in writing the accessible locations into the jwt.
Some actions also required to be executed in the four eyes principal, e.g. a second user needs to login (30 seconds validity with a refresh if possoible) in order to confirm the action. Are there existing mechanisms which are capable of handling such a thing?
Any advice, sources or thoughts are welcome. Feel free to ask for more details if necessary.
You could look at these posts, they helped me: https://chrissainty.com/securing-your-blazor-apps-authentication-with-clientside-blazor-using-webapi-aspnet-core-identity/

Generate a token based on the windows user who makes the request

I have searched all over for an answer to this, and not found anything that seems to answer my question. Which feels like it should be an easy one (but clearly isn't).
I have an API which authenticates using a token. This token I generate from my application - more specifically, I have a new Token Generation web call that will return a token. Currently, I pass in a cookie with the user and password information, and it uses this to identify who I am and what I should be allowed to do. This is all working absolutely fine and hunky-dory.
I am achieving this process by making the Token Generation use OWIN Cookie Authentication, which means that the cookie is read and the Identity is set. I am then able to use this identity to confirm whether the user is allowed to access the system.
What I now want to do is replace this Cookie Authentication process by authenticating against a Windows User (everything is windows based, and this will be an option so non-windows users can still use the cookie authentication route). But I cannot discover how to straightforwardly do this.
Note that I don't actually need to validate that the user is genuine or refer back to the AD at all. If you provide a windows user that matches a user in the system, you can log in.
So how can I - easily - get the requesting user into the Identity Name? Or is this not possible?
If you are looking for information on the current user accessing your program, assuming the program is running on the user's machine and is windows based, you can simply query windows for the user's username or any other publicly available information about the user.
Refer to https://learn.microsoft.com/en-us/dotnet/api/system.environment?view=netframework-4.8 for information on the Enviroment class and what it's features are.
If you could provide some code or further clarity I could help you further.

How to organize communication in an asp.net web application using separate authorization server, web api, ui?

The requirements
we have 3 modules ui, api, IdentityServer (IS) (client, resource, IS in terms of IdentityServer)
all the modules should be separated from each other (separate dbs for IS and api)
api is stateless (all the needed auth info got from tokens)
the api will have resources like \projects, \users, etc.
another entry point may be added in the future like another-ui which will communicate with the IS and api and will have its own claims
The problems
The main problem is that the resources of api like \projects\12345, \users\, \projects\123456\users, etc. may also be needed as claims in IS. For example, api module reads the access token of authorized user and see the claim projects that equals ["222", "12345"], so the resource \projects\12345 or \projects\123456\users are allowed for that user.
Users are identities in IS and resources in api at the same time. Projects are claims in IS and resources in api at the same time.
I thought of book-keeping these entities that are represented in both modules through the ids (guids). But ids won`t solve all the problems.
Some of them are:
creation of a new project with its id should grant that user the rights to use it in the future, so we need save the claim for that user in some way. The modules are separated, so should we call the IS api to create that claim for that user and then proceed with project creation. How the communication between the two (IS and api) should be organized? Do we need to register the api as another client in IS?
How should updates of users in IS like changing the email, phone (the values one may log in with) will update the api. I thought of showing warnings that the auth email (got from token) does not match the info email.
Could you, please, explain how modern systems coupe with the per resource access?
Thank you for your time.
First you need to make sure what a claim is.
Claim is not a permission or a role, it's what the user is. Based on what the user is, then you can assume the permissions.
https://learn.microsoft.com/en-us/aspnet/core/security/authorization/claims?view=aspnetcore-3.0
A claim is a name value pair that represents what the subject is, not what the subject can do.
So starting from that, you can get the claims and do the following.
Let's say that a user is the owner of a project. When the new project is created, the project api can update the identity server and add a claim to the user saying he is the owner.
In your apis the owner of a project has a set of permissions and based in those, access to specific resources
In the DDD Domain driven design world, a little bit of data duplication does not matter. So duplicating the possible claims that your application needs in terms of roles (again, not ids but a mapping of one or more claims to specific roles) is not a bad practice.
When you update some kind of claim from your api, you should do so in a transactional way. Think first if you need the email to be saved in both. You will get the user data from the claims anyway on every request. Is it even something you need as a claim? If not have it in your api only.
Communication between apis is organized in many ways. If you need transactions or eventual consistency is something you should also consider. Communicating with events or queues is the microservices way to go, with patterns like the SAGA being the coordinator.

MVC authentication with additional user details

We are currently starting to use MVC and are now looking at authentication. .net Authentication isn't necessarily our strongest point, so looking for some advise or pointers.
Our current set up:-
Basic Windows authentication
system uses the authenticated user to query a 3rd party system to get their current roles
these roles are then stored in session variables and used when ever authorisation is required
Any additional user details are called upon as and when needed from various tables
What we'd like to achieve :-
Basic Windows authentication (perhaps create a forms authentication cookie on the back of it)
System users the authenticated user to query 3rd party system to get their current role/s,
These roles are stored within the cookie, and can be accessed via User.Roles etc
Any additional user details (i.e. user favourite colour) will be called on authentication and store against the user profile. The additional user details will be stored in a single table as key value pairs.
Is this the correct way to go about this? we're struggling to find any samples etc to match the scenario we are after.
unfortunately, we need to use this 3rd party system to access the roles, this is achieved via a web service call.
Are there any new advances with MVC 4 which could greater handle authentication with additional user details?
any help, or advise would be greatly appreciated. :)
Sounds like a perfect candidate for federated authentication. You could even use WIF (Windows Identity Foundation) which is now part of the Base Class Library.
In general, federated authentication consist of following parts: delegating the authentication to an external identity provider, consuming identity provider's response, persisting the identity locally (in a cookie perhaps).
WIF has solutions for all these concerns, it is built around the WS-Federation protocol. The really, really great benefit of this is that you can switch between different identity providers easily. This is something that you could consider useless, until you see it in action and immediately you start to create complicated business scenarios in your head.
Using WIF requires some knowledge and specific questions can be answered easily. However, until you get at least some basic knowledge, this sounds like a mumbo-jumbo. You should definitely start by reading a free ebook, Claims-Based Identity and Access Control from here
http://msdn.microsoft.com/en-us/library/ff423674.aspx
Just download it and start reading. I promise you'll immediately find answers to many of your questions and page by page you'll feel this constant "wow, so that's how it should be done!".
Just to provide a specific answer to one of your questions: user data can be persisted in the authentication cookie. If you stick with WIF's model of Claims, expressing arbitrary data is natural: a claim is a pair (claim type, claim value). This requires however to switch to SessionAuthenticationModule as forms authentication module could possibly produce cookies that are too large:
http://www.wiktorzychla.com/2012/09/forms-authentication-revisited.html
(the session authentication module has a special "session" mode where the large part of the identity is stored locally at the server in the session container so that the cookie is really small)
And yes, the federated identity model works with MVC authorization tags. Claims of type role are interpreted as user roles. The remote identity provider can then even set user roles and you can guard your MVC controllers in the usual way.
If you are lucky your 3rd party component might bring a Claims provider with it so you could use Claims based authentication and let the Claims provider supply the additional user data in form of Claims that you can use in your application. For a tutorial see this link. If you cannot access a Claims provider, the known security building blocks still work for MVC. So for your additional roles, you could create a RoleProvider that requests the roles and configure it in your application. You can then secure your controllers or actions with the Authorize-attribute.
In order to optimize the request for roles so that you do not have to request it from the 3rd party system over and over again, there are some alternatives:
As you propose in your question, you can store them in the cookie. But be aware that cookies are stored on the client computer and could be tampered with. So if you have a Forms authentication cookie that you can use, you could store it in the UserData of this cookie. This cookie is already encrypted so that users cannot change it easily. As you want to use Windows authentication at least in the first step, you do not have a Forms authentication cookie that you could use. In the context of security, it is always advisable to set up upon a widely used and well tested framework, so I'd not recommend to create a cookie of your own and store the roles there (though it wouldn't be a too daunting task in this specific case to encrypt/sign the cookie data).
You could also store the roles in a Session variable. Downside is that the session times out after a while and you'd have to be prepared for this case. On the other hand, session memory is located on the server so that it is not that easy for users to tamper with (and if they could, you'd have lots of other problems).
Another component you could use is the Cache on the server; though you'd have to be careful not to mix data for various users as it is shared among users, it is also located on the server and provides a more fine grained control on when the data are invalidated. So you could configure a time frame after that any user would be authorized with a new role set in case it was changed.
Your RoleProvider would need to implement the caching technology (Cookie, Session or Cache).
As for your last point regarding the user profiles, I can imagine that the User Profiles of ASP.NET 2.0 still work. I don't have any experience with it, so I can't give you a recommendation on whether to use it or not. On the other hand, these data don't seem to be too security critical so you can also store them in a cookie or session memory once the user has been authenticated.

Options for single sign-on between ASP.NET and MVC.NET solutions?

I have an ASP.NET solution that acts as the primary customer portal for my customers. On this website the users can log-in access their important financial information and more. The website uses a custom authentication scheme that checks the user's username (their email) and their password (salt-hashed) against a Users table in a local database.
I am building a new MVC.NET solution that is more of a web-app tool to be used by these same customers for ordering. I want to re-use the sign-on mechanism of the ASP.NET portal to authenticate users. The goal is to save the user from remembering two log-ins or even having to supply the same log-in twice.
What are my options for allowing users who sign on to the ASP.NET solution to then be auto authenticated to the MVC.NET solution? I've listed some ideas below but are these "bad" or is there a more elegant solution? I'd love your input.
Common Cookie I could create a common cookie that the ASP.NET site creates and the MVC.NET site looks for. But is that secure enough?
Token in Query String I could create a token id on the ASP.NET site that is stored in the local database and is then passed in the query string of the link to the MVC.NET site which takes the token id and validates it against the same database.
Hybrid A bit of both?
Other? Got a better idea?
I've recently done something quite similar (the major difference being that it was internal to the company rather than for external customers) using OpenId.
The implementation of OpenId for .NET is called DotNetOpenAuth which should be suitable for your purposes.
It did take me a while to implement; but it works very well, is very flexible, and extremely secure.
More information about openid (from Wikipedia):
OpenID is an open standard that allows users to be authenticated by certain co-operating sites (known as Relying Parties or RP) using a third party service, eliminating the need for webmasters to provide their own ad hoc systems and allowing users to consolidate their digital identities.
Users may create accounts with their preferred OpenID identity providers, and then use those accounts as the basis for signing on to any website which accepts OpenID authentication. The OpenID standard provides a framework for the communication that must take place between the identity provider and the OpenID acceptor (the "relying party").2 An extension to the standard (the OpenID Attribute Exchange) facilitates the transfer of user attributes, such as name and gender, from the OpenID identity provider to the relying party (each relying party may request a different set of attributes, depending on its requirements).
The OpenID protocol does not rely on a central authority to authenticate a user's identity. Moreover, neither services nor the OpenID standard may mandate a specific means by which to authenticate users, allowing for approaches ranging from the common (such as passwords) to the novel (such as smart cards or biometrics).
Oh, and if you'd like further encouragement, Stack Exchange uses it!
#Jmrnet: in response to your last comment:
Perhaps I was unclear. OpenId in and of itself is simply for validating credentials from one location to another (more or less). It's entirely possible to implement as an SSO model where users do nothing different whatsoever - they don't have to choose a provider, or register, or anything like that. For example, in my setup, the user enters a username and password in a web portal, and then clicks a button to launch another site being automatically logged in by OpenId. Nothing different for the user at all! OpenId can be used with any initial authentication model you can think of (note the bolded section in the snippet from wikipedia).
Take a look at SAML:
http://en.wikipedia.org/wiki/Security_Assertion_Markup_Language
It works using XML and supports encryption.
I am currently implementing two SSO solutions for the same project.
In one, we are interfacing with an external partner and are using SAML.
In the other, we are allowing logged in users access to our Sharepoint and using the "Token in Query String" approach, since we trust Sharepoint to access our membership tables. This approach is much easier than dealing with SAML tokens.
There are many methods you can use, Mansfied described OpenID and RandomUs1r described SAML. Also, you can store relevant information in localStorage or in the session. I believe you should store relevant information with session.
It is not safe to put this in the query string, because if I register and log in, I will see something like UserID=1234 in the URL. If I change that to UserID=1235 and the ID is existent, then I can do some things in the name of the other user. This is called identity theft, which should be prevented by any means possible. So you should never have this kind of info in your URLs. Also, if you store the id of the user, you should obfuscate it somehow. For instance if you store the value in local storage and instead of 1234 you store encrypt(1234, salt), then the consistency of user action will be maintained.

Categories