1
votes

I have a recyclerview in my app which with a get, it retrieves all the documents in a collection. Each document contains the uid of the person who created it. I would like to implement a security rule in which you retrieve only the documents matches the uid of the owner. It looks like quite trivial, but I am not able to make it working.

Database has a structure like this

cars
|
|-documentA
|-documentB
|-documentC

an each document:

documentA
|
|
|-fieldA: aaa
|-fieldB: bbb
|-userId: aklsjdaosjfpasf

Security rules at firestore

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{cars=**}/{carId}  {
    allow read: if request.auth.uid == resource.data.userId;
    allow write: if request.auth.uid != null;
  }
  }
}

EDIT query:

query = firestore.collection("cars").limit(10L)

Firestore Adapter for make queries for the recyclerview

public abstract class FirestoreAdapter<VH extends RecyclerView.ViewHolder>
        extends RecyclerView.Adapter<VH> {

    private static final String TAG = "Firestore Adapter";

    private Query mQuery;
    private ListenerRegistration mRegistration;

    private ArrayList<DocumentSnapshot> mSnapshots = new ArrayList<>();

    public FirestoreAdapter(Query query) {
        mQuery = query;
    }

    public void startListening() {
        // TODO(developer): Implement
    }

    public void stopListening() {
        if (mRegistration != null) {
            mRegistration.remove();
            mRegistration = null;
        }

        mSnapshots.clear();
        notifyDataSetChanged();
    }

    public void setQuery(Query query) {
        // Stop listening
        stopListening();

        // Clear existing data
        mSnapshots.clear();
        notifyDataSetChanged();

        // Listen to new query
        mQuery = query;
        startListening();
    }

    @Override
    public int getItemCount() {
        return mSnapshots.size();
    }

    protected DocumentSnapshot getSnapshot(int index) {
        return mSnapshots.get(index);
    }

    protected void onError(FirebaseFirestoreException e) {};

    protected void onDataChanged() {}
}
2
What exactly is not working with your security rules? Also only allowing read to matching users but allowing write to all authenticated users seems wrongMax
I am not able to retrieve anything from my recyclerview, it gives me an errar that I do not have enough permissions. The idea allowing to let all users auth in the app write is because everyone can register a car but only its owner can see it.enriqueanaemma garcia cardenas
This approach is wrong, if you allow someone to write a document, they can read it. You probably want to use allow create instead of allow writeMax
Ok, that makes sense. I change in that way. Understood the difference between create and write.enriqueanaemma garcia cardenas
Can you add to your question the query you use to fetch data?Renaud Tarnec

2 Answers

2
votes

You have to note that security rules are not filters, as explained in the documentation:

Once you secure your data and begin to write queries, keep in mind that security rules are not filters. You cannot write a query for all the documents in a collection and expect Cloud Firestore to return only the documents that the current client has permission to access.

With

query = firestore.collection("cars").limit(10L)

you are querying independently of the userId, hence the problem.

You need to adapt your query with whereEqualTo() as follows:

//get the value of uid
query = firestore.collection("cars").whereEqualTo("userId", uid).limit(10L)
1
votes

Based on the comments, I think this might be the solution. According to the OP, all users should be able to register a car, but only the user who created a car should be able to see it.

The correct permissions in this case would look like this:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /cars/{carId}  {
      allow read, write: if request.auth.uid == resource.data.userId;
      allow create: if request.auth.uid != null;
    }
  }
}

For rules pre version 2:

There is also a problem with the permission URL, you can use the following syntax to match all documents in a collection: /cars/{documemts=**}/, but your path /{cars=**}/{carId} is invalid, thereofore the rule will never be enforced for your query.

The path /cars/{carId} will refer to any document in the collection 'cars', storing the name of the document as 'carId'.