Chris Chong
Chris Chong

Reputation: 371

Relationships and ACL in Baqend

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.

Upvotes: 2

Views: 178

Answers (2)

Wolle
Wolle

Reputation: 19

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:

  1. superusers are always allowed.
  2. explicitly denied users and roles are always denied.
  3. 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.

Upvotes: 2

Erik
Erik

Reputation: 3048

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 ...

  1. Deny access for everyone: --> Set the only allow rule for admin
  2. 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.
  3. 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:

  1. Better caching. Attribute-level ACLs would severely limit how we can cache and therefore accelerate your database requests.
  2. 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.

Upvotes: 1

Related Questions