I’m trying to understand how to lock down document permissions while using flexible sync. Here is the scenario that’s tripping me up.
Let’s say I’ve added a project ID to a list in custom user data. I use that to add and remove access to particular documents that have that project ID as a field. Once a user has access to that document they would have permission to change that field to any project they have access to, correct?
Is there no way to allow users to created and edit documents in a project, without allowing them to also “steal” a document by moving it to a new project? I’ve experimented with making some fields read-only, but that prevents users from creating in a particular project.
At the moment, the only solution I’ve come up with is by only allowing reading out of one collection, and writing to another. By doing this, I could perform server side logic that validates that a “write” is valid before submitting it to the true collection.
Is this a pattern that other people use? Are there other pattens that I’m missing here?
We use the list of projects in the user document to check if a user can create or update a project file. If the user has the profile file’s projectId in their list of projects they are allowed to do both.
Imagine that user #1 invites user #2 to their project, so now user #2 has projects: [1,2]. With this, user #2 can now take the project file they now have access to and change the projectId to 2. This effectively removes access for the user who created the document.
Essentially, I feel like this is where having more dynamic field level permissions is important. Its difficult to grant access to some users to create or update files in a project without also granting them permission to move those files to new projects.
Ok, thanks - that clarifies it a bit but I am not sure why it’s an issue.
As the developer, you have total control over what a user can do. Much of that comes from how the UI is implemented. If the app simply doesn’t expose the projectId, or if it does, make it a non-editable field to ‘other’ users (for example), that would prevent a user from changing the ownership of another users project.
A role’s field-level permissions determine whether a user can read or write fields within the document. These permissions only affect the field they apply to, so a user can have read or write access to only a subset of the entire document.
That allows the developer to further lock down data. If you implement a Role that only the owning user can modify the projectId and require all projectId’s to be unique, then a projectId would never be altered or duplicated (‘stolen’)
Sure, I can prevent a user from doing this from the UI, but that isn’t secure enough for our use case. It needs to be protected on the server. Ideally we can accomplish this using role-based permissions so that development and maintenance is as easy as possible.
The issue I see with field level permissions is that I don’t think I can differentiate between creating a document in a project and updating it. How can we allow a “non-project owner” to add a file to a project, without allowing them to also move files out of a project?
I can’t see a way to use field level permissions to make the projectId field writable in one of those contexts, but not the other. If, for example, a user has “contributor” role assigned to them that only allows them to read the projectId field, then they won’t be able to set the projectId field even on creation of the document.
Realm/Atlas doesn’t really have a concept of “files” or “moving” data - there are only documents and fields within the document, and they can only be deleted, inserted or modified - no moving.
I stress that because data is data - whatever it represents. If a user has access to read data…well… they have access to that data and can copy paste as much as they want.
However, if you create a situation on the server where, for example projectId’s must be unique and unchangeable, that would prevent the user from ‘moving a file out of the project and into another project’ - it could be the same data but would have a different projectId and therefore not be ‘stolen’ - and lock it down so only an owner can delete a project and document or change the projectId (I even question that as once it’s set, it should not be changeable)
That’s actually quite simple - write access but no read access. In the UI the user can create their document and then write it out to whatever project they are allowed to access - but after that they cannot read or modify it, unless they are the owner of the project.
However, that sounds restrictive; I would think the user should have the ability to modify their own document in any project they have access to so a setup could be as follows
The owner of a project has read/write access to all documents in the project and can add/remove contributors (users) - the projectId however is static and must be unique
Users that have access to that project can read documents in the project, and can read/write documents they contribute
Why not? If they can write the data then they can set the projectId - a simple check would guarantee uniqness before being written.
I’m using files / projects as examples of documents - I was not suggesting that a user is putting binary data in to mongo.
Let me drill down to a very specific question.
What flexible permissions role can be used to allow a user to create a document with a specified field, such as projectId, but prevent them from updating that field?
From my experiments, if a role makes a field read only, then a user cannot set that field even on creation. As such, its difficult to express a server side restriction that allows “collaborators” to add “files” to a project without also allowing them to change the projectId field.
Roles and Rule permissions are pretty flexible. In a collaboration environment it’s often times where a user can write their own data only, but read others. It just-so-happens that’s one of the use cases covered in the Permissions Guide: Write Own Data, Read All Data
If you want to prevent a field from being modified; if it exists, don’t allow modification. Or you can leverage server side functions or use a field that’s populated only upon first save (with say… a timestamp) and have a requirement that the field in question can only be written to if the timestamp is “”. OR I think I saw a field can be immutable. There are a number of other solutions as well.