| | 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 |