Permission linking between LDAP users groups and Django permissions (custom if possible) - permissions

Hello again every one,
I have a question: I successfully implemented django-auth-ldap, the LDAP users can request successfully my DRF API. But nows, for my projetc needs, I have to define permissions depending of the group.
Indeed, I will have like 12 groups in my app. Depending of the group, I will authorize or not the user to request a given route, BUT even if I defined the global var AUTH_LDAP_MIRROR_GROUPS = True, and saw in my database the are linked to a group (see capture):
Users in database
Groups from LDAP inserted in db thx to django-auth_ldap settings
User linked to the groups defined
But now, I have some other problems: I do not know how to implement permissions depending of the group the user belong. In fact, if a user belong to the group ServerAdministrator, I want to allow him to access to every route accessible, but I dont know where to see this in the received request in my view?
As I understood, I should implement custom permissions I should write programmatically in a User object (which should inherit from django AbstractUser)
If yes, How does it work? Should I empty my whole Database and then let django-auth-ldap insert users and it also will create the given permissions defined inside the database?
Maybe it is not clear, do not hesitate to ask questions if I can be more precise.
Kind regards.
Benjamin

Related

How can I give a user the query-groups role but only allow him to query his own group in Keycloak?

I'm using Keycloak 19 and I'd like to give my users the authorization to create other user within their own group.
I was able to give access to users to see only the users from their own group by combining the realm_management:query-users role and the activation of fine grained permissions on the concerned group and setting a Group policy on the view-members permission.
I wanted to do the same for groups but it seems that the realm_management:query-groups allows one to see all groups. I was expecting it to work like its users counterpart but it seems like it works more like the realm_management:view-users role.
Moreover when I want to create a new user, it tells my I actually need the query-groups role in addition to the query-users role. So I feel like I'm reaching some kind of dead end here.
How could I configure the roles and permissions to allow users of a specific group to be able manage users within their own group or sub groups ?
The only solution I can think of is to move this in an external app that will handle the additional security of not letting a user see the groups. The app would be the one in charge of doing the change once it verified the user has the rights.

How to create a hierarchy in Cumulocity?

I have a question regarding Cumulocity. I want to create a site hierarchy in Cumulocity, we can go up to sub-tenant level only but I want to create a hierarchy up to 2 level.
Let's take an example of schools, its locations, and different branches. Here I want to attach an owner with each branch and that owner should be able to register only their own users and devices. I was trying to achieve it using groups, roles etc but was not able to do it. If anyone can suggest how to proceed for this use case.
I can see two possible options using which this can be tried:
Groups
Custom Apps (Angular apps)
But I am not sure how to proceed as there is no direct UI for the user to group assignment and REST API for this assignment is giving me errors.
You can use the inventory permissions for configuring access rights that are limited to a certain group see documentation
The managing of only your own users can be achieved by giving a user the global permission for USER_MANAGEMENT_CREATE. Make sure to revoke the ADMIN and READ role as well.
I would not recommend to solve this with apps on the UI side. That way you can of course hide information from the user but he may still be access it via API. Only with the RBAC you can really ensure on API level that the access is managed correctly.

Is claims based authorization appropriate for individual resources

