0

I have set up a read rule on my firestore, and it works fine when doing a get on a single document by id, but fails with a FirebaseError: Missing or insufficient permissions. error when getting the collection.

It seems that it is the wildcard in the path that does not bind correctly when querying the collection. I have boiled down to a minimal example, which I logically don't think should fail the permission, but it does. It is as follows:

Data (formatted, but of course orrganized in collection/domument):

"items": {                   // collection "items"
   "item1" : {               // document "item1"
      "name": "first item"   // just dome dummy data
   }
}

the rules:

service cloud.firestore {
    match /databases/{database}/documents {
        match /items/{itemId} {
            allow read: if itemId != null;
        }
    }
}

The code (typescript) I use to access the database

// This line works fine, returns the document
firebase.firestore().collection("/items").doc("item1").get()

// This line gets a "FirebaseError: Missing or insufficient permissions." error
firebase.firestore().collection("/items").get()

I have tried changing the rule to

allow read: if itemId != null || itemId == null;

Which logically should be always true. However, the results are still the same, which lead me to believe there is some problems binding to the itemId wildcard.

Just as a sanity check, I also changed the rule to

allow read: if true;

And now both the get() on the collection and the document works fine (as expected), without any permission errors.

So am I missing something here, or is this a bug in firestore???

  • When would you expect this rule to specifically reject access? It seems to me that you don't have a clear rejection case, which means your rule just doesn't have much of a purpose in the first place. – Doug Stevenson Apr 09 '19 at 09:32
  • 1
    Of course my domain is more complicated than this, I just boiled down the problem to a minimum set of code to reproduce the problem. The main problem is that the issue of binding the wildcard / document id prohibits me from making any meaningful access rules. And I see nowhere in the documentation that the wildcards are only good for getting single documents and not collection queries. – Niklas Hallenfur Apr 09 '19 at 09:52
  • I think it would be better (for the purpose of this question) to show what you're actually trying to accomplish here with a real rule that doesn't work the way you expect. Without a clear purpose to your rule, it's difficult to say if you're even thinking about the problem correctly. – Doug Stevenson Apr 09 '19 at 09:57
  • Good point, should have done that. Just wanted to make it simple, since I thought I had narrowed down to where the problem was, and didn't want to clutter the question – Niklas Hallenfur Apr 09 '19 at 10:15

3 Answers3

1

First of all, your rule does not make sense to me. What's the purpose of checking if the document id is not null? There is no way a valid document will have a null document id.


From Queries and security rules:

When writing queries to retrieve documents, keep in mind that security rules are not filters—queries are all or nothing. To save you time and resources, Cloud Firestore evaluates a query against its potential result set instead of the actual field values for all of your documents. If a query could potentially return documents that the client does not have permission to read, the entire request fails.

In your case it's likely that firestore deemed that your query can potentially return documents you might not have permission to read. It somehow thinks that it's possible that some documents would have a null document id, thereby rejecting the whole request.

When you change the rule to allow read: if true; it works because Firestore evaluated it and knows that the rule would definitely pass for every single document, therefore granting you read access.

Swift
  • 3,250
  • 1
  • 19
  • 35
1

The rule you're proposing doesn't work because (as it is implemented currently), the wildcard variable has an undefined value for list (query) type requests (but not for get type requests, because the document ID is of course coming directly from the client). Queries might match multiple documents, and your query doesn't specify a document ID, so it can't be used in the rule.

If you are ever expecting a rule to decide, on a per-document basis, whether or not it belongs in query results, that is also never going to work. This is because rules are not filters. All filters have to come from the client. If any of the documents that could possibly exist for the given filters would be rejected by the rule, then the entire request is rejected. (It is not scalable to actually check all the documents at the time of the requests - that could be incredibly slow).

In other words, don't use the wildcard variable if you want to affect queries. Only use properties of the documents that could match, and make sure the client is specifying all of the relevant filters.

Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441
  • Is it safe to say, "{wildcard}'s can only be used in rules by queries that pass a single document id into a `get()`"? Ex: `db.collection("cities").doc("SF").get();` would work and `db.collection("cities").where("capital", "==", true).get()` would not? – user1710344 Dec 09 '20 at 02:50
0

if you want to disallow reading multiple documents at once

then this is the rule

service cloud.firestore {
    match /databases/{database}/documents {
        match /items/{itemId} {
            allow list: if false;
            allow get: if true ;
        }
    }
}
Amina Darwish
  • 328
  • 3
  • 5