Firebase Security rules to restrict access on all paths but one?











up vote
0
down vote

favorite













Question:



For the different top-level firestore collections below, how to restrict access to all but one of the paths?




We are building a data schema in Firestore to support a chat app for teachers across multiple schools.



The top-level firestore collections include:




  • /siteAdminUsers

  • /schools

  • /schools/{schoolId}/teachers

  • /schools/{schoolId}/chats


Below is the security rules setup we are trying now - where we check for:




  1. valid user auth

  2. expected value exists in userClaim variable request.auth.token.chatFlatList


However, the read listener for /messages is being blocked.




Error message:



FirebaseError: [code=permission-denied]: Missing or insufficient permissions






service cloud.firestore {
match /databases/{database}/documents {

match /{document=**} {
allow read, write: if false;
}

match /schools/{schoolId}/chats/{discussionId}/messages {
allow write: if false;
allow read: if request.auth != null
&& request.auth.token != null
&& request.auth.token.chatFlatList.val().contains($discussionId);
}
}




Details



We are using cloud functions for all data read/write, so for almost every case we can just block all client access.



The one exception is for the chat discussions, where we need to set a snapshot listener in the mobile client to know when there are new messages.



Sub-collection notes:



At a school, there are discussion sessions for school staff (teachers, admins, etc)



/schools/{schoolId}/chats/{discussionId}


Where each discussion-document contains:




  1. list of participant teacher ids

  2. subcollection for actual messages where each document is an indivual posted message:


/schools/{schoolId}/chats/{discussionId}/messages



User Claim code from Cloud Function



Looking at the cloud function logs, we have verified that the userClaim is being set.



return firebaseAdmin
.auth()
.setCustomUserClaims(
uid, {
chatFlatList: 'id1 id2 id3'
}
);


UPDATE #1



Tried the following variation where rules skip/omit the check on userClaim and auth.token.



However, still same permission error.



service cloud.firestore {
match /databases/{database}/documents {

match /{document=**} {
allow read, write: if false;
}

match /schools/{schoolId}/chats/{discussionId}/messages {
allow write: if false;
allow read: if request.auth != null;
}

}
}









share|improve this question
























  • Have you tried simply allowing all access to messages, just to see if the problem is specifically with the interpretation of chatFlatList?
    – Doug Stevenson
    Nov 13 at 3:26










  • @Doug, post is updated with listing for trying rules setup as you descibe. I was wondering - is it maybe that the main "global rule" match /{document=**} , somehow overwrites the custom rule for messages? I was trying to find something in the docs that explains if at least 1 rule is matched for true, then that is enough .. not sure if I missed that detail, but didn't see it. Thanks
    – Gene Bo
    Nov 13 at 3:39












  • You can reject the entire database like that, then allow specific parts. It's totally doable. You just can't allow some part of the database, then reject it later. Once allowed, always allowed for that user.
    – Doug Stevenson
    Nov 13 at 4:21










  • It sounds like I'm missing something - because I am trying to implement as you describe where first part rejects all, and the next part allows for a specific path. The above rules structure is still rejecting the specific path (listed in update #1) that I am trying to allow read access to. Is there some variation I can maybe try that you know to have worked for you .. either with ordering of the rules, or some different pattern cfg? If I can't figure this out - the back-up plan is to just run a poll thread on client every 15 seconds to call a cloud function asking for new messages. Thank you
    – Gene Bo
    Nov 13 at 17:16










  • Hi @Doug, tho I have a work-around to poll the server, I would like to understand this for security setups likely to be nec. down the road; and also since the poll-server option is not inline w/best practices. Next steps for me: a) Set 100-200 point bounty here to see about finding a solution, b) Look to hire a freelancer versed in security rules. Any suggestions are appreciated, thank you
    – Gene Bo
    Nov 15 at 2:15















up vote
0
down vote

favorite













Question:



For the different top-level firestore collections below, how to restrict access to all but one of the paths?




We are building a data schema in Firestore to support a chat app for teachers across multiple schools.



The top-level firestore collections include:




  • /siteAdminUsers

  • /schools

  • /schools/{schoolId}/teachers

  • /schools/{schoolId}/chats


Below is the security rules setup we are trying now - where we check for:




  1. valid user auth

  2. expected value exists in userClaim variable request.auth.token.chatFlatList


However, the read listener for /messages is being blocked.




Error message:



FirebaseError: [code=permission-denied]: Missing or insufficient permissions






