Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access control design patterns

I'm working on a PHP application, and I'd like to add access control to some of my objects. I didn't tag this question as PHP, as I feel this question is not language specific.

Say I have a 'Service class'

abstract class Service {


}

Many services use this as a baseclass. One pseudo example would be:

class Companies extends Service {

  function getCompanyInfo($id) {
      //...
  }

}

Later down the road I want to add access control. The example 'getCompanyInfoById' method is a 'read' operation, so this would require a 'read' privilege.

At this point I can implement this in the following way:

  1. Add accesscontrol to the Service class. Every method (such as getCompanyInfoById) must call the 'hasPrivilege' method internally before completing the operation and returning the result.
  2. Wrap all Service objects in a some kind of Proxy object that will checks privileges before calling the method in the inner-object.
  3. Completely separate access control, and force the 'caller' to check privileges before calling the method.

Cons for every option:

  1. This requires changing all Services, and requires them to be aware of Access control. I feel this goes against Separation of concerns.
  2. This breaks OOP features, such as Polymorphism. The caller no longer knows what interfaces any service supports.
  3. This is the most flexible, but the big drawback is that checking permission is now implicit. Developers can 'forget' or complex codepaths can cause unauthorized services to be called.

Are there better ways to approach this altogether?

like image 310
Evert Avatar asked Dec 17 '09 11:12

Evert


1 Answers

Another solution could be a little variant of your 1.

ex.

class Service
{
  var $ACL = //some hash map with acl
}

class Companies extends Service
{

  function getCompanyById($id)
  {
    //real code
  }
}

class SafeCompanies extends Companies
{
//If a method must be "protected" with an ACL, you must override them in this way
  function getCompanyById($id)
  {
    $this->check('read'); //raise an exception if current user haven't READ privilege
    parent::getCompanyById($id);    
  }  
} 

in this way you dont mix responsibilities and still can use polymorphism

my 2 cents

like image 52
Daniele Teti Avatar answered Nov 15 '22 10:11

Daniele Teti