Firebase customised rules [duplicate] - android

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"
}
}
}
}

Related

Firebase permission denied when attempting to load only records tagged as "public"

My rules look like this:
{
"rules": {
"userShaders": {
"$uid": {
"shaders": {
".write": "auth.uid === $uid",
".read": "auth.uid === $uid || data.child('public').val() == true"
}
}
}
}
}
My data looks like this:
userShaders
8v4N3yLlXAU1cpRiaDj5kkDQaKn1
shaders
myShaderName
attr_1: ""
attr_2: ""
public: false
I am not logged in as this user and am attempting to query their data. I expect to succesfully get back 0 records because they have none marked as public.
However, I'm getting a permission denied error.
My query looks like this:
val shaderRef = db
.getReference("userShaders/${uid}/shaders")
.orderByChild("public")
.equalTo(true);
shaderRef.get().addOnSuccessListener {
// do something with the data
}
To summarize, I am trying to query for only public data, while simultaneously making a rule that non-public data is impossible to fetch by other users. I want to write a query such that I may receive 0 or many records back, but never a permission denied error.
The most important thing to realize is that Firebase security rules don't filer data. Instead they merely check that you're only requesting data you are authorized for.
Your code already queries only for the public data, so you need to validate that query in your rules with something like:
"shaders": {
".read": "query.orderByChild === 'public' &&
query.equalTo === true"
}
Even with that you will still need separate read operations for the shared that this user created and all public shaders, as there's no way to express that OR condition in a single query.
Well, I ended up just separating my data into separate public and private sections in Firebase like this:
"userShaders": {
"$uid": {
"shaders": {
"public": {
".write": "auth.uid === $uid",
".read": "true"
},
"private": {
".write": "auth.uid === $uid",
".read": "auth.uid === $uid"
},
}
}
}
It's more work, because when I update the isPrivate boolean I have to make sure to delete it from the other section, but it does get the job done.
Open to other answers if there's another way to do this.

Firebase Realtime Chat Rules

I made a chat application using firebase realtime database. Users can send private messages to each other. How should the rules part be? I keep getting emails from Firebase that the rules are not reliable.
This is my firebase Collections:
This is my firebase Rules:
{
"rules": {
".read": "auth.uid!=null",
".write": "auth.uid!=null",
}
}
Only an authenticated admin user can read and write their own admin-user data:
{
"rules": {
"admin-users": {
"$userId": {
".read" : "auth.uid === $userId",
".write": "auth.uid === $userId"
}
}
}
}
Or:
{
"rules": {
"admin-users": {
"$user": {
".read" : "data.child('userUid').val() === auth.uid",
".write": "data.child('userUid').val() === auth.uid"
}
}
}
}
An authenticated user can read all data under Users.
An authenticated user can can only update their own data except the 'userUid' field. Can only update the 'userUid' field if it is a new document creation ('!data.exists()') e.g when it is a signup/register.
An authenticated admin can read and write all the data in Users including the 'userUid' field.
{
"rules": {
"users": {
".read": "auth !== null",
"$userId": {
"userId": {
".write": "root.child('admin-users').child(auth.uid).exists() || !data.exists()"
},
"$other_fields": {
".write": "$userId === auth.uid || root.child('admin-users').child(auth.uid).exists()"
}
}
}
}}
Only Admins can read and write everything in under Chats
Authenticated users can read chat messages in which their userUid matches either 'senderId' or 'receiverId'
Authenticated users can write/update a message only if their userUid matches 'senderId'.
{
"rules": {
"chats": {
".read": "root.child('admin-users').hasChild(auth.uid)",
".write": "root.child('admin-users').hasChild(auth.uid)",
"$chat": {
"$message": {
".read": "auth !== null && data.child('receiverId').val() === auth.uid || data.child('senderId').val() === auth.uid",
".write": "auth !== null && !data.exists() || data.child('senderId').val() === auth.uid"
}
}
}
}}
These sample rules are just to give guidance on how security rules work. You can create different rules that can work as well with your use case. See link for more details https://firebase.google.com/docs/rules/insecure-rules
https://firebase.google.com/docs/database/security/core-syntax

how can I read and write as an admin even if the rules set to false in Firebase Realtime Database