service cloud.firestore {
match /databases/{database}/documents {

match /{document=**} {
allow read, write: if false;
}

match /schools/{schoolId}/chats/{discussionId}/messages {
allow write: if false;
allow read: if request.auth != null
&& request.auth.token != null
&& request.auth.token.chatFlatList.val().contains($discussionId);
}
}




Details



We are using cloud functions for all data read/write, so for almost every case we can just block all client access.



The one exception is for the chat discussions, where we need to set a snapshot listener in the mobile client to know when there are new messages.



Sub-collection notes:



At a school, there are discussion sessions for school staff (teachers, admins, etc)



/schools/{schoolId}/chats/{discussionId}


Where each discussion-document contains:




  1. list of participant teacher ids

  2. subcollection for actual messages where each document is an indivual posted message:


/schools/{schoolId}/chats/{discussionId}/messages



User Claim code from Cloud Function



Looking at the cloud function logs, we have verified that the userClaim is being set.



return firebaseAdmin
.auth()
.setCustomUserClaims(
uid, {
chatFlatList: 'id1 id2 id3'
}
);


UPDATE #1



Tried the following variation where rules skip/omit the check on userClaim and auth.token.



However, still same permission error.



service cloud.firestore {
match /databases/{database}/documents {

match /{document=**} {
allow read, write: if false;
}

match /schools/{schoolId}/chats/{discussionId}/messages {
allow write: if false;
allow read: if request.auth != null;
}

}
}









share|improve this question
























  • Have you tried simply allowing all access to messages, just to see if the problem is specifically with the interpretation of chatFlatList?
    – Doug Stevenson
    Nov 13 at 3:26










  • @Doug, post is updated with listing for trying rules setup as you descibe. I was wondering - is it maybe that the main "global rule" match /{document=**} , somehow overwrites the custom rule for messages? I was trying to find something in the docs that explains if at least 1 rule is matched for true, then that is enough .. not sure if I missed that detail, but didn't see it. Thanks
    – Gene Bo
    Nov 13 at 3:39












  • You can reject the entire database like that, then allow specific parts. It's totally doable. You just can't allow some part of the database, then reject it later. Once allowed, always allowed for that user.
    – Doug Stevenson
    Nov 13 at 4:21










  • It sounds like I'm missing something - because I am trying to implement as you describe where first part rejects all, and the next part allows for a specific path. The above rules structure is still rejecting the specific path (listed in update #1) that I am trying to allow read access to. Is there some variation I can maybe try that you know to have worked for you .. either with ordering of the rules, or some different pattern cfg? If I can't figure this out - the back-up plan is to just run a poll thread on client every 15 seconds to call a cloud function asking for new messages. Thank you
    – Gene Bo
    Nov 13 at 17:16










  • Hi @Doug, tho I have a work-around to poll the server, I would like to understand this for security setups likely to be nec. down the road; and also since the poll-server option is not inline w/best practices. Next steps for me: a) Set 100-200 point bounty here to see about finding a solution, b) Look to hire a freelancer versed in security rules. Any suggestions are appreciated, thank you
    – Gene Bo
    Nov 15 at 2:15













up vote
0
down vote

favorite









up vote
0
down vote

favorite












Question:



For the different top-level firestore collections below, how to restrict access to all but one of the paths?




We are building a data schema in Firestore to support a chat app for teachers across multiple schools.



The top-level firestore collections include:




  • /siteAdminUsers

  • /schools

  • /schools/{schoolId}/teachers

  • /schools/{schoolId}/chats


Below is the security rules setup we are trying now - where we check for:




  1. valid user auth

  2. expected value exists in userClaim variable request.auth.token.chatFlatList


However, the read listener for /messages is being blocked.




Error message:



FirebaseError: [code=permission-denied]: Missing or insufficient permissions






