0

I'm using the Objective-C API for Firebase to fetch data and am able to do so when my security rules (set via the Firebase online dashboard) don't utilize any wildcard paths, e.g.:

{
  "rules": {
    "user" : {
      ".read" : true,
      ".write" : true
    },
    "users" : {
      ".read" : true,
      ".write" : false
    }
  }
}

But when I try enact what should be identical security rules using wildcard paths and fetch objects, the completion handler never executes, e.g.:

{
  "rules": {
    "user" : {
      ".read" : true,
      ".write" : true
    },
    "users" : {
      "$userId" : {
        ".read" : true,
        ".write" : false
      }
    }
  }
}

I used the Firebase documentation at the following URL and can't figure out what I'm doing wrong: https://www.firebase.com/docs/security/quickstart.html

I don't think the problem is Objective-C specific, but just to be thorough I'm using the method -[FQuery observeSingleEventOfType:FEventTypeValue withBlock:^(FDataSnapshot *snapshot) { }] to fetch my data.


Update: Here's the output of po query for the particularly FQuery I'm using to debug:

(/users {
    ep = 0;
    i = hidden;
    sp = 0;
})

Update 2: Here's my data structure, in case that is relevant:

{
  "user" : {
    "HhMeloQDY4" : {
      "info" : {
        "name" : "Anita Borg"
      }
    },
    "QxnjCNOj3H" : {
      "info" : {
        "name" : "Charles Babbage"
      }
    },
    "zeNalC4ktf" : {
      "info" : {
        "name" : "Beyoncé"
      }
    }
  },
  "users" : {
    "HhMeloQDY4" : {
      "hidden" : false
    },
    "QxnjCNOj3H" : {
      "hidden" : false
    },
    "zeNalC4ktf" : {
      "hidden" : true
    }
  }
}

Update 3: Here's my Objective-C code for how I create my FQuery object:

Firebase *firebase = [[Firebase alloc] initWithUrl:@"https://<my-app-name>.firebaseio.com"];
[[firebase childByAppendingPath:@".info/connected"] observeEventType:FEventTypeValue withBlock:^(FDataSnapshot *snapshot) {
    BOOL isConnected = [snapshot.value boolValue];
    // broadcast whether app is connected to Firebase
}];
Firebase *directory = [firebase childByAppendingPath:@"users"];
FQuery *query = [directory queryOrderedByChild:@"hidden"];
query = [query queryEqualToValue:value];
[query observeSingleEventOfType:FEventTypeValue withBlock:^(FDataSnapshot *snapshot) {
    // data successfully retrieved from Firebase
}];
Ken M. Haggerty
  • 24,902
  • 5
  • 28
  • 37

1 Answers1

2

You have added read access at the path /users/specific_user_id/ but you're attempting to read at the path /users/, which has no read access allowed.

You'll need to provide access to the path you are attempting to read, not just a subset of its children. See security rules are not filters.

Edit: Just adding some ObjC code to clarify

With the query presented

Firebase *directory = [self.myRootRef childByAppendingPath:@"users"];

you are querying the nodes directly inside the users node. However, if you review the structure, what's inside the users node is not queryable as there are no rules directly under /users, where I have commented.

"users" : {
  //OH NOES! There are no rules here!
  "$userId" : {
     ".read" : true,
     ".write" : false
   }

Your rules are inside the $userId, which represents and applies to that parent only

"$userId" : {
    //these rules *only* apply inside each userId.
    ".read" : true,
    ".write" : false
}

So with your structure, this query would work and it would query the content inside users/HhMeloQDY4 only.

Firebase *directory = [self.myRootRef childByAppendingPath:@"users/HhMeloQDY4"];

So the end result is that you need to assign the rules directly under the /users node that will allow you to query for content within it's child nodes.

"users" : {
  ".read" : true,
  ".write" : false
  "$userId" : {
  }

This would allow you to read each node under users node ($userId and it's children) but not write to them.

Jay
  • 34,438
  • 18
  • 52
  • 81
Kato
  • 40,352
  • 6
  • 119
  • 149
  • I understand that security rules are not filters, but am confused by where I am attempting to read from `/users//` rather than `/users/`, and I think that in both of my security rules I am explicitly allowing read access via `".read" : true`. Can you elaborate? – Ken M. Haggerty Mar 16 '16 at 14:59
  • I've added an update to the question that includes my data structure, in case that clarifies anything. I'm still confused as to how my question is a duplicate. – Ken M. Haggerty Mar 16 '16 at 20:44
  • @KenM.Haggerty Can you update your question with the actual ObjC code (be brief please) you are using to query/observe the node in question. Kato's answer is correct but seeing your code (which may be malformed) may help us get you going in a better direction and help you get the rules straightened out. – Jay Mar 16 '16 at 23:01
  • @KenM.Haggerty you're trying to use Firebase security rules to filter data, which is simply not possible. To be able to query `/users` you must have read access to `/users`, which your rules don't allow. – Frank van Puffelen Mar 16 '16 at 23:16
  • @FrankvanPuffelen Hmm. I would like to provide full read access to `/users` and am explicitly *not* trying to filter using security rules by setting `".read" : true` under `$userId`, but I must be misunderstanding something about how wildcard path rules work. – Ken M. Haggerty Mar 17 '16 at 14:42
  • @Jay Done! Hope this helps. – Ken M. Haggerty Mar 17 '16 at 14:59
  • @KenM.Haggerty I added some content to the answer that may clarify it in an ObjC way. The question is kind of a duplicate but if you are just getting started with rules, trying to decipher the info in the question linked can be daunting. However, it was a strong question so once you wrap your brain around the rules a bit, refer back to the other question and answer. – Jay Mar 17 '16 at 18:34