I can't figure out why firebase won't let me do this specific write. I feel like I do it the same in the simulator and it works there. Below are my security rules for this section.
"joinRequests" : {
"$clanid": {
"$requesterid" : {
".read" : "$requesterid === auth.uid || root.child('clans/' + $clanid + '/members/' + auth.uid + '/admin').val() === true",
".validate": "newData.hasChildren(['request'])",
"request" : {
".write" : "true",
".validate": "newData.hasChildren(['name', 'message'])",
"name" : {
".validate": "newData.isString()"
},
"message" : {
".validate": "newData.isString()"
},
"$other": {
".validate": false
}
},
"approved" : {
".write" : "root.child('clans/' + $clanid + '/members/' + auth.uid + '/admin').val() === true || ($requesterid === auth.uid && !newData.exists())",
".validate": "newData.isBoolean()"
},
"$other": {
".validate": false
}
}
}
},
In the code for my android app I run these two lines:
dataSnapshot.child("request").getRef().removeValue();
dataSnapshot.child("approved").getRef().removeValue();
What I find weird is that it allows me to remove the "approved" value but not the "request" value. The dataSnapshot is a $requesterid. If I run this line in the simulator and it allows the write:
/joinRequests/QV28VJYG/c1cef959-2dd3-4cab-8649-2b81892cffa6/request
The error I get in android studio is this:
W/RepoOperation: setValue at /joinRequests/QV28VJYG/qRlJt4UIAcRVIe9VXoYVBa68tO43/request failed: DatabaseError: Permission denied
It must be something dumb that I'm doing but I can't imagine what it would be. Any help would be great, Thanks.
newData is a snapshot that represent how data will look like after the operation took place.
newData.hasChildren(['request']) tells firebase to make sure that the request node exists after the operation was executed. Therefore, deletion of this node is prohibited.
Related
My Firebase Database structures is as follows:
{
"accounts" : {
"API_Keys" : {
"Unique ID over here" : {
"api_key" : "None",
}
}
},
"users" : {
"Unique UID over here" : {
"email" : "abc#gmail.com",
"username": "abc",
"age": "18"
},
}
}
I have implemented the following security rules for this.
{
"rules": {
"accounts": {
"API_Keys":{
"$uid":{
".read": "$uid === auth.uid && auth != null ",
".write": "$uid === auth.uid && auth != null"
}
}
},
"users": {
"$uid":{
".read": "$uid === auth.uid && auth != null ",
".write": "$uid === auth.uid && auth != null"
}
}
}
}
The user is going to link in his personal details and also an API Key. No user should be allowed to access any one else's keys somehow. Are the above rules satisfactory for this? Am i missing something?
It looks OK to me, though usually you reverse the order of the test to "auth != null && auth.uid == $uid", as seen in the documentation. You can test for yourself using the rules simulator in the Firebase console.
I am trying to extend a social android aap, currently its rules are public, its data structure is something like this,
{
"posts" : {
"postId1" : {
"authorId" : "abcd",
},
"postId2" : {
"authorId" : "abcd",
},
"postId3" : {
"authorId2" : "wxyz",
},
"postId4" : {
"authorId2" : "wxyz",
}
}
}
I want to allow an authenticated user to create and delete his own post in "posts" node
I tried this,
{
"rules": {
".read":"auth.uid != null",
".write":false,
"questions": {
"$uid": {
".write": "$uid === auth.uid"
}
}
}}
But this does not allow a user to create a post although a user can edit or delete his pre-existing post in "posts" node, it seems that there is no write permission within the "posts" node.
But if i allow write permission for "posts" then due to cascading rules, every authenticated user can access other's data. How can I achieve my desired functionality?
First please see firebase-bolt for writing rules for real time database: https://github.com/firebase/bolt
This tool makes it easy to write rules.
And for your rules here is a sample which will allow only the author to update post:
{
"rules": {
".read": "auth.uid != null",
"posts": {
"$postId": {
".write": "data.val() == null && newData.child('uid').val() == auth.uid || data.val() != null && newData.val() != null && data.child('uid').val() == auth.uid || data.val() != null && newData.val() == null && newData.child('uid').val() == auth.uid"
},
".read": "auth.uid != null"
}
}
}
and the firebase bolt equivalent is below :
path / {
read() {auth.uid != null}
}
path /posts {
read() {auth.uid != null}
/{postId}{
create() { this.uid == auth.uid}
delete() { this.uid == auth.uid}
update() { prior(this.uid) == auth.uid}
}
}
I'm testing Firebase Rules to add more security to the data entry in the Firebase database. I would like to ensure that:
Only Firebase Authenticated "users" can read/write their own account information into "accounts"
only Firebase Authenticated "users" can read/write their own character data into "messages".
For this purpose I have written the following Rules:
{
"rules": {
"account": {
"$uid": {
".read": "auth.uid === $uid",
".write": "auth.uid === $uid"
}
},
"messages": {
"$message_id": {
".read": "auth !== null",
".write": "auth.uid === newData.child('_uid').val() &&
root.child('account').hasChild(auth.uid) === true"
},
}
}
}
The above rules look to be correct, however I get "failed: DatabaseError: Permission denied" on (3) of the "messages" child nodes that I am pushing in for a logged-in user account.
Here is a code snippet of my push to firebase method:
public void saveToFirebase(){
String echo = "";
String _uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
DatabaseReference mCurrentRecord = mFirebaseGame.push();
Log.d(LOG, "User is " + _uid + "\nNew record ID: " + mCurrentRecord.getKey());
gameCharacter.map.put("_uid", _uid);
try{
for(String keys : gameCharacter.map.keySet()){
echo += keys + ":" + gameCharacter.map.get(keys) + "\n";
mCurrentRecord.child(keys).setValue(gameCharacter.map.get(keys));
}
}
catch(Exception e){
error = e.toString();
}
}
And here is the permission-denied error that I am getting:
I cannot follow why I would get permission denied errors only for the child nodes "txtStr, txtCharName and txtEner", while the rest have been successfully pushed to the database.
I hope you can point out if I miss anything in my Firebase Rules structure or anything. Thank you.
The correct answer to this question is as #Frank van Puffelen pointed out, by inserting ALL child node values at once by calling mCurrentRecord.setValue(gameCharacter.map), and not to iterate putting data to setValue() separately.
This is because of the "messages" Rule, which checks for a group of bulk-inserted child nodes in newData.
"messages": {
"$message_id": {
".read": "auth !== null",
".write": "auth.uid === newData.child('_uid').val() &&
root.child('account').hasChild(auth.uid) === true"
},
}
I have below data stored in my firebase:
firebaseRoot
admins
simplelogin:1:
users
simplelogin:1
email: abc#xyz.com
picture: csd
provider: password
uid: simplelogin:1
simplelogin:2
email: abc1#xyz.com
picture: zsd
provider: password
uid: simplelogin:1
and following security rules:
{
"rules": {
"admins": {
".read": "root.child('admins').child(auth.uid).val() === true",
".write": "root.child('admins').child(auth.uid).val() === true"
},
"users": {
"$user":{
".read": "$user === auth.id || root.child('admins').child(auth.uid).val() === true",
".write": "$user === auth.id"
}
}
}
}
My authorization requirements are as below.
admins can be read and added only by the existing admin only. This works.
All users can be read by the admin but should not be able to write user data.
a user can read and update his own user data.
Currently with above rules, I am not able read users data both for admins and logged in users. I get below error message. Please provide your help. Thanks.
var rootRef = new Firebase('https://xxxxx.firebaseio.com/');
var users = rootRef.child('users');
users.on('value', function(snap) {
console.log(snap.key(), snap.val());
}, function(error) {
console.log(error);
});
Error:
Error: permission_denied: Client doesn't have permission to access the desired data.
There are two pitfalls when it comes to Firebase security rules:
rules cascade
This means that once you give somebody (read or write) access on a certain level in the JSON structure, you cannot take that right away anymore on a lower level
rules are not filters
This means that you can only read a node if you have read access to all data in that node. If you only have read access to part of the data, a read operation for the complete data will fail.
In your security rules, you only give permission to read (some of) the children under users. So trying to read the entire users.on('value' will fail.
You can solve this by giving the administrator .read access to the users node.
"users": {
".read": "root.child('admins').child(auth.uid).val() === true",
"$user":{
".read": "$user === auth.id",
".write": "$user === auth.id"
}
}
Here is my working example:
ajsecuretest
roles
simplelogin:1
role: 'admin'
simplelogin:2
role: 'editor'
users
simplelogin:1
email: 'abc#xyz.com'
picture: 'a.jpg'
provider: 'password'
uid: 'simplelogin:1'
simplelogin:2
email: 'xyz#abc.com'
picture: 'b.jpg'
provider: 'password'
uid: 'simplelogin:2'
Rules:
{
"rules": {
"roles":{
".read": "root.child('roles').child(auth.uid).child('role').val() === 'admin'",
".write": "root.child('roles').child(auth.uid).child('role').val() === 'admin'",
"$id" : {
".read" : "$id === auth.uid"
}
},
"users": {
".read" : "root.child('roles').child(auth.uid).child('role').val() === 'admin'",
"$user":{
".read": "$user === auth.uid",
".write": "$user === auth.uid"
}
}
}
}
I am Developing an App where you live in a flat and have roommates, now I'm trying to disable access for all users that don't live in that flat.
Here are my Rules:
{
"rules": {
// no access
".read": "false",
".write": "false",
"Users" : {
"$userID" : {
//read on User Folder for all Users
".read" : "auth != null",
//write only for the user itself
".write" : "$userID === auth.uid"
}
},
"Flat" : {
"$flatID" : {
//Flat (identified through flatID) can only be accessed, if you are a roommate
".read" : "$flatID === root.child('Users').child(auth.uid).child('flatID').val()",
".write" : "$flatID === root.child('Users').child(auth.uid).child('flatID').val()"
}
}
}
}
My Database looks somewhat like this:
root
.Users
..uID
...(data)
...flatID : number
.Flat
..flatID
...(data)
So the flatID of that User is stored in his "folder" at root/Users/uID/flatID, which I try to get here: root.child('Users').child(auth.uid).child('flatID').val() and then I check it with the "folder" flatID.
Now if I try to write any Data into the flat, I don't have the right permission, and I cannot find my error.
The Users/userID rule is working fine
Thanks in advance :)
Edit:
The Data looks like this:
root
_Flat
__1
___name : "asdf"
__2
___(more Flats, for the Problem we only need one)
_Users
__F8XpTmxfIzYzrEY92alBOnx5eTO2 (Auth ID)
___flatID : 1
__nextUserID
___NextUserData
My Java Code to edit the flatname is:
fref.child("Flat").child(flatID).child("name").setValue(flatNameInput.getText().toString())
The flatID is a variable with the flatID for that user