REST, caching, and authorizing with multiple user roles - rest

We have a multi-tenant system with multiple different levels of access--sometimes even for the same user as they switch between multiple roles. We're beginning a discussion on moving over to a RESTful implementation of things. I'm just starting to get my feet wet with the whole REST thing.
So how do I go about limiting access to the correct records when they access a resource, particularly when taking caching into consideration? If user A access example.com/employees they would receive a different response than user B; user A may even receive a different response as he switches to a different role. To help facilitate caching, should the id of the role be somehow incorporated into the uri? Maybe something like example.com/employees/123 (which violates the rules of REST), or as some sort of subordinate resource like example.com/employees/role/123 (which seems silly, since role/### is going to be appended to URIs all over the place). I can help but think I'm missing something here.
edited to mention multi-tenancy

Having the user credentials act as an out of band resource identifier (ie. presenting different views on the same URL to different roles) will turn nasty down the road. Users and applications exchange URLs between them, things turn sour when that happens and the URL simply returns different content for different credentials.
I would say that each role has a different view of the world, therefore each role should access a different path to the service:
admins connect to example.com/admin/employees
users connect to example.com/users/employees
role foo probably connects to example.com/foo/employees
This way you separate the 'this role sees the world as such and such' part from the 'this view of the world is accessible to role foo' part. An admin can connect to example.com/users/employees and verify how an ordinary user sees the world, w/o the admin having to impersonate a lower privileged alias first.
You can also use the DNS part for same purpose: admin.example.com/employees vs. users.example.com/employees. This is specially viable for a related scenario, when the 'role' is not a security role but a multi-tenant namespace (ie. each service provisioned account gets its own 'view' of the service).

Related

Keycloak redirect fails when number of roles are in the hundreds

I have 2 users, one with less than 30 roles and one with 400 roles. When I login with the 30 role user, I can reach the redirect URL without issues. But when I log in with the 400 role user, the request to the redirect URL doesn't complete. If I reduce the number of roles in the 400 role user then it will work. So, is there a way to disable passing roles in the java access token or increase some limit somewhere that's causing the failure?
I would suggest to focus rather on roles reduction/optimization than forcing the transmission (raising limits) over the maximum number of roles inside tokens (or anywhere else).
Some interesting questions (among others) to start with:
Which protected resources am I going to serve?
What am I trying to protect? and what are the associated risks? (build a Threat Model)
How do resources are served by each application? and how are they distributed among my applications?
What kind of resources are they? How can I group them? Which sets are identifiable? or what are the relationships between them? What actions are possible against all sets of resources?
Who are the users of each application? How will they interact with my resources? Which flows are sensitive?
What roles can I define for all my resources?
Which role can apply to each application, resource type or set?
What kind of user groups can I create?
Do I need additional attributes or claims for each set of roles or users/groups?
I firmly believe that if you answer all these questions you will end up having a bunch of roles instead of hundreds. Think security by design and follow principle of least privilege.
Focus on your use case
Now as far as I understand, your blocking point is that you are assuming that each resource is unique, sensitive and requires its own permissions, and consequently a role definition. While it may be true in some cases, in most other cases it does not mean that you have to use the token roles/scopes/claims to secure your assets deep at the resource-level. I'll try to illustrate this sentence by an example.
RBAC and authorizations example for your use case
Let's assume that:
you have millions of sensitive resources to serve
each registered user of your application has access to a (different) set of these resources.
your resources are splitted into, say, 3 categories (e-books, videos, musics).
each resource can be downloaded, uploaded, deleted.
your application will meet unregistered users, registered users, contributors and administrators
registered users will always have read access to resources (not a single action will ever allow a modification)
contributors are particular registered users who can perform special actions including modification ('upload', 'edit')
contributors and administrators may have access to various administrative parts of the application
your application will evolve by serving additional categories of resources in the future and new actions will be available to users later (such as 'flag', 'edit' or 'share link').
Then first things first:
organize your resources accordingly by serving them behind categorized paths such as: .../myapp/res/ebooks, .../myapp/res/videos, .../myapp/res/musics
identify your resources via UUID such that a resource may look like: .../myapp/res/ebooks/duz7327abdhgsd95a
Now imagine that your business risks or at least the greatest risks you wish to avoid are:
unregistered users having gaining access or rights for any part of the application or resource
uncontrolled registration process (robots, spam, no mail verification, fake users, ...)
registered users gaining illegal privileges (unauthorized actions, access to other categories, illegal administrative rights)
discovery of available resources by any mean
You will note that I voluntarily didn't listed:
registered user having illegal access to certain resources. For example: maliciously pointed/provided by an existing user.
This is because it is not a high risk as you may hold contact information about registered users as well as log activity and actions, quota or requests throttling, and you may be able to ban them or start legal action against them. Your registration process is also assumed robust and secure. Nonetheless if its considered a critical risk you can address this with extra mechanisms (cf. suggestions at the end). But never will it result in adding extra roles, such as one per resource, as it does not fit in any security model.
That being said, finally, here are the roles and authorizations scheme you may come with:
SCOPE / AUDIENCE
MY_APP
ROLES
USER
CONTRIBUTOR
ADMINISTRATOR
CLAIMS / ATTRIBUTES
CATEGORIES
ACTIONS
--> POSSIBLE USER GROUPS
USERS
Roles: USER
Claims: CATEGORIES(variable), ACTIONS('download')
CONTRIBUTORS
Roles: USER, CONTRIBUTOR
Claims: CATERGORIES(variable), ACTIONS('download', 'upload', 'edit')
ADMINISTRATORS
Roles: USER, CONTRIBUTOR, ADMINISTRATOR
Claims: CATEGORIES(*), ACTIONS(*)
Following this model, assigning the correct group to each registered user will provide high-grade security by mitigating/controlling the main risks. As claims/attributes are defined in the token(s) (managed and signed by Keycloak) then you can trust this information in your application and serve your resources accordingly and safely. There is also no risk of illegal access or discovery of resources as you are using UUIDs, only registered users having had access once to a resource will know it and registration with appropriate category access will be needed for another user to access it (to only be able to read it basically). Of course you may store in a database the list of resources to which each user has access to, raising the overall security to a very high level.
However, if the latest is not enough you may also implement rolling UUIDs or temporary links for your resources when served to users. To go farther you may also define groups and masks for your categories, resources and actions.
In fine, in this example I made use exclusively of token claims to define roles (common claim), categories and actions (custom claims). In terms of security the authentication and identity will be the first-line security followed by roles then categories, actions and stored list of resources per user (db).
Other alternatives are obviously possible, its just an example. Still, I hope it helps!
To fix this problem you should start from defining client scope mappings for each of you applications (e.g. oidc clients). Main idea of this facility is that even if your user is super duper admin with all existing roles, all of his roles actually don't required for any particular application. For example client foo which defines following roles:
foo_user
foo_viewer
to perform its security logic need to know only whether currently logged user has foo_user or foo_viewer, but it doesn't care about has this user roles bar_user or bar_admin from application bar. So our goal is to make Keycloak return for any client access token with only valuable set of roles for this client. And roles scope mappings is you friend here. You can set for client foo scope like:
foo.foo_user
foo.foo_viewer
bar.bar_admin
and now even if logged user has role "bar.bar_admin" this will not go to access_token since client foo doesn't take this role into account. After applying some scope settings you can test them at 'Clients -> $CLIENT_OIDC_ID -> Client scopes tab -> Evaluate sub tab.
As for you case with 400 roles, i'm quite confident that none of your application requires all of 400 roles, so precise scope configuration for you apllications can drammatically reduce access token size.
But if i'm mistaken and you really have an application that rely on large amount of roles you should look into you runtime settings.
For example if you run keycloak behind reverse proxy like nginx large tokens may not fit in default HTTP parameters buffer size (afaik about 2-4kb) so you have to increase it via appropriate nginx configuration option. Another example is tomcat which has about 16kb as default HTTP header buffer, so if you send request with very large access token in Authorization header Tomcat may not handle this request properly.

RESTful API Design based on the RBAC model

The problem to face lies in the design of a RESTful API that can manage requests from multiple roles in an RBAC-based solution.
Currently we have different resources that can be accessed from different users, which can have one or more roles grouped according to their privileges.
The API we're trying to define must be as clear as possible to the client but without the overhead of adding additional metadata to the URL that could damage and even conflict with the REST practices and definitions. Therefore, we must avoid at all costs include information about the roles inside the URL. The plan is to use JWT tokens that carry in their payloads the info needed to know which permissions has the user making the request.
Having raised our current situation, let's provide an example and state the problem to solve:
Suppose we have * financiers * and * providers * as users with some roles who both want to access ** attentions ** (our resource). Should we add before the resource ** attentions ** information about the * user * whose trying to access the resource?
The endpoints in that case should be defined (as an example) as:
https://example.com/api/v1/financiers/:id/attentions
https://example.com/api/v1/providers/:id/attentions
This way we're attempting to inform the respective controllers that we want the ** attentions ** for that specific role / user which are, in some way, a sub-resource of them.
On the other hand, we could simply implement a much simpler endpoint as follows:
https://example.com/api/v1/attentions
The logic about which attentions return from the database should be now implemented in an unique method that must handle this two roles (and potentially new ones that could come up in the following features). All the information needed must be obtained from the payload from the token, exposing a much more generic API and freeing the web client from the responsibility of which endpoint call depending on the role.
I want to highlight that the attentions are managed in a Microservices Architecture and, hence, the logic to retrieve them is gathered in a single service. The cost of the API Gateway to route the two (and potentially more) of the endpoints from the first solution is a variable not to discard in our specific situation.
Having exposed our current situation:
Which we'll be the best approach to handle this issue?
Is there another alternative not contemplated that could ease the role management and provide a clean API to expose to the client?
In the second solution, is correct to return only the attentions accessible to that specific user based on the roles that it has? Isn't it counterintuitive to access an endpoint and only get some of the resources from that collection (and not all) based on its role?
I hope that someone could clarify the approach we're taking as there are little and none literature that I've found regarding this issue.
There there are multiple solutions for such kind of filtration, and developer have to select one depending on given situation.
As per my experience I can list following.
Structure
When data can't be accessed directly and developer has to use a relation (i.e a table JOIN). In that case URL have to include both the main and sub entities. Before going with this approach a good check is to ask, if the same URL can be used with POST ?
Example
If we have to fetch list of roles assigned to a specific user or want to assign additional roles then we can use
GET users/:uid/roles
POST users/:uid/roles
Security
With Multi-tenant systems where each user can have his/her private resources, i.e other users are prohibited from accessing those resources. Developer should save tenancy information and to filter the resources according to current authentication, without bothering client or requiring any additional info in URL
Example
Phone album of the user
GET photos
POST photos
Search
If it is not security or structure related but client still want to filter the result set depending on his scenario. then developer should use query-string for the filtration.
Example
Client have to fetch messages from his/her inbox or outbox or want messages which are not yet read. or he/she want to search his/her inbox
GET messages?folder=inbox
GET messages?folder=inbox&status=unread
GET messages?search=nasir

REST API design: one endpoint with if/else logic or two separate role based endpoints

I have an API design/versioning conundrum.
Let's say I have an endpoint /api/customers which GETs all customers (ignore pagination). There's a twist though: if a regular user accesses this endpoint, they will only get the customers created by that user and no one else (I can check the access token and the sub field to determine who sent the request). Other usecase: if an admin accesses this endpoint, they should get ALL customers, regardless of who acquired them.
Now my question is from an API design perspective: is it better to have an if/else role check within the API controller itself to determine do I return ALL (admin) customers or specific (user) customers, OR should I differentiate between endpoints for the user and admin? I.e. admin only endpoint for all customers would be /api/admin/customers and regular users can still access their /api/customers?
In REST, it is normal to have multiple resources that share the same representations.
For example, the "authors' preferred version" of an academic paper is a mapping whose value changes over time, whereas a mapping to "the paper published in the proceedings of conference X" is static. These are two distinct resources, even if they both map to the same value at some point in time. The distinction is necessary so that both resources can be identified and referenced independently. A similar example from software engineering is the separate identification of a version-controlled source code file when referring to the "latest revision", "revision number 1.2.7", or "revision included with the Orange release." -- Fielding, 2000
It is perfectly consistent with that approach that you might have one resource for "all users", and another resource for "users created by Bob".
Where things get twisty is the case where you want to use the same resource identifier to provide different representations. That is, when Alice looks at "users created by me", she sees "users created by Alice", and when Bob looks at "users created by me", he sees "users created by Bob".
One possibility is to have "users created by me" redirect to the appropriate resource. It works, for values of "works" that permit extra round trips when the destination resource isn't already in the local cache.
In HTTP/2, server push may spare you some of that round trip pain.
The rules for shared caches should protect you from sending Alice's view of the "me" resource to Bob, and vice versa, but it is useful to be aware of the meanings of the various headers so that you don't inadvertently disable that protection.
Having different resources can be a problem in some "read your own writes" settings, because the caches won't know that an unsafe request has invalidated both resources. Bob creates a new user via a POST to "users created by me", and the corresponding cache entry is invalidated... but "all users" is a different cache key, and does not get invalidated. So if Bob looks at the all users view, he may see a previously cached copy without the changes that he just saw in his own view.
In some cases, it can make sense to consider sub-resources.
/api/customers
/api/customers#created-by-Alice
/api/customers#created-by-Bob
But if you are trying to reduce the amount of irrelevant data being exchanged, then that's not a good fit.
It should be same endpoint. Otherwise, each front-end which calling your API must have the same logic to determine the role and endpoint mapping.
It depends on your project.
If there's only 2 cases as you mentioned
only get customers created by that user for regular users
get all customers for admin users
then, it'd be better to use 1 endpoint by adding middleware to check current user role.
If you're plan to extend your project.
e.g. if admin users are also needed to get the customers created by that user, it'd better to create 2 endpoint. one for all customers, another one for current user's customers. like - api/customers/all, api/customers/me
I think /api/customers is fine for the cases mentioned. It's analogous to a web page request to index.html returning different content to different users.
If you want to extend it (e.g. Alice requesting Bob's list), you could support optional query params:
/api/customers?accessibleTo=bob
/api/customers?createdBy=bob
This would likely require an authorization check (Does Alice have access to Bob's list?), returning 403 (or 404, depending on your philosophy) when not authorized.
Also don't forget about caching. Avoid the possibility that two requests to the same URL (/api/customers) for different users will result in one user getting the other's list.

What are Kubernetes Users for?

I'm studying Kubernetes now, and have a question about Kubernetes Users. I learned how to create Users and how to limit access by Role, but when should I use it? For example, if a malicious user (not a k8s user, but an operating user) penetrates the k8s server, they can switch the administrator easily (if they can see .kube/config). In addition to that, if a user switches his or her user account and forgets to switch back, then another person who enters next can also use the first user's account. I doubt if I misunderstand the usage of k8s Users, but there seems to be no documents about why k8s prepared it. I assume that Users are only used for doing something from within pods, but if so, what's the difference between Users and Service Accounts?
Kubernetes has a very loose idea of a user. It knows that authentication is a thing, and that the output of that is a name and maybe some groups and tags. But really all it does it hand that info off to the authorization plugins to decide if a given request is allowed or not. ServiceAccounts are a specific object type because they generate you a JWT signed by the cluster, but there isn't a specific User type, that only exists within the context of your authentication plugin(s).

How to scope and persist claims to different clients in IdentityServer 3?

I'm new to IdentityServer3 and have multiple MVC clients where users have claims which potentially could conflict and give undesired authorization.
Here is an example with two clients able to send emails and notifications to the users. A user might have access to both applications but should only be able to recieve notifications in Application A. How can we prevent the user from recieving notifications in Application B?
Application A
Claim Type: ApplicationFunctionality Claim Value:
RecieveNotifications
Claim Type: ApplicationFunctionality Claim Value: RecieveEmails
Application B
Claim Type: ApplicationFunctionality Claim Value: RecieveEmails
Would a resonable solution be to implement somekind of logic in a class using the IUserService interface?
Would it be correct to use claims in the way I described above across multiple clients, where we sometimes reuse claims for cross-client functionality. I guess it would require me to namespace the claims (perhaps using the requested scope name the client sends to IdentityServer) in order to distinguish claims for different clients and prevent unauthorized access between the clients.
Here is an example of user claim types/claim values:
Name: John Doe
Email: john.doe#acme.com
PreferedLanguages: English,Swedish,Spanish
ApplicationFunctionality: ClientA.RecieveEmails
ApplicationFunctionality: ClientB.RecieveEmails
ApplicationFunctionality: ClientA.RecieveNotifications
ApplicationFunctionality: ClientB.RecieveNotifications
ApplicationFunctionality: ClientA.ViewBackorders
ApplicationFunctionality: ClientA.DeleteBackorder
ApplicationFunctionality: ClientB.SearchProductInformation
CompanyID: 1145
CompanyID: 6785
CompanyName: Acme Inc
ApplicationLicense: ClientA.PayingNormalUser
ApplicationLicense: ClientB.FreeUser
A user from Company Acme Inc have several CompanyID's which is used when filtering data we request from webservices\databases in the data layer. The user have access to multiple applications where he/she could have different levels of functionality depending on what license they have bought in the applications. Some functionality exist in multiple clients but that doesn't mean the user are authorized to same functionality in all clients he/she have access to.
I would appreciate some guidelines about claims, or perhaps point me to some good resources about the subject. I have read that claims primary is used for identity related information (email, name, department, favorite color, shoe size etc), but if no role\permissions style claims should be used with claims then how should information about what a user is authorized to do in the clients be persisted and how should data be filtered in webservices/databases (resource providers) so the user only sees data he/she are authorized to see?
My first thoughts where that the id_token and access token would be convenient to use since they are issued by the STS (IdentityServer) and then later persisted in cookies. The STS would first be required to perform lookup of user account in Active Directory which contains user identity related information together with an lookup (using the username of the Active Directory user account) in custom database containing information about role\permissions and claims of the user.
How should I persist the roles/permissions and claims of a user if not using cookie persisted tokens provided by IdentityServer?
Clients (applications) and users can have their own set of claims. It looks like you want to have applications which have access to different resources. This is where you should use scopes. Basically define two scopes which define action on that resource (this is one common way of doing it) ie one for 'reading' emails and one for 'writing' emails (eg emails.read and emails.write) subsequently the other scopes can be backorders.read and backorders.delete. It's just good practice to have consistent naming here.
Ok now since weve defined those two scopes, you can now define two clients, one which has only the emails.read scope and the other one has both the read and write scopes. All this means is that one client has access to more resources than the other.
All the user identity claims should stick to the user itself. Application/client specific should never be associated with the user. Name,Email,ApplicationLicense, and PreferredLanguages are all valid claims for the user because they describe the user itself and what can be asserted about them.
For "complex" authorization you may want to look at this sample for some ideas on how to set up compound security policies or authorization.
It sounds like you want to expose a different value to different clients for the same claim. This seems like a logical thing to want to do, especially if you are integrating with clients that are not within your control and thus cannot dictate to them what to expect in each claim, or what scopes to request. A simple example might be the "roles" claim - you may wish to send different values depending on the app that's making the request. If you're joining someone else's enterprise, perhaps with multiple OpenID Connect Providers, you don't always have a choice over the scopes or claim names.
I feel that Nat Sakimura eludes to this in the OpenID Connect FAQ video, https://www.youtube.com/watch?v=Kb56GzQ2pSk (1 minute 40s), the idea that an entity might want to expose a different identity to different clients.
In terms of implementation, we've added a table with [identityId, clientId, attributeName, attributeValue] to allow us to store the same identity attribute for different clients. In our case, these identity attributes become claims in the outgoing JWT. As most attributes about a user are global (i.e. not client specific), we treat the data in this table as overrides to a base set, which saves duplicating the same data for each client unnecessarily. The iUserService.GetProfileDataAsync() method has access to the Client, so can tailor its response depending on the consumer of the data.