Siva
Siva

Reputation: 45

Firestore role based authentication not working as expected

Trying to enable security roles for Android firestore app

following this document: https://firebase.google.com/docs/firestore/solutions/role-based-access

    service cloud.firestore {
   match /databases/{database}/documents {
     match /Dairy/{dairyId} {
        function isSignedIn() {
          return request.auth != null;
        }

        function getRole() {
          //both of the below statements are not working
          //return resource.data.roles[request.auth.uid];
          return get(/databases/$(database)/documents/Dairy/$(dairyId)).data.roles[request.auth.uid];

        }

        function isOneOfRoles(array) {
          return isSignedIn() && (getRole() in array);
        }

        function isValidNewDoc() {
          return resource.data == null
            && request.resource.data.roles[request.auth.uid] == 'OWNER';
        }

        allow write: if isValidNewDoc() || isOneOfRoles(['OWNER']);

        allow read: if isOneOfRoles(['OWNER', 'ADMIN']);

        match /{document=**} {
          allow read: if isOneOfRoles(['OWNER', 'ADMIN']);
        }
     }

     match /DairyOwnerProfile/{user_profile} {
        function isUserSignedIn() {
          return request.auth != null;
        }

        function isValidNewProfile() {
          // Valid if Dairy does not exist and the new Dairy has the correct owner.
          return isUserSignedIn() && resource.data == null
            && request.resource.data.uid == request.auth.uid;
        }
        allow read, write: if isUserSignedIn() && (user_profile == request.auth.uid || isValidNewProfile());
     }
   }
}

Domain model is

Create document is working for below document model with path /databases/{database}/documents/DairyOwnerProfile/{USER_ID}

public class DairyOwnerProfile {
    private String uid;
    private String name;
    private String phone;
    private String dairyId;
}

But create and read not working for Dairy collection and all its sub collections Dairy model below store in path /databases/{database}/documents/Dairy/{dairyId}

public class Dairy {

    private String id;
    private String dairyName;
    private boolean active;
    private String address;
    private Date updateTime;
    private Map<String, Role> roles;
}
public enum Role {
    OWNER, FARMER, ADMIN, MANAGER
}

trying since few days, but couldn't figure-out what's wrong with above firestore security rule

Tried isValidNewDoc() method with below variants

//Not working
function isValidNewDoc() {
    return resource.data == null
            && request.resource.data.roles[request.auth.uid] == 'OWNER';
}

//Not working
function isValidNewDoc() {
          return resource.data == null
            && request.resource.data == null;
}

//Not working
function isValidNewDoc() {
  return resource.data == null
    && request.resource.data != null;
}


//Not working
function isValidNewDoc() {
  return resource.data == null;
}


//working
function isValidNewDoc() {
   return isSignedIn();
}

//Working, Create and update both worked (Sub collection read/write failed)
//but this allows overwriting existing document by another user, adding "resource.data == null" with && causing it to fail
function isValidNewDoc() {
  return request.resource.data.roles[request.auth.uid] == 'OWNER';
}

This is the error got in Android studio console com.google.firebase.firestore.FirebaseFirestoreException: PERMISSION_DENIED: Missing or insufficient permissions.

I am doing something wrong with the rule or hierarchy of data is the issue

Have many sub collections under Dairy collection, read/write on those sub collections also failing

this issue blocking my first version of android App release, please point me in right direction to find and fix the issue

Note: this is my first experience with android and firestore

please let me know if more information is required.

Sample Data stored in Forestore without security rule

Upvotes: 1

Views: 914

Answers (1)

Juan Lara
Juan Lara

Reputation: 6854

Use resource == null instead of resource.data == null:

function isValidNewDoc() {
      return resource == null
        && request.resource.data.roles[request.auth.uid] == 'OWNER';
    }

Upvotes: 3

Related Questions