Permalink
Browse files

initial commit

  • Loading branch information...
0 parents commit 92fe43182db5b10d03e48448d164468a5647bbf9 @ceeram ceeram committed Feb 20, 2012
Showing with 402 additions and 0 deletions.
  1. +127 −0 Controller/Component/Auth/AclAuthorize.php
  2. +200 −0 Test/Case/Controller/Component/Auth/AclAuthorizeTest.php
  3. +75 −0 readme.textile
@@ -0,0 +1,127 @@
+<?php
+/**
+ * PHP 5
+ *
+ * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
+ * Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ *
+ * Licensed under The MIT License
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link http://cakephp.org CakePHP(tm) Project
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+
+App::uses('BaseAuthorize', 'Controller/Component/Auth');
+App::uses('Router', 'Routing');
+
+/**
+ * An authorization adapter for AuthComponent. Provides the ability to authorize using row based CRUD mappings.
+ * CRUD mappings allow you to translate controller actions into *C*reate *R*ead *U*pdate *D*elete actions.
+ * This is then checked in the AclComponent as specific permissions.
+ *
+ * For example, taking `/posts/view/1` as the current request. The default mapping for `view`, is a `read` permission
+ * check. The Acl check would then be for the Post record with id=1 with the `read` permission. This allows you
+ * to create permission systems that focus more on what is being done to which record, rather than the specific actions
+ * being visited, or only what is being done to resources.
+ *
+ * @package Cake.Controller.Component.Auth
+ * @since 2.0
+ * @see AuthComponent::$authenticate
+ * @see AclComponent::check()
+ */
+class AclAuthorize extends BaseAuthorize {
+
+/**
+ * Sets up additional actionMap values that match the configured `Routing.prefixes`.
+ *
+ * @param ComponentCollection $collection The component collection from the controller.
+ * @param string $settings An array of settings. This class does not use any settings.
+ */
+ public function __construct(ComponentCollection $collection, $settings = array()) {
+ parent::__construct($collection, $settings);
+ $this->_setPrefixMappings();
+ }
+
+/**
+ * sets the crud mappings for prefix routes.
+ *
+ * @return void
+ */
+ protected function _setPrefixMappings() {
+ $crud = array('create', 'read', 'update', 'delete');
+ $map = array_combine($crud, $crud);
+
+ $prefixes = Router::prefixes();
+ if (!empty($prefixes)) {
+ foreach ($prefixes as $prefix) {
+ $map = array_merge($map, array(
+ $prefix . '_index' => 'read',
+ $prefix . '_add' => 'create',
+ $prefix . '_edit' => 'update',
+ $prefix . '_view' => 'read',
+ $prefix . '_remove' => 'delete',
+ $prefix . '_create' => 'create',
+ $prefix . '_read' => 'read',
+ $prefix . '_update' => 'update',
+ $prefix . '_delete' => 'delete'
+ ));
+ }
+ }
+ $this->mapActions($map);
+ }
+
+/**
+ * Authorize a user using the mapped actions and the AclComponent.
+ *
+ * @param array $user The user to authorize
+ * @param CakeRequest $request The request needing authorization.
+ * @return boolean
+ */
+ public function authorize($user, CakeRequest $request) {
+ if (!isset($this->settings['actionMap'][$request->params['action']])) {
+ throw new CakeException(__d('cake_dev',
+ 'AclAuthorize::authorize() - Attempted access of un-mapped action "%1$s" in controller "%2$s"',
+ $request->action,
+ $request->controller
+ ));
+ }
+
+ if (empty($request->params['pass'][0])) {
+ return false;
+ }
+ $object = $this->_getModel();
+ $acoNode = $this->_getAco($object, $request->params['pass'][0]);
+ if (!$acoNode) {
+ return false;
+ }
+ $user = array($this->settings['userModel'] => $user);
+ $Acl = $this->_Collection->load('Acl');
+ return $Acl->check(
+ $user,
+ $acoNode,
+ $this->settings['actionMap'][$request->params['action']]
+ );
+ }
+
+ protected function _getModel() {
+ $modelClass = $this->_Controller->modelClass;
+ return $this->_Controller->{$modelClass};
+ }
+
+ protected function _getAco($object, $id) {
+ if (!$object->Behaviors->attached('Acl')) {
+ return false;
+ }
+ $tmp = $object->id;
+ $object->id = $id;
+ try {
+ $aco = $object->node(null, 'Aco');
+ } catch (CakeException $e) {
+ return false;
+ }
+ $object->id = $tmp;
+ return $aco[0]['Aco'];
+ }
+}
@@ -0,0 +1,200 @@
+<?php
+/**
+ * AclAuthorizeTest file
+ *
+ * PHP 5
+ *
+ * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
+ * Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ *
+ * Licensed under The MIT License
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link http://cakephp.org CakePHP(tm) Project
+ * @package Cake.Test.Case.Controller.Component.Auth
+ * @since CakePHP(tm) v 2.0
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+
+App::uses('AclAuthorize', 'Authorize.Controller/Component/Auth');
+App::uses('ComponentCollection', 'Controller');
+App::uses('AclComponent', 'Controller/Component');
+App::uses('CakeRequest', 'Network');
+App::uses('CakeResponse', 'Network');
+
+class TestAclAuthorize extends AclAuthorize {
+
+ function _getModel() {}
+
+ function _getAco() {
+ return 'Post.1';
+ }
+
+}
+
+class AclAuthorizeTest extends CakeTestCase {
+
+/**
+ * setup
+ *
+ * @return void
+ */
+ public function setUp() {
+ Configure::write('Routing.prefixes', array());
+
+ parent::setUp();
+
+ $this->Acl = $this->getMock('AclComponent', array(), array(), '', false);
+ $this->Components = $this->getMock('ComponentCollection');
+
+ $this->auth = new TestAclAuthorize($this->Components);
+ }
+
+/**
+ * setup the mock acl.
+ *
+ * @return void
+ */
+ protected function _mockAcl() {
+ $this->Components->expects($this->any())
+ ->method('load')
+ ->with('Acl')
+ ->will($this->returnValue($this->Acl));
+ }
+
+/**
+ * test authorize() without a mapped action, ensure an exception is thrown.
+ *
+ * @expectedException CakeException
+ * @return void
+ */
+ public function testAuthorizeNoMappedAction() {
+ $request = new CakeRequest('/posts/foobar/1', false);
+ $request->addParams(array(
+ 'controller' => 'posts',
+ 'action' => 'foobar',
+ 'pass' => array(1)
+ ));
+ $user = array('User' => array('user' => 'mark'));
+
+ $this->auth->authorize($user, $request);
+ }
+
+/**
+ * test check() passing
+ *
+ * @return void
+ */
+ public function testAuthorizeCheckSuccess() {
+ $request = new CakeRequest('posts/view/1', false);
+ $request->addParams(array(
+ 'controller' => 'posts',
+ 'action' => 'index',
+ 'pass' => array(1)
+ ));
+ $user = array('User' => array('user' => 'mark'));
+
+ $this->_mockAcl();
+ $this->Acl->expects($this->once())
+ ->method('check')
+ ->with($user, 'Post.1', 'read')
+ ->will($this->returnValue(true));
+
+ $this->assertTrue($this->auth->authorize($user['User'], $request));
+ }
+
+/**
+ * test check() failing
+ *
+ * @return void
+ */
+ public function testAuthorizeCheckFailure() {
+ $request = new CakeRequest('posts/edit/1', false);
+ $request->addParams(array(
+ 'controller' => 'posts',
+ 'action' => 'edit',
+ 'pass' => array(1)
+ ));
+ $user = array('User' => array('user' => 'mark'));
+
+ $this->_mockAcl();
+ $this->Acl->expects($this->once())
+ ->method('check')
+ ->with($user, 'Post.1', 'update')
+ ->will($this->returnValue(false));
+
+ $this->assertFalse($this->auth->authorize($user['User'], $request));
+ }
+
+
+/**
+ * test getting actionMap
+ *
+ * @return void
+ */
+ public function testMapActionsGet() {
+ $result = $this->auth->mapActions();
+ $expected = array(
+ 'create' => 'create',
+ 'read' => 'read',
+ 'update' => 'update',
+ 'delete' => 'delete',
+ 'index' => 'read',
+ 'add' => 'create',
+ 'edit' => 'update',
+ 'view' => 'read',
+ 'remove' => 'delete'
+ );
+ $this->assertEquals($expected, $result);
+ }
+
+/**
+ * test adding into mapActions
+ *
+ * @return void
+ */
+ public function testMapActionsSet() {
+ $map = array(
+ 'create' => array('generate'),
+ 'read' => array('listing', 'show'),
+ 'update' => array('update'),
+ 'random' => 'custom'
+ );
+ $result = $this->auth->mapActions($map);
+ $this->assertNull($result);
+
+ $result = $this->auth->mapActions();
+ $expected = array(
+ 'add' => 'create',
+ 'create' => 'create',
+ 'read' => 'read',
+ 'index' => 'read',
+ 'add' => 'create',
+ 'edit' => 'update',
+ 'view' => 'read',
+ 'delete' => 'delete',
+ 'remove' => 'delete',
+ 'generate' => 'create',
+ 'listing' => 'read',
+ 'show' => 'read',
+ 'update' => 'update',
+ 'random' => 'custom',
+ );
+ $this->assertEquals($expected, $result);
+ }
+
+/**
+ * test prefix routes getting auto mapped.
+ *
+ * @return void
+ */
+ public function testAutoPrefixMapActions() {
+ Configure::write('Routing.prefixes', array('admin', 'manager'));
+ Router::reload();
+
+ $auth = new AclAuthorize($this->Components);
+ $this->assertTrue(isset($auth->settings['actionMap']['admin_index']));
+ }
+
+}
Oops, something went wrong.

0 comments on commit 92fe431

Please sign in to comment.