David L
David L

Reputation: 1344

How to configure Firebase Security Rules based on user profile?

I have read the Firebase Security Rules documentation. I have implemented authentication through Firebase (Firebase Auth), but I can't understand how to properly configure security Rules in Firebase based on each user's profile.

Consider the following data structure

{
    "company": {
        "idCompany1": {
            "data": {
                "address": "",
                "companyName": "Company 1",
                "logo": "assets/ApliansLogo.png",
                "nit": "",
                "phone": ""
            },
            "users": {
                "idUser1": {
                    "idCompany": "idCompany1",
                    "idUser": "idUser1",
                    "name": "Charlie",
                    "profile": "Admin"
                },
                "idUser2": {
                    "idCompany": "idCompany1",
                    "idUser": "idUser2",
                    "name": "John",
                    "profile": "Basic"
                },
                "idUser3": {
                    "idCompany": "idCompany1",
                    "idUser": "idUser3",
                    "name": "Jack",
                    "profile": "Basic"
                }
            }
        },
        "idCompany2": {
            "data": {
                "address": "",
                "companyName": "Company 2",
                "logo": "assets/ApliansLogo.png",
                "nit": "",
                "phone": ""
            },
            "users": {
                "idUser3": {
                    "idCompany": "idCompany2",
                    "idUser": "idUser3",
                    "name": "Jack",
                    "profile": "Admin"
                }
            }
        }
    },
    "users": {
        "idUser1": {
            "data": "[email protected]",
            "empresas": {
                "idCompany1": true
            }
        },
        "idUser2": {
            "data": "[email protected]",
            "empresas": {
                "idCompany1": true
            }
        },
        "idUser3": {
            "data": "[email protected]",
            "empresas": {
                "idCompany1": true,
                "idCompany2": true
            }
        }
    }
}

As you can see, Charlie is the Company1's Admin, John has a Basic profile in the same company and Jack can access both companies (Company1 with a Basic profile and Company2 with an Admin profile).

idUserX are Firebase Auth Generated UIDs. idCompanyX are unique IDs generated by Firebase.

The rules I would like to implement are the following:

Rule #1

A user can only read or write information in the companies to which it belongs (users/$idUser/companies/$idCompany == true)

Rule #2

Only the Admin user of a company X can give another user access to his company, for which the idCompanyX: true is created from the App within users/$idUser/companies.

Rule #3

The same user or an Admin are the only ones who can create or modify the user's data within users

I have read Use conditions in Realtime Database Rules, but I am not sure how to do it. The App's alghoritms handles the different roles, but I would like to add the database security layer and I don't know how to do it. At this moment I have only configured:

{
  "rules": {
    "company" : {
      ".read": "auth != null",
      ".write": "auth != null",
        }
      }
    },
    "users" : {
      "$user_id" : {
        ".read": "auth != null",
        ".write": "auth.uid === $user_id"           
  }
}

How can I configure the Firebase security rules based on the authentication and profile of each user?

APPEND:

The way I'm using in Flutter to read data is:

Future<EmpresaDatosModel> cargarEmpresaDatosListado(String idCompany) async {
    
   Query resp = db.child('company/$idCompany/data');
   resp.onChildAdded.forEach((element) {
      final temp = EmpresaDatosModel.fromJson(Map<String,dynamic>.from(element.snapshot.value));
    });
    await resp.once().then((snapshot) {});
    return temp;
}

And to write...

db.child('company/$idCompany/data')
    .update(Map<String, dynamic>.from(_map));

Upvotes: 0

Views: 366

Answers (1)

Frank van Puffelen
Frank van Puffelen

Reputation: 598728

The most important thing to realize is that rules don't filter data.

This mean that this read won't work for your use-case:

Query resp = db.child('company');
resp.onChildAdded.forEach((element) {
  ...

The reason is that this requires that the user has full read permission on /company, which your use-case doesn't allow.


There are usually two options:

  1. Only read a specific child node (e.g. /company/idCompany1) that you need to display in the app. In that case, you can use security rules on /company/$companyId to secure access to that node.
  2. Query for specific child nodes, and then use security rules to validate that query.

I don't think securely querying is possible here, because your use-case depends on reading from /user/... and you can't read from another location in a query.


So it seems that you can't allow your security requirements on your current data structure. That means you likely have to modify you data structure to allow the security model you want. This may mean duplicating data about who is in a company under that company's JSON in the database.

Upvotes: 0

Related Questions