Practical Applications of Zend_Acl
Upcoming SlideShare
Loading in...5
×

Like this? Share it with your network

Share

Practical Applications of Zend_Acl

  • 13,940 views
Uploaded on

Access Control Lists are a tool that allows us to map permissions to objects - within Zend_Acl this maps to a hierarchical arrangement of roles and resources....

Access Control Lists are a tool that allows us to map permissions to objects - within Zend_Acl this maps to a hierarchical arrangement of roles and resources.

This talk will follow through the basic use of Zend_Acl and steadily build a series of practical examples to illustrate the different methods of creating and enforcing an ACL for an application. This will include how to implement some of the more complicated hierarchical relationships and advanced conditions through the use of assertions. We will also cover the design considerations of where to attach the ACL, with the differences between applying it to controllers or models. With a functioning ACL in place, we will examine some of the methods for persisting the list and whether that list should be static or dynamic.

Alongside the straight functionality of our code, we will also examine how to effectively unit test it, improving its performance and analysing the level of security that has been created.

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
No Downloads

Views

Total Views
13,940
On Slideshare
9,152
From Embeds
4,788
Number of Embeds
27

Actions

Shares
Downloads
296
Comments
3
Likes
12

Embeds 4,788

http://merewood.org 2,309
http://yugeon-dev.blogspot.com 1,747
http://yugeon-dev.blogspot.ru 605
http://abragin.com 26
http://pf2wozlpnywwizlw.mjwg6z3tobxxiltdn5wq.cameleo.ru 22
http://www.merewood.org 21
http://abtasty.com 12
http://yugeon-dev.blogspot.co.at 10
http://farem-sao.blogspot.com 5
http://mlocal.merewood.org 5
http://www.linkedin.com 3
http://yugeon-dev.blogspot.nl 3
http://merewood.org:6081 3
http://yugeon-dev.blogspot.de 2
https://www.linkedin.com 2
http://yugeon-dev.blogspot.in 2
http://m.merewood.org 1
http://hghltd.yandex.net 1
http://ranksit.com 1
http://yugeon-dev.blogspot.fi 1
http://yugeon-dev.blogspot.it 1
http://www.365dailyjournal.com 1
http://mrowan8832.merewood.org.moovapp.com 1
http://yugeon-dev.blogspot.co.il 1
http://yugeon-dev.blogspot.ie 1
http://webcache.googleusercontent.com 1
http://translate.googleusercontent.com 1

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Practical Applications of Zend_Acl Rowan Merewood
  • 2. Who is this? @rowan_m Software Engineer Team Lead http://merewood.org 2
  • 3. Why do this? So you don't have to. Problems encountered, solutions discovered, lessons learned. 3
  • 4. What do you want? More concept? - or - More code? 4
  • 5. What does this solve? The “Gold Standard” for security. 5
  • 6. Gold Standard Gold 79 Au thentication 196.97 Gold 79 Au thorisation 196.97 Gold 79 Au diting 196.97 B.W. Lampson. Computer Security in the Real World. Computer, 37(6):37–46, 2004 http://research.microsoft.com/en-us/um/people/blampson/69-SecurityRealIEEE/69-SecurityRealIEEE.htm 6
  • 7. Gold Standard Gold 79 Au thentication 196.97 Gold 79 Au thorisation 196.97 You are here. Gold 79 Au diting 196.97 B.W. Lampson. Computer Security in the Real World. Computer, 37(6):37–46, 2004 http://research.microsoft.com/en-us/um/people/blampson/69-SecurityRealIEEE/69-SecurityRealIEEE.htm 7
  • 8. Role-based Access Control Roles Resources Privileges Assertions Oh my! 8
  • 9. Warning! There is no right answer 9
  • 10. Roles • A named group of privileges for a resource. • A role may inherit from many parent roles • Build the tree from leaf to root 10
  • 11. Roles • A user is a leaf node Client Contact Developer Lead Developer Employee Rowan 11
  • 12. Roles • A user is a leaf node Client Contact Developer Lead Developer Sales Employee Evil Rowan Rowan 12
  • 13. Roles • Use inheritance sparingly • Avoid circular dependencies • Over-complicated relationships • Difficult to configure 13
  • 14. Resources • Objects with which users can interact • A resource may have one parent • Build the tree from root to leaf 14
  • 15. Resources Ship Federation Klingon Galaxy class NCC-1701-D NCC-1701-E 15
  • 16. Resources Ship Federation Klingon Galaxy class Allow “bridge crew” role the “activate cloak” privilege NCC-1701-D NCC-1701-E 16
  • 17. Resources Allow “*” role the “self destruct” privilege asserting “is captain” Ship Federation Klingon Galaxy class NCC-1701-D NCC-1701-E 17
  • 18. Privileges • Simple – just strings • Qualifies the operation a role may perform against a resource • Shared vocabulary: CRUD 18
  • 19. Assertions • An arbitrary condition attached to the ACL returning true or false • Has access to the role, resource, privilege and ACL • Power and flexibility open to abuse 19
  • 20. Assertions • "user" can "view" a "group photo" if "user is a member of the group" • "user" can "create" an "comment" if "the user has submitted less than 5 comments in the last hour" • "job scheduler" may "schedule" a "task" if "no instances of the task are running" 20
  • 21. Assertions • "user" can "view" a "group photo" if "user is a member of the group" • "user" can "create" an "comment" if "the user hasDirect relationshipless than 5 and the resource. submitted between the role comments in All dependencies are passed in. the last hour" “Visibility” is a good concept to keep in the ACL • "job scheduler" may "schedule" a "task" if "no instances of the task are running" 21
  • 22. Assertions • "user" can "view" a "group photo" if "user is a member of the group" • "user" can "create" an "comment" if "the user has submitted less than 5 comments in the last hour" Border-line – most dependencies contained • "job scheduler" may "schedule" a "task" if Does the time-based system state count as “authorisation”? "no instances of the task are running" 22
  • 23. Assertions • "user" can "view" a "group photo" if "user is a member of the group" • "user" can "create" an "comment" if "the user has submitted less thanoutside the scope in Advanced dependencies definitely 5 comments This is a “pre-add” check for the model the last hour" • "job scheduler" may "schedule" a "task" if "no instances of the task are running" 23
  • 24. Let's see some code Zend_Acl Zend_Acl_Role_Interface Zend_Acl_Resource_Interface Zend_Acl_Assert_Interface 24
  • 25. Simple, Static ACL $acl = new Zend_Acl(); $eng = new Zend_Acl_Role('engineering'); $scotty = new Zend_Acl_Role('scotty'); $kirk = new Zend_Acl_Role('kirk'); $dilCrys = new Zend_Acl_Resource('dilithium crystals'); $acl->addRole($eng); $acl->addRole($scotty, $eng); $acl->addRole($kirk); $acl->addResource($dilCrys); $acl->allow($eng, $dilCrys); 25
  • 26. Simple, Static ACL echo "Can Scotty replace the dilithium crystals?n"; echo ($acl->isAllowed('scotty', 'dilithium crystals', 'replace')) ? "Can don" : "Cannae don"; echo "Can Kirk seduce the dilithium crystals?n"; echo ($acl->isAllowed('kirk', 'dilithium crystals', 'seduce')) ? "Really cann" : "Obviously notn"; rowan@swordbean:~$ php test01.php Can Scotty replace the dilithium crystals? Can do Can Kirk seduce the dilithium crystals? Obviously not 26
  • 27. Implementing Resource Any entity in your system: • Controllers • Models • Users • Files • Processes 27
  • 28. Implementing Resource class Ship implements Zend_Acl_Resource_Interface { public $captain; public $registry; public function getResourceId() { return $this->registry; } } $acl = new Zend_Acl(); $kirk = new Zend_Acl_Role('kirk'); $acl->addRole($kirk); $ship = new Ship(); $ship->captain = 'kirk'; $ship->registry = 'ncc-1701'; $acl->addResource($ship); 28
  • 29. Adding an Assertion class IsCaptainOf implements Zend_Acl_Assert_Interface { public function assert(Zend_Acl $acl, Zend_Acl_Role_Interface $role = null, Zend_Acl_Resource_Interface $resource = null, $privilege = null) { if ( !($resource instanceof Ship) ) { throw new Zend_Acl_Exception( 'IsCaptainOf assertion only valid on Ships' ); } return ($role->getRoleId() == $resource->captain); } } $assert = new IsCaptainOf(); $acl->allow('kirk', 'ncc-1701', 'destruct', $assert); echo "Can Kirk order self-destruct?n"; echo ($acl->isAllowed('kirk', 'ncc-1701', 'destruct')) ? "Star Trek III: The Search for Spockn" : "Non"; 29
  • 30. Adding an Assertion class IsCaptainOf implements Zend_Acl_Assert_Interface { public function assert(Zend_Acl $acl, Zend_Acl_Role_Interface $role = null, Zend_Acl_Resource_Interface $resource = null, $privilege = null) { if ( !($resource instanceof Ship) ) { throw new Zend_Acl_Exception( 'IsCaptainOf assertion only valid on Ships' ); } return ($role->getRoleId() == $resource->captain); } Increasing complexity } Introducing extra points of failure $assert = new IsCaptainOf(); $acl->allow('kirk', 'ncc-1701', 'destruct', $assert); echo "Can Kirk order self-destruct?n"; echo ($acl->isAllowed('kirk', 'ncc-1701', 'destruct')) ? "Star Trek III: The Search for Spockn" : "Non"; 30
  • 31. Dynamic ACL Store config. in the DB Build on the fly One size does not fit all 31
  • 32. Database structure 32
  • 33. Database structure Users not given permissions directly 33
  • 34. Database structure Role hierarchy restricted to Group → User 34
  • 35. Database structure Permissions assigned to 1 Group 35
  • 36. Database structure Resource is free text Does not need DB link e.g. Controllers 36
  • 37. Database structure Same for privilege 37
  • 38. Database structure Class name fragment 38
  • 39. DB Classes class Users extends Zend_Db_Table_Abstract { protected $_name = 'users'; protected $_primary = 'user_id'; protected $_dependentTables = array('UserGroups'); protected $_rowClass = 'User'; } class Groups extends Zend_Db_Table_Abstract { protected $_name = 'groups'; protected $_primary = 'group_id'; protected $_dependentTables = array('UserGroups'); protected $_rowClass = 'Group'; } 39
  • 40. DB Classes class UserGroups extends Zend_Db_Table_Abstract { protected $_name = 'user_groups'; protected $_primary = array('user_id', 'group_id'); protected $_referenceMap = array( 'User' => array( 'columns' => array('user_id'), 'refTableClass' => 'Users', 'refColumns' => array('user_id'), ), 'Group' => array( 'columns' => array('group_id'), 'refTableClass' => 'Groups', 'refColumns' => array('group_id'), ), ); } 40
  • 41. DB Classes class Permissions extends Zend_Db_Table_Abstract { protected $_name = 'permissions'; protected $_primary = 'permission_id'; protected $_referenceMap = array( 'Group' => array( 'columns' => array('group_id'), 'refTableClass' => 'Groups', 'refColumns' => array('group_id'), ), ); } 41
  • 42. Implementing Role interface Role_Interface extends Zend_Acl_Role_Interface { public function getType(); } class User extends Zend_Db_Table_Row_Abstract implements Role_Interface { public function getType() { return 'User'; } public function getRoleId() { return $this->getType().':'.$this->user_id; } } class Group extends Zend_Db_Table_Row_Abstract implements Role_Interface { public function getType() { return 'Group'; } public function getRoleId() { return $this->getType().':'.$this->group_id; } } 42
  • 43. What do we want to enforce? Users in the “command” group may issue orders to users subordinate to them 43
  • 44. Implementing Resource 44
  • 45. Implementing Resource interface Resource_Interface extends Zend_Acl_Role_Interface { public function getType(); } class Order extends Zend_Db_Table_Row_Abstract implements Resource_Interface { public function getType() { return 'Order'; } public function getResourceId() { $id = $this->getType(); if ($this->order_id) { $id .= ':'.$this->order_id; } return $id; } } 45
  • 46. Populate the DB mysql> select * from groups; +----------+-------------+ | group_id | name | +----------+-------------+ | 1 | command | | 2 | bridge crew | +----------+-------------+ mysql> select * from permissions; +---------------+-------+----------+----------+-----------+------------+ | permission_id | type | group_id | resource | privilege | assert | +---------------+-------+----------+----------+-----------+------------+ | 1 | allow | 1 | Order | read | NULL | | 2 | allow | 1 | Order | create | IsSuperior | | 3 | allow | NULL | Order | belay | IsIssuer | | 4 | allow | 2 | Order | read | NULL | +---------------+-------+----------+----------+-----------+------------+ 46
  • 47. Populate the DB mysql> select u.name, g.name as `group`, r.name as `rank` from users u inner join user_groups ug on u.user_id = ug.user_id inner join groups g on ug.group_id = g.group_id inner join user_ranks ur on u.user_id = ur.user_id inner join ranks r on ur.rank_id = r.rank_id; +------+-------------+---------+ | name | group | rank | +------+-------------+---------+ | kirk | command | captain | | rand | bridge crew | yeoman | +------+-------------+---------+ 47
  • 48. Issuing an order $issuer = Zend_Auth::getInstance()->getIdentity(); $u = new Users(); $subord = $u->find(2)->current(); $order = new Order(); $order->superior_user_id = $issuer->user_id; $order->subordinate_user_id = $subord->user_id; $order->detail = "Get your red shirt, it's time for an away mission."; $acl = new AclWrapper(); if (!$acl->isAllowed($issuer, $order, 'create')) { throw new Zend_Controller_Action_Exception( 'Not allowed to create order!' , 403); } $order->save(); 48
  • 49. Issuing an order $issuer = Zend_Auth::getInstance()->getIdentity(); $u = new Users(); $subord = $u->find(2)->current(); $order = new Order(); $order->superior_user_id = $issuer->user_id; You could move $order->subordinate_user_id = $subord->user_id; this check $order->detail = "Get your red shirt, onto the model it's time for an away mission."; $acl = new AclWrapper(); if (!$acl->isAllowed($issuer, $order, 'create')) { throw new Zend_Controller_Action_Exception( 'Not allowed to create order!' , 403); } $order->save(); 49
  • 50. Building the ACL class AclWrapper { public function isAllowed(User $role = null, Resource_Interface $resource = null, $privilege = null) { $acl = new Zend_Acl(); $groups = $user->findGroups(); foreach ($groups as $group) { $acl->addRole($group); } $acl->addRole($user, $groups); if (strpos($resource->getResourceId(), ':')) { $parent = new Zend_Acl_Resource($resource->getType()); $acl->addResource($parent); $acl->addResource($resource, $parent); } else { $acl->addResource($resource); } [...] 50
  • 51. Building the ACL class AclWrapper { public function isAllowed(User $role = null, Resource_Interface $resource = null, $privilege = null) { $acl = new Zend_Acl(); $groups = $user->findGroups(); Add Group roles foreach ($groups as $group) { Add the User role $acl->addRole($group); } $acl->addRole($user, $groups); if (strpos($resource->getResourceId(), ':')) { $parent = new Zend_Acl_Resource($resource->getType()); $acl->addResource($parent); $acl->addResource($resource, $parent); } else { $acl->addResource($resource); } [...] 51
  • 52. Building the ACL class AclWrapper { public function isAllowed(User $role = null, Resource_Interface $resource = null, $privilege = null) { $acl = new Zend_Acl(); $groups = $user->findGroups(); foreach ($groups as $group) { $acl->addRole($group); } $acl->addRole($user, $groups); if (strpos($resource->getResourceId(), ':')) { $parent = new Zend_Acl_Resource($resource->getType()); $acl->addResource($parent); $acl->addResource($resource, $parent); } else { $acl->addResource($resource); ':' means adding an instance } and its parent [...] 52
  • 53. Building the ACL foreach ($groups as $group) { foreach ($groups->findPermissions as $permission) { $assert = null; $classname = $permission->assert; if ( $classname && class_exists($classname) && is_subclass_of($classname, 'Zend_Acl_Assert_Interface') ) { $assert = new $classname(); } $op = ($permission->type == 'allow') ? 'allow' : 'deny'; $acl->$op($group, $resource, $permission->privilege, $assert); } } return $acl->isAllowed($role, $resource, $privilege); } } 53
  • 54. Building the ACL foreach ($groups as $group) { foreach ($groups->findPermissions as $permission) { $assert = null; $classname = $permission->assert; if ( $classname && class_exists($classname) && is_subclass_of($classname, 'Zend_Acl_Assert_Interface') ) { $assert = new $classname(); } Validate as much as possible! $op = ($permission->type == 'allow') ? 'allow' : 'deny'; $acl->$op($group, $resource, $permission->privilege, $assert); } } return $acl->isAllowed($role, $resource, $privilege); } } 54
  • 55. Asserting Superiority class IsSuperior implements Zend_Acl_Assert_Interface { public function assert( Zend_Acl $acl, Zend_Acl_Role_Interface $role = null, Zend_Acl_Resource_Interface $resource = null, $privilege = null) { if (!$role instanceof User) { throw new Zend_Acl_Exception('Assertion only applies to Users'); } if (!$resource instanceof Order) { throw new Zend_Acl_Exception('Assertion only applies to Orders'); } $supRank = $role->findRanks()->current(); $subRank = $resource->findUsersBySubordinate()->current(); return ($supRank->rank_id > $subRank->rank_id); } } 55
  • 56. Issuing an order $issuer = Zend_Auth::getInstance()->getIdentity(); $u = new Users(); $subord = $u->find(2)->current(); $order = new Order(); $order->superior_user_id = $issuer->user_id; $order->subordinate_user_id = $subord->user_id; $order->detail = "Get your red shirt, it's time for an away mission."; $acl = new AclWrapper(); if (!$acl->isAllowed($issuer, $order, 'create')) { throw new Zend_Controller_Action_Exception( 'Not allowed to create order!' , 403); } $order->save(); 56
  • 57. Conclusions Is this the right way? 57
  • 58. Attaching the ACL • Controller and Action? • Model and Method? • Business object and Action? • All of the above? 58
  • 59. Unit testing • Pass the Zend_Acl into your wrapper • Use a factory 59
  • 60. Caching the ACL • Build everything for the User? • Build everything for the Resource? • Build everything for everything! 60
  • 61. Advice • Think about what you want to protect • Test your solution with realistic data • Assume that you are wrong 61
  • 62. Questions? 62
  • 63. Feedback http://joind.in/2054 “...even a well presented talk by a charismatic speaker upset me.” 63
  • 64. Credits http://www.flickr.com/photos/innoxiuss/2824204305/ http://www.flickr.com/photos/carianoff/2849384997/ 64