0

I have some rules like:

    rules_version = '2';
service cloud.firestore {

    

  match /databases/{database}/documents {
         
    match /teams/{teamId} {
        allow read, write, delete, list: 
      if debug(teamId) in debug(request.auth.token.teams)
      
      allow create:
      if true;
      
    }
    
  }
}

I am using claims to control access. Each user has an array of teams in their token. That part is working fine.

Basically, teamId (coming from the path) doesn't exist. Nothing is printed in the log for this variable. I can't figure out whats going on. Is there some different way to access that teamId variable?


by doing some logs, it seems that for accessing /teams/teamXXXX I'm getting multiple rule hits. First on /database/default/documents/teams and then again on /database/default/documents/teams/teamXXX The first rule pass is failing because {teamId} is not defined on that path. I need to somehow allow access to the collection while limiting access to the child documents


It looks like the way I'm accessing teams may be causing a problem. I'm getting teams by doing a query like:

instance.collection("teams").where('owners',
            arrayContains: FirebaseAuth.instance.currentUser!.uid);

This must be triggering the rule check where no {teamId} in the path. I thought about wrapping my match statement like:

match /teams/{document=**}
  allow read:
  if (request.auth.uid != "")

  match /teams/{teamId} {
        allow read, write, delete, list: 
      if debug(teamId) in debug(request.auth.token.teams)

      allow create:
      if true;

    }
}

I'm worried that this will just allow all documents. I'm stuck.

majestiq
  • 545
  • 8
  • 25
  • by doing some logs, it seems that for accessing /teams/teamXXXX I'm getting multiple rule hits. First on /database/default/documents/teams and then again on /database/default/documents/teams/teamXXX The first rule pass is failing because {teamId} is not defined on that path. I need to somehow allow access to the collection while limiting access to the child documents. – majestiq Aug 18 '21 at 22:38
  • Please [edit] your post to include any additional information you have to your question. Avoid adding this in the comments, as they are harder to read and can be deleted easier. The edit button for your post is just below the post's tags. – Kevin M. Mansour Aug 18 '21 at 22:39
  • If you have any data which is private I would suggest the implementation like in this [thread](https://stackoverflow.com/questions/46585330/firestore-security-rules-for-public-and-private-fields) using private fields. And also to have access to collections by restricting the access to child documents I would suggest to have a seperate collection which consist the names of collections you have and brief data about them. Please check if it helps. And also can you please check the this [documentation?](https://firebase.google.com/docs/firestore/security/rules-structure) – Rajeev Tirumalasetty Aug 19 '21 at 08:26
  • I am using FireStore and not Firebase realtime database. I don't think that supports private fields. – majestiq Aug 19 '21 at 13:55

1 Answers1

1

answering my own question.

When doing a search / list on a collection, it still matches the rule of /teams/{teamId} even though you are not specifically querying by teamId.

Meaning a search like instance.collections("teams").where(...) will still match /teams/{teamId}

In the match, {teamId} will be blank. Instead, you must look at the input paramters coming in via the "resource" variable. The items you have in the "where" clauses will appear in the resource variable. You must use the resource data to resolve your rules.

So I had to separate the "list" rule form the rest of the rules.

majestiq
  • 545
  • 8
  • 25
  • Long time ago, but can you share the actual working rule you used to achieve this? – TommyBs Jan 27 '23 at 06:10
  • I'm sorry, I don't have the actual rule anymore but something like check the resource.data variable. It will contain the items you are using in your where clause. So you can check if request.auth.uid == resource.data.user_id. In this case, the assumption is that you used where("user_id", "==", "xxxxx). Note, resource.data is not the document itself, it is the request. – majestiq Jan 28 '23 at 07:41