Handle multi level of roles

467 views Asked by At

I have a multi applications which works with authenticated users.
All these applications can be deployed together for differents clients but with the same user database.
For example a chain of hotels.
User's roles informations are available in a header in each request.

For example a manager has full access in his own hotel but only read access in another hotel.
Ex:

{
    ["organization":"paris","roles":[ADMIN,ROOT]],
    ["organization":"london","roles":[READ]]
}

How can I handle many levels of roles by organizations?
I read some documentation in the symfony about voters and roles but nothing about roles in a kind of groups.

2

There are 2 answers

0
goto On

Voter is the way to go

// src/Security/PostVoter.php
namespace App\Security;

use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;

class OrganisationVoter extends Voter
{
    // these strings are just invented: you can use anything
    const READ= 'READ';
    const EDIT = 'EDIT ';

    protected function supports($attribute, $subject); bool //todo
    protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
    {
        // [...] check class like documentation
        $organisation= $subject;

        switch ($attribute) {
            case self::READ:
                return $this->canView($organisation, $user);
            case self::EDIT:
                return $this->canEdit($organisation, $user);
        }
    }

    private function canView(Organisation $organisation, User $user)
    {
        //here your logic if your user has the same organisation
    }

    private function canEdit(Organisation $organisation, User $user)
    {
        //here your logic if your user has the same organisation than the one in parameter and the good level of right (admin, root)
    }
}

Then in your controller (or twig or wherever)

    if ($this->security->isGranted(OrganisationVoter::EDIT, $organisation)) {
        return true;
    }
0
David Brossard On

What you describe has "attribute-based access control" written all over. helps you externalize / decouple authorization from the application / API you want to protect. This means you can develop functionality independently of the authorization logic.

There are a couple of standards out there - namely XACML and ALFA (abbreviated language for authorization).

This is what the architecture looks like:

XACML Architecture

  • the Policy Enforcement Point (PEP) intercepts the business flow and create an authorization request which it sends to the PDP
  • The Policy Decision Point (PDP) evaluates the incoming request against the policies it's been configured with. It eventually returns a decision to the PEP
  • The PDP may use Policy Information Points (PIP) to retrieve missing metadata (a user's department, role, location; a resource's department, owner...)

The previous answer forces you to implement a voter. That's very brittle and will require coding and updating it regularly as your requirements change. In ALFA, you don't need to do that. You simply write policies in plain old English that use the attributes you are interested in. For instance:

  • A user with role == "manager" can do action == "view" on object of type == "hotel"
  • A user with role == "manager" can do action == "edit" on object of type == "hotel" if hotel.owner == user.name