Don't get the simplest FireStore security rule to work as if it would not find my file - though looks like examples - google-cloud-firestore

I don't get this running, no matter what I do. I have already removed all rules, nevertheless I get simulated read denied. I habe tried companies/4U4kZKXkr3rHA6B04S5K and /companies/4U4kZKXkr3rHA6B04S5K as location, copy pasted the document id and the collection multiple times, nothing... To me, it looks just like all the running examples, I found
What am I doing wrong?!
UPDATE: I used these rules before, which did not work:
match /databases/{database}/documents {
// the request object contains info about the authentication status of the requesting user
// if the .auth property is not set, the user is not signed in
function isSignedIn() {
return request.auth != null;
}
// return the current users entry in the employees collection
function getEmployeeData() {
return get(/databases/$(database)/documents/employees/$(request.auth.uid)).data
}
// check if the current user has access to specific company
function accessCompany(companyId) {
return isSignedIn() && getEmployeeData()['companyId'] == companyId;
}
// check if the current user has a specific role
function hasRole(role) {
return isSignedIn() && getEmployeeData()[role] == true;
}
// check if the user has any of the given roles (list)
//function hasAnyRole(roles) {
// return isSignedIn() && getRoles().keys().hasAny(roles);
//}
}
match /users/{user} {
// anyone can see a specific users profile data (name, email etc), in a real scenario you might want to make this more granular
allow get: if true;
// noone can query for users
allow list, create: if false;
// users can modify their own data
allow update, delete: if request.auth.uid == user;
}
match /employees/{user} {
// only allow admins to set roles. Of course a user should be able to retrieve its own designated roles
allow get: if request.auth.uid == user || hasRole('admin');
allow list: if hasRole('admin');
allow update: if hasRole('admin');
allow create, delete: if false;
}
match /companies/{document=**} {
allow get, list, create, update, delete: if true;
}
}

By default, no read and write access is allowed to any document. If you want to allow access to a document, you must have at least one rule that matches the query that would allow that access. If you have commented out all your rules, then I would expect no reads or writes to be allowed.
Minimally, adding a rule like this will allow read access to all documents in the companies collection:
match /companies/{id} {
allow read: if true;
}
I suggest reviewing the documentation on security rules to better learn how they work.

Related

Unable to set up firebase storage access rule based on metadata

Facing an issue in setting up access rules. So till now we have been storing user data as <user_id>/. And the basic rule as this has been working fine
// Grants a user access to a node matching their user ID
service firebase.storage {
match /b/{bucket}/o {
// Files look like: "<UID>/path/to/file.txt"
match /{userId}/{allPaths=**} {
allow read, write: if request.auth != null && request.auth.uid == userId;
}
}
}
But now i want a user to be able to store a file under any {userId} as long as he is the owner of the file.
I am doing that by setting the owner metadata attribute when trying to write the file and updating the access rules.
Updated access rules
// Grants a user access to a node matching their user ID
service firebase.storage {
match /b/{bucket}/o {
// Files look like: "<UID>/path/to/file.txt"
match /{userId}/{allPaths=**} {
allow read, write: if request.auth != null
&& (request.auth.uid == userId || resource.metadata.owner == request.auth.uid);
}
}
}
I have verified that the metadata is being set correctly by uploading the file to the user’s own path. But when i try to write under some other user’s path, i am getting access denied
See the screenshot of the metadata info of the file i am trying to upload
Finally found the issue.
I didn't read the documentation carefully. When writing a file, in order to check the metadata of the incoming file, we have to use request.resource. So the write rule had to be request.resouce.metadata.owner
Updated rule that works
// Grants a user access to a node matching their user ID
service firebase.storage {
match /b/{bucket}/o {
// Files look like: "<UID>/path/to/file.txt"
match /{userId}/{allPaths=**} {
allow read: if request.auth != null
&& (request.auth.uid == userId || resource.metadata.owner == request.auth.uid);
allow write: if request.auth != null
&& (request.auth.uid == userId || request.resource.metadata.owner == request.auth.uid);
}
}
}

How To Add Firebase Rules To Specific User To read And Write And all other User only read?

I Have Created firebase and flutter app and google is sending me emails saying firebase rules are not good. How do I make those rules better? I want to give permission to login users to read and my account to read and write permission.
I hope that will help you.
service cloud.firestore {
match /databases/{database}/documents {
// Make sure the uid of the requesting user matches name of the user
// document. The wildcard expression {userId} makes the userId variable
// available in rules.
match /users/{userId} {
allow read, update, delete: if request.auth != null && request.auth.uid == userId;
allow create: if request.auth != null;
}
}
}
This is a correct way you can secure database.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Line below secure whole database so users are not alowed to create any new collections etc.
match /{document=**} {
allow read, write: if false;
}
match /app/{dataId} {
allow read: if true;
allow write: if isAdmin();
}
match /posts/{dataId} {
allow read: if resource.data.isPublic == true || isAdmin();
allow write: if isAdmin();
}
}
}
function isAdmin() {
return request.auth.token.admin == true;
}
Users don't have any .admin variables. You have to assign them using firebase functions. Read about custom claims.

Troubleshoot simple custom firebase security rules function