I understand the usage of claims for things I would commonly refer to as "roles" or "permissions". I know that claims are more general, but from what I have seen in practice, it usually boils down to this: If user has this set of claims they can access certain areas, or perform certain functions.
Imagine a wiki application. You might have a content_contributor claim that would allow a user to add content, a content_admin claim that would allow a user to remove content, and a modify_user claim that would allow the granting of contributor rights to other user.
Taking this example a step farther, I may want to restrict users so that they can only see content created by themselves or their team.
If a user can only see content created by themselves, would we have a claim for each piece of content they created, or would we delegate that authorization to the application?
When you are talking about roles and permissions then you are talking about authorization.
Claims are typically not for authorization. (Identity)Claims are there to model the identity of the user: who is the user? The claims on itself do not tell anything about authorization. A user can have a role claim, but this doesn't tell the application what the user is allowed to do.
Authorization is done by the application, based on who the user is. Think of authorization as a set of rules, like:
18+: allow when user is older than 18 (DateOfBirth).
Use car: allow when user has a drivers license.
Or something like that.
Roles are a bit confusing, as they are often misused for authorization. Please read this article for some background information.
The problem with roles IMO is that these are not universal. I can be a Doctor in one hospital, while I'm a Patient in another. And I can be Admin for one tenant, but a User for another tenant. So they have only meaning within a certain context.
The only reason to include roles as claim is that you won't need to lookup this information as it is already present. But given the previous remark, you actually can't include this information. And it will only give you headaches when you do. Because you can't do simple things like update or change permissions or profile settings, until the user logs in again.
So as a rule of thumb: keep authorization close to the resource (api / website). Because that is the place where the business rules are implemented. And that's the place where you can store and update permissions, etc.
Keep a seperation of concerns when it comes to authentication and authorization. Authentication tells you who the user is, and authorization tells you what the user is allowed to do. Don't mix these two.
Translating this to your wiki application:
Create a seperate context where you store authorization information like roles and permissions. You can manage this in a central resource (for multiple applications) or use the context in your application. I would not mix this context with the business context.
Add a user in the authorization context and add a role content_contributor. Within the application read the permissions (from the central API, the local authorization context, a settings file, or anything that suits best) for that user (based on the sub claim). Cache it to speed up performance, and apply the rules to determine whether the user is allowed to access the resource.
You can extend this with resource-based authorization. Save the value of the sub claim in the content record to identify the owner. When the current user matches the sub claim value, then the current user is the owner.
You can use the same approach for teams. Add a teams table to the business context and link the user to one or more teams. Directly using the sub claim value or indirectly, using a Users table, also in the business context, where the user is linked to the sub claim value. You can add name, etc. in case you want to show this information (like in a report).
You can save team id and / or user id or sub claim value (owner is member of the same team as current user) in the content record in order to determine the allowed access for the user.
My setup would be like this:
Identity context: users + userclaims. For authentication only. Application independent.
Authorization context: users (id = sub claim) + per application: roles, permissions, etc. In seperate 'local' databases or in a central database. For authorization only.
Business context: users (Id, Name, 'foreign key' sub claim, without the actual database relation as the table is outside the context) + teams, profile, settings, etc. Linked to the sub claim value when users table is omitted.
In order to keep the users table in the business context up-to-date, periodically refresh the values. You can for instance update values when the user logs in after x time. Or once in a while query the Identity Context (using the API) to request user information (using the identities User Info endpoint).
In all contexts there can be a users table, but they all have a different meaning and contain other information. So there is no redundant information.
Authorization takes place inside the application and is based on the business rules (policies) and authorization information from the authorization context.
As a final remark, when the current system requires role claims (like for User.IsInRole() or [Authorize("role")]) then you can read (from cache) the role / permissions on each call and add these to the claims collection of the current user (claims transformation).

Authorization in GraphQL servers

