Permissions

Since Decidim has multiple roles, we needed a permissions system to discover what actions can a user perform, given their roles. The basis of the current permissions system were added on #3029, so be sure to check that PR (and the related ones) to read the discussion and the motivations behind the change.

Overview

When checking for permission to perform an action, we check this chain:

  1. The component permissions

  2. The participatory space permissions

  3. The core permissions

This way we are going from more specific to more general.

Explanation

We wrap the permission and its context in a PermissionsAction object. It also holds the state of the permission (whether it has been allowed or not).

Each component and space must define a Permissions class, inheriting from Decidim::DefaultPermissions. The Permissions class must define a permissions instance method. this class will receive the permission action, and the permissions method must return the permission action. The Permissions class can set the action as allowed or disallowed.

There is a small limitation in the permission action state machine: once it has been disallowed it cannot be reallowed. This is to avoid mischievous modules modifying permissions.

Permission actions have a scope. It is usually either :public or :admin, and the Permissions class usually handles the :public scope, while it delegates the :admin one to another specialized class.

Add a new Action

Proposals example

We are going to reproduce the steps to add an action (endorse) for a proposal step by step.

Configuring a new 'endorse' action

  1. Edit decidim-proposals/lib/decidim/proposals/component.rb

  2. Add the new 'endorse' action into the component.actions array and save the file:

component.actions = %w(endorse vote create)
  1. Translate the action for the corresponding key: en.decidim.components.proposals.actions.endorse = Endorse

  2. Edit app/permissions/decidim/proposals/permissions.rb and add the corresponding permission, using authorized? method to run the authorization handler logic.

  3. In the endorse proposals controller, enforce that the user has permissions to perform the endorse action before actually doing it, using the enforce_permission_to method:

enforce_permission_to :endorse, :proposal, proposal: proposal
  1. In the proposals templates, change regular links and buttons to endorse a proposal with calls to action_authorized_link_to and action_authorized_button_to helpers.

  2. Restart the server to pick up the changes.

Using the new 'endorse' action

  1. Now an admin user should be able to go to a participatory space with a proposals component panel and click on its Permissions link (the icon with a key). There, an authorization handler can be set for the endorse action.

  2. Go to a Proposal detail in the front-end

  3. Try to endorse the current proposal

    • If the user has not granted the selected permission, the 'endorse' button should block the action and allow the user to grant the permission with the selected authorization handler logic.

    • If the logger user has already granted the selected permission, the user should be able to perform the endorsement.

Permissions settings could also be set for an specific resources apart from the full component. Actions should also be related to the resource.

  1. Edit decidim-proposals/lib/decidim/proposals/component.rb

  2. Add the 'endorse' action into the resource.actions array for the proposal resource definition and save the file:

resource.actions = %w(endorse vote)
  1. Only if this is the first resource action added, edit the proposals admin templates and use the resource_permissions_link helper to link the resource permissions page from each resource in the listing.

<%= resource_permissions_link(proposal) %>
  1. In the proposals permission class, pass an extra resource named parameter to the calls to the authorized? method.

authorized?(:endorse, resource: proposal)
  1. In the proposals templates, also add the extra resource parameter to the action_authorized_link_to and action_authorized_button_to helpers.

  2. Restart the server to pick up the changes.

Using permissions at resource level

  1. Now an admin user should be able to go to a participatory space with a proposals component panel and click on its Permissions link (the icon with a key). There, an authorization handler can be set for the endorse action.