I'm trying to figure out if this is possible with baqend, or even the correct approach to begin with.
I have a bunch of users, using the default user account system that comes with Baqend.
Some of these users will be administrators of a company. A company will have somewhere between 1 and 5 users who are administrators.
There is a separate data class that contains a record for the company and an array of users who are the administrators.
Like this:
{
id: "/db/Companies/123-456-789",
name: "Test Co",
admins: [
{ id: "/db/Users/10", name: "Joe Schmo" },
{ id: "/db/Users/11", name: "Kate Skate" },
{ id: "/db/Users/12", name: "Johny Begood" }
]
}
What is the approach to ensure that only users 10, 11, and 12 can modify the contents of the admins array and whatever else is contained in /db/Companies/123-456-789 ?
Is it as simple as inserting the additional admin's info into the array and also adding that person to the ACL of /db/Companies/123-456-789 at the same time or right after?
Also what is the way to remove a persons ACL? I see how to set it here: https://www.baqend.com/guide/topics/user-management/#permissions but how do we do remove or delete? And what is the difference between explicitly denying that user in the ACL vs that user simply not existing (and I guess by default being denied? Assuming the entire collection is set to NOT be public in the first place).
For our use, just because an administrator leaves does not mean he leaves OUR APP, he might go work for another customer who uses our app and his user account should remain valid, but with no more access to the company record.
I think you already have it quite right: you can add administrators to a company by adding them to the admins array and by explicitly allowing them read and write access in the ACLs. To remove admin rights, you can simply remove the explicit allow rules for the soon-to-be-ex admin.
In Baqend, permissions are enforced like this:
superusers are always allowed.
explicitly denied users and roles are always denied.
if there is no allow rule for a record, access is public. As soon as there is at least one allow rule, only allowed users are granted access.
Since every record is public unless there is at least one allow rule, your record will be protected when you allow access to the administrators. However, it will be public again as soon as you remove the last administrator from the access ruleset. Therefore, it's probably a good idea to always explicitly allow write access to your Baqend app admin, so that there is always at least one allow rule.
let me try to explain how exactly ACLs in Baqend work.
TL;DR
To secure your object /db/Companies/123-456-789 you can simply add an allow rule for each of your three user ids (/db/Users/10. /db/Users/11, /db/Users/12) to the object acls of your company object like this:
db.Companies.load("/db/Companies/123-456-789").then(function(company) {
company.allowWriteAccess("/db/Users/10");
company.allowWriteAccess("/db/Users/11");
company.allowWriteAccess("/db/Users/12");
return company.save();
})
This ensures that only these users can edit the company object. Notably, this list of rules is independent of the list of admins contained in your company object. To revoke the write access of a user, you can use deleteWriteAccess in the same way we used allowWriteAccess before.
This means your users can leave a Company easily without leaving your app.
I hope this answers your question. Because ACLs are complex I will try to explain the general approach in more detail now.
How ACLs Work
On which level can access be controlled?
There are two levels to control access to your data:
On table level (so-called Schema ACLs)
On object level (so-called Object ACLs)
Schema ACLs define who is allowed access to the table in general. For example, you could define that the User table is not readable for the public by granting read access only to the admin:
allowReadAccess("/db/Role/admin") // Schema ACLs can only be set by the admin
You can define rules for reading, updating, inserting and querying on the table separately.
Object ACLs defines access on the lower level. You can use it to deny access to a specific object. For example, you could define that only the user itself can update its own User object, like this:
allowWriteAccess("<userId>")
For objects, you can define rules for reading and writing separately.
Who has access now (how are permission evaluated)?
In order to access an object, a user needs to have general permission to access the table (Schema ACLs) and also permission to access the object itself (Object ACLs). This means the Schema ACLs are evaluated first if they grant you access, the Object ACLs are evaluated as well.
Which rules can I define?
There are two types of rules that can be defined to allow or deny access:
Allow Rules define who has access in general. These rules are checked first. If you do not define allow rules, everyone has general access.
Deny Rules defines who is denied access (even if the user was allowed by an allow rule). These rules are checked after the allow rules.
Take a look at the JS API for ACLs for the actual method documentation.
These separate rules can be tricky at the start but they are really powerful. Let's do some examples. How can I use these rules to ...
Deny access for everyone: --> Set the only allow rule for admin
Allow access for logged-in users but not for some guy Peter (like when you block someone is a chat application): --> Set an allow rule for the loggedin role and a deny rule for Peter.
Only allow access from backend code modules: --> Set an allow rule for the node role (see below for the explanation of Roles).
Who can I grant or deny access?
There are two entities you can use in your allow and deny rules:
Users from the predefined User table can be granted or denied access
Groups of Users defined in the predefined Role table can be granted or denied access
The predefined roles admin, loggedin (represents all logged-in users) and node (represents backend code modules that access the database)
What is the default access for my tables?
Tables and objects are publically accessible by default if not configured otherwise.
What about attribute-level ACLs
There are no attribute level ACLs in Baqend. This means when you have a User object with a private email address and a public name you can only make the object private or public.
The solution for this is to use two objects, one for the private information and one for the public information and then link the two. For the User, this would mean you make the actual User object private and define a new Profile table where you keep the public user information.
While this solution is more work when defining your schema, there are good reasons why Baqend does not support attribute-level ACLs. Without going into too much detail:
Better caching. Attribute-level ACLs would severely limit how we can cache and therefore accelerate your database requests.
Expensive evaluation. Attribute-level ACLs are much harder to evaluate and therefore slow down database access. Object-level ACLs, on the other hand, can be pushed down to our database system and are evaluated very efficiently.
Something missing
I hope these explanations help to understand the ACL system better. If there is something missing here, just comment and I will add it.
Related
I have an AWS Amplify application that has a structure with multi-organizations:
Organization A -> Content of Organization A
Organization B -> Content of Organization B
Let's say we have the user Alice, Alice belongs to both organizations, however, she has different roles in each one, on organization A Alice is an administrator and has more privileges (i.e: can delete content or modify other's content), while on Organization B she is a regular user.
For this reason I cannot simply set regular groups on Amplify (Cognito), because some users, like Alice, can belong to different groups on different organizations.
One solution that I thought was having a group for each combination of organization and role.
i.e: OrganizationA__ADMIN, OrganizationB__USER, etc
So I could restrict the access on the schema using a group auth directive on the Content model:
{allow: group, groupsField: "group", operations: [update]},
The content would have a group field with a value: OrganizationA__ADMIN
Then I could add the user to the group using the Admin Queries API
However, it doesn't seem to be possible to add a user to a group dynamically, I'd have to manually create each group every time a new organization is created, which pretty much kills my idea.
Any other idea on how I can achieve the result I'm aiming for?
I know that I can add the restriction on code, but this is less safe, and I'd rather to have this constraint on the database layer.
Look into generating additional claims in you pre-token-generation handler
Basically you can create an attribute that includes organization role mapping
e.g.
{
// ...
"custom:orgmapping": "OrgA:User,OrgB:Admin"
}
then transform them in your pre-token-generation handler into "pseudo" groups that don't actually exist in the pool.
I'm developing a huge application in django and I need a permission system and I assume that the native user/group permission within django is not sufficient. Here my needs:
The application will be available through multiple departments. In each department there will be nearly the same actions. But maybe an user will be allowed to add a new team member in department A and in department B he is only allowed to view the team list and in the other departments he has no access at all.
I though using a RBAC system would be most appropriate. Roles must also be inheritable, stored in a model an managable through an interface. Any good ideas or suggestions? Regards
What you are looking for is called abac aka Attribute-Based Access Control. It's an evolution of RBAC as an access control model. In RBAC, you define access control in terms of roles, groups, and potentially permissions. You then have to write code within your application to make sense of the roles and groups. This is called identity-centric access control.
In ABAC, there are 2 new elements:
attributes which are a generalization of groups and roles. Attributes are a key-value pair that can describe anyone and anything. For instance, department, member, and action are all attributes.
policies tie attributes together to determine whether access should be granted or denied. Policies are a human-friendly way of expressing authorization. Rather than write custom code in your app, you write a policy that can be centrally managed and reused across apps, databases and APIs.
There are a couple of ABAC languages such as xacml and alfa. Using ALFA, I could write the following policy:
A user will be allowed to add a new team member in department A
In department B he is only allowed to view the team list
In the other departments he has no access at all.
Roles must also be inheritable, stored in a model an managable through an interface.
policyset appAccess{
apply firstApplicable
policy members{
target clause object = "member"
apply firstApplicable
/**
* A user can add a member to a department if they are a manager and if they are assigned to that department.
*/
rule addMember{
target clause role == "manager" and action == "add"
permit
condition user.department == target.department
}
}
}
One of the key benefits of ABAC is that you can develop as many policies as you like, audit them, share them, and not have to touch your application code at all because you end up externalizing authorization.
There are several engines / projects that implement ABAC such as:
AuthZForce (a Java library for XACML authorization)
Axiomatics Policy Server (commercial product - disclaimer: I work there)
AT&T XACML
There are two components to this question:
First, role management. Roles can be achieved through group membership, i.e. departmentA_addMember & departmentB_listMembers. These Groups would have corresponding permissions attached, e.g. "Member | Add" and "Member | View". A department in this context may have more resources included, that require separate permissions. Django allows to extend Objects with custom Permissions.
Second, inheritance. Do I understand you want to have individual Groups being member of other groups? Then this is something Django would require you to implement yourself.
However, should you be looking for a really more complex authentication solution, it may be worthwhile to integrate with 3rd party services through, e.g. django-allauth. There are sure more/other solutions, just to throw in one name.
A user story has an Owner and Assignments. Trying to figure out the best use of Owners, Assignments and Roles.
When you create an entity, your user becomes listed as Owner. Any item can have only one owner at a time.
An owner can always edit and delete his items, even if his role doesn't have edit or delete permissions for this type of items. This allows every person to edit or delete items they created by mistake.
Not everybody can change owner for an item; there is a special role permission 'can change owner' in the roles settings. If you don't have such permission (even with Add/Edit/Delete permissions) you still won't be able to change the ownership.
Each entity can have unlimited amount of people assigned to it. Usually you assign a person to an entity, if this person is going to work on it.
Any user can always change the state of the items he's assigned to, even if his role doesn't have edit permissions for this type of items. This allows every person to mark their share of work as completed.
Role indicates what kind of work this person will perform (development \ analysis \ testing \ etc.). A set of available roles can be customized as described at https://guide.targetprocess.com/settings/how-to-customize-assignments-area.html
Role also affect what you'll see in your ToDo list: https://guide.targetprocess.com/filters/filters-for-personal-todo-list.html
I am using IS WSO2 for authorization with XACML. I am am able to achieve authorization for static resource. But I am not sure with the design when it comes to granularization.
Example : if I have method like getCarDetails(Object User) where I should get only those cars which are assigned to this particular user, then how to deal this with XACMl?
Wso2 provides support for PIP where we can use custom classes which can fetch data from database. But I am not sure if we should either make copy of original database at PDP side or give the original database to PIP to get updated with live data.
Because Cars would be dynamic for the application eg. currently 10 cars assigned to user Alice. suddenly supervisor add 20 more car in his list which will be in application level database. Then how these other 20 cars will be automatically assigned in policy at PDP level until it also have this latest information.
I may making some mistake in understanding. But I am not sure how to deal with this as in whole application we can have lots of this kind of complex scenario where some times we will get data for one user from more than 4 or 5 tables then how to handle that scenario?
Your question is a great and the answer will highlight the key benefits of XACML and externalized authorization as a whole.
In XACML, you define generic, global rules, about what is allowed and what isn't using what I would call high-level attributes e.g. attributes of the vehicle (in your case) or the user (role, department, ...)
For instance a simple rule could be (using the ALFA syntax):
policy viewCars{
target clause actionId=="view" and resourceType=="car"
apply firstApplicable
rule allowSameRegion{
permit
condition user.region==car.region
}
}
Both the user's region and the car's region are maintained inside the application's database. The values are read using a PIP or Policy Information Point (details here).
In your example, you talk about direct assignment, i.e. a user has been directly assigned to a vehicle. In that case, the rule would become:
policy viewCars{
target clause actionId=="view" and resourceType=="car"
apply firstApplicable
rule allowAssignedVehicle{
permit
condition user.employeeId==car.assignedUser
}
}
This means that the assigned user information must be kept somewhere, in the application database, a CSV file, a web service, or another source of information. It means that from a management perspective, an administrator would add / remove vehicles from a user's assigned list (or perhaps the other way around: add / remove assigned users from a vehicle's assigned user list).
The XACML rule itself will not change. If the supervisor adds 20 more cars to the employee's list (maintained in the application-level database), then the PDP will be able to use that information via the PIP and access will be granted or denied accordingly.
The key benefit of XACML is that you could add a second rule that would state a supervisor can see the cars he/she is assigned to (the normal rule) as well as the cars assigned to his/her subordinates (a new proxy-delegate rule).
This diagram, taken from the Axiomatics blog, summarizes the XACML flow:
HTH, let me know if you have further questions. You can download ALFA here and you can watch tutorials here.
Sorry for the confusing title. I tried to make it less verbose, but...
What I'm wondering is: Does Django's new row level permissions (a) fix the design problem that comes with multi-tenant applications (I don't mean multiple users, but rather multiple instances working with the same db/db schema), or is it (b) just a more complex version of permissions that allows you to manage permissions at the row level based on the standard User and Auth apps' rules.
(ie, I want to limit access to objects a, b, c to this account, and d, e, f to this account VS a user can access the title of a blog post but not the content)
django-authority let's you implement row-level permissions along with django's table-level permissions using the same syntax for both. So it allows you to restrict users A, B to operate only on object C, but not D.
Restricting access to the field-level (title, content) is even more granular and cannot be handled here.