| 1 | = Row Level Permission design = |
| 2 | [[TOC()]] |
| 3 | |
| 4 | == User story == |
| 5 | As a user I want to specify for each object who is allowed to edit, view, and own (delete, give others permissions) |
| 6 | |
| 7 | == Requirements == |
| 8 | * The solution should NOT require MOLGENIS designers to change their data model. |
| 9 | * It should not be needed to set permission rules on ALL objects but instead permissions must be set to be 'inheritable' between related objects |
| 10 | (NB: in MOLGENIS data model we want to specificy these relations as a 'partOf' version of the xref). |
| 11 | |
| 12 | == Architecture == |
| 13 | A runtime configuration option can be enabled and that 'under water' links an 'permission' system table to 'auth' to set permissions on any object. |
| 14 | Big advantage is that one doesn't need to change the datamodel. A known drawback is that this table may become very large however as in practice users will not set many permissions. |
| 15 | |
| 16 | This design has the following components: |
| 17 | |
| 18 | === 1. Permission table === |
| 19 | |
| 20 | Example fields in this permission table: |
| 21 | entityName: xref(MolgenisEntity) |
| 22 | entityId: int |
| 23 | actor: xref(MolgenisGroup [MolgenisUser extends MolgenisGroup?]) |
| 24 | permission: {owner, view, edit, execute} |
| 25 | unique(entityName,entityId,actor) |
| 26 | |
| 27 | === 2. Automatic filtering of any 'row level secured entity' using subselects === |
| 28 | Change the Login class to to inject a QueryRule that has 'subselect' to search permissions and enable filtering in selects and updates. Semicode exle: |
| 29 | {{{ |
| 30 | SELECT ... FROM Investigation WHERE id IN (select entityId from MolgenisPermissions |
| 31 | where actor=${currentActor} AND entityName='Investigation' AND permission IN('owner','read','write','execute')) |
| 32 | }}} |
| 33 | |
| 34 | This solution also allows entities to 'inherit' the permissions from a 'parent' object (as long as there is a foreign key path). |
| 35 | Semicode example, when ObservationElement would 'inherits' permissions from Investigation: |
| 36 | {{{ |
| 37 | SELECT ... FROM ObservationElement JOIN Investigation WHERE investigation.id IN (select entityId from MolgenisPermissions |
| 38 | where actor=${currentActor} AND entityName='Investigation' AND permission IN('owner','read','write','execute')) |
| 39 | }}} |
| 40 | |
| 41 | === 3. A decorator to automatically set default owner === |
| 42 | At every insert on a 'row level permission' secured entity there must a an appropriate owner be inserted into MolgenisPermissions. |
| 43 | |
| 44 | === 4. Sharing user interface === |
| 45 | Generated forms are enhanced with |
| 46 | * an additional actionInput where users that are owner can show a 'sharing' dialog (that is a button in both list and edit views) |
| 47 | * this sharing dialog lists all permissions for this entity (SELECT ... FROM MolgenisPermission WHERE entityName=%currentEntity% AND entityId=%currentId%) |
| 48 | * and allows users to add/remove rules. Minimally one 'owner' should remain. |
| 49 | |
| 50 | === 5. Admin user interface === |
| 51 | Extend the security 'admin' user interface where I can tick |
| 52 | * which entities should have row level security, |
| 53 | * what entities should 'inherit' row level security. |
| 54 | * what the default permissions are |