Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Firebase: set security rules depending on user roles

Tags:

I would like to implement "write" security rules in Firebase depending on users roles.
My data structure is like this:

+ myapp   + users     + john       + email: "[email protected]"       + roles         + administrator: true     + mary       + email: "[email protected]"       + roles         + moderator: true     + ...   + documents     + -JVmo6wZM35ZQr0K9tJu       + ...     + -JVr56hVTZxlAI5AgUaS       + ...     + ... 

I want - for example - that only administrator users can write documents.
These are the rules I've come to:

{   "rules": {     ".read": true,     "$documents": {       ".write": "root.child('users').child(auth.uid).child('roles').child('administrator').val() === true"     }   } } 

But it doesn't work: not even administrator users can write documents...
Is my understanding of Firebase security rules totally flawed?

UPDATE: Just before Jenny's answer (believe it or not :-), I did implement the exact same solution he provides (of course based on Kato's comment).
Though, making some tests, I could not let the rules structure

{   "rules": {     "documents" {       "$document" {         ".read": "root.child('users').child(auth.uid).child('roles').child('documents').child('read').val() === true",         ".write": "root.child('users').child(auth.uid).child('roles').child('documents').child('write').val() === true"       }     }   } } 

work... I always got a warning like this:

"FIREBASE WARNING: on() or once() for /documents failed: Error: permission_denied: Client doesn't have permission to access the desired data. " 

So I came up with this structure, instead:

{   "rules": {     "documents" {       ".read": "root.child('users').child(auth.uid).child('roles').child('documents').child('read').val() === true",       ".write": "root.child('users').child(auth.uid).child('roles').child('documents').child('write').val() === true"     }   } } 

Which indeed works, for me: if I set a roles/customers/read node to true on a user he can read all documents, otherwise he can't (and the same for write).

My doubts now are:

  • why I could not let the first rule (as suggested by Kato) work?
  • do you see any possible security hole in a rule like the one I did came up with?
  • are rules using "$" variables necessary/useful even if you don't have to allow/deny the readability/writeability of each single document based on it's key, but you just want to allow/deny the readability/writeability of a node as a whole?
like image 666
MarcoS Avatar asked Sep 03 '14 09:09

MarcoS


People also ask

What are the different roles that can be assigned to a user in Firebase?

In the Firebase console, you can assign any of the basic roles (Owner, Editor, Viewer), the Firebase Admin/Viewer roles, or any of the Firebase predefined product-category roles.


1 Answers

Based on the names of your user records, they don't match auth.uid, which is probably a Simple Login id, such as twitter:2544215.

Start by adjusting your users to be stored by their Simple Login uid:

+ myapp   + users     + twitter:2544215       + email: "[email protected]"       + roles         + administrator: true     + twitter:2544216       + email: "[email protected]"       + roles         + moderator: true     + ...   + documents     + -JVmo6wZM35ZQr0K9tJu       + ...     + -JVr56hVTZxlAI5AgUaS       + ...     + ... 

Next, add a security rule so that administrators can access documents. You have a couple options here, depending on your specific use case.

  1. To give administrators write access to contents of each document:

    {   "rules": {     "documents": {       "$documents": {         ".write": "root.child('users').child(auth.uid).child('roles').child('administrator').val() === true"       }     }   } } 
  2. Or, alternatively, give them access to the whole collection:

    {   "rules": {     "documents": {       ".write": "root.child('users').child(auth.uid).child('roles').child('administrator').val() === true"     }   } } 

The difference between these two being the $documents variable that moves the security rule one step further into the hierarchy.

(This was mostly just an aggregation of comments by @Kato into answer form)

like image 79
mimming Avatar answered Oct 13 '22 22:10

mimming