Developer:Ownership Sharing and Permissions

From myExperiment

Jump to: navigation, search

Ownership, Sharing and Permissions

By Sergejs Aleksejevs, 13th August 2008    /    Last updated on 29th October 2008


Contents


Policies and Permissions

Policies

Along with adding contributions to the system a policy for each of them is also created. There can be just one policy per contribution, but a policy can be applied to multiple contributions (this is available in the backend, but at the moment is not exposed in the UI).


Data Structure

Policy contains:

  • two sets of view/edit/download permissions --
    • set of public properties - for anonymous (i.e. not logged in) users;
    • set of protected properties - for the contributor and their friends (if the uploader is a user), or for accepted members of a network (if the uploader is a network);
  • share mode & update mode attributes.


Initially the system was designed to use two sets of view/edit/download attributes for public and protected use. Then a decision was made that such implementation is not scalable (for instance, what happens if we were to introduce a new category of users or a new layer of permissions, like 'allow_to_distribute'?), and thus needs to be reimplemented.

For this reason two additional attributes were added - share_mode and update_mode. These two were to replace the original system with two sets of different permissions by having integer codes, each standing for a particular set permissions for all users at once. However, for reasons of backwards compatibility it was impossible to remove completely the sets of separate attributes (which are still used in controllers and models, but the views are already using modes). This leads to an important integrity constraint:

 NB! Modes that are used in policy should always be consistent with sets of individual attributes.

Recent work was done to implement a self-correcting code that is executed every time right before the call to authorized() method on policy is performed.


Three Level Mapping

The processing logic which deals with policies needs to perform three level mapping to achieve correct data flow between things that are displayed to the user in the UI, new policy system that uses modes, and the legacy system which works with bit fields from the sets of attributes. These mappings are presented below.


Image:3WayMapping - Sharing.png

Image:3WayMapping - Updating.png


Cascading Dependencies for Actions

Another very important design decision was to have cascading dependencies on the actions that are associated with contributables. Technically, all the actions can be classified into 4 different groups:

  • view
  • download
  • edit
  • actions allowed to owner only

myExperiment codebase assumes that there is a hierarchy (in the presented order) of those actions. This means that those users, that are allowed to view a resource, can't do any thing else; those, that are allowed to download, are automatically allowed to view the item; those with edit permissions are allowed to view and download; finally, users with owner rights can do anything.

Point to mention here is that, for example, if a check is carried out successfully to show that current user has edit permission, the code WILL AUTOMATICALLY assume the dependencies listed above. No further checks on the data in the bit fields of sets of attributes will be done. Potentially, this can easily lead to serious inconsistencies in the database. However, as mentioned before, myExperiment codebase now possesses a self-correcting code that checks that all these values are consistent (that is that values in modes correspond to bit values in the sets of view/edit/download permission, and that all the dependencies are present, too).

 Note: some of the modes can have conflicting requirements - for example: sharing mode "this is a private <workflow|file|pack>" and update mode "all friends can update".
 In this case, DB entry for this policy will have flags for view & download by public/protected members set to false, but 'edit_protected' flag would be set to true.
 This shows that data in the DB entry has inconsistency (and doesn't support the cascading dependencies). Nevertheless, this is the only correct way to represent the
 state of user selection in the backend - imagine that the system would update bit-field flags correspondingly to have 'view_protected' and 'download_protected' set to
 true, because 'edit_protected' is set to true. This would change user-selected sharing mode from "this is a private <workflow|file|pack>" to "only friends are allowed
 to view and download" - and so the user-defined mode would be changed, which is definitely not what is desired. Still, having this state of data in DB is not a problem
 - as the rest of the code "knows" that if one is having edit permissions, then they also have view and download permissions. As a result everything's working fine.


Permissions

  • Each policy can have an arbitrary number of permissions which specify individual access rights (or, in other words, are used to set policies for individual contributors).
  • Permissions override policy settings.
  • All occurrences of sharing some resouces with groups is done via permissions (and is treated completely separate from sharing/updating modes and bit-field flags).


Identified order of Policy/Permissions checks

The following sequence of checks was identified to perform best to authenticate a user to perform the required action (see also FB case 921).

 Note: this doesn't cover implementation details (like missing policies, using defaults, etc) - just the
 high-level view on the authentication process.
  • permissions set for individual users should always override settings that are set out in policies and group permissions for which current user is a member (no matter if these increase or decrease access rights of the affected user);
  • if there are no individual permissions, but group permissions exist, then group permissions can give more access rights to the user, but cannot restrict the access rights provided by the policy;
  • if no individual / group permissions are set, policy settings are used.


Interactions of Policies and Permissions (NB! Needs revision!)

This section explains how Policies and Permissions work together. (This needs revision with respect to the latest work in authorization scope - given that new auth module is being produced, which works around ActiveRecord to improve performance).


When actions (like view, edit, download or delete) are called to be executed over contributables, the system needs to check if the current user is actually allowed to perform that action. In order to carry out this check, a chain of method calls in different models is executed: Contributable.authorized?() -> Contribution.authorized?() -> Policy.authorized?(). The controller which tries to execute the necessary action calls authorized?() method on the contributable which is to be affected by the action. That method calls authorized?() method of the 'parent' contribution object that, in turn, calls authorized?() method of the policy associated with this contribution.

authorized?() method of the policy checks the following:

  • that the current policy belongs to the contribution that is being tested;
  • that the desired action can be categorised into one of view / edit / download / actions that are allowed just for owners;
  • that permission to view or download can be granted with no further checks if the current user is allowed to edit this contribution;
  • if the current user is anonymous (that is not logged in), public permissions of the contributable are checked to see if that action is authorised;
  • else if the current user is known, then -
    • action is definitely authorised if the current user is the owner or administrator of the contributable;
    • alternatively, searching for specific permissions for current user; decision is made based on these permissions, if any;
    • if not owner/administrator and no individual permissions found, then policy settings are checked (the code also checks if the contributor is a 'friend' - in other words, a member of the protected group - or not: based on this "public" or "protected" policy settings are fetched;
    • if current action is not yet authorized, search for group permissions is done - if user is a member of a group that is authorized to perform a certain action, these settings would extend access rights granted by the policy;
  • for not logged in users public settings of the policy will be checked.
Personal tools