I'm writing a custom cloud function (official documentation) in Firestore security rules that checks to make sure the submitting user is the content owner, per the official documentation.
I'm applying the custom function to the correct path /collection/{documents}/subcollection/{subcollectiondocuments} where every subcollectiondocument has a userId field that's not null. These documents do not have a uid field, but I tried it anyway in 2 and 4 below.
All versions of the custom function below (belongsToRequestor 1,2,3 and 4) generate a "Property resource is undefined on object" error in the Cloud Firestore rules playground simulator.
Do I need to pass something into the custom function, or am I making some other mistake?
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
function belongsToRequestor1() {
return
request.auth.uid == resource.data.userId;
}
function belongsToRequestor2() {
return
request.auth.uid == resource.data.uid;
}
function belongsToRequestor3() {
return
request.auth.uid == request.resource.data.userId;
}
function belongsToRequestor4() {
return
request.auth.uid == request.resource.data.uid;
}
…
match /collection/{documents}/subcollection/{subcollectiondocuments} {
allow update: if
belongsToRequestor1();
// or belongsToRequestor2(); or belongsToRequestor3(); or belongsToRequestor4();
…
} }
I'm not sure how to implement this answer to another question to "…enter the path to an actual document that exists if you want to test your rule that uses its field values." Each document in subcollectiondocuments has an id auto-generated by firebase.
Update: adding database screenshot (with fake data), as requested (properties = collection and reviews == subcollection):
Thanks for any help!

Firebase Security rules to restrict access on all paths but one?

Question:
For the different top-level firestore collections below, how to restrict access to all but one of the paths?
We are building a data schema in Firestore to support a chat app for teachers across multiple schools.
The top-level firestore collections include:
/siteAdminUsers
/schools
/schools/{schoolId}/teachers
/schools/{schoolId}/chats
Below is the security rules setup we are trying now - where we check for:
valid user auth
expected value exists in userClaim variable request.auth.token.chatFlatList
However, the read listener for /messages is being blocked.
Error message:
FirebaseError: [code=permission-denied]: Missing or insufficient permissions
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if false;
}
match /schools/{schoolId}/chats/{discussionId}/messages {
allow write: if false;
allow read: if request.auth != null
&& request.auth.token != null
&& request.auth.token.chatFlatList.val().contains($discussionId);
}
}
Details
We are using cloud functions for all data read/write, so for almost every case we can just block all client access.
The one exception is for the chat discussions, where we need to set a snapshot listener in the mobile client to know when there are new messages.
Sub-collection notes:
At a school, there are discussion sessions for school staff (teachers, admins, etc)
/schools/{schoolId}/chats/{discussionId}
Where each discussion-document contains:
list of participant teacher ids
subcollection for actual messages where each document is an indivual posted message:
/schools/{schoolId}/chats/{discussionId}/messages
User Claim code from Cloud Function
Looking at the cloud function logs, we have verified that the userClaim is being set.
return firebaseAdmin
.auth()
.setCustomUserClaims(
uid, {
chatFlatList: 'id1 id2 id3'
}
);
UPDATE #1
Tried the following variation where rules skip/omit the check on userClaim and auth.token.
However, still same permission error.
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if false;
}
match /schools/{schoolId}/chats/{discussionId}/messages {
allow write: if false;
allow read: if request.auth != null;
}
}
}
I think the issue here is that you are writing a rule on the collection called messages.
All match statements should point to documents, not collections.
https://firebase.google.com/docs/firestore/security/rules-structure
You should try adding /{document=**} after your path to messages, something like:
match /schools/{schoolId}/chats/{discussionId}/messages/{document=**} {
allow write: if false;
allow read: if request.auth != null;
}
This worked for me if I wanted to read and write all collection but not one collection named "backStage";
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{collection}/{document} {
allow read: if true
allow write: if (collection != "backStage");
}
}
}
Here's a solution (seems to be working), which includes the check on chatFlatList user claim variable (from original question) for a substring :
match /schools/{schoolId}/chats/{discussionId}/messages {
allow write: if false;
allow read: if request.auth != null
&& request.auth.token.chatFlatList.matches(discussionId);
}
Figured this out thanks to:
Firebase storage rules based on custom parameters
Here the post shows there is not any $ notation to access the path var. I recall seeing this in a security rules example code example - maybe it's specific to database tiers?
https://firebase.google.com/docs/reference/security/storage/#string
https://regex-golang.appspot.com/assets/html/index.html
Trying some example inputs here, to get an understanding for how to create the regex's.

Firestore rules why this doesn't work?

I have tasks collection on root level and here is my rules (yeah, super global for now):
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read: if resource.data.private == false;
allow write: if request.auth.uid != null;
}
}
}
Single task has field private: Boolean and I want to give read permission to all tasks that has private: false and writing is allowed only for logged in users.
firestore.collection('/tasks').onSnapshot(snapshot => {})
At least with onSnapshot this read rule doesn't work. I give an error:
Uncaught Error in onSnapshot: Error: Missing or insufficient permissions
So am I doing something wrong or what is happening here?
Apparently "you can't query data you have no access to". Because only private: false tasks are readable the query should be changed from this:
firestore.collection('/tasks').onSnapshot(snapshot => {})
to following:
firestore.collection('/tasks').where('private', '==', false).onSnapshot(snapshot => {})
after requesting only data I have access to, it started working!