service cloud.firestore {
match /databases/{database}/documents {

match /{document=**} {
allow read, write: if false;
}

match /schools/{schoolId}/chats/{discussionId}/messages {
allow write: if false;
allow read: if request.auth != null
&& request.auth.token != null
&& request.auth.token.chatFlatList.val().contains($discussionId);
}
}




Details



We are using cloud functions for all data read/write, so for almost every case we can just block all client access.



The one exception is for the chat discussions, where we need to set a snapshot listener in the mobile client to know when there are new messages.



Sub-collection notes:



At a school, there are discussion sessions for school staff (teachers, admins, etc)



/schools/{schoolId}/chats/{discussionId}


Where each discussion-document contains:




  1. list of participant teacher ids

  2. subcollection for actual messages where each document is an indivual posted message:


/schools/{schoolId}/chats/{discussionId}/messages



User Claim code from Cloud Function



Looking at the cloud function logs, we have verified that the userClaim is being set.



return firebaseAdmin
.auth()
.setCustomUserClaims(
uid, {
chatFlatList: 'id1 id2 id3'
}
);


UPDATE #1



Tried the following variation where rules skip/omit the check on userClaim and auth.token.



However, still same permission error.



service cloud.firestore {
match /databases/{database}/documents {

match /{document=**} {
allow read, write: if false;
}

match /schools/{schoolId}/chats/{discussionId}/messages {
allow write: if false;
allow read: if request.auth != null;
}

}
}









share|improve this question
















Question:



For the different top-level firestore collections below, how to restrict access to all but one of the paths?




We are building a data schema in Firestore to support a chat app for teachers across multiple schools.



The top-level firestore collections include:




  • /siteAdminUsers

  • /schools

  • /schools/{schoolId}/teachers

  • /schools/{schoolId}/chats


Below is the security rules setup we are trying now - where we check for:




  1. valid user auth

  2. expected value exists in userClaim variable request.auth.token.chatFlatList


However, the read listener for /messages is being blocked.




Error message:



FirebaseError: [code=permission-denied]: Missing or insufficient permissions






service cloud.firestore {
match /databases/{database}/documents {

match /{document=**} {
allow read, write: if false;
}

match /schools/{schoolId}/chats/{discussionId}/messages {
allow write: if false;
allow read: if request.auth != null
&& request.auth.token != null
&& request.auth.token.chatFlatList.val().contains($discussionId);
}
}




Details



We are using cloud functions for all data read/write, so for almost every case we can just block all client access.



The one exception is for the chat discussions, where we need to set a snapshot listener in the mobile client to know when there are new messages.



Sub-collection notes:



At a school, there are discussion sessions for school staff (teachers, admins, etc)



/schools/{schoolId}/chats/{discussionId}


Where each discussion-document contains:




  1. list of participant teacher ids

  2. subcollection for actual messages where each document is an indivual posted message:


/schools/{schoolId}/chats/{discussionId}/messages



User Claim code from Cloud Function



Looking at the cloud function logs, we have verified that the userClaim is being set.



return firebaseAdmin
.auth()
.setCustomUserClaims(
uid, {
chatFlatList: 'id1 id2 id3'
}
);


UPDATE #1



Tried the following variation where rules skip/omit the check on userClaim and auth.token.



However, still same permission error.



service cloud.firestore {
match /databases/{database}/documents {

match /{document=**} {
allow read, write: if false;
}

match /schools/{schoolId}/chats/{discussionId}/messages {
allow write: if false;
allow read: if request.auth != null;
}

}
}






google-cloud-firestore google-cloud-functions firebase-security-rules






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 13 at 3:37

























asked Nov 13 at 3:13









Gene Bo

5,49244192




5,49244192












  • Have you tried simply allowing all access to messages, just to see if the problem is specifically with the interpretation of chatFlatList?
    – Doug Stevenson
    Nov 13 at 3:26










  • @Doug, post is updated with listing for trying rules setup as you descibe. I was wondering - is it maybe that the main "global rule" match /{document=**} , somehow overwrites the custom rule for messages? I was trying to find something in the docs that explains if at least 1 rule is matched for true, then that is enough .. not sure if I missed that detail, but didn't see it. Thanks
    – Gene Bo
    Nov 13 at 3:39












  • You can reject the entire database like that, then allow specific parts. It's totally doable. You just can't allow some part of the database, then reject it later. Once allowed, always allowed for that user.
    – Doug Stevenson
    Nov 13 at 4:21










  • It sounds like I'm missing something - because I am trying to implement as you describe where first part rejects all, and the next part allows for a specific path. The above rules structure is still rejecting the specific path (listed in update #1) that I am trying to allow read access to. Is there some variation I can maybe try that you know to have worked for you .. either with ordering of the rules, or some different pattern cfg? If I can't figure this out - the back-up plan is to just run a poll thread on client every 15 seconds to call a cloud function asking for new messages. Thank you
    – Gene Bo
    Nov 13 at 17:16










  • Hi @Doug, tho I have a work-around to poll the server, I would like to understand this for security setups likely to be nec. down the road; and also since the poll-server option is not inline w/best practices. Next steps for me: a) Set 100-200 point bounty here to see about finding a solution, b) Look to hire a freelancer versed in security rules. Any suggestions are appreciated, thank you
    – Gene Bo
    Nov 15 at 2:15


















  • Have you tried simply allowing all access to messages, just to see if the problem is specifically with the interpretation of chatFlatList?
    – Doug Stevenson
    Nov 13 at 3:26










  • @Doug, post is updated with listing for trying rules setup as you descibe. I was wondering - is it maybe that the main "global rule" match /{document=**} , somehow overwrites the custom rule for messages? I was trying to find something in the docs that explains if at least 1 rule is matched for true, then that is enough .. not sure if I missed that detail, but didn't see it. Thanks
    – Gene Bo
    Nov 13 at 3:39












  • You can reject the entire database like that, then allow specific parts. It's totally doable. You just can't allow some part of the database, then reject it later. Once allowed, always allowed for that user.
    – Doug Stevenson
    Nov 13 at 4:21










  • It sounds like I'm missing something - because I am trying to implement as you describe where first part rejects all, and the next part allows for a specific path. The above rules structure is still rejecting the specific path (listed in update #1) that I am trying to allow read access to. Is there some variation I can maybe try that you know to have worked for you .. either with ordering of the rules, or some different pattern cfg? If I can't figure this out - the back-up plan is to just run a poll thread on client every 15 seconds to call a cloud function asking for new messages. Thank you
    – Gene Bo
    Nov 13 at 17:16










  • Hi @Doug, tho I have a work-around to poll the server, I would like to understand this for security setups likely to be nec. down the road; and also since the poll-server option is not inline w/best practices. Next steps for me: a) Set 100-200 point bounty here to see about finding a solution, b) Look to hire a freelancer versed in security rules. Any suggestions are appreciated, thank you
    – Gene Bo
    Nov 15 at 2:15
