How to handle Authorization in GraphQL servers?
Shall I pass the JWT token in the Authentication header of every requests and check for the authorized user after resolve() and check for the role of user on every query and mutation
Introduction
First of all, a common approach for authentication as you state is using a signed JWT that contains the id of the user making the request.
Now let's have a look at the different parameters we can use when considering the authorization of a given request.
who is making the request?
determined by the user id mentioned above. More information about the requester like associated user roles can be looked up in the database. This means that we need to maintain a User table if we are using SQL for example, and add new users to this table on registration.
which operation should be executed?
users might be granted read-only access. Certain mutations or queries are only allowed for certain users.
which fields are included in the query/mutation response?
some fields should be only accessed by certain users.
Permissions
With this information in mind, we can come up with different permission systems. Most commonly, in such a system, no operation is allowed by default. When a request comes in, the parameters mentioned above can be matched with the existing permissions and if a matching permission is found, the request is granted.
Role-based permissions
In certain applications, a role-based approach works great.
For example, for a simpler version of Stack Overflow, we could have the roles EVERYONE, AUTHENTICATED and MODERATOR. A sensible permission rule could be this:
EVERYONE can read questions/answers
requester: doesn't matter (everyone)
operations: allQuestions, allAnswers queries
fields: text
Other rules (leaving parameters out):
* AUTHENTICATED users can create new questions/answers
* MODERATOR users can create new questions/answers
* MODERATOR users can delete questions/answers.
Now for example, if a non-authenticated requests comes in that asks for the allQuestions query, that's fine as we find a permission that allows it (the first).
If on the other hand an authenticated requests comes in for a user that doesn't have the MODERATOR role and includes the deleteQuestion mutation, there is no permission to be found for these parameters. So the request is rejected.
Graph permissions
While role-based permissions represent a solid permission system already, they are not suited at all if we want to make granting permission dependant on things like the relation between the requester and the requested node. In our example, it would be quite the work to add the simple rule that any user is allowed to delete their own questions/answers.
At Graphcool, we have come up with a powerful yet rather simple approach that we call graph permissions to tackle this issue. Let's make the following additional parameters available when checking permissions:
which node is about to be accessed or modified?
determined by a node id
Then we can express permissions using a GraphQL query against a special permission schema to grant or reject permissions on a node level. Access to a given node is only given, if the permission query contains at least one leaf-node that is not null.
In our case, we could specify this permission query:
query {
allAnswers(filter:{
authorId: $userId,
id: $nodeId
}) {
id
}
}
For a given node and user specified by GraphQL variables $userId and $nodeId, we use a query argument filter to either return an empty list if the node wasn't created by the current user, or something non-null otherwise.

Claims-based auth and circles of users

Let's think of a simple REST-based web service to store and retrieve JSON objects. Without any authentication, every user can access any data.
Now let's add usage of JWTs to authenticate users. Of course, since we are not doing authorization, still every user can access anything, but at least now we know who accesses what.
Next step: When storing an object, save the user's sub claim with the object, and verify that the user's sub claim matches the one of the requested object, and if so, deliver it. Now we have authorization on a per-user basis. So far, so easy.
Now let's add the possibility to let users share objects with other users. For the sake of simplicity, say, we want to have predefined groups (i.e., roles) and we want to let the user choose which group (role) has access to the objects they create. This is still easy, as you have a predefined list of groups, so you can let the user choose one or more, and attach them to the object. Additionally, the identity provider needs to be configured in a way that it put a groups claim into every user's token, so we can match them. As we can already see from the length of this paragraph, things become more complex.
Question 1: Am I right so far, that handling "static" groups this way it the way to go?
Now, let's give the users the opportunity to create groups on their own. This is still not complicated, but how do we make the identity provider use the dynamically created groups? For sure we do not want to make an administrator update the identity provider's configuration every day ;-).
Question 2: How do we handle dynamically created groups?
Now, finally, let's forget about groups, and let's say, that we want to allow the users to be able to simply share their objects with other users. This should be configurable for every object individually. How do we do this? Do we save a list of users on the object? If so, what exactly do we save? The sub claim? If so, how does the owner user know the appropriate values? Or ...?
And: Supposed the users want to put their friends dynamically into dynamically generated circles, how would we do that?
Question 3: How do tokens and dynamically created groups with dynamically assigned users work with each other?
In my opinion the tokens should only include identity-information(-claims) you'll need to identify the user on your ressource server or that wont change when refreshing, since you wouldn't want your user (or your app in place) to have to refresh his access tokens each and every time his permissions change (since access tokens grant access for a specific amount of time you wouldn't want your user to have access to certain ressources that he's lost the access rights to since his last token refresh by not refreshing the token and simply using the old one either). The more security related information you append to your token, the more vulnerability you may add to your system (depending on your token lifetime).
Stating so, I would (and always do) identify the users roles or groups by his user-id (which is included in the jwt-token) on the ressource server. To achieve this, I always attach the users identity-information to the current request on my ressource server and attach "dynamic"-claims like the users role or group to the identity.
By adding only the identity information I need to identify the user and the user's rights on my ressource server, I tend to use my identity providers across multiple applications without handling application scope on the identity provider, so I can use the exact same access token for multiple independent ressource servers.