1 <?xml version="1.0" encoding="UTF-8"?>
3 <sect1 id="zend.acl.introduction">
4 <title>Introduction</title>
7 <classname>Zend_Acl</classname> provides a lightweight and flexible access control list
8 (<acronym>ACL</acronym>) implementation for privileges management. In general, an
9 application may utilize such <acronym>ACL</acronym>'s to control access to certain
10 protected objects by other requesting objects.
14 For the purposes of this documentation:
20 a <emphasis>resource</emphasis> is an object
21 to which access is controlled.
27 a <emphasis>role</emphasis> is an object
28 that may request access to a Resource.
34 Put simply, <emphasis>roles request access to resources</emphasis>. For
35 example, if a parking attendant requests access to a car, then the parking attendant is the
36 requesting role, and the car is the resource, since access to the car may not be granted to
41 Through the specification and use of an <acronym>ACL</acronym>, an application may control
42 how roles are granted access to resources.
45 <sect2 id="zend.acl.introduction.resources">
46 <title>Resources</title>
49 Creating a resource in <classname>Zend_Acl</classname> is very simple.
50 <classname>Zend_Acl</classname> provides the resource,
51 <classname>Zend_Acl_Resource_Interface</classname>, to facilitate creating resources in
52 an application. A class need only implement this interface, which consists of a single
53 method, <methodname>getResourceId()</methodname>, for <classname>Zend_Acl</classname> to
54 recognize the object as a resource. Additionally,
55 <classname>Zend_Acl_Resource</classname> is provided by <classname>Zend_Acl</classname>
56 as a basic resource implementation for developers to extend as needed.
60 <classname>Zend_Acl</classname> provides a tree structure to which multiple resources
61 can be added. Since resources are stored in such a tree structure, they can be
62 organized from the general (toward the tree root) to the specific (toward the tree
63 leaves). Queries on a specific resource will automatically search the resource's
64 hierarchy for rules assigned to ancestor resources, allowing for simple inheritance of
65 rules. For example, if a default rule is to be applied to each building in a city, one
66 would simply assign the rule to the city, instead of assigning the same rule to each
67 building. Some buildings may require exceptions to such a rule, however, and this can
68 be achieved in <classname>Zend_Acl</classname> by assigning such exception rules to
69 each building that requires such an exception. A resource may inherit from only one
70 parent resource, though this parent resource can have its own parent resource, etc.
74 <classname>Zend_Acl</classname> also supports privileges on resources (e.g., "create",
75 "read", "update", "delete"), so the developer can assign rules that affect all
76 privileges or specific privileges on one or more resources.
80 <sect2 id="zend.acl.introduction.roles">
84 As with resources, creating a role is also very simple. All roles must implement
85 <classname>Zend_Acl_Role_Interface</classname>. This interface consists of a single
86 method, <methodname>getRoleId()</methodname>, Additionally,
87 <classname>Zend_Acl_Role</classname> is provided by <classname>Zend_Acl</classname> as
88 a basic role implementation for developers to extend as needed.
92 In <classname>Zend_Acl</classname>, a role may inherit from one or more roles. This is
93 to support inheritance of rules among roles. For example, a user role, such as "sally",
94 may belong to one or more parent roles, such as "editor" and "administrator". The
95 developer can assign rules to "editor" and "administrator" separately, and "sally"
96 would inherit such rules from both, without having to assign rules directly to "sally".
100 Though the ability to inherit from multiple roles is very useful, multiple inheritance
101 also introduces some degree of complexity. The following example illustrates the
102 ambiguity condition and how <classname>Zend_Acl</classname> solves it.
105 <example id="zend.acl.introduction.roles.example.multiple_inheritance">
106 <title>Multiple Inheritance among Roles</title>
109 The following code defines three base roles - "guest",
110 "member", and "admin" - from which other roles may
111 inherit. Then, a role identified by "someUser" is established and
112 inherits from the three other roles. The order in which these roles appear in the
113 <varname>$parents</varname> array is important. When necessary,
114 <classname>Zend_Acl</classname> searches for access rules defined not only for the
115 queried role (herein, "someUser"), but also upon the roles from which
116 the queried role inherits (herein, "guest", "member", and
120 <programlisting language="php"><![CDATA[
121 $acl = new Zend_Acl();
123 $acl->addRole(new Zend_Acl_Role('guest'))
124 ->addRole(new Zend_Acl_Role('member'))
125 ->addRole(new Zend_Acl_Role('admin'));
127 $parents = array('guest', 'member', 'admin');
128 $acl->addRole(new Zend_Acl_Role('someUser'), $parents);
130 $acl->add(new Zend_Acl_Resource('someResource'));
132 $acl->deny('guest', 'someResource');
133 $acl->allow('member', 'someResource');
135 echo $acl->isAllowed('someUser', 'someResource') ? 'allowed' : 'denied';
139 Since there is no rule specifically defined for the "someUser" role and
140 "someResource", <classname>Zend_Acl</classname> must search for rules that may be
141 defined for roles that "someUser" inherits. First, the "admin" role is visited, and
142 there is no access rule defined for it. Next, the "member" role is visited, and
143 <classname>Zend_Acl</classname> finds that there is a rule specifying that "member"
144 is allowed access to "someResource".
148 If <classname>Zend_Acl</classname> were to continue examining the rules defined for
149 other parent roles, however, it would find that "guest" is denied access to
150 "someResource". This fact introduces an ambiguity because now
151 "someUser" is both denied and allowed access to "someResource", by reason of having
152 inherited conflicting rules from different parent roles.
156 <classname>Zend_Acl</classname> resolves this ambiguity by completing a query when
157 it finds the first rule that is directly applicable to the query. In this case,
158 since the "member" role is examined before the "guest" role, the example code would
165 When specifying multiple parents for a role, keep in mind that the last parent
166 listed is the first one searched for rules applicable to an authorization query.
171 <sect2 id="zend.acl.introduction.creating">
172 <title>Creating the Access Control List</title>
175 An Access Control List (<acronym>ACL</acronym>) can represent any set of physical or
176 virtual objects that you wish. For the purposes of demonstration, however, we will
177 create a basic Content Management System (<acronym>CMS</acronym>)
178 <acronym>ACL</acronym> that maintains several tiers of groups over a wide variety of
179 areas. To create a new <acronym>ACL</acronym> object, we instantiate the
180 <acronym>ACL</acronym> with no parameters:
183 <programlisting language="php"><![CDATA[
184 $acl = new Zend_Acl();
189 Until a developer specifies an "allow" rule, <classname>Zend_Acl</classname> denies
190 access to every privilege upon every resource by every role.
195 <sect2 id="zend.acl.introduction.role_registry">
196 <title>Registering Roles</title>
199 <acronym>CMS</acronym>'s will nearly always require a hierarchy of permissions to
200 determine the authoring capabilities of its users. There may be a 'Guest' group to
201 allow limited access for demonstrations, a 'Staff' group for the majority of
202 <acronym>CMS</acronym> users who perform most of the day-to-day operations, an 'Editor'
203 group for those responsible for publishing, reviewing, archiving and deleting content,
204 and finally an 'Administrator' group whose tasks may include all of those of the other
205 groups as well as maintenance of sensitive information, user management, back-end
206 configuration data, backup and export. This set of permissions can be represented in a
207 role registry, allowing each group to inherit privileges from 'parent' groups, as well
208 as providing distinct privileges for their unique group only. The permissions may be
209 expressed as follows:
212 <table id="zend.acl.introduction.role_registry.table.example_cms_access_controls">
213 <title>Access Controls for an Example CMS</title>
218 <entry>Unique Permissions</entry>
219 <entry>Inherit Permissions From</entry>
232 <entry>Edit, Submit, Revise</entry>
237 <entry>Editor</entry>
238 <entry>Publish, Archive, Delete</entry>
243 <entry>Administrator</entry>
244 <entry>(Granted all access)</entry>
252 For this example, <classname>Zend_Acl_Role</classname> is used, but any object that
253 implements <classname>Zend_Acl_Role_Interface</classname> is acceptable. These groups
254 can be added to the role registry as follows:
257 <programlisting language="php"><![CDATA[
258 $acl = new Zend_Acl();
260 // Add groups to the Role registry using Zend_Acl_Role
261 // Guest does not inherit access controls
262 $roleGuest = new Zend_Acl_Role('guest');
263 $acl->addRole($roleGuest);
265 // Staff inherits from guest
266 $acl->addRole(new Zend_Acl_Role('staff'), $roleGuest);
269 Alternatively, the above could be written:
270 $acl->addRole(new Zend_Acl_Role('staff'), 'guest');
273 // Editor inherits from staff
274 $acl->addRole(new Zend_Acl_Role('editor'), 'staff');
276 // Administrator does not inherit access controls
277 $acl->addRole(new Zend_Acl_Role('administrator'));
281 <sect2 id="zend.acl.introduction.defining">
282 <title>Defining Access Controls</title>
285 Now that the <acronym>ACL</acronym> contains the relevant roles, rules can be
286 established that define how resources may be accessed by roles. You may have noticed
287 that we have not defined any particular resources for this example, which is simplified
288 to illustrate that the rules apply to all resources. <classname>Zend_Acl</classname>
289 provides an implementation whereby rules need only be assigned from general to
290 specific, minimizing the number of rules needed, because resources and roles inherit
291 rules that are defined upon their ancestors.
296 In general, <classname>Zend_Acl</classname> obeys a given rule if and only if a
297 more specific rule does not apply.
302 Consequently, we can define a reasonably complex set of rules with a minimum amount of
303 code. To apply the base permissions as defined above:
306 <programlisting language="php"><![CDATA[
307 $acl = new Zend_Acl();
309 $roleGuest = new Zend_Acl_Role('guest');
310 $acl->addRole($roleGuest);
311 $acl->addRole(new Zend_Acl_Role('staff'), $roleGuest);
312 $acl->addRole(new Zend_Acl_Role('editor'), 'staff');
313 $acl->addRole(new Zend_Acl_Role('administrator'));
315 // Guest may only view content
316 $acl->allow($roleGuest, null, 'view');
319 Alternatively, the above could be written:
320 $acl->allow('guest', null, 'view');
323 // Staff inherits view privilege from guest, but also needs additional
325 $acl->allow('staff', null, array('edit', 'submit', 'revise'));
327 // Editor inherits view, edit, submit, and revise privileges from
328 // staff, but also needs additional privileges
329 $acl->allow('editor', null, array('publish', 'archive', 'delete'));
331 // Administrator inherits nothing, but is allowed all privileges
332 $acl->allow('administrator');
336 The <constant>NULL</constant> values in the above <methodname>allow()</methodname> calls
337 are used to indicate that the allow rules apply to all resources.
341 <sect2 id="zend.acl.introduction.querying">
342 <title>Querying an ACL</title>
345 We now have a flexible <acronym>ACL</acronym> that can be used to determine whether
346 requesters have permission to perform functions throughout the web application.
347 Performing queries is quite simple using the <methodname>isAllowed()</methodname>
351 <programlisting language="php"><![CDATA[
352 echo $acl->isAllowed('guest', null, 'view') ?
353 "allowed" : "denied";
356 echo $acl->isAllowed('staff', null, 'publish') ?
357 "allowed" : "denied";
360 echo $acl->isAllowed('staff', null, 'revise') ?
361 "allowed" : "denied";
364 echo $acl->isAllowed('editor', null, 'view') ?
365 "allowed" : "denied";
366 // allowed because of inheritance from guest
368 echo $acl->isAllowed('editor', null, 'update') ?
369 "allowed" : "denied";
370 // denied because no allow rule for 'update'
372 echo $acl->isAllowed('administrator', null, 'view') ?
373 "allowed" : "denied";
374 // allowed because administrator is allowed all privileges
376 echo $acl->isAllowed('administrator') ?
377 "allowed" : "denied";
378 // allowed because administrator is allowed all privileges
380 echo $acl->isAllowed('administrator', null, 'update') ?
381 "allowed" : "denied";
382 // allowed because administrator is allowed all privileges