2

As shown below, I want to set up a security rule when a user exists in the "users" node, the user can access the "email" node. Meeting the case, I used builtin exists() function but it doesn't seem working correctly. I've just been getting "Missing or insufficient permissions." Just in case, the user exists under the "users" node for sure.

This issue still occurs when using the get() function, where incorporating this issue(Firestore security rule get() not work)

I'm totally not sure why this rule doesn't work. Would be appreciated if you could give me any help.

service cloud.firestore { 
  match /databases/{database}/documents {
    match /emails/{email} {
      allow read, write: if exists(/databases/$(database)/documents/users/$(request.auth.uid));
    }

    match /users/{userId} {
      allow read, write: if request.auth != null;
    }
  }
}
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
miz-k
  • 965
  • 1
  • 7
  • 9

2 Answers2

1

Did you try use get() instead of exists()? For me this is working

allow read, write: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data != null
dubace
  • 1,601
  • 1
  • 19
  • 27
  • Thank you for your reply. I've tried this, but doesn't work. Except for some specific nodes, get()/exist() works perfectly on my Firestore. But I've been encountering this kind of issue not working as expected... Don't know why. – miz-k Nov 05 '17 at 01:46
0

When you creating signIn options, you also should set "requestIdToken" to options builder to then use it in Firestore Rules like "request.auth.uid":

GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
            .requestIdToken(getString(R.string.default_web_client_id))
            .requestEmail()
            .build()

When you get GoogleSignInAccount(for example) in your activity's onActivityResult, then you have to set it to Firestore singleton instance:

 private fun firebaseAuthWithGoogle(acct: GoogleSignInAccount) {

    AppState.googleAccount = acct

    val mAuth = FirebaseAuth.getInstance()

    val credential = GoogleAuthProvider.getCredential(acct.idToken, null)

    mAuth.signInWithCredential(credential)
            .addOnCompleteListener(this, object : OnCompleteListener<AuthResult> {

                override fun onComplete(@NonNull task: Task<AuthResult>) {

                    when (task.isSuccessful) {

                        true -> // good, continue from this line
                        false -> showError("error sign in with google account")
                    }
                }
            })
}
android51130
  • 1,077
  • 2
  • 9
  • 14
  • Thanks a lot for your precise code. I've created token and "request.auth.uid" is working correctly in the other nodes except this trouble some node. It seems pretty wired... Guess I'm doing something wrong. – miz-k Nov 06 '17 at 04:44
  • From toyr security rule I can say you want to let ANY existing user to access ANY email ? Is it true? – android51130 Nov 07 '17 at 18:49
  • If you will provide the code which you are using to create users in firestore - it will be pretty clear to analyze your rule – android51130 Nov 07 '17 at 18:53
  • You already checked FirebaseAuth.getInstance().currentUser.uid is exists in firestore database? – android51130 Nov 07 '17 at 18:55