From 2e9d9479a6b4361745919b1f1c7692c95bc90f1d Mon Sep 17 00:00:00 2001 From: mark_story Date: Mon, 3 Jan 2011 01:49:06 -0500 Subject: [PATCH] Moving another part of AuthComponent's authorize strategies into BaseAuthorize. Implementing CrudAuthorize and adding tests for it. --- .../components/auth/base_authorize.php | 37 +++++ .../components/auth/crud_authorize.php | 59 +++++++ .../components/auth/crud_authorize.test.php | 149 ++++++++++++++++++ 3 files changed, 245 insertions(+) create mode 100644 cake/libs/controller/components/auth/crud_authorize.php create mode 100644 cake/tests/cases/libs/controller/components/auth/crud_authorize.test.php diff --git a/cake/libs/controller/components/auth/base_authorize.php b/cake/libs/controller/components/auth/base_authorize.php index a7828eae5..cc19acb26 100644 --- a/cake/libs/controller/components/auth/base_authorize.php +++ b/cake/libs/controller/components/auth/base_authorize.php @@ -36,6 +36,21 @@ abstract class BaseAuthorize { */ public $actionPath = null; +/** + * Action -> crud mappings. Used by authorization objects that want to map actions to CRUD roles. + * + * @var array + * @see CrudAuthorize + */ + protected $_actionMap = array( + 'index' => 'read', + 'add' => 'create', + 'edit' => 'update', + 'view' => 'read', + 'delete' => 'delete', + 'remove' => 'delete' + ); + /** * Constructor * @@ -87,4 +102,26 @@ abstract class BaseAuthorize { $this->actionPath . $path ); } + +/** + * Maps crud actions to actual controller names. Used to modify or get the current mapped actions. + * + * @param mixed $map Either an array of mappings, or undefined to get current values. + * @return mixed Either the current mappings or null when setting. + */ + public function mapActions($map = array()) { + if (empty($map)) { + return $this->_actionMap; + } + $crud = array('create', 'read', 'update', 'delete'); + foreach ($map as $action => $type) { + if (in_array($action, $crud) && is_array($type)) { + foreach ($type as $typedAction) { + $this->_actionMap[$typedAction] = $action; + } + } else { + $this->_actionMap[$action] = $type; + } + } + } } \ No newline at end of file diff --git a/cake/libs/controller/components/auth/crud_authorize.php b/cake/libs/controller/components/auth/crud_authorize.php new file mode 100644 index 000000000..5e6c9c85c --- /dev/null +++ b/cake/libs/controller/components/auth/crud_authorize.php @@ -0,0 +1,59 @@ +_actionMap[$request->params['action']])) { + trigger_error(__( + 'CrudAuthorize::authorize() - Attempted access of un-mapped action "%1$s" in controller "%2$s"', + $request->action, + $request->controller + ), + E_USER_WARNING + ); + return false; + } + $Acl = $this->_controller->Components->load('Acl'); + return $Acl->check( + $user, + $this->action($request, ':controller'), + $this->_actionMap[$request->params['action']] + ); + } +} \ No newline at end of file diff --git a/cake/tests/cases/libs/controller/components/auth/crud_authorize.test.php b/cake/tests/cases/libs/controller/components/auth/crud_authorize.test.php new file mode 100644 index 000000000..684fc4b97 --- /dev/null +++ b/cake/tests/cases/libs/controller/components/auth/crud_authorize.test.php @@ -0,0 +1,149 @@ +controller = $this->getMock('Controller', array(), array(), '', false); + $this->Acl = $this->getMock('AclComponent', array(), array(), '', false); + $this->controller->Components = $this->getMock('ComponentCollection'); + + $this->auth = new CrudAuthorize($this->controller); + } + +/** + * setup the mock acl. + * + * @return void + */ + protected function _mockAcl() { + $this->controller->Components->expects($this->any()) + ->method('load') + ->with('Acl') + ->will($this->returnValue($this->Acl)); + } + +/** + * test authorize() without a mapped action, ensure an error is generated. + * + * @expectedException Exception + * @return void + */ + function testAuthorizeNoMappedAction() { + $request = new CakeRequest('/posts/foobar', false); + $request->addParams(array( + 'controller' => 'posts', + 'action' => 'foobar' + )); + $user = array('User' => array('user' => 'mark')); + + $this->auth->authorize($user, $request); + } + +/** + * test check() passing + * + * @return void + */ + function testAuthorizeCheckSuccess() { + $request = new CakeRequest('posts/index', false); + $request->addParams(array( + 'controller' => 'posts', + 'action' => 'index' + )); + $user = array('User' => array('user' => 'mark')); + + $this->_mockAcl(); + $this->Acl->expects($this->once()) + ->method('check') + ->with($user, 'Posts', 'read') + ->will($this->returnValue(true)); + + $this->assertTrue($this->auth->authorize($user, $request)); + } + +/** + * test check() failing + * + * @return void + */ + function testAuthorizeCheckFailure() { + $request = new CakeRequest('posts/index', false); + $request->addParams(array( + 'controller' => 'posts', + 'action' => 'index' + )); + $user = array('User' => array('user' => 'mark')); + + $this->_mockAcl(); + $this->Acl->expects($this->once()) + ->method('check') + ->with($user, 'Posts', 'read') + ->will($this->returnValue(false)); + + $this->assertFalse($this->auth->authorize($user, $request)); + } + + +/** + * test getting actionMap + * + * @return void + */ + function testMapActionsGet() { + $result = $this->auth->mapActions(); + $expected = array( + 'index' => 'read', + 'add' => 'create', + 'edit' => 'update', + 'view' => 'read', + 'delete' => 'delete', + 'remove' => 'delete' + ); + $this->assertEquals($expected, $result); + } + +/** + * test adding into mapActions + * + * @return void + */ + 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( + '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); + } + +}