Skip to content
Koen Teuwen edited this page Jul 16, 2021 · 6 revisions

To get started, it's helpful to look at the ACL documentation from Zend Framework. So that you have an idea of how the ACL works.

Configuration

To configure the ACL for your module, create a key in the ServiceManager that does this. This key is called <module>_acl. In it, you do the following things:

  • You base the ACL on the global ACL ('acl'), or the ACL of another module.
  • You add all resources for the module (a rule of thumb for this is to add one resource for each Service).
  • You configure who has what privileges for all resources.
  • Then you return the ACL.

Roles

The following roles are available:

  • admin
  • user
  • guest
  • active_member
  • sosuser
  • apiuser
  • tueguest

For an up-to-date list of roles, always check the code.

Default permissions

By default, users with the admin role have all rights. Basically, users do not have any other rights. If you do not want to give an admin the rights to do something, you must specify this with $acl->deny().

All rights given to the guest user will automatically be given to the user role.

Example

// in the service definition
'decision_acl' => function ($sm) {
    $acl = $sm->get('acl');

    // add resources for this module
    $acl->addResource('organ');

    $acl->allow('guest', 'organ', 'list')
    $acl->allow('user', 'organ', array('view', 'viewMembers'));

    // admins are not allowed to delete organs
    $acl->deny('admin', 'organ', 'delete');

    return $acl;
},

(So this is in the ServiceManager configuration, which you can find in your Module class)

Use

Basically, checking permissions works the following way:

// obtain the ACL for this module
$acl = $sm->get('decision_acl');

// obtain the role of the current user
$userRole = $sm->get('user_role');

// check if the user is allowed to do this operation
if (!$acl->isAllowed($userRole, 'decision', 'delete')) {
	// this will reroute the user to a 403 page (you should use translation here)
	throw new \User\Permissions\NotAllowedException(
		'Not allowed to view admin interface'
	);
	// note that this is not the only way to deal with this
}

Where to use

It is best to implement these checks in the Service. After all, this is where all the data goes. And the most important part of the ACL is data access. So by implementing all these checks in the Services, it is also easier to see if these checks have been forgotten somewhere.

AbstractAclService

To make this easier, you can have your service extender the Application\Service\AbstractAclService.

To do this, you must implement the getAcl() and the getDefaultResourceId() methods. The getAcl() method should extract the ACL of your module from the service manager. And the getDefaultResourceId() method should return the resource ID of the service. For an example, see Education\Service\Exam.

The AbstractAclService has an isAllowed() method, which in the basics you only need to give a privilege to. This then calls the ACL itself (which you retrieve in getAcl()) with the appropriate role and resource (the one defined in getDefaultResourceId()).

Example

// check if the current user has the view privilege on the resource
$this->isAllowed('view');

// check if the current user has the 'edit' on the 'exam' resource
$this->isAllowed('edit', 'exam');

Access Denied

If you find that a user is not allowed to manipulate certain data, or that the user is not allowed to see certain data, there are several possibilities.

Throw the appropriate exception

The most common is that data is requested to which the user has no access at all. In that case, it is recommended to throw the exception User\Permissions\NotAllowedException. If this is not caught anywhere, the website will display the 403 page, with the message given to the Exception. Don't forget to pass this message through translate()!

Example

if (!$this->isAllowed('upload')) {
    $translator = $this->getTranslator();
    throw new \User\Permissions\NotAllowedException(
        $translator->translate('You are not allowed to upload exams')
    );
}

It is also possible to catch this Exception in the controller and then decide to do something else.

Give less data

In some cases, you may not want to allow a user to view all the data. An example of this is the commission page on the current website. Non-logged-in users see a list of all committees here. Logged-in users can also see the members of these committees.

In other words, in the Service where you retrieve the data, you can decide not to return all the data.

ACL in views

Sometimes it can be useful to add ACL checks in views. For example to decide whether a button should be displayed or not. Of course it is important that there is always a check in the service. Do not let anything depend on the views! You can perform ACL checks in the views with the help of the ACL view helper.

Example

if($this->acl('activity_acl')->isAllowed('activity', 'create')) {
    // Show activity creation button
}

Extended ACL features

Since PR #292 more extensive rights are possible with the ACL. Using the database, administrators automatically get administrator rights. And through ACL rules you can check if a user is a member of an organ.

Organs check

For this you need to extend your model a little bit. The model that these rights apply to must implement the User\Permissions\Resource\OrganResourceInterface. This extends from the ResourceInterface of the ACL itself. So you need to implement the getResourceId() and getResourceOrgan() methods.

As an example, you have an activity model. In this, getResourceId() would just return activity. And getResourceOrgan() returns a Decision\Model\Organ. Namely, the body that has rights over that model.

Now you can add the following rule:

use User\Permissions\Assertion\IsOrganMember;

/* ... */

$acl->allow('user', 'activity', 'edit', new IsOrganMember());

And you can check if a user has the rights to edit this activity as follows:

// $user comes from the ServiceManager service 'user_role'.
// So $activity implements User\Permissions\Resource\OrganResourceInterface.
$acl->isAllowed($user, $activity, 'edit');

This will be allowed, if $user is in the body that returns $activity->getResourceOrgan().