1
votes

I am out of ideas. Hope a fresh eye can help.

I have the following security rules:

function isUser (request, userKey) {
  return request.auth.uid == userKey;
}

function isAuthorized(request){
    return request.auth.uid != null;
}

function isAdmin (request) {
  return root.child('users').child(request.auth.uid).child('isAdmin').val() == true;
}

service cloud.firestore{
    match /databases/{database}/documents {
        match /users/{uid} {
          allow create: if isAuthorized(request) || isAdmin(request);
          allow update: if isUser(request, uid) || isAdmin(request);
        }

        match /userReadable/{objectType}/{uid} {
          allow read: if isUser(request, uid) || isAdmin(request);
          allow write: if isAdmin(request);
        }

        match /userWriteable/{objectType}/{uid} {
          allow read: if isAdmin(request);
          allow write: if isUser(request, uid) || isAdmin(request);
        }

        match /userOwned/{objectType}/{uid} {
          allow read: if isUser(request, uid) || isAdmin(request);
          allow write: if isUser(request, uid) || isAdmin(request);
        }
    }
}

I am setting the document in the following code:

 FirebaseFirestore db = getDB();
        PulseFirebaseModel pulse = new PulseFirebaseModel((PulseModel) object);
        try {
            final DocumentReference doc = db.collection(COLLECTION_USER_WRITABLE)
                    .document(OBJECT_PULSE_SAMPLE)
                    .collection(FirebaseApp.getInstance().getUid())
                    .document();

            doc.set(pulse, SetOptions.merge())
                    .addOnCompleteListener(new OnCompleteListener<Void>() {
                        @Override
                        public void onComplete(@NonNull Task<Void> task) {
                            if(task.isSuccessful()){
                                Log.d(TAG, "Saved sample: " + doc.getId() +"\t"+doc.getPath());
                                onSuccess();
                            }else{
                                onFailure("Could not save Ppg\t"
                                        + task.getException().getMessage()
                                        + "\ndoc Path:" + doc.getPath()
                                        + "\ndoc id: " + doc.getId()
                                        + "\n" + task.getResult());
                            }
                        }
                    });
        } catch (FirebaseApiNotAvailableException e) {
            e.printStackTrace();
        }
    }

I am getting the following Permission denied message:

PERMISSION_DENIED: Missing or insufficient permissions.

doc Path:userWriteable/pulseSample/xxxxx/Bba6pdgfMY98NmsAg1Hl

doc id: Bba6pdgfMY98NmsAg1Hl

this is my UID as registered by FirebaseApp : Uid: xxxxx

the /users/{uid} match works perfectly. And I haven't implemented the other 2 matches. I looked at this question as well as this and this I am signed in and request is sent with the correct request.auth.uid

I simply can't figure it out. Any help will be appreciated.

1
Interesting to see your use of FirebaseApp.getInstance().getUid(). It seems to return the same UID as FirebaseAuth.getInstance().getCurrentUser().getUid(), but it's not in the documentation for FirebaseApp .Bob Snyder
@BobSnyder - At the end of the day, there is the default underlying FirebaseApp which is used in FirebaseAuth. If you look at the getInstance here: firebase.google.com/docs/reference/android/com/google/firebase/…froy001

1 Answers

1
votes

Because you are writing to an auto-generated document ID with document(), your rules need to include a wildcard for the document ID at the end of the path:

match /userWriteable/{objectType}/{uid}/{docId} { // <== added /{docId}
  allow read: if isAdmin(request);
  allow write: if isUser(request, uid) || isAdmin(request);
}