As an admin I am trying to get the users data so that I could 'read' and 'write' even through the rules of the firebase 'read','write' set to be false.
users
|
"uid"
|-firstname: "xyz"
|-lastname: "xyz"
|-email: "xyz#gmail.com"
Here, is my rules
"users": {
"$uid": {
".read": "auth != null && $uid === auth.uid",
".write": "auth != null && $uid === auth.uid"
}
}
when I am retrieving users data from firebase using FirebaseRecyclerOptions, users data display only when I set rules read and write to true but I want even if the rules set to be false through admin I could read and write. Is this possible
FirebaseRecyclerOptions<Model> options =
new FirebaseRecyclerOptions.Builder<Model>()
.setQuery(FirebaseDatabase.getInstance().getReference("Users"), Model.class)
.build();
Add a boolean to your user object and call it admin, set it false for all the users except you.
Now copy that to your firebasee rules:
"users": {
".read":
"root.child('users').child($uid).child('Admin').val()",
".write":"
"root.child('users').child($uid).child('Admin').val()"
,"$uid": {
".read": "auth != null && $uid === auth.uid",
".write": "auth != null && $uid === auth.uid"
}
}
}
}
Just like the isActivated boolean I have in my Users you can create a boolean called isAdmin.Add it to your admin class , give it set and get methods in your class.When you upload it to firebase you can read and write this data.
Then let your firebase rules to do the job.
It depends on what "as an admin" means to you. If the application administrator is only you for example, you could simply hard-code your own UID in the security rules:
"users": {
".read": "auth.uid === 'yourOwnUid'"
"$uid": {
".read": "auth != null && ($uid === auth.uid",
".write": "auth != null && $uid === auth.uid"
}
}
This grants the one user access to all of /users, while everyone else can only read their own child node under that path.
Hard-coding the UID like this works great during development, as you're likely the only administrator. Later on when closer to release, you'll want to store a list of administrator UIDs in the database:
"Admins": {
"yourOwnUid": true,
"otherUid": true
}
You can then check in your rules whether the current user's UID exists in this path with:
"users": {
".read": "root.child('Admins').child(auth.uid).exists()"
...
}

Firebase Security Permissions

I'm having trouble with a user who is trying to access someone else's email. I'm getting E/ContactsFragment.java: Finding email failed. DatabaseError: Permission denied. It's also worth noting that the email gets checked before going into the database and also the email that I inputted is the same as the one in the database.
Basically, what I'm trying to do is for user1 to find the user2's email. From there, I will do something with the email.
{
"rules": {
"users":{
".indexOn": ["email"],
"$uid":{
".read": "auth !== null",
"email":{
".write": "auth !== null && $uid === auth.uid",
".validate": "newData.isString()"
}
}
}
}
}
Here's my data structure:
Here's my code that is trying to access the email:
final String TAG = "ContactsFragment.java";
FirebaseDatabase.getInstance().getReference().child("users").orderByChild("email").equalTo(email).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// some code
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.e(TAG,"Finding email failed. " + databaseError);
}
});
How can I fix it? Am I missing something important?
Currently, your rules are only granting read access to children under the /users node, but not the /users node itself, which will deny them from querying the list.
If you move your .read rule outside of the $uid child, it will allow users to query the the /users list node:
{
"rules": {
"users":{
".indexOn": ["email"],
".read": "auth !== null",
"$uid":{
"email":{
".write": "auth !== null && $uid === auth.uid",
".validate": "newData.isString()"
}
}
}
}
}
Queries are attached to the list node rather than child nodes under the list, so the .read permission needs to be granted on the list itself. For example, your query is being attached to the /users node:
FirebaseDatabase.getInstance().getReference().child("users").orderByChild("email").equalTo(email)[...]
This is because rules are applied in an atomic manner, and therefore a .read rule at a deep path will not allow access to a shallower path.

Firebase database rules. Allow when wildcard's child === auth.uid

Structure:
{
"accounts" : {
"JGeRgwAUBM..." : {
"active" : true,
"created" : 1468406951438,
"key" : "JGeRgwAUBM..."
}
}
Rules:
{
"rules": {
".read": false,
".write": false,
"accounts": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid"
}
}
}
}
Goal:
Instead of using the auth.uid as key for the data, I would rather prefer to use the generated key from push().getKey()
{
"accounts" : {
"theKeyIGetFrom: push().getKey()" : {
"active" : true,
"created" : 1468406951438,
"auth_uid" : "JGeRgwAUBM..."
}
}
Looking for the rule set for something like this:
{
"rules": {
".read": false,
".write": false,
"accounts": {
"$key": {
".read": "$key.auth_uid === auth.uid",
".write": "$key.auth_uid === auth.uid"
}
}
}
}
Answering your question, you will be able to achieve the rules you want with the rules bellow.
{
"rules": {
"accounts": {
"$key": {
".read": "data.child(auth_uid).val() === auth.uid",
".write": "data.child(auth_uid).val() === auth.uid"
}
}
}
}
But keep in mind that, to retrieve and write data, you would need to already know the $key's since you wont be able to get any data by accessing /accounts. Thats beacause you don't have read/write rules to access the specific /accounts branch.
If it was in my hands I would prefer going with your current /accounts/uid solution. You would always be easly able to retrieve users data since you could get the current authenticated user uid.

Categories

Resources