I see a similar issue in Firebase User UID not matching Auth UID,
however mine is slightly different, instead of comparing the key in the path I am trying to compare the value with the auth.uid.
It looks like a bug according to my testing, I tried to log it with Firebase, but Andres replied that comparing the data values is not the way to work the rules.
The data is stored with the Key "id" which has the value 455, if I hard code 455 in the rules, it works fine. If I reference "äuth.id" it fails. I can tell auth.id is failing because if I test with a different function such as hasChild('auth.id') it works fine, I am using this as a workaround for now.This is on the Realtime database with rules v2.
In all tests I am trying to do a read at /test
Data:
test
|-677
| |-jf:"golf"
|-ff:"tennis"
|-id: 455
Auth token :
{
"provider": "anonymous",
"uid": "455"
}
Rule that fails which should have passed :
read: "data.child('id').val()==auth.id"
Rule that works hard coded:
read: "data.child('id').val()==455"
Rules that works indicating the value in auth.id is correct
read: "data.child('id').val==455 && root.child('test').hasChild(auth.uid)"
read: root.child('test').hasChild(auth.uid)"
Related
Can someone help to solve why this firestore rule is not working. Am I missing something simple ??
If you look at the clip below you see my rule for /users/{userId} is allow read: if request.auth.uid == userId; BUT THE SIMULATION FAILS , and my chrome console also confirms "Missing or insufficient permissions"
You can't use wildcards for document locations like that in the simulator. Your "Location" string on the left should identify a single document.
Also, if you want to test authentication, you will need to provide a UID to test with in the "Firebase UID" field.
In your case, you will want to test using the same UID string value in both the document location and the UID fields.
I've a firebase entry like this:
ID111
nconfirmations: 4
Antoher one like this:
ID222
sender_identifier: 111
I want to make a firebase rule that would reference the ID111 content once ID222 is set as the one that is able to read.
I tried with this:
{
"rules": {
"Chat": {
"$uid": {
".read": "auth!=null
&& ($uid.contains(data.child('sender_identifier').val()
&& (root.child('Chat/'ID'+root.child('Chat/$uid/sender_identifier').val()/nconfirmations').val()>=2)) ",
For
$uid.contains(data.child('sender_identifier').val()
I get to do the mentioned limitation, of just ID222 being the one that can read as it has "111", but if I do that, it looks like I can no longer reference any more entries with data, at this point data only refers to the ID222 entry.
I have tried to access the content with a root path, as shown in the rule but it just doesn't fly.
If the rule were to work properly I guess it should give the intended result as 'ID'+root.child('Chat/$uid/sender_identifier').val() should return "ID111".
How could this be done? Is it even possible?
This looks syntactically incorrect:
root.child('Chat/'ID'+root.child('Chat/$uid/sender_identifier').val()/nconfirmations').val()
My best guess is that you're trying to do:
root.child('Chat/ID'+root.child('Chat/$uid/sender_identifier').val()+'/nconfirmations').val()
Which would use the value from path /Chat/ID.../nconfirmations in the validation, with ... being the values read from /Chat/$uid/sender_identifier.
If that's not the problem, please update your question with the minimal complete code that is reading the data, and the actual JSON you're validating against as text. You can get this by clicking the "Export JSON" link in the overflow menu (⠇) on your Firebase Database console.
I am attempting very simple thing and that is matching request.auth.uid to a field value in my transaction documents (like this resource.data.useruid) in Firebase security rule in order to get transactions of a particular logged in user. However, I don't get any documents while querying for them and get an error instead.
This is how the collection looks like - just one document there with useruid field.
The field's value is mapped to the users uid (screenshot taken in the Authentication -> Users tab.
And the rule looks like this
I should get the one document back but every time I query the documents with that user logged in (I am using angularfire2 for those purposes) I get Error: Missing or insufficient permissions.
If I modify the rule condition to return always true or if I only check for truthiness of request.auth.uid I get the query result alright. The funny thing though is that with resource.data involved - eg. checking for value of the amount field in the firebase rule - the condition is never met. I tried to write it like
allow read, write: if resource.data.amount == 3
and got the error again. Seems like I don't get the resource.data Map at all.
I feel like I am missing something obvious, although after reading the guides, it seems alright to me and I am already out of ideas. The debugging capabilities (or lack of) make the whole process very slow.
Could you please explain to me, why I don't get the resource.data Map in the firebase security rule or point me to a place where the problem might be?
You have most probably missed one specific point in the doc: your query fails "because it does not include the same constraints as your security rules". See https://firebase.google.com/docs/firestore/security/rules-query#secure_and_query_documents_based_on_authuid
The following, with your security rules works perfectly:
firebase.auth().signInWithEmailAndPassword("xxxx#xxxx.com", "xxxxx")
.then(function (info) {
db.collection("transactions").where("userid", "==", info.uid).get().then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
console.log(doc.id, " => ", doc.data());
});
});
});
If you remove the where clause, you get the exact error you are getting
How do I check if user on client sided created document with only firebase.firestore.FieldValue.serverTimestamp()?
I have following:
allow create: if request.resource.data.timestamp == ??
What should I have instead of ??. I have tried serverTimestamp() firebase.firestore.FieldValue.serverTimestamp(), now or now() but it doesn't work.
It is possible to do it in Firebase like this:
".validate": "newData.child('timestamp').val() === now"
I am looking for the same solution. Any ideas? Thanks
You can access the current request timestamp in Security Rules using the request.time attribute (docs), which is the Firestore equivalent to the Realtime Databases's now. You'll therefore want something like:
allow create: if request.resource.data.timestamp == request.time;
For serverTimestamp() this should evaluate to true.
You should always validate client input in Security Rules, even if you're using serverTimestamp(). Security Rules doesn't automatically know the server input the value instead of the client, so without this check, a malicious client could create a different created at time.
I am trying to secure my firebase database to allow the creation of new records, but not allow the deletion of existing records. Ultimately, I plan to utilise Firebase authentication in my app as well, and allow users to update existing records if they are the author, but I am trying to get the simple case working first.
However! No matter what I try in the database rules simulator, despite what the documentation seems to suggest, the value of data.exists() seems to always be true. From what I what I can understand from the documentation, the variable data represents a record in the database as it did before an operation took-place. That is to say, for creates, data would not exist, and for updates/deletes, data would refer to a real record that exists in the database. This does not seem to be the case, to the point where I am actually suspecting a bug in Firebase, as when setting the following rules on my database, all write operations are disallowed:
{
"rules": {
".read": true,
".write": "!data.exists()"
}
}
No matter what values I put into the simulator, be it Location or Data. I have even written a small EmberJS app to verify if the Simulator is telling the truth and it too, is denied permission for all write operations.
I really have no idea where to go from here as I am pretty much out of things to try. I tried deleting all records from my database, which lets the simulator think it can perform write operations, but my test app still gets PERMISSION_DENIED, so I don't know what's causing inconsistencies there.
Is my understanding of the predefined data variable correct? If so, why can't I write the rules I want? I have seen snippets literally trying to achieve my "create only, no-delete" rule that seem to line up with my understanding.
Last note: I am trying this in a totally new Firebase project with JUST the rules above, and only ~a few records of junk data laying around my database.
Because you have placed the !data.exists() at the root location of your database, data refers to the entire database. You will only be able to write to the database when it is completely empty.
You indicate that you run your tests with only a few records of junk data laying around my database. Those records will cause data.exists() to be true.
You can achieve your goal by placing the !data.exists() rule in your tree at the specific location where you want to require that no data already exists. This is typically done at a location with a wildcard key, as in the example you linked:
{
"rules": {
// default rules are false if not specified
"posts": {
".read": true, // everyone can read all posts
"$postId": {
// a new post can be created if it does not exist
// existing posts can only be edited by their original "author"
".write": "!data.exists() && newData.exists() || data.child('author').val() == auth.uid",
".validate": "newData.hasChildren(['title', 'author', 'timestamp'])",
}
}
}
}