cofoundry-cms / cofoundry

Cofoundry is an extensible and flexible .NET Core CMS & application framework focusing on code first development
https://www.cofoundry.org
MIT License
835 stars 146 forks source link

Fine grained permissions for documents (and other)? #420

Open JornWildt opened 3 years ago

JornWildt commented 3 years ago

I don't see any way to restrict access to some documents - but not all? The permission system seems to be either everything or nothing. You cannot restrict access to for instance one sub-directory of the documents or some categories.

What would be the best way to implement that?

I'm asking because my booking system needs to store copies of booking contracts - and Cofoundry documents seems perfect for this. I can make those contracts inaccessible for anonymous users, so that tenants won't be able to see all the contracts. But later on I might want to have a set of standard documents available for anonymous users - but still not the contracts.

HeyJoel commented 3 years ago

There's no resource-level permission restrictions support, and that would be pretty fiddly to implement and manage in a user interface. If you have any examples of other systems that do this well that might be a useful reference.

Perhaps a simpler way to do this would be to allow you to customize the permission checking process in code, then you could hard-code certain rules like the one you describe, as it sounds specific to pre-defined roles and tags.

Currently the only way you could do this would be to override/wrap each of the command handlers for documents, but that's quite fiddly and requires you to keep it in sync with updates.

JornWildt commented 3 years ago

I haven't seen anyone doing this "simple" in a way that is both understandable and efficient in database queries.

First of all you could probably don't want to assign permissions to each and every document that needs it. You would most likely want to have a folder based system where you can restrict access to certain folders - and access restrictions would then propagate downwards in the hierarchy.

And neither documents nor images have folders in Cofoundry. So that it the first road block.

But assigning access restrictions to tags would most likely also solve most issues - marking something with the tag "internal" could restrict access to a certain role. But tags are very loose and as an end-user you don't get much help when trying to figure out which tag to use.

Where I work, we have a folder based system where all main entities are placed. Each folder has a list of users associated to it - either individually or by opening up for roles that identifies users.

Every database query then needs to join in the access tables and the role definitions to see if the current user has access to the relevant piece of data. But, since folders may contain folders, there is yet another part of the SQL that needs to traverse the folder hierarchy upwards to very access to the upper folders - or perhaps changing the access in the upper levels adds the access restrictions to the lower levels on update (I'm not sure).

And, yes, it is really difficult to explain to users why they don't see a particular piece of data!

JornWildt commented 3 years ago

For a time I worked with PostNuke (Zikula nowadays). Here they used regular expressions for access control. Each module has it's own resource format string - for documents it could be "/folder-1/folder-2/document-name" and then the admin could state access to documents as a regex similar "/folder-1/*" to grant access to all stuff in folder-1.

That was neither trivial nor efficient as you cannot use the regex in database queries.

JornWildt commented 3 years ago

Perhaps a simpler way to do this would be to allow you to customize the permission checking process in code

Not really. It all falls back to be able to implement checks when querying the database.

If I query for the first 30 documents matching XYZ then I don't want to retrieve 30 documents from the database, check permissions in code, and then throw away the 29 of them, resulting in only a single document being display in my list of 30 documents per page.

JornWildt commented 3 years ago

Since Cofoundry does not have folders for documents (though it has directories for pages?) I would suggest a minimal solution like this:

When creating or updating a document, you are presented with a checkbox list for restricting access to certain roles. By default all boxes would be checked (granting access to everybody). Each checkbox adds a certain role to the access restriction.

When querying that database, you would need to pass the current user's role(s) to the query and make sure that role is included in the access restriction list.

With such a system you could exclude or include anonymous users - as long as "anonymous" becomes a concrete role, not just the lack of both roles and user ID (you might need the anonymous user to be a real user).

JornWildt commented 3 years ago

But, to return to my original issue - I'll have to add my own simplified document storage system, where access needs to go through the booking system. Shouldn't be to big an issue - especially since I'm only ever going to store small HTML texts (e-mails) which I can easily throw into a NVARCHAR(MAX) column.

JornWildt commented 3 years ago

Hopefully you will excuse me for shamelessly copying much of your document asset handling :-)

JornWildt commented 3 years ago

That didn't take too long :-) See https://github.com/Bogevang-spejderhytte/website/tree/main/Bogevang.Booking.Domain/Documents.

Thanks for providing all the necessary infrastructure such as sending mails, permission checking, dependency injection with associated startup scanning and auto update (love that!) - and more. That is very useful to build on.