Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding user permissions and how to apply it

I am developing a module for a site using Social Engine, which uses Zend Framework. I am new to both Zend Framework and Social Engine but have experience in OOP and MVC architecture so could get to grips with basics relatively quickly.

Its a test module I'm developing so have just built a simple module where the user can create, edit or delete CD information. Then there is a widget which can be displayed where they like which shows there CD information.

I am now at the point where I need to set permissions of what CDs people can see etc. So I studied other modules and found the Poll module to be a concrete example.

Looking at other modules I realised that when you create something, they let the user set their permissions manually.

So added this code to my form to create a select box with relevant permissions:

$auth = Engine_Api::_()->authorization()->context;
$user = Engine_Api::_()->user()->getViewer();
$viewOptions = (array) Engine_Api::_()->authorization()->getAdapter('levels')->getAllowed('ryan', $user, 'auth_view');
$viewOptions = array_intersect_key($availableLabels, array_flip($viewOptions));

$privacy = null;

if( !empty($viewOptions) && count($viewOptions) >= 1 ) {
    // Make a hidden field
    if(count($viewOptions) == 1) {
        //$this->addElement('hidden', 'auth_view', array('value' => key($viewOptions)));
        $privacy  = new Zend_Form_Element_Hidden('auth_view');
        $privacy->setValue(key($viewOptions));
        // Make select box
    } else {
        $privacy = new Zend_Form_Element_Select('auth_view');
        $privacy->setLabel('Privacy')
                ->setDescription('Who may see this CD?')
                ->setMultiOptions($viewOptions)
                ->setValue(key($viewOptions));
        /*$this->addElement('Select', 'auth_view', array(
            'label' => 'Privacy',
            'description' => 'Who may see this CD?',
            'multiOptions' => $viewOptions,
            'value' => key($viewOptions),
        ));*/
    }
}

$this->addElements(array($artist, $title, $privacy, $submit));

To be honest I'm not entirely sure what this code does apart from obviously create a select box and fill it with values specified.

So if the user selects 'Everyone' everyone should be able to delete and edit that cd, and so on.

Obviously I thought controller must have some code that might deal with determining whether the user has the rights to view each cd etc.

So scanning the Poll controller I found this is in the init function of the controller:

public function init() {
    // Get subject
    $poll = null;
    if( null !== ($pollIdentity = $this->_getParam('poll_id')) ) {
        $poll = Engine_Api::_()->getItem('poll', $pollIdentity);
        if( null !== $poll ) {
            Engine_Api::_()->core()->setSubject($poll);
        }
    }

    // Get viewer
    $this->view->viewer = $viewer = Engine_Api::_()->user()->getViewer();
    $this->view->viewer_id = Engine_Api::_()->user()->getViewer()->getIdentity();

    // only show polls if authorized
    $resource = ( $poll ? $poll : 'poll' );
    $viewer = ( $viewer && $viewer->getIdentity() ? $viewer : null );
    if( !$this->_helper->requireAuth()->setAuthParams($resource, $viewer, 'view')->isValid() ) {
        return;
    }
}

And in each action at the top they have some different authorization code, one such example is the editAction which has this code right at the top:

// Check auth
if( !$this->_helper->requireUser()->isValid() ) {
    return;
}
if( !$this->_helper->requireSubject()->isValid() ) {
    return;
}
if( !$this->_helper->requireAuth()->setAuthParams(null, null, 'edit')->isValid() ) {
    return;
}

also in the same action is has several other bits i don't understand what they are doing, below is random snippets from the editAction in the Poll controller:

$auth = Engine_Api::_()->authorization()->context;
$roles = array('owner', 'owner_member', 'owner_member_member', 'owner_network', 'registered', 'everyone');

// Populate form with current settings
$form->search->setValue($poll->search);
foreach( $roles as $role ) {
    if( 1 === $auth->isAllowed($poll, $role, 'view') ) {
        $form->auth_view->setValue($role);
    }
    if( 1 === $auth->isAllowed($poll, $role, 'comment') ) {
        $form->auth_comment->setValue($role);
    }
}

// CREATE AUTH STUFF HERE
if( empty($values['auth_view']) ) {
    $values['auth_view'] = array('everyone');
}
if( empty($values['auth_comment']) ) {
    $values['auth_comment'] = array('everyone');
}

$viewMax = array_search($values['auth_view'], $roles);
$commentMax = array_search($values['auth_comment'], $roles);

My problem is I really don't understand much if any of the above and after sitting on it for a couple of days and googling to my fingers hurt I still don't really have a clue if I am 100% honest. Can any of the above be cleared up for me, help explain things to me, and if possible how can i apply the permissions I want to my module.

