2
votes

I have an app where I have data objects and these objects can be read/write either by single users or by group of users. I'm trying to figure out what is the best approach to write a security rules for such a logic and best way to structure my real time DB.

I have tried to look for a solution but I have never found my exact use case. Here is example of my DB:

{
  "data": {
    "data1": {
      "id": "data1",
      "name": "Some data",
      "content": "Some content...",
      "visibility": "private",
      "owner": "user1"
    },
    "data2": ...
  },

  "dataPermissions": {
    "data1": {
      "user1": "read",
      "user2": "write",
      "group1": "write"
    },
    "data2": {...}
  },

  "groupMembers": {
    "group1": {
      "user3": true,
      "user4": true
    }
  },

  "userGroups": {
    "user4": {
      "group1": true
    }
    ...
  }
}

My question is how to setup security rules to check whether user can read/write to data node? I know how to check for a single user. But I can't figure out how to check for the group. How to check in security rules that eg. user4 can read/write to data1 node? Since I can have several groups per user and several groups per data nodes I can't really address it with dynamic variable $uid.

Please note that I'm open to changes in db structure. I'm more curious how to deal with this problem in general without to much of duplicating datas (like saving all users from a group to dataPermissions under group id node) in order to keep DB maintenance sane.

Here is how I check for user permissions in security rules:

"data": {
  "$dataId": {
    ".read": "data.child('owner').val() == auth.uid || data.child('visibility').val() == 'public' || root.child('dataPermissions/' + $dataId + '/' + auth.uid).exists()",
    ".write": "false"
  }
},

Thanks for help.

1
I dont think it's actually possible to check permission for group members with your current structure. So the solution would be to change the structure. Two options come to mind: Have all group members under permissions or Have all group members under data (like owner). Both options come with the challenge of maintaining permissions (user leaves a group for example) - André Kool
Yeah, I did consider this as well, but I did want to avoid maintaining N permission nodes just because someone is added/leaves group. So I was curious if there is some better solution. If not, I guess I will have to go this way and keep maintaining a lot of nodes. - Tomáš Pustelník

1 Answers

0
votes

Ok, I have solved this, though it is a bit complicated approach. But I couldn't figure a better one. I store all users and groups with access rights to given data object in this form:

dataUsers
|_ data-1
   |_ user-1: 1
   |_ user-2: 3
   |_ group-1: 1

Number describes what actions can user do with data (read/write etc.).

Then I have permissions node with similar structure, but instead of group I put here uid of group members. That way I can target every single user for given data object in security rules. And since one user can have more than one access rights sources for given object (he may be owner of the data + can be member of several groups with different access rights to data) I keep track of all different AR sources for given user and on each update recalculate resulting AR for given user to take the highest number from all his AR sources.

permissions
|_ data-1
   |_ user-1:
      |_ data-1: 1
      |_ group-1: 1
   |_ user-2:
      |_ data-1: 3
      |_ group-2: 2
   |_ user-3:
      |_ group-1: 1