| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- Reviewed: no -->
- <sect1 id="zend.acl.introduction">
- <title>Introduction</title>
- <para>
- <classname>Zend_Acl</classname> provides a lightweight and flexible access control list
- (<acronym>ACL</acronym>) implementation for privileges management. In general, an
- application may utilize such <acronym>ACL</acronym>'s to control access to certain
- protected objects by other requesting objects.
- </para>
- <para>
- For the purposes of this documentation:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- a <emphasis>resource</emphasis> is an object
- to which access is controlled.
- </para>
- </listitem>
- <listitem>
- <para>
- a <emphasis>role</emphasis> is an object
- that may request access to a Resource.
- </para>
- </listitem>
- </itemizedlist>
- <para>
- Put simply, <emphasis>roles request access to resources</emphasis>. For
- example, if a parking attendant requests access to a car, then the parking attendant is the
- requesting role, and the car is the resource, since access to the car may not be granted to
- everyone.
- </para>
- <para>
- Through the specification and use of an <acronym>ACL</acronym>, an application may control
- how roles are granted access to resources.
- </para>
- <sect2 id="zend.acl.introduction.resources">
- <title>Resources</title>
- <para>
- Creating a resource in <classname>Zend_Acl</classname> is very simple.
- <classname>Zend_Acl</classname> provides the resource,
- <classname>Zend_Acl_Resource_Interface</classname>, to facilitate creating resources in
- an application. A class need only implement this interface, which consists of a single
- method, <methodname>getResourceId()</methodname>, for <classname>Zend_Acl</classname> to
- recognize the object as a resource. Additionally,
- <classname>Zend_Acl_Resource</classname> is provided by <classname>Zend_Acl</classname>
- as a basic resource implementation for developers to extend as needed.
- </para>
- <para>
- <classname>Zend_Acl</classname> provides a tree structure to which multiple resources
- can be added. Since resources are stored in such a tree structure, they can be
- organized from the general (toward the tree root) to the specific (toward the tree
- leaves). Queries on a specific resource will automatically search the resource's
- hierarchy for rules assigned to ancestor resources, allowing for simple inheritance of
- rules. 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 <classname>Zend_Acl</classname> by assigning such exception rules to
- each building that requires such an exception. A resource may inherit from only one
- parent resource, though this parent resource can have its own parent resource, etc.
- </para>
- <para>
- <classname>Zend_Acl</classname> also supports privileges on resources (e.g., "create",
- "read", "update", "delete"), so the developer can assign rules that affect all
- privileges or specific privileges on one or more resources.
- </para>
- </sect2>
- <sect2 id="zend.acl.introduction.roles">
- <title>Roles</title>
- <para>
- As with resources, creating a role is also very simple. All roles must implement
- <classname>Zend_Acl_Role_Interface</classname>. This interface consists of a single
- method, <methodname>getRoleId()</methodname>, Additionally,
- <classname>Zend_Acl_Role</classname> is provided by <classname>Zend_Acl</classname> as
- a basic role implementation for developers to extend as needed.
- </para>
- <para>
- In <classname>Zend_Acl</classname>, a role may inherit from one or more roles. This is
- to support inheritance of rules among roles. For example, a user role, such as "sally",
- may belong to one or more parent roles, such as "editor" and "administrator". The
- developer can assign rules to "editor" and "administrator" separately, and "sally"
- would inherit such rules from both, without having to assign rules directly to "sally".
- </para>
- <para>
- Though the ability to inherit from multiple roles is very useful, multiple inheritance
- also introduces some degree of complexity. The following example illustrates the
- ambiguity condition and how <classname>Zend_Acl</classname> solves it.
- </para>
- <example id="zend.acl.introduction.roles.example.multiple_inheritance">
- <title>Multiple Inheritance among Roles</title>
- <para>
- The following code defines three base roles - "guest",
- "member", and "admin" - from which other roles may
- inherit. Then, a role identified by "someUser" is established and
- inherits from the three other roles. The order in which these roles appear in the
- <varname>$parents</varname> array is important. When necessary,
- <classname>Zend_Acl</classname> searches for access rules defined not only for the
- queried role (herein, "someUser"), but also upon the roles from which
- the queried role inherits (herein, "guest", "member", and
- "admin"):
- </para>
- <programlisting language="php"><![CDATA[
- $acl = new Zend_Acl();
- $acl->addRole(new Zend_Acl_Role('guest'))
- ->addRole(new Zend_Acl_Role('member'))
- ->addRole(new Zend_Acl_Role('admin'));
- $parents = array('guest', 'member', 'admin');
- $acl->addRole(new Zend_Acl_Role('someUser'), $parents);
- $acl->add(new Zend_Acl_Resource('someResource'));
- $acl->deny('guest', 'someResource');
- $acl->allow('member', 'someResource');
- echo $acl->isAllowed('someUser', 'someResource') ? 'allowed' : 'denied';
- ]]></programlisting>
- <para>
- Since there is no rule specifically defined for the "someUser" role and
- "someResource", <classname>Zend_Acl</classname> must search for rules that may be
- defined for roles that "someUser" inherits. First, the "admin" role is visited, and
- there is no access rule defined for it. Next, the "member" role is visited, and
- <classname>Zend_Acl</classname> finds that there is a rule specifying that "member"
- is allowed access to "someResource".
- </para>
- <para>
- If <classname>Zend_Acl</classname> were to continue examining the rules defined for
- other parent roles, however, it would find that "guest" is denied access to
- "someResource". This fact introduces an ambiguity because now
- "someUser" is both denied and allowed access to "someResource", by reason of having
- inherited conflicting rules from different parent roles.
- </para>
- <para>
- <classname>Zend_Acl</classname> resolves this ambiguity by completing a query when
- it finds the first rule that is directly applicable to the query. In this case,
- since the "member" role is examined before the "guest" role, the example code would
- print "allowed".
- </para>
- </example>
- <note>
- <para>
- When specifying multiple parents for a role, keep in mind that the last parent
- listed is the first one searched for rules applicable to an authorization query.
- </para>
- </note>
- </sect2>
- <sect2 id="zend.acl.introduction.creating">
- <title>Creating the Access Control List</title>
- <para>
- An Access Control List (<acronym>ACL</acronym>) can represent any set of physical or
- virtual objects that you wish. For the purposes of demonstration, however, we will
- create a basic Content Management System (<acronym>CMS</acronym>)
- <acronym>ACL</acronym> that maintains several tiers of groups over a wide variety of
- areas. To create a new <acronym>ACL</acronym> object, we instantiate the
- <acronym>ACL</acronym> with no parameters:
- </para>
- <programlisting language="php"><![CDATA[
- $acl = new Zend_Acl();
- ]]></programlisting>
- <note>
- <para>
- Until a developer specifies an "allow" rule, <classname>Zend_Acl</classname> denies
- access to every privilege upon every resource by every role.
- </para>
- </note>
- </sect2>
- <sect2 id="zend.acl.introduction.role_registry">
- <title>Registering Roles</title>
- <para>
- <acronym>CMS</acronym>'s will nearly always require a hierarchy of permissions to
- determine the authoring capabilities of its users. There may be a 'Guest' group to
- allow limited access for demonstrations, a 'Staff' group for the majority of
- <acronym>CMS</acronym> users who perform most of the day-to-day operations, an 'Editor'
- group for those responsible for publishing, reviewing, archiving and deleting content,
- and finally an 'Administrator' group whose tasks may include all of those of the other
- groups as well as maintenance of sensitive information, user management, back-end
- configuration data, backup and export. This set of permissions can be represented in a
- role registry, allowing each group to inherit privileges from 'parent' groups, as well
- as providing distinct privileges for their unique group only. The permissions may be
- expressed as follows:
- </para>
- <table id="zend.acl.introduction.role_registry.table.example_cms_access_controls">
- <title>Access Controls for an Example CMS</title>
- <tgroup cols="3">
- <thead>
- <row>
- <entry>Name</entry>
- <entry>Unique Permissions</entry>
- <entry>Inherit Permissions From</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>Guest</entry>
- <entry>View</entry>
- <entry>N/A</entry>
- </row>
- <row>
- <entry>Staff</entry>
- <entry>Edit, Submit, Revise</entry>
- <entry>Guest</entry>
- </row>
- <row>
- <entry>Editor</entry>
- <entry>Publish, Archive, Delete</entry>
- <entry>Staff</entry>
- </row>
- <row>
- <entry>Administrator</entry>
- <entry>(Granted all access)</entry>
- <entry>N/A</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- <para>
- For this example, <classname>Zend_Acl_Role</classname> is used, but any object that
- implements <classname>Zend_Acl_Role_Interface</classname> is acceptable. These groups
- can be added to the role registry as follows:
- </para>
- <programlisting language="php"><![CDATA[
- $acl = new Zend_Acl();
- // Add groups to the Role registry using Zend_Acl_Role
- // Guest does not inherit access controls
- $roleGuest = new Zend_Acl_Role('guest');
- $acl->addRole($roleGuest);
- // Staff inherits from guest
- $acl->addRole(new Zend_Acl_Role('staff'), $roleGuest);
- /*
- Alternatively, the above could be written:
- $acl->addRole(new Zend_Acl_Role('staff'), 'guest');
- */
- // Editor inherits from staff
- $acl->addRole(new Zend_Acl_Role('editor'), 'staff');
- // Administrator does not inherit access controls
- $acl->addRole(new Zend_Acl_Role('administrator'));
- ]]></programlisting>
- </sect2>
- <sect2 id="zend.acl.introduction.defining">
- <title>Defining Access Controls</title>
- <para>
- Now that the <acronym>ACL</acronym> contains the relevant roles, rules can be
- established that define how resources may be accessed by roles. You may have noticed
- that we have not defined any particular resources for this example, which is simplified
- to illustrate that the rules apply to all resources. <classname>Zend_Acl</classname>
- provides an implementation whereby rules need only be assigned from general to
- specific, minimizing the number of rules needed, because resources and roles inherit
- rules that are defined upon their ancestors.
- </para>
- <note>
- <para>
- In general, <classname>Zend_Acl</classname> obeys a given rule if and only if a
- more specific rule does not apply.
- </para>
- </note>
- <para>
- Consequently, we can define a reasonably complex set of rules with a minimum amount of
- code. To apply the base permissions as defined above:
- </para>
- <programlisting language="php"><![CDATA[
- $acl = new Zend_Acl();
- $roleGuest = new Zend_Acl_Role('guest');
- $acl->addRole($roleGuest);
- $acl->addRole(new Zend_Acl_Role('staff'), $roleGuest);
- $acl->addRole(new Zend_Acl_Role('editor'), 'staff');
- $acl->addRole(new Zend_Acl_Role('administrator'));
- // Guest may only view content
- $acl->allow($roleGuest, null, 'view');
- /*
- Alternatively, the above could be written:
- $acl->allow('guest', null, 'view');
- //*/
- // Staff inherits view privilege from guest, but also needs additional
- // privileges
- $acl->allow('staff', null, array('edit', 'submit', 'revise'));
- // Editor inherits view, edit, submit, and revise privileges from
- // staff, but also needs additional privileges
- $acl->allow('editor', null, array('publish', 'archive', 'delete'));
- // Administrator inherits nothing, but is allowed all privileges
- $acl->allow('administrator');
- ]]></programlisting>
- <para>
- The <constant>NULL</constant> values in the above <methodname>allow()</methodname> calls
- are used to indicate that the allow rules apply to all resources.
- </para>
- </sect2>
- <sect2 id="zend.acl.introduction.querying">
- <title>Querying an ACL</title>
- <para>
- We now have a flexible <acronym>ACL</acronym> that can be used to determine whether
- requesters have permission to perform functions throughout the web application.
- Performing queries is quite simple using the <methodname>isAllowed()</methodname>
- method:
- </para>
- <programlisting language="php"><![CDATA[
- echo $acl->isAllowed('guest', null, 'view') ?
- "allowed" : "denied";
- // allowed
- echo $acl->isAllowed('staff', null, 'publish') ?
- "allowed" : "denied";
- // denied
- echo $acl->isAllowed('staff', null, 'revise') ?
- "allowed" : "denied";
- // allowed
- echo $acl->isAllowed('editor', null, 'view') ?
- "allowed" : "denied";
- // allowed because of inheritance from guest
- echo $acl->isAllowed('editor', null, 'update') ?
- "allowed" : "denied";
- // denied because no allow rule for 'update'
- echo $acl->isAllowed('administrator', null, 'view') ?
- "allowed" : "denied";
- // allowed because administrator is allowed all privileges
- echo $acl->isAllowed('administrator') ?
- "allowed" : "denied";
- // allowed because administrator is allowed all privileges
- echo $acl->isAllowed('administrator', null, 'update') ?
- "allowed" : "denied";
- // allowed because administrator is allowed all privileges
- ]]></programlisting>
- </sect2>
- </sect1>
- <!--
- vim:se ts=4 sw=4 et:
- -->
|