Firebase Firestore server side rules - problems - google-cloud-firestore

I have an app in iOS that I'm nearly complete and I'm working to configure the server side rules in Firestore. I'm copying the rules identically to another app I have which users the same authentication and database structure. This set of code is not working however.
My data structure has two root collections: User and Feed. Feed is a public collection that any authenticated user should be able to access.
The User Collection and sub collections should only be accessible to the authenticated user who is logged in.
The feed access is working correctly here, but I'm not able to read and presumably not write anything to the user collection/subcollections.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read, write: if request.auth.uid == userId;
}
match /feed/{docId} {
allow read, write: if request.auth != null;
}
}
}
This works - so it is established that the authentication is working. The user documentID is the same as the UID in the authentication table. I'm going nuts with this.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read: if request.auth != null;
}
}
}

I got it to work with this - I still don't understand why my other app works but not this one.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId}/{document=**} {
allow read, write: if request.auth.uid == userId;
}
match /feed/{docId} {
allow read, write: if request.auth != null;
}
}
}

Related

Firestore Security Rule that allows writing only to user's own document?

I want to restrict documents in certain collections to only have write access to the user whose uid matches the document id. This does not work, however, as it produces an invalid permission error on the client.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
function isSignedIn() {
return request.auth != null;
}
function isOwnDocument() {
return request.auth.uid == request.resource.id;
}
match /userSettings/{doc} {
allow write: if isOwnDocument();
allow read: if isSignedIn();
}
}
}
You can pass the docId variable directly in the isOwnDocument() function instead of reading from the request.resource object as shown below:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
function isSignedIn() {
return request.auth != null;
}
function isOwnDocument(docId) {
return request.auth.uid == docId;
}
match /userSettings/{docId} {
allow write: if isOwnDocument(docId);
allow read: if isSignedIn();
}
}
}
The resource property might be undefined in explained in this answer.
request.auth.uid == resource.id can be used to be but that'll throw an error if the document does not exist since your rule is works for write ops that includes create and update too). This rule will work only when used with allow create:. But best to pass the ID directly in the function parameters so it'll support both operations.

Firestore security rule that only allows writes on documents to specific fields?

I know that Firestore security rules cannot restrict document reads at the field level, but can they only allow a write if the write is updating a specific field?
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /someCollection/{doc} {
// Anyone can read
allow read: if true;
// Only allow write if signed in and the field they are changing is `count`
allow write: if request.auth != null && ?????;
}
}
}

How to write security rules for just a document

I have a collection called users with fields such as email, frame, lname, uid, ts and role
I am trying to write a rule that request only authenticated users to interact with it
Below is the rule I tried
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read, write : if isSignedIn();
}
}
function isSignedIn(){
return request.auth.uid != null;
}
}
The problem I have is to understand the path in match. I cannot format it and my simulation is denying me the access
What can I do?
What exactly must be in the users{userId} path?
This one works for me try removing the function like this
match /Users/{userId} {
allow read, write :if request.auth != nul;
}

Firestore security when retrieving document by id denies permission

When I directly retrieve a document using .doc().get() firestore security rues deny permission. What do I need to do to allow CRUD operations for authenticated users of my Ionic app?
I have the following function in my PWA Ionic app
``` async getUserProfile(): Promise<firebase.firestore.DocumentSnapshot> {
const user: firebase.User = await this.authProvider.getUser();
this.currentUser = user;
console.log('found current user');
this.userProfile = firebase.firestore().doc(`userProfile/${user.uid}`);
console.log('returing userprofile', this.userProfile.get());
return this.userProfile.get();
}```
But the call to this.userprofile.get() fails due to security warning from Firestore Security rules
found current user
returing userprofile
ZoneAwarePromise
__zone_symbol__state: 0
__zone_symbol__value: FirebaseError: Missing or insufficient permissions. at new e (http://localhost:8100/vendor.js:92760:23) at http://localhost:8100/vendor.js:102987:28
.
.
.
(http://localhost:8100/polyfills.js:10248:56)
code: "permission-denied"
name: "FirebaseError"
toString: ƒ ()
message: "Missing or insufficient permissions."
stack: "FirebaseError: Missing or insufficient permissions.\n at new e
The Firestore Security Rules are set simply as
service cloud.firestore {
match /databases/{database}/documents {
match /userProfile/{userId}/{documents=**} {
allow read, update, get,delete: if request.auth != null && request.auth.uid == userId;
allow create: if request.auth != null;
}
}
}
What should be the correct security rule to implement to allow authenticated users to CRUD their documents? Or the correct way to retrieve the document from the collection
UPDATE: It works directly from the simulator but not from the app
Some inspiration. I use this very basic role based access to allow read and write where a normal user can read and admins can write:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
function googleProvider() {
return request.auth.token.firebase.sign_in_provider == "google.com";
}
function getUserData() {
return get(/databases/$(database)/documents/users/$(request.auth.uid)).data
}
allow read: if googleProvider() && getUserData().roles['user'] == true;
allow write: if googleProvider() && getUserData().roles['admin'] == true;
}
}
}
What version of security rules do you have?
There is a hint for the version 1:
Security rules use version 1 by default. In version 1, recursive wildcards match one or more path items. They do not match an empty path, so match /cities/{city}/{document=} matches documents in subcollections but not in the cities collection, whereas match /cities/{document=} matches both documents in the cities collection and subcollections.
That could explain why you can't get the data you want.
The version 2 behaves different:
In version 2 of the security rules, recursive wildcards match zero or more path items. match/cities/{city}/{document=**} matches documents in any subcollections as well as documents in the cities collection.
Here you can see the whole docu for it.
The version should be on top of your rules like here:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Matches any document in the cities collection as well as any document
// in a subcollection.
match /cities/{city}/{document=**} {
allow read, write: if <condition>;
}
}
}

Security Rules for Firestore to allow access to all subcollections based on UID

So trying to setup my firestore database and I have a collection called Users that stores the users information. I also have subcollections of Towers for each user. My users documents have a playerUid field that I use for security settings. Here are my current security rules:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read: if request.auth.uid != null;
}
match /users/{user=**}{
allow read, create: if request.auth.uid != null;
allow update: if request.auth.uid == resource.data.playerUid;
}
}
}
this allows users to read, create both their user document and the subcollection of tower documents, but they cant edit the subcollection. There is no playerUid in the tower documents. Is there a way to use the playerUid in the user document to authenticate for updating the towers? Or do I need to add a playerUid field to the tower documents to authenticate against
You can get the user document in the rules of the Towers subcollection as shown in the Firestore documentation on accessing other documents:
allow delete: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.admin == true
Alternatively you can indeed include the UID if the user in the documents of the subcollection. That will prevent needing an extra document read in the rules.
This snippet may be able to help you
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read: if request.auth.uid != null;
}
match /users/{user=**}{
allow read, create: if request.auth.uid != null;
allow update: if request.auth.uid == user; // <== THIS LINE
}
}
}
Wouldn't this match the 'user' path with the 'uid'?
I will try test this when I have some time.
It would save a get call if it does work.