7.8. Ownership Access

There's more to an application than its controllers and action methods. Sometimes you want to allow a user to access a controller and action, but only when that user is working with content objects that he owns within that system. For example, a user might be allowed to edit blog entries, but only his *own* blog entries. In these cases, we need to know if the current user is the owner of the blog entry he is attempting to work with.

7.8.1. Preparing Your Content Objects

First, you need to add a special method on your content objects. In the example, we will call the method accessIsOwner(), but you can call it whatever you like.

The special ownership method on your content object should take two params in this order: a Solar_Auth_Adapter instance, and a Solar_Role_Adapter instance. The method you write can then check the current user's authenticated identity and/or assigned roles, and then return true if the user is considered an owner of the content object (or false if not).

As an example, let's say we have a model record for a blogs entry, and that the database table for that model includes a column called author_handle (i.e., the username handle of the person who created the blog entry). We could write a method like this on the blogs record class:

<?php
class Vendor_Model_Blogs_Record
{
    public function accessIsOwner(Solar_Auth_Adapter $auth, Solar_Role_Adapter $role)
    {
        // check the record's 'author_handle' column to see
        // if it matches the current authenticated user.
        if ($this->author_handle == $auth->handle) {
            return true;
        }
        
        // not the original author, so don't treat as an owner.
        return false;
    }
}

7.8.2. Configure Access To Recognize Ownership

For each kind of content object in the system, you will need to tell Solar_Access_Adapter what method to use on each object to determine if the user is an owner or not. In the above example, we have the Vendor_Model_Blogs_Record::accessIsOwner() method. We make a corresponding entry in the 'owner_method' config key for Solar_Access_Adapter:

<?php
$config['Solar_Access_Adapter']['owner_method'] = array(
    'Vendor_Model_Blogs_Record' => 'accessIsOwner',
);

The 'owner_method' config setting is an array of key-value pairs where the key is the class name of the object being checked, and the value is the method on that class. Later, when we call $user->access->isOwner(), the adapter will loop through these keys, see if the object being controller matches a class in the array, and call the corresponding method to check ownership.

7.8.3. Access Control List Entries

As noted in an earlier section, you can use an 'owner' entry type to specify that the user has to be the owner of an object being checked in the controller and action.

# flag      type        name        class                   action
# ----      ----        ----        -----                   ------
# allow users to edit their own posts
allow       owner       -           Vendor_App_Blog         edit

7.8.4. Integration With Controllers

Now that we have the special ownership method on our content class, and the access adapter knows what methods to check on which content classes, we can integrate an ownership access check in our controller actions.

Using the "Intra-Action Access Control" approach from the previous section, adding ownership checks would look like this:

<?php
abstract class Vendor_Controller_Page extends Solar_Controller_Page
{
    public $user;
    
    protected function _setup()
    {
        parent::_setup();
        $this->user = Solar_Registry::get('user');
    }
    
    protected function _isUserAllowed($object = null)
    {
        if ($this->user->access->isAllowed($this, $this->_action, $object)) {
            return true;
        } else {
            $this->_error('Access denied.');
            $this->_response->setStatusCode(403);
            return false;
        }
    }
}

class Vendor_App_Blog extends Vendor_Controller_Page
{  
    public function actionEdit($id = null)
    {
        // ... perform preliminary logic ...
        
        // get the blog item for editing
        $item = $this->_model->blogs->fetch($id);
        
        // check access
        if (! $this->_isUserAllowed($item)) {
            return;
        }
        
        // ... rest of the action here ...
    }
}
  • In the _isUserAllowed() method, we have added a single parameter to allow passing of a content object for ownership checks. Likewise, the call to isAllowed() passes the content object along for checking.

  • The actionEdit() method retrieves the blog entry before checking access controls. Only after the entry is retrieved do we check to see if the user is allowed to access this object within the context of this controller and action.



Local