How to limit get access for owners only in firebase storage? - firebase-storage

I'm testing new Firebase Storage local Emulator. For my rules, it gives me the following error:
com.google.firebase.rules.runtime.common.EvaluationException: Error: {path/to/my/file/storage.rules} line [5], column [21]. Null value error.
The rules:
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /item/{id}/file.txt {
allow get: if request.auth.uid != null && request.auth.uid == resource.metadata.owner; // Error line 5
allow delete: if request.auth.uid != null && request.auth.uid == resource.metadata.owner;
// Only allow uploads of any image file that's less than 100MB
allow write: if request.auth.uid != null && request.auth.uid == request.resource.metadata.owner
&& request.resource.size < 100 * 1024 * 1024;
}
}
}
It seems like the rules for GET are invalid. Maybe it's because of the resource.metadata.owner that doesn't exist? If it's true, then how can I limit the access for owners of the file only?

Update
Try to check if the metadata itself exists before comparing it
allow get: if request.auth.uid != null && resource.metadata.owner != null && resource.metadata.owner == request.auth.uid;
If you find any future issues, test it in a deployed project as it may just be a fault in the emulator
Source:
https://firebase.google.com/docs/rules/basics#custom-claim_attributes_and_roles
https://firebase.google.com/docs/reference/security/database#request_methods

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);
}
}
}

Debugging firestore security rules with emulator does not work

I have written some firebase rules, using firebase emulator. I tried to debug the request which I am sending to the rules, using debug() function. Yet it doesn't print anything. My rules:
function printResource() {
return debug(resource) || true;
}
match /users/{userId} {
allow read, delete: if something....;
allow create: if printResource() && userIsAuthenticated() && userOwnsResource(userId) && debug(isUserNameAvailable(debug(request))) && getAfter(
/databases/$(database)/documents/usernames/$(request.resource.data.username)
).data.owner == userId;
}
I tried as well the following:
match /users/{userId} {
allow read, delete: if something....;
allow create: if debug(userIsAuthenticated()) && debug(userOwnsResource(userId)) && debug(isUserNameAvailable(debug(request))) && getAfter(
/databases/$(database)/documents/usernames/$(request.resource.data.username)
).data.owner == userId;
}
Nothing is being printed. My debug() function is not working, but I don't know why. Is there another way I can print my resource object?

Firestore Rules Simulator - Request is Null for subcollections

The following rules produce an error on "request" in the nested (**) match:
Error running simulation — Error: simulator.rules line [10], column [30]. Null value error.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Allow users to only edit their records
match /users/{userId}{
allow read, update, delete: if request.auth.uid == userId;
allow create: if request.auth.uid != null;
match /{documents=**} {
allow read, write: if request.auth.uid == userId;
}
}
}
}
The simulator test that is failing is:
GET: /users/MyUserId/items/MyItemId
This is using "password" authentication, but even running this as "unauthenticated" produces the same error, as if the rule is not being compiled correctly by the simulator.
Further troubleshooting shows it works live in the database, just not in the simulator. So must be a simulator bug.

Firestore read simulation fails, no highlighted line

So, I typically don't have problems writing firestore rules but I'm coming up short on why this simulation fails.
If you don't want to follow the image link:
Rules:
service cloud.firestore {
match /databases/{database} {
match /server_credentials/{document = **} {
allow read, write: if false;
}
match /users/{user_uid} {
allow read, write;
match /signatures/{sig_id} {
allow read: if request.auth.uid != null && resource.data.access == "public";
allow read, write: if request.auth.uid == user_uid;
}
match /identity/{credential} {
allow read, write: if request.auth.uid == user_uid;
}
}
match /signatures/{sig_id} {
allow read, list;
allow write: if false;
}
}
}
Auth details:
Google as provider and foo as the uid.
I'm testing a simple read to users/foo
Any help would be quite nice.
This line is incorrect:
match /databases/{database} {
It should be this:
match /databases/{database}/documents {
This mistake is causing none of your rules to apply at all, and all access is being rejected by default.

Q: Firestore Security Error: Missing or insufficient permissions

I'm currently using Firestore for database and ran in to insufficient permission error. What I don't understand is why isPartner() will work when my path is
users/{uid}
but give me permission error when it's
object/{objectID}
Security Rules
service cloud.firestore {
match /databases/{database}/documents {
match /users/{uid} {
allow read: if isSignedIn();
allow write: if isOwner(uid) || isPartner();
match /object/{objectID} {
allow read, write : if isPartner() || isOwner(uid);
}
function isOwner(userID) {
return request.auth.uid == userID
}
function isPartner() {
return resource.data.partnerUID == request.auth.uid
}
}
}