like image 248
RSM Avatar asked Jul 17 '12 10:07

RSM


1 Answers

I will provide a brief descriptions of how to use the Authorization, however more detailed information would need to be inferred by reviewing SocialEngine's code. As a note, while we don't compile documentation for SocialEngine, our developers have used the PHPDocumentor style syntax through out our code and you can use an IDE like Neatbeans (http://netbeans.org/) to quickly access that information.

SocialEngine has a few controller action helper classes that are used for query authorization within action controllers:

  • application/modules/Authorization/Controller/Action/Helper/RequireAuth.php
  • application/modules/Core/Controller/Action/Helper/RequireAbstract.php
  • application/modules/Core/Controller/Action/Helper/RequireAdmin.php
  • application/modules/Core/Controller/Action/Helper/RequireSubject.php
  • application/modules/Core/Controller/Action/Helper/RequireUser.php

For the most part the only ones you'll concern yourself with are these:

  • application/modules/Authorization/Controller/Action/Helper/RequireAuth.php
  • application/modules/Core/Controller/Action/Helper/RequireSubject.php
  • application/modules/Core/Controller/Action/Helper/RequireUser.php

A good example of how these helpers are used can be found in the Album_AlbumController class: application/modules/Album/controllers/AlbumController.php

public function init()
{
if( !$this->_helper->requireAuth()->setAuthParams('album', null, 'view')->isValid() ) return;

if( 0 !== ($photo_id = (int) $this->_getParam('photo_id')) &&
null !== ($photo = Engine_Api::_()->getItem('album_photo', $photo_id)) )
{
Engine_Api::_()->core()->setSubject($photo);
}

else if( 0 !== ($album_id = (int) $this->_getParam('album_id')) &&
null !== ($album = Engine_Api::_()->getItem('album', $album_id)) )
{
Engine_Api::_()->core()->setSubject($album);
}
}

public function editAction()
{
if( !$this->_helper->requireUser()->isValid() ) return;
if( !$this->_helper->requireSubject('album')->isValid() ) return;
if( !$this->_helper->requireAuth()->setAuthParams(null, null, 'edit')->isValid() ) return;

The code in the init function simply set's the requirements for accessing the page, and then within the editAction function, checks are ran against the authorization data. The requireSubject and requireUser helpers are pretty straight forward:

  1. requireSubject expects that subject for the page is set which in the above example gets done in the init function
  2. requireUser checks to see if the viewer is a logged in user

The requireAuth helper is a little less straight forward. I'll omit most of the abstract inner-workings for the sake of brevity. In the end, the helper points to the Authorization_Api_Core::isAllowed function: application/modules/Authorization/Core/Api.php

/**
* Gets the specified permission for the context
*
* @param Core_Model_Item_Abstract|string $resource The resource type or object that is being accessed
* @param Core_Model_Item_Abstract $role The item (user) performing the action
* @param string $action The name of the action being performed
* @return mixed 0/1 for allowed, or data for settings
*/
public function isAllowed($resource, $role, $action = 'view')

The $resource and $role objects that the function expects are instances of Zend_Db_Table_Row which is termed Models within SocialEngine and are expected to be located in the Models directory of a module. When the isAllowed function is invoked, the authorization api will query the database against the engine4_authorization_allow, engine4_authorization_levels and engine4_authorization_permissions tables.

  1. The engine4_authorization_levels table contains the member levels created by SocialEngine out of the box, as well as custom member levels created from the Manage > Member Levels section in the admin panel.
  2. The engine4_authorization_permissions table contain all the default and admin specified permission handling, such as member level settings.
  3. The engine4_authorization_allow contains the the permission data for individual objects. For example information about who is able to view a photo album would be placed there. Whether or not a engine4_authorization_allow.role_id (maps to item id for a model) is allowed to access the engine4_authorization_allow.resource_id (maps to item id for a model) is determined by the engine4_authorization_allow.value column which should contain a number 0-5.

application/modules/Authorization/Api/Core.php

class Authorization_Api_Core extends Core_Api_Abstract
{
/**
* Constants
*/
const LEVEL_DISALLOW = 0;
const LEVEL_ALLOW = 1;
const LEVEL_MODERATE = 2;
const LEVEL_NONBOOLEAN = 3;
const LEVEL_IGNORE = 4;
const LEVEL_SERIALIZED = 5;

0) Not allowed to access the linked resource. This is the same as the row not existing in the allow table

1) Allowed too access the linked resource

2) Allowed to access and moderate resources (ie. Superadmin, Admin and Moderator member level)

3-5) Get ignored as disallowed. These expect some custom logic in order to handle authorization appropriately.

like image 127
SocialEngine Avatar answered Oct 29 '22 12:10

SocialEngine