<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>
<channel>
	<title>Chris Morrell &#187; galahad-fe</title>
	<atom:link href="http://cmorrell.com/tag/galahad-fe/feed" rel="self" type="application/rss+xml" />
	<link>http://cmorrell.com</link>
	<description>The personal home page of Chris Morrell</description>
	<lastBuildDate>Thu, 02 Sep 2010 01:05:13 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Namespacing ACL resources &amp; Galahad_Acl</title>
		<link>http://cmorrell.com/webdev/zf/namespacing-acl-resources-galahad-acl-737</link>
		<comments>http://cmorrell.com/webdev/zf/namespacing-acl-resources-galahad-acl-737#comments</comments>
		<pubDate>Wed, 17 Mar 2010 16:04:25 +0000</pubDate>
		<dc:creator>inxilpro</dc:creator>
				<category><![CDATA[Zend Framework]]></category>
		<category><![CDATA[galahad-fe]]></category>
		<category><![CDATA[wishlist]]></category>
		<guid isPermaLink="false">http://cmorrell.com/?p=737</guid>
		<description><![CDATA[In most of my applications I like to handle authorization (querying the ACL) in one (or more) of three ways: Authorize access to a model&#8217;s method Authorize access to a controller action Authorize access to an arbitrary &#8220;permission&#8221; In general &#8230; <a href="http://cmorrell.com/webdev/zf/namespacing-acl-resources-galahad-acl-737">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>In most of my applications I like to handle authorization (querying the ACL) in one (or more) of three ways:</p>
<ul>
<li>Authorize access to a model&#8217;s method</li>
<li>Authorize access to a controller action</li>
<li>Authorize access to an arbitrary &#8220;permission&#8221;</li>
</ul>
<p>In general I find it&#8217;s best to keep authorization within the domain (querying the ACL within my models when they&#8217;re accessed) as this provides the most consistent behavior.  For example, if I eventually add a REST API to my application I don&#8217;t have to duplicate all my authorization logic in the new REST controllers.  When the application calls something like <code>Default_Model_Post::save()</code> it either saves or throws an ACL exception, no matter where it was called from.  This is great in that it saves me from having to duplicate code and keeps my system more secure.</p>
<p>On the other hand, there are times when it&#8217;s just a lot easier to handle authorization in the controller.  For example, if guests should never access my &#8220;Admin&#8221; module, it doesn&#8217;t make sense to ever let them access /admin/ URLs.  Also, if you&#8217;re using Zend_Navigation, having ACL resources that match controller actions lets you utilize its ACL integration.</p>
<p>If you&#8217;re ever going to mix these two techniques, you&#8217;ll eventually bump into the case where a model and a controller share the same name.  What if you need to set permissions on a &#8220;user&#8221; controller and different permissions on a &#8220;user&#8221; model?  This is where namespacing comes into play.  As suggested by the <a href="http://framework.zend.com/manual/en/zend.view.helpers.html#zend.view.helpers.initial.navigation.setup" target="_blank">Zend Framework manual</a>, I always name my controller action resources in the format <code>mvc:module.controller.action</code>.  I name my model resources similarly, in the format <code>model:module.modelName.methodName</code>.  In both theses cases, &#8220;mvc&#8221; and &#8220;model&#8221; are the namespace, and everything following the colon is the actual resource name.  Now I can refer to my &#8220;admin&#8221; module as <code>mvc:admin</code> and the models within my admin module as <code>model:admin</code>.</p>
<p>This is where things get interesting.  If you set up your ACL chains correctly, you can set permissions on whole modules or models and have those rules cascade to their child controllers or methods.  For example, say you set up your ACL as follows:</p>
<pre class="brush: php;">
$acl = new Zend_Acl();
$acl-&gt;addResource('mvc:');
$acl-&gt;addResource('mvc:admin', 'mvc:');
$acl-&gt;addResource('mvc:admin.user', 'mvc:admin');
$acl-&gt;addResource('mvc:admin.user.create', 'mvc:admin.user');
$acl-&gt;addRole('guest');
$acl-&gt;addRole('admin', 'guest');
$acl-&gt;deny();
$acl-&gt;allow('admin', 'mvc:admin');
</pre>
<p>Now if a user with the role &#8220;admin&#8221; tries to access the resource &#8220;mvc:admin.user.create&#8221; (http://basename/admin/user/create) they will be allowed, but a user with the role &#8220;guest&#8221; will not.  Using this technique gives you as much granularity as you need in your ACL, but at the same time lets you set broad permissions where appropriate.</p>
<p>This is where <code>Galahad_Acl</code> comes into play.  Setting up all these resources can be tedious, as is checking permissions in each controller.  <code>Galahad_Acl</code> in conjunction with <code>Galahad_Model_Entity</code> and <code>Galahad_Controller_Plugin_Acl</code> automate everything but the actual permissions that are specific to your application.</p>
<p><span id="more-737"></span></p>
<p>By default, whenever <code>Galahad_Acl</code> has a role added to it in the format &#8220;namespace:resource.subResourse&#8221; (etc) it automatically adds the resources up the chain.  For example, if I add &#8220;mvc:default.index.index&#8221; to a Galahad_Acl object, it would add the following resources to the ACL:</p>
<ul>
<li>mvc:</li>
<li>mvc:default (parent = &#8220;mvc:&#8221;)</li>
<li>mvc:default.index (parent = &#8220;mvc:default&#8221;)</li>
<li>mvc:default.index.index (parent = &#8220;mvc:default.index&#8221;)</li>
</ul>
<p><code>Galahad_Controller_Plugin_Acl</code> takes this a step further by automatically adding any controller action that&#8217;s dispatched to the ACL and then checking against the ACL.  This means that with the following ACL:</p>
<pre class="brush: php;">
$acl = new Galahad_Acl();
$acl-&gt;addRole('guest');
$acl-&gt;addRole('staff', 'guest');
$acl-&gt;addRole('admin', 'staff');
$acl-&gt;addResource('mvc:blog.entry.view');
$acl-&gt;deny();
$acl-&gt;allow('admin', 'mvc:');
$acl-&gt;allow('staff', 'mvc:blog');
$acl-&gt;allow('guest', 'mvc:blog.entry.view');
</pre>
<p>The following would be true:</p>
<ul>
<li>Role &#8220;admin&#8221; would be allowed access to any URL (&#8220;admin&#8221; is allowed access to &#8220;mvc:&#8221;)</li>
<li>Role &#8220;staff&#8221; would be allowed access to /blog/entry/edit even though permissions weren&#8217;t explicitly set for the resource &#8220;mvc:blog.entry.edit&#8221; (because &#8220;staff&#8221; is allowed to access &#8220;mvc:blog&#8221;)</li>
<li>Role &#8220;guest&#8221; would be allowed to view /blog/entry/view but no other portion of the blog (&#8220;guest&#8221; is allowed access to the specific resource &#8220;mvc:blog.entry.view&#8221;)</li>
</ul>
<p><code>Galahad_Model_Entity</code> works similarly.  By default each entity adds itself to the ACL in the format &#8220;model:module.modelName&#8221; so that the model <code>Default_Model_User</code> has the resource ID &#8220;model:default.user&#8221;.  Each model has a method called <code>_initAcl</code> which lets you manage permissions on a per-model basis.  This is better demonstrated in code:</p>
<pre class="brush: php;">
class Default_Model_Post extends Galahad_Model_Entity
{
    protected function _initAcl($acl)
    {
        // Deny permissions to anything on this model unless explicitly allowed
        // We don't have to add &quot;model:default.post&quot; because Galahad_Model_Entity
        // automatically does that for us
        $acl-&gt;deny(null, $this);
        // Allow guests to fetch the content of posts
        $acl-&gt;allow('guest', $this, 'fetch')
        // Allow admins to save changes to posts
        $acl-&gt;allow('admin', $this, 'save')
    }
    public function save()
    {
        if (!$this-&gt;getAcl()-&gt;isAllowed($this-&gt;getRole(), $this, 'save')) {
            throw new Galahad_Acl_Exception('Current user is not allowed to save posts');
        }
        $dataMapper = $this-&gt;getDataMapper();
        return $dataMapper-&gt;save($this);
    }
}
</pre>
<p>So, as you can see, the model denies access to itself unless explicitly allowed, and then allows access to certain methods for certain roles.</p>
<p>All three of these classes are in their early stages of development, but I&#8217;d love some feedback on the ideas/suggestions on how to make them better.</p>
<p>Check out the code on GitHub:</p>
<ul>
<li><a href="http://github.com/inxilpro/Galahad-FE/blob/master/library/Galahad/Acl.php" target="_blank">Galahad_Acl</a></li>
<li><a href="http://github.com/inxilpro/Galahad-FE/blob/master/library/Galahad/Controller/Plugin/Acl.php" target="_blank">Galahad_Controller_Plugin_Acl</a></li>
<li><a href="http://github.com/inxilpro/Galahad-FE/blob/master/library/Galahad/Model/Entity.php" target="_blank">Galahad_Model_Entity</a></li>
</ul>
<p>Also, for more information about the <code>Galahad_Model</code> system, check out my previous post on <a href="http://cmorrell.com/web-development/more-php-modelling-383">modeling in the Zend Framework</a>.</p>
<div class="su-linkbox" id="post-737-linkbox"><div class="su-linkbox-label">Link to this post!</div><div class="su-linkbox-field"><input type="text" value="&lt;a href=&quot;http://cmorrell.com/webdev/zf/namespacing-acl-resources-galahad-acl-737&quot;&gt;Namespacing ACL resources &amp; Galahad_Acl&lt;/a&gt;" onclick="javascript:this.select()" readonly="readonly" style="width: 100%;" /></div></div>]]></content:encoded>
			<wfw:commentRss>http://cmorrell.com/webdev/zf/namespacing-acl-resources-galahad-acl-737/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
