I’m creating a website with a whitelabel system that I need to limit the access to the firestore collections and documents based on a Role system.
The rules are:
- Users will receive a custom claim called “role” that is the ID of a
document of the role collection - This Role document can allow the user read, write, delete
documents in a specific collection and also could limit this user
to a single whitelabel if the field whitelabelId is set. - If the user can read a collection, there is a whitebaleId set and
the documents of the collection have a whitelabelId field set, this
user can read ONLY the documentos associated to his whitelabel. - If a user can read a collection and there is no whitelabelId set in
his associated Role document, this user will be able to read all the documents
in this collection - If the user have a whitelabelId set in his Role but the collection
that he is reading have no whitelabelId in their docs set, this user
will be able to read all the documents
What is the issue?
I have a user that can read the videos collection and this user is associated to a specific whitelabel, so, this user should be reading ONLY the videos that belong to this whitelabel but this is not working as expected. The user is being able to read all docs.
Here it is the rules:
<code>function isAuthenticated() {
return request.auth != null;
}
function isAdmin() {
return request.auth != null && request.auth.token.role == 'Admin';
}
function canRead(collection){
let roleDoc = get(/databases/$(database)/documents/roles/$(request.auth.token.role)).data;
// User can read the collection based on the Role Doc
let userCanReadCollection = roleDoc.collections[collection].read == true;
// Role Doc does not contain the whitelabelId field
let roleIsBasedOnWhitelabel = !("whitelabelId" in roleDoc);
// whitelabelId field is not in the retrieved doc
let docDoesNotContainWhitelabelIdField = !("whitelabelId" in resource.data);
// Retrieved doc whitelabelId is the same of the role whitelabelId
let docIsTheSameWhitelabelId = resource.data.whitelabelId == roleDoc.whitelabelId;
return isAdmin() || (isAuthenticated() && userCanReadCollection && (roleIsBasedOnWhitelabel || docDoesNotContainWhitelabelIdField || docIsTheSameWhitelabelId));
}
match /videos/{videoId}{
allow read: if canRead('videos');
allow create: if canCreate('videos');
allow update: if canUpdate('videos');
allow delete: if canDelete('videos');
}
</code>
<code>function isAuthenticated() {
return request.auth != null;
}
function isAdmin() {
return request.auth != null && request.auth.token.role == 'Admin';
}
function canRead(collection){
let roleDoc = get(/databases/$(database)/documents/roles/$(request.auth.token.role)).data;
// User can read the collection based on the Role Doc
let userCanReadCollection = roleDoc.collections[collection].read == true;
// Role Doc does not contain the whitelabelId field
let roleIsBasedOnWhitelabel = !("whitelabelId" in roleDoc);
// whitelabelId field is not in the retrieved doc
let docDoesNotContainWhitelabelIdField = !("whitelabelId" in resource.data);
// Retrieved doc whitelabelId is the same of the role whitelabelId
let docIsTheSameWhitelabelId = resource.data.whitelabelId == roleDoc.whitelabelId;
return isAdmin() || (isAuthenticated() && userCanReadCollection && (roleIsBasedOnWhitelabel || docDoesNotContainWhitelabelIdField || docIsTheSameWhitelabelId));
}
match /videos/{videoId}{
allow read: if canRead('videos');
allow create: if canCreate('videos');
allow update: if canUpdate('videos');
allow delete: if canDelete('videos');
}
</code>
function isAuthenticated() {
return request.auth != null;
}
function isAdmin() {
return request.auth != null && request.auth.token.role == 'Admin';
}
function canRead(collection){
let roleDoc = get(/databases/$(database)/documents/roles/$(request.auth.token.role)).data;
// User can read the collection based on the Role Doc
let userCanReadCollection = roleDoc.collections[collection].read == true;
// Role Doc does not contain the whitelabelId field
let roleIsBasedOnWhitelabel = !("whitelabelId" in roleDoc);
// whitelabelId field is not in the retrieved doc
let docDoesNotContainWhitelabelIdField = !("whitelabelId" in resource.data);
// Retrieved doc whitelabelId is the same of the role whitelabelId
let docIsTheSameWhitelabelId = resource.data.whitelabelId == roleDoc.whitelabelId;
return isAdmin() || (isAuthenticated() && userCanReadCollection && (roleIsBasedOnWhitelabel || docDoesNotContainWhitelabelIdField || docIsTheSameWhitelabelId));
}
match /videos/{videoId}{
allow read: if canRead('videos');
allow create: if canCreate('videos');
allow update: if canUpdate('videos');
allow delete: if canDelete('videos');
}
Here it is the Role document of this user:
Here it is an example of a video document:
So, what am I doing wrong to allow this user read all the documents?