I'm making the security rules for Firebase Firestore, but I can't reference the map inside another map, as shown in the image below. I need to reference the type and whether it is active.
Document with Map inside another Map:
I tried to use the following command:
get (/databases/$(database)/documents/after_sales/{after_salesUID}/users_type).data.type in ['admin', 'approver'] &&
get (/databases/$(database)/documents/after_sales/{after_salesUID} /users_type.data.active == true;
When trying to test access to the document, I receive the following error message "Error while running the simulation: An unknown error has occurred".
I am unsure of your complete database structure but I created a collection named 'companies' and a document in it.
These rules worked for me:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /companies/{companyID} {
allow read: if get(/databases/$(database)/documents/companies/$(companyID)).data.user_types[request.auth.uid].admin == true;
}
}
}
I am not sure which location you are trying to access in your db but that's how you can read values in nested maps. Apparently it's after_sales ID in your case that I made user UID in my test.
Related
Once again, I'm trying to set up a database on firestore. It's a very simple one which would store emails list from my landing page. But I can't getting work.
The Javascript Console, throw this error:
InvalidStateError: A mutation operation was attempted on a database that did not allow mutations."
This is my security rules:
rules_version = '2';
service cloud.firestore {
match /databases/{databases}/documents {
match /emailList/{list} {
allow create: if true;
allow update: if true;
allow delete: if false;
}
}
}
It might be something easy, but this project already carried out with my patience
Make sure your FireFox is setup correctly.
For IndexedDB to work you need history turned on.
Options > 'FireFox will Remember history'
I'm getting "Missing or insufficient permissions" when I have a security rule that checks for a subfield. For example:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /entries/{id} {
allow read: if resource.data.business.id == "hh7AvLpTbFGRmCGodLV4";
}
}
}
The only document I have in entries collection:
{
"batchId": "bnzVkufp9mM6yGokUYug",
"business": {
"id": "hh7AvLpTbFGRmCGodLV4"
}
}
My query:
firestore()
.collection('entries')
.where('batchId', '==', 'bnzVkufp9mM6yGokUYug')
If I changed the security rule to allow read: if resource.data.batchId == "bnzVkufp9mM6yGokUYug", it works fine. Is there something that I missed?
Note:
The rule works fine when tested using "Rules playground" in Firebase Console, but failed in production.
I have another project that works fine with rules that check for subfield. However, for 2 new firebase projects that I created, it doesn't work.
I found a related problem from 2017 (Firestore security rules, nested field). Could this be the same issue re-appearing again?
One important thing to realize is that security rules are not filters.
Right now, your rule is saying that all queries on the "entries" collection must specify a filter for business.id that equals "hh7AvLpTbFGRmCGodLV4". The query you have now does not have that filter, so the rule is always going to reject it. If you want the query to work with those rules, it will have to be like this:
firestore()
.collection('entries')
.where('batchId', '==', 'bnzVkufp9mM6yGokUYug')
.where('business.id', '==', 'hh7AvLpTbFGRmCGodLV4')
I'm trying to secure my Firebase (google cloud storage) files based on user data. In firestore, I use a rule based on getting database content (look up the uid in users table and match a field) and that's working fine. I'm trying to use the same kind of rules in firebase storage but in the simulator I get Error: simulator.rules line [12], column [17]. Function not found error: Name: [get].; Error: Invalid argument provided to call. Function: [get], Argument: ["||invalid_argument||"]. My rules look like this:
match /b/{bucket}/o {
function isAuth() {
return request.auth != null && request.auth.uid != null
}
function isAdmin() {
return isAuth() &&
"admin" in get(/databases/$(database)/documents/users/$(request.auth.uid)).data.roles;
}
function clientMatch(client) { // expects user's "client" field to be ID of client
return isAuth() &&
client == get(/databases/$(database)/documents/users/$(request.auth.uid)).data.client;
}
match /P/Clients/{client}/{allPaths=**} {
allow read, write: if isAdmin() || clientMatch(client);
}
}
}
Line 12 is the one beginning client == get, in clientMatch().
I haven't been able to tell whether these functions are only supported for Firestore (db) rules, or whether they should work for storage as well.
If this doesn't work, what are my options? How do people look up user data for Firebase storage security?
You currently can't reference Firestore documents in Storage rules. If you would like to see that as a feature of Storage rules, please file a feature request.
Consider instead using a Cloud Functions storage trigger to perform some additional checks after the file is uploaded, and remove the file if you find that it's not valid.
This is now possible with cross-service security rules. You have to use firestore. namespace before the get() and exists() functions as shown below:
function isAdmin() {
return isAuth() && "admin" in firestore.get(/databases/$(database)/documents/users/$(request.auth.uid)).data.roles;
}
Do note that you'll be charged for read operations just like in Firestore security rules.
Writing rules for Firestore it seems that custom variables are not working.
Did anyone know why or have seen similar behaviour?
Using the below I got access denied although the uid is in the array of admin.
service cloud.firestore {
match /databases/{database}/documents {
match /conferences/{confid} {
allow read,write: if request.auth.uid in get(/databases/$(database)/documents/conferences/$(confid)).data.admin;
}
}
}
Simulator is giving the below error:
Function [get] called with path to nonexistent resource: /databases/%28default%29/documents/conferences/%7Bconfid%7D
Also testing this on a real devices I got access denied.
If however I use the ID of the document like below it works and access is granted.
service cloud.firestore {
match /databases/{database}/documents {
match /conferences/{confid} {
allow read,write: if request.auth.uid in get(/databases/$(database)/documents/conferences/ySWLb8NSTj9sur6n2CbS).data.admin;
}
}
}
Obviously I can't hardcode this for each and every ID.
UPDATE
Apart from logging the case with support I have done some further testing.
On the below the simulator is now granting access.
service cloud.firestore {
match /databases/{database}/documents {
match /conferences/{confID}{
allow read, write: if request.auth.uid in get(/databases/$(database)/documents/conferences/$(confID)/permissions/permission).data.users;
}
}
}
For reference I use the below to query from my web-application:
db.collection("conferences")
.get()
.then(query => {
console.log("SUCCESS!!!")
query.forEach(function(doc) {
// doc.data() is never undefined for query doc snapshots
console.log(doc.id, " => ", doc.data());
});
}).catch((e) => {
console.log(e)
})
This is the log from the browser:
FirebaseError: Missing or insufficient permissions.
at new FirestoreError (webpack-internal:///./node_modules/#firebase/firestore/dist/index.cjs.js:352:28)
at JsonProtoSerializer.fromRpcStatus (webpack-internal:///./node_modules/#firebase/firestore/dist/index.cjs.js:5649:16)
at JsonProtoSerializer.fromWatchChange (webpack-internal:///./node_modules/#firebase/firestore/dist/index.cjs.js:6146:44)
at PersistentListenStream.onMessage (webpack-internal:///./node_modules/#firebase/firestore/dist/index.cjs.js:14350:43)
at eval (webpack-internal:///./node_modules/#firebase/firestore/dist/index.cjs.js:14279:30)
at eval (webpack-internal:///./node_modules/#firebase/firestore/dist/index.cjs.js:14319:28)
at eval (webpack-internal:///./node_modules/#firebase/firestore/dist/index.cjs.js:7411:20)
I am using the latest Firebase package 5.8.3.
If I change the above rule to something simple like below it got access as long as I am logged in with a user:
service cloud.firestore {
match /databases/{database}/documents {
match /conferences/{confID}{
allow read, write: if request.auth.uid != null
}
}
}
This even confuses me more. Is this because the rule is more complex and it takes too long to get this verified and gives back access denied?
Update-2
Quickly tested this in a mobile app via Flutter. Same result. Access denied with this ruleset.
service cloud.firestore {
match /databases/{database}/documents {
match /conferences/{confID}{
allow read, write: if request.auth.uid in get(/databases/$(database)/documents/conferences/$(confID)/permissions/permission).data.users;
}
}
}
I think my problem was the query's don't match security rules. If you would only access a single specific document it would work but if you query multiple documents in a collection you got blocked by the security rules.
I had two options. Restructure my data so that a single document will hold all the data I need or redesign security rules to match query's.
In the end I have attached to each document an indentifier like the UID to make sure query's match the security rules.
One solution would be to put the users with permissions into an array in the conference document instead,
so request.resource.data.permissions
So, instead of this:
get(/databases/$(database)/documents/conferences/$(confID)/permissions/permission).data.users
use this:
request.resource.data.permissions
This wouldn't solve the get() problem, but it would eliminate the need for a get() call, which could save you 15% or more on your quota.
I posted a question about this yesterday but I'm creating a new one with more details.
Firestore .setData is blocked by update rule not create
I've run the simulator and the rules work there. Also when I create the document and change setData in the swift code to update the code works. It appears to only fail when creating the document. But the catch is that when I remove the update rule or simply change it to allow update: if false; the setData (or seen as create by the rules) executes properly. I have no clue whats going on nor do I know of any tools for getting a better insight.
match /users_real/{userID} {
allow create: if true;
allow read: if isOwner(userID);
allow update: if (request.writeFields.size() == 1);
}
set data:
self.docRef.collection("users_real").document("adfadsf").setData(post) { (error) in
if let error = error {
print("He dead!: \(error.localizedDescription)")
}
else {
print("it worked, for now")
}
}
Firebase Support confirms that there is a bug related to the evaluation of request.writeFields.size(). No estimate was given of when it will be fixed.
The existence of the bug can be demonstrated with the following rules:
service cloud.firestore {
match /databases/{database}/documents {
match /cities/{city} {
// This should always evaluate to true, but does not.
allow create: if (request.writeFields.size() == 1) || (request.writeFields.size() != 1);
allow update: if true;
}
}
}
Although the create rule should always evaluate to true, an attempt to create a city fails with Permission Denied. It seems that the problem with request.writeFields affects not only the rule in which it appears, but also other rules for the path. For the rules shown above, an attempt to update an existing city also fails with Permission Denied.