15

I am trying to base a security rule on a reference to another object.

I have a collection of users and collection of roles. A user object has a field called "role" that is a reference to a particular document in the roles collection.

users
  id
  name
  role <-- reference to particular role

roles
  id
  name
  isSuperUser

The goal here is to allow a user with a particular role (the role with isSuperUser == true) to edit any other role or it's sub-collections;

Here are my rules that I would have thought would have worked:

service cloud.firestore {
   match /databases/{database}/documents {
    match /users/{userId=**} {
     allow read, write: if request.auth.uid == userId;
   }
   match /roles/{roleId=**} {
      function isSuperUser() {
       return get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role.isSuperuser == true;
      }
      allow read: if request.auth.uid != null;
      allow write: if isSuperUser();
   }
}

I have confirmed the following works, but it's not really that useful...

get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role != null;

If there is a better way to accomplish role base security, I am all ears.

The lack of any debugging tools makes this quite frustrating.

Geo242
  • 451
  • 5
  • 13
  • 1
    Basically I am looking for the same thing. I have a "fish" collection, that is owned by a user. Instead of storing the user id, I store a reference to the user. So now, I want to check whether fish.user.id is the same as auth.uid. Is that possible or should I store the userId only? – Jaap Weijland Dec 04 '17 at 12:09
  • had the idea of getting the data directly from the reference as in `request.data.refField.data` but apparently [thats not supported](https://stackoverflow.com/questions/49446590/firestore-security-rules-with-reference-fields) – galki Dec 20 '18 at 13:08

2 Answers2

2

I know it's been a while since the original question but I've had a similar issue and I hope this could help you or others.

Your condition is: get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role.isSuperuser == true;

But role is a reference, which (apparently) means you need to get it as well. Try this:

get(get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role).data.isSuperuser == true;

blap
  • 76
  • 6
  • @JaapWeijland no, unfortunately it didn't. The reference to the other object doesn't seem to be path that I can use to pass to the "get" function. – Geo242 Dec 05 '18 at 07:59
0

Have you tried to move the wildcard to a nested path?

service cloud.firestore {
  match /databases/{database}/documents {
    match /users/{userId} {
      allow read, write: if request.auth.uid == userId;
      match /{role=**} {
        allow read: if request.auth.uid != null;
        allow write: if isSuperUser();
      }
    }
  }
}