Have you tried simply allowing all access to messages, just to see if the problem is specifically with the interpretation of chatFlatList?
– Doug Stevenson
Nov 13 at 3:26




Have you tried simply allowing all access to messages, just to see if the problem is specifically with the interpretation of chatFlatList?
– Doug Stevenson
Nov 13 at 3:26












@Doug, post is updated with listing for trying rules setup as you descibe. I was wondering - is it maybe that the main "global rule" match /{document=**} , somehow overwrites the custom rule for messages? I was trying to find something in the docs that explains if at least 1 rule is matched for true, then that is enough .. not sure if I missed that detail, but didn't see it. Thanks
– Gene Bo
Nov 13 at 3:39






@Doug, post is updated with listing for trying rules setup as you descibe. I was wondering - is it maybe that the main "global rule" match /{document=**} , somehow overwrites the custom rule for messages? I was trying to find something in the docs that explains if at least 1 rule is matched for true, then that is enough .. not sure if I missed that detail, but didn't see it. Thanks
– Gene Bo
Nov 13 at 3:39














You can reject the entire database like that, then allow specific parts. It's totally doable. You just can't allow some part of the database, then reject it later. Once allowed, always allowed for that user.
– Doug Stevenson
Nov 13 at 4:21




You can reject the entire database like that, then allow specific parts. It's totally doable. You just can't allow some part of the database, then reject it later. Once allowed, always allowed for that user.
– Doug Stevenson
Nov 13 at 4:21












It sounds like I'm missing something - because I am trying to implement as you describe where first part rejects all, and the next part allows for a specific path. The above rules structure is still rejecting the specific path (listed in update #1) that I am trying to allow read access to. Is there some variation I can maybe try that you know to have worked for you .. either with ordering of the rules, or some different pattern cfg? If I can't figure this out - the back-up plan is to just run a poll thread on client every 15 seconds to call a cloud function asking for new messages. Thank you
– Gene Bo
Nov 13 at 17:16




It sounds like I'm missing something - because I am trying to implement as you describe where first part rejects all, and the next part allows for a specific path. The above rules structure is still rejecting the specific path (listed in update #1) that I am trying to allow read access to. Is there some variation I can maybe try that you know to have worked for you .. either with ordering of the rules, or some different pattern cfg? If I can't figure this out - the back-up plan is to just run a poll thread on client every 15 seconds to call a cloud function asking for new messages. Thank you
– Gene Bo
Nov 13 at 17:16












Hi @Doug, tho I have a work-around to poll the server, I would like to understand this for security setups likely to be nec. down the road; and also since the poll-server option is not inline w/best practices. Next steps for me: a) Set 100-200 point bounty here to see about finding a solution, b) Look to hire a freelancer versed in security rules. Any suggestions are appreciated, thank you
– Gene Bo
Nov 15 at 2:15




Hi @Doug, tho I have a work-around to poll the server, I would like to understand this for security setups likely to be nec. down the road; and also since the poll-server option is not inline w/best practices. Next steps for me: a) Set 100-200 point bounty here to see about finding a solution, b) Look to hire a freelancer versed in security rules. Any suggestions are appreciated, thank you
– Gene Bo
Nov 15 at 2:15

















active

oldest

votes











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














 

draft saved


draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53273250%2ffirebase-security-rules-to-restrict-access-on-all-paths-but-one%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown






























active

oldest

votes













active

oldest

votes









active

oldest

votes






active

oldest

votes
















 

draft saved


draft discarded



















































 


draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53273250%2ffirebase-security-rules-to-restrict-access-on-all-paths-but-one%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

How to send String Array data to Server using php in android

Title Spacing in Bjornstrup Chapter, Removing Chapter Number From Contents

Is anime1.com a legal site for watching anime?