Firebase Cloud Storage security rules: what do "/b/" and "/o" mean in bucket match statement? - firebase

This question is regarding Firebase Cloud Storage security rules, documented at https://firebase.google.com/docs/storage/security and related pages.
The statement to match a generic bucket is match /b/{bucket}/o: the documents explain that {bucket} is a wildcard (akin to *) to match any bucket name, but to me it seems that the meaning of the leading /b/ and trailing /o are left unexplained, can anyone help me understand the meaning of those path segments?

The /b signals the next component of the URI is the relevant bucket: /b/{bucket}.
The /o signals the next component of the URI is the name (or path) of the relevant object in that bucket: /o/path/to/object.png
Note: Storage Buckets don't have a concept of folders, an object's name can include slashes, but to the server, the slash is just part of the file name and has no special meaning.
So a rule that names /b/{bucket}/o/publicUserFiles/{request.auth.uid}/profile.png would define a rule for the profile.png file, stored in a "folder" named with the relevant user's UID, under another "folder" called publicUserFiles, in the relevant bucket.
Instead of putting /b/{bucket}/o at the front of every rule, you can lift it out to the top of the file.
i.e.
service firebase.storage {
match /b/{bucket}/o/images/{imageId} {
allow write: // some rule here;
}
match /b/{bucket}/o/profileImages/{imageId} {
allow write: // some rule here;
}
}
becomes
service firebase.storage {
match /b/{bucket}/o {
match /images/{imageId} {
allow write: // some rule here;
}
match /profileImages/{imageId} {
allow write: // some rule here;
}
}
}

Related

Do Firestore subdocuments inherit any permissions from parent documents?

E.g. I have a document parentDoc with a collection subDocs and a childDoc that is part of that subDocs collection. If a user does not have permission to read the parentDoc, will they also be unable to read the childDoc?
If by "permissions" you mean "security rules", that is correct. The default for security rules is users do NOT have access.
Yes and No, this is highly dependant on your rules themselves and if you are using wild cards. As a rule of thumb, all requests are denied by default and must match a valid Security Rule to read from that location, these rules then cascade down from top to bottom and cannot override a previous directory.
for example:
service cloud.firestore {
match /databases/{database}/documents {
match /myDocument/ {
// this targets a document named "myDocument"
// this WILL be in effect as no rule above applies to this location
match /posts/{moreDocuments} {
// this targets all documents under a collection called "posts"
// this WILL override the above rule on documents that follow this path
// as no wild card above exists to conflict with this location
}
}
match /{document=**} {
// this uses a wild card that applies to ALL children documents as a default
// this will override any following Security Rules
}
match /otherDocument/ {
// this targets a document named "otherDocument
// this will NOT be in effect as the rule above applies to this location
}
}
}

Firebase storage rules for writing at specific path not considered

I have a very simple Firebase Storage structure:
> check-in-station-content
> reports
These are two folders and I am trying to set up a restriction on the check-in-station-content to accept only video/mp4 files, not bigger than 30MB and to be uploaded only by authenticated parties. So, my rules looks like this:
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read: if request.auth != null;
}
match /check-in-station-content {
// Allow write files, subject to the constraints:
// 1) File is less than 30MB
// 2) Content type is video/mp4
match /{videoId} {
allow write: if request.auth != null && request.resource.size < 30 * 1024 * 1024 && request.resource.contentType.matches('video/mp4')
}
}
}
}
Then, when I go to the UI for the storage and click the Upload button, nothing is stopping me of uploading whatever file having whatever size
When you use the Firebase console, you actually bypass all the security rules, since you are interacting with Cloud Firestore as the owner of the project (or another role with similar access, e.g. Editor). The rules apply only when you are using one of the Client SDKs or the other Client APIs.
By the way, note that your rule matches the check-in-station-background-content path and no the check-in-station-content one.

How to debug firestore.rules variables and functions?

I am having difficulty trying to diagnose a particular rule in my firestore.rules file. See that question here for context.
Is there a way to debug the firestore.rules file and/or functions? I'm using unit testing and the emulators to test my rules, but I would really love to see exactly what values are being evaluated by the rules engine.
For instance, here is my firestore.rules file:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /organizations/{orgId} {
allow read: if isAdmin();
allow create, update: if isAdmin();
match /classes/{classId} {
allow read: if request.auth.uid != null;
allow create, update: if isAdmin();
match /students/{studentId} {
allow read: if isAdmin() || belongsToCurrentClass();
allow create, update: if isAdmin();
}
}
}
}
}
function isAdmin() {
// removed for security
}
function belongsToCurrentClass() {
// retuns true if the authenticated user is the teacher of the requested class
return get(/databases/$(database)/documents/organizations/$(orgId)/classes/$(classId)).data.teacherUid == request.auth.uid;
}
What I'd love to do is set breakpoints or step through the code. When attempting CRUD operations on a organizations/{orgId}/classes/{classId}/students/{studentId} path I'd love to inspect exactly what values the orgId, classId, and studentId variables are holding, as well as the resource and request parameters. I'd love to inspect exactly which document (if any) is returned by the get request in belongsToCurrentClass and what the return value is.
Does anyone know of any way to do this? I think I'd answer my question referred to above in 10 seconds if I could just see the data being evaluated.
There is a local emulator for Cloud Firestore security rules. This is your best (and really only) tool for digging into security rule execution. There is no step-through debugging, but you can see a lot of debug output in the console.
https://firebase.google.com/docs/rules/emulator-setup
We can add the built-in debug function to rules. As noted in a comment, you'll see an unhelpful message like this in the browser:
Received: [path] Expected: [bool]. for 'list' # L6
On the plus side, we won't forget to remove debug messages. Tail the log file to see the output: tail -f firestore-debug.log
For example, to see which paths are being called:
match /databases/{database}/documents {
match /{document=**} {
allow create, read, update, delete: if debug(request.path);
}
}

Firestore security rules: check for not exists(/collection/document)

In firebase firestore security rules, I want to allow a request only if a particular document does not exist. My code is:
match /users/{user_id} {
allow create: if !exists(/databases/$(database)/merchants/$(request.auth.uid));
}
I am pretty sure the document does not exist but it does not work.
Both exists() and !exists() give false somehow, or maybe !exists() raises some error.
I have even tried:
match /users/{user_id} {
allow create: if exists(/databases/$(database)/merchants/$(request.auth.uid)) == false;
}
Is there any way to make this work?
Are your rules inside the database block? Cause I had a similar problem and was actually putting the rule bellow the database block, and my rule was using the $(database)parameter just like yours
service cloud.firestore {
match /databases/{database}/documents {
match /users/{user_id} {
allow create: if !exists(/databases/$(database)/merchants/$(request.auth.uid));
}
}
}

Firebase Storage security rules - read condition not working

Regardless what I put in the read condition, I able to read the files
For example:
service firebase.storage {
match <firebase-storage-url> {
match /{userId}/{allPaths=**}{
allow read: if '1'== '2';
allow write: if true
}
}
}
Although 1 not equal 2 I able to read firebase storage files. How it can happens?

Resources