Search code examples
phpzend-framework2zend-acl

Zend ACL and access to specific objects


I need an ACL for my application layer and I've been looking into Zend ACL which seems to cover my needs but I'm confused by the following [1]:

For example, if a default rule is to be applied to each building in a city, one would simply assign the rule to the city, instead of assigning the same rule to each building. Some buildings may require exceptions to such a rule, however, and this can be achieved in Zend\Permissions\Acl\Acl by assigning such exception rules to each building that requires such an exception.

This is great. Exactly what I need. However, how do I accomplish this?

From reading through the documentation for Zend ACL, I can't actually find an example of this. So, lets say I have a City and Building resource and each implements the ResourceInterface. Something like this:

class City implements ResourceInterface {

   public function getResourceId()
   {
      return "city"; // Is this supposed to be the "type" or the "unique Id"?
   }

   public $buildings = array();

}

class Building implements ResourceInterface {

   public function getResourceId()
   {
      return "building"; // Again, the "type" or "unique Id"?
   }

}

As the comments in the code above might already make clear, what is the resource Id? does it represent the "type" of the resource, i.e. this is a City or Building, or does it require to be a unique Id, i.e. "city-1", etc?

If the answer is that it needs to be the "type" then the question becomes; how do I specify unique buildings? However, if the answer is that the Id needs to be unique then the question becomes; how do I identify the "type" of the resource and "blanket" permission each building as stated in the quote taken from the documentation.

Any insight would be much appreciated.

[1] http://zf2.readthedocs.org/en/latest/modules/zend.permissions.acl.intro.html


Solution

  • the resource Id needs to be a unique value. and for assigning global rules you need to use inheritance for the resources . simple you need to pass the city resource as the parent for the building resource when you adding resources to the acl.

    here is a sample :

    $acl = new Acl();
    
    //the original Acl resource class takes a `resourceId` as constructor parameter
    $mycity1 = new Resource('mycity1');
    $acl->addResource($mycity1);
    
    $mybuiding1 = new Resource('mybulding1');
    //city is the buildings parent
    $acl->addResource($mybuiding1,$mycity1);
    
    //you dont even have to create a class just define the resource as string
    $acl->addResource('secure_buildings',$mycity1);
    
    $acl->addRole('myrole1');
    //roles have inheritance too
    $acl->addRole('myrole2','myrole1');
    
    //myrole1 and myrole2 has access to city and all its building
    $acl->allow('myrole1','mycity1');
    //myrole2 has access to city and all its building except 'secure_buildings'
    $acl->deny('myrole2','secure_buildings');
    

    the child resource bulding inherits the rules from parent city if none is defined for it.

    UPDATE for comment :

    ACL doesn't know and doesn't care what resource type you have as long as they have unique resource ids, acl threats all resources as equal and only looks for resourceId and inheritance.

    when you defining the rules you only need to provide the resourceId for the allow and deny , it doesn't matter what type they are as long as they are defined as a resource and added to the ACL's stack.

    and when you doing $acl->inAllowed you only need a roleId and resourceId and again acl doesn't care about their type , only that they have been defined as a resource abd that they have parent or not...

    Sample : i hope this is enough sample

    $acl = new Acl();
    $acl->addResource('City'); //all the cities
    $acl->addResource('myCity1', 'City'); //city1 inherits City
    $acl->addResource('Building', 'City'); //all the buildings in all the cities
    $acl->addResource('normal_buildings', 'Building');
    $acl->addResource('secure_buildings', 'Building');
    $acl->addResource('top_secure_buildings', 'secure_buildings');
    
    $acl->addRole('Civilian');
    $acl->addRole('High_Level_Security', 'Civilian');
    
    $acl->allow('Civilian', 'City');
    $acl->deny('Civilian', 'secure_buildings');
    
    $acl->allow('High_Level_Security', 'secure_buildings');
    $acl->deny('High_Level_Security', 'top_secure_buildings');
    
    var_dump($acl->isAllowed('Civilian', 'City'));//true  -> direct allow rule
    var_dump($acl->isAllowed('Civilian', 'myCity1'));//true  -> inherited from City allow rule
    var_dump($acl->isAllowed('Civilian', 'Building'));//true  -> inherited from City allow rule
    var_dump($acl->isAllowed('Civilian', 'normal_buildings'));//true  -> inherited from City allow rule
    var_dump($acl->isAllowed('Civilian', 'secure_buildings'));//false  -> direct deny rule
    var_dump($acl->isAllowed('Civilian', 'top_secure_buildings'));//false   -> inherited from secure_building deny rule
    
    var_dump($acl->isAllowed('High_Level_Security', 'City'));//true  -> inherited from Civilian->City allow rule
    var_dump($acl->isAllowed('High_Level_Security', 'myCity1'));//true  -> inherited from Civilian->City allow rule
    var_dump($acl->isAllowed('High_Level_Security', 'Building'));//true  -> inherited from Civilian->City allow rule
    var_dump($acl->isAllowed('High_Level_Security', 'normal_buildings'));//true  -> inherited from Civilian->City allow rule
    var_dump($acl->isAllowed('High_Level_Security', 'secure_buildings'));//true  -> direct allow rule
    var_dump($acl->isAllowed('High_Level_Security', 'top_secure_buildings'));//false  -> direct deny rule