Blame | Last modification | View Log | RSS feed
<?php/*** SecurityComponentTest file** CakePHP(tm) Tests <http://book.cakephp.org/2.0/en/development/testing.html>* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)** Licensed under The MIT License* For full copyright and license information, please see the LICENSE.txt* Redistributions of files must retain the above copyright notice** @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)* @link http://book.cakephp.org/2.0/en/development/testing.html CakePHP(tm) Tests* @package Cake.Test.Case.Controller.Component* @since CakePHP(tm) v 1.2.0.5435* @license http://www.opensource.org/licenses/mit-license.php MIT License*/App::uses('SecurityComponent', 'Controller/Component');App::uses('Controller', 'Controller');/*** TestSecurityComponent** @package Cake.Test.Case.Controller.Component*/class TestSecurityComponent extends SecurityComponent {/*** validatePost method** @param Controller $controller* @return boolean*/public function validatePost(Controller $controller) {return $this->_validatePost($controller);}}/*** SecurityTestController** @package Cake.Test.Case.Controller.Component*/class SecurityTestController extends Controller {/*** components property** @var array*/public $components = array('Session', 'TestSecurity');/*** failed property** @var boolean false*/public $failed = false;/*** Used for keeping track of headers in test** @var array*/public $testHeaders = array();/*** fail method** @return void*/public function fail() {$this->failed = true;}/*** redirect method** @param string|array $url* @param mixed $code* @param mixed $exit* @return void*/public function redirect($url, $status = null, $exit = true) {return $status;}/*** Convenience method for header()** @param string $status* @return void*/public function header($status) {$this->testHeaders[] = $status;}}class BrokenCallbackController extends Controller {public $name = 'UncallableCallback';public $components = array('Session', 'TestSecurity');public function index() {}protected function _fail() {}}/*** SecurityComponentTest class** @package Cake.Test.Case.Controller.Component*/class SecurityComponentTest extends CakeTestCase {/*** Controller property** @var SecurityTestController*/public $Controller;/*** oldSalt property** @var string*/public $oldSalt;/*** setUp method** @return void*/public function setUp() {parent::setUp();$request = new CakeRequest('posts/index', false);$request->addParams(array('controller' => 'posts', 'action' => 'index'));$this->Controller = new SecurityTestController($request);$this->Controller->Components->init($this->Controller);$this->Controller->Security = $this->Controller->TestSecurity;$this->Controller->Security->blackHoleCallback = 'fail';$this->Security = $this->Controller->Security;$this->Security->csrfCheck = false;Configure::write('Security.salt', 'foo!');}/*** Tear-down method. Resets environment state.** @return void*/public function tearDown() {parent::tearDown();$this->Controller->Session->delete('_Token');unset($this->Controller->Security);unset($this->Controller->Component);unset($this->Controller);}/*** Test that requests are still blackholed when controller has incorrect* visibility keyword in the blackhole callback** @expectedException BadRequestException*/public function testBlackholeWithBrokenCallback() {$request = new CakeRequest('posts/index', false);$request->addParams(array('controller' => 'posts', 'action' => 'index'));$this->Controller = new BrokenCallbackController($request);$this->Controller->Components->init($this->Controller);$this->Controller->Security = $this->Controller->TestSecurity;$this->Controller->Security->blackHoleCallback = '_fail';$this->Controller->Security->startup($this->Controller);$this->Controller->Security->blackHole($this->Controller, 'csrf');}/*** Ensure that directly requesting the blackholeCallback as the controller* action results in an exception.** @return void*/public function testExceptionWhenActionIsBlackholeCallback() {$this->Controller->request->addParams(array('controller' => 'posts','action' => 'fail'));$this->assertFalse($this->Controller->failed);$this->Controller->Security->startup($this->Controller);$this->assertTrue($this->Controller->failed, 'Request was blackholed.');}/*** test that initialize can set properties.** @return void*/public function testConstructorSettingProperties() {$settings = array('requirePost' => array('edit', 'update'),'requireSecure' => array('update_account'),'requireGet' => array('index'),'validatePost' => false,);$Security = new SecurityComponent($this->Controller->Components, $settings);$this->Controller->Security->initialize($this->Controller, $settings);$this->assertEquals($Security->requirePost, $settings['requirePost']);$this->assertEquals($Security->requireSecure, $settings['requireSecure']);$this->assertEquals($Security->requireGet, $settings['requireGet']);$this->assertEquals($Security->validatePost, $settings['validatePost']);}/*** testStartup method** @return void*/public function testStartup() {$this->Controller->Security->startup($this->Controller);$result = $this->Controller->params['_Token']['key'];$this->assertNotNull($result);$this->assertTrue($this->Controller->Session->check('_Token'));}/*** testRequirePostFail method** @return void*/public function testRequirePostFail() {$_SERVER['REQUEST_METHOD'] = 'GET';$this->Controller->request['action'] = 'posted';$this->Controller->Security->requirePost(array('posted'));$this->Controller->Security->startup($this->Controller);$this->assertTrue($this->Controller->failed);}/*** testRequirePostSucceed method** @return void*/public function testRequirePostSucceed() {$_SERVER['REQUEST_METHOD'] = 'POST';$this->Controller->request['action'] = 'posted';$this->Controller->Security->requirePost('posted');$this->Security->startup($this->Controller);$this->assertFalse($this->Controller->failed);}/*** testRequireSecureFail method** @return void*/public function testRequireSecureFail() {$_SERVER['HTTPS'] = 'off';$_SERVER['REQUEST_METHOD'] = 'POST';$this->Controller->request['action'] = 'posted';$this->Controller->Security->requireSecure(array('posted'));$this->Controller->Security->startup($this->Controller);$this->assertTrue($this->Controller->failed);}/*** testRequireSecureSucceed method** @return void*/public function testRequireSecureSucceed() {$_SERVER['REQUEST_METHOD'] = 'Secure';$this->Controller->request['action'] = 'posted';$_SERVER['HTTPS'] = 'on';$this->Controller->Security->requireSecure('posted');$this->Controller->Security->startup($this->Controller);$this->assertFalse($this->Controller->failed);}/*** testRequireAuthFail method** @return void*/public function testRequireAuthFail() {$_SERVER['REQUEST_METHOD'] = 'AUTH';$this->Controller->request['action'] = 'posted';$this->Controller->request->data = array('username' => 'willy', 'password' => 'somePass');$this->Controller->Security->requireAuth(array('posted'));$this->Controller->Security->startup($this->Controller);$this->assertTrue($this->Controller->failed);$this->Controller->Session->write('_Token', array('allowedControllers' => array()));$this->Controller->request->data = array('username' => 'willy', 'password' => 'somePass');$this->Controller->request['action'] = 'posted';$this->Controller->Security->requireAuth('posted');$this->Controller->Security->startup($this->Controller);$this->assertTrue($this->Controller->failed);$this->Controller->Session->write('_Token', array('allowedControllers' => array('SecurityTest'), 'allowedActions' => array('posted2')));$this->Controller->request->data = array('username' => 'willy', 'password' => 'somePass');$this->Controller->request['action'] = 'posted';$this->Controller->Security->requireAuth('posted');$this->Controller->Security->startup($this->Controller);$this->assertTrue($this->Controller->failed);}/*** testRequireAuthSucceed method** @return void*/public function testRequireAuthSucceed() {$_SERVER['REQUEST_METHOD'] = 'AUTH';$this->Controller->request['action'] = 'posted';$this->Controller->Security->requireAuth('posted');$this->Controller->Security->startup($this->Controller);$this->assertFalse($this->Controller->failed);$this->Controller->Security->Session->write('_Token', array('allowedControllers' => array('SecurityTest'), 'allowedActions' => array('posted')));$this->Controller->request['controller'] = 'SecurityTest';$this->Controller->request['action'] = 'posted';$this->Controller->request->data = array('username' => 'willy', 'password' => 'somePass', '_Token' => '');$this->Controller->action = 'posted';$this->Controller->Security->requireAuth('posted');$this->Controller->Security->startup($this->Controller);$this->assertFalse($this->Controller->failed);}/*** testRequirePostSucceedWrongMethod method** @return void*/public function testRequirePostSucceedWrongMethod() {$_SERVER['REQUEST_METHOD'] = 'GET';$this->Controller->request['action'] = 'getted';$this->Controller->Security->requirePost('posted');$this->Controller->Security->startup($this->Controller);$this->assertFalse($this->Controller->failed);}/*** testRequireGetFail method** @return void*/public function testRequireGetFail() {$_SERVER['REQUEST_METHOD'] = 'POST';$this->Controller->request['action'] = 'getted';$this->Controller->Security->requireGet(array('getted'));$this->Controller->Security->startup($this->Controller);$this->assertTrue($this->Controller->failed);}/*** testRequireGetSucceed method** @return void*/public function testRequireGetSucceed() {$_SERVER['REQUEST_METHOD'] = 'GET';$this->Controller->request['action'] = 'getted';$this->Controller->Security->requireGet('getted');$this->Controller->Security->startup($this->Controller);$this->assertFalse($this->Controller->failed);}/*** testRequireGetSucceedWrongMethod method** @return void*/public function testRequireGetSucceedWrongMethod() {$_SERVER['REQUEST_METHOD'] = 'POST';$this->Controller->request['action'] = 'posted';$this->Security->requireGet('getted');$this->Security->startup($this->Controller);$this->assertFalse($this->Controller->failed);}/*** testRequirePutFail method** @return void*/public function testRequirePutFail() {$_SERVER['REQUEST_METHOD'] = 'POST';$this->Controller->request['action'] = 'putted';$this->Controller->Security->requirePut(array('putted'));$this->Controller->Security->startup($this->Controller);$this->assertTrue($this->Controller->failed);}/*** testRequirePutSucceed method** @return void*/public function testRequirePutSucceed() {$_SERVER['REQUEST_METHOD'] = 'PUT';$this->Controller->request['action'] = 'putted';$this->Controller->Security->requirePut('putted');$this->Controller->Security->startup($this->Controller);$this->assertFalse($this->Controller->failed);}/*** testRequirePutSucceedWrongMethod method** @return void*/public function testRequirePutSucceedWrongMethod() {$_SERVER['REQUEST_METHOD'] = 'POST';$this->Controller->request['action'] = 'posted';$this->Controller->Security->requirePut('putted');$this->Controller->Security->startup($this->Controller);$this->assertFalse($this->Controller->failed);}/*** testRequireDeleteFail method** @return void*/public function testRequireDeleteFail() {$_SERVER['REQUEST_METHOD'] = 'POST';$this->Controller->request['action'] = 'deleted';$this->Controller->Security->requireDelete(array('deleted', 'other_method'));$this->Controller->Security->startup($this->Controller);$this->assertTrue($this->Controller->failed);}/*** testRequireDeleteSucceed method** @return void*/public function testRequireDeleteSucceed() {$_SERVER['REQUEST_METHOD'] = 'DELETE';$this->Controller->request['action'] = 'deleted';$this->Controller->Security->requireDelete('deleted');$this->Controller->Security->startup($this->Controller);$this->assertFalse($this->Controller->failed);}/*** testRequireDeleteSucceedWrongMethod method** @return void*/public function testRequireDeleteSucceedWrongMethod() {$_SERVER['REQUEST_METHOD'] = 'POST';$this->Controller->request['action'] = 'posted';$this->Controller->Security->requireDelete('deleted');$this->Controller->Security->startup($this->Controller);$this->assertFalse($this->Controller->failed);}/*** Simple hash validation test** @return void*/public function testValidatePost() {$this->Controller->Security->startup($this->Controller);$key = $this->Controller->request->params['_Token']['key'];$fields = 'a5475372b40f6e3ccbf9f8af191f20e1642fd877%3AModel.valid';$unlocked = '';$this->Controller->request->data = array('Model' => array('username' => 'nate', 'password' => 'foo', 'valid' => '0'),'_Token' => compact('key', 'fields', 'unlocked'));$this->assertTrue($this->Controller->Security->validatePost($this->Controller));}/*** Test that validatePost fails if you are missing the session information.** @return void*/public function testValidatePostNoSession() {$this->Controller->Security->startup($this->Controller);$this->Controller->Session->delete('_Token');$key = $this->Controller->params['_Token']['key'];$fields = 'a5475372b40f6e3ccbf9f8af191f20e1642fd877%3AModel.valid';$this->Controller->data = array('Model' => array('username' => 'nate', 'password' => 'foo', 'valid' => '0'),'_Token' => compact('key', 'fields'));$this->assertFalse($this->Controller->Security->validatePost($this->Controller));}/*** test that validatePost fails if any of its required fields are missing.** @return void*/public function testValidatePostFormHacking() {$this->Controller->Security->startup($this->Controller);$key = $this->Controller->params['_Token']['key'];$unlocked = '';$this->Controller->request->data = array('Model' => array('username' => 'nate', 'password' => 'foo', 'valid' => '0'),'_Token' => compact('key', 'unlocked'));$result = $this->Controller->Security->validatePost($this->Controller);$this->assertFalse($result, 'validatePost passed when fields were missing. %s');}/*** Test that objects can't be passed into the serialized string. This was a vector for RFI and LFI* attacks. Thanks to Felix Wilhelm** @return void*/public function testValidatePostObjectDeserialize() {$this->Controller->Security->startup($this->Controller);$key = $this->Controller->request->params['_Token']['key'];$fields = 'a5475372b40f6e3ccbf9f8af191f20e1642fd877';$unlocked = '';// a corrupted serialized object, so we can see if it ever gets to deserialize$attack = 'O:3:"App":1:{s:5:"__map";a:1:{s:3:"foo";s:7:"Hacked!";s:1:"fail"}}';$fields .= urlencode(':' . str_rot13($attack));$this->Controller->request->data = array('Model' => array('username' => 'mark', 'password' => 'foo', 'valid' => '0'),'_Token' => compact('key', 'fields', 'unlocked'));$result = $this->Controller->Security->validatePost($this->Controller);$this->assertFalse($result, 'validatePost passed when key was missing. %s');}/*** Tests validation of checkbox arrays** @return void*/public function testValidatePostArray() {$this->Controller->Security->startup($this->Controller);$key = $this->Controller->request->params['_Token']['key'];$fields = 'f7d573650a295b94e0938d32b323fde775e5f32b%3A';$unlocked = '';$this->Controller->request->data = array('Model' => array('multi_field' => array('1', '3')),'_Token' => compact('key', 'fields', 'unlocked'));$this->assertTrue($this->Controller->Security->validatePost($this->Controller));}/*** testValidatePostNoModel method** @return void*/public function testValidatePostNoModel() {$this->Controller->Security->startup($this->Controller);$key = $this->Controller->request->params['_Token']['key'];$fields = '540ac9c60d323c22bafe997b72c0790f39a8bdef%3A';$unlocked = '';$this->Controller->request->data = array('anything' => 'some_data','_Token' => compact('key', 'fields', 'unlocked'));$result = $this->Controller->Security->validatePost($this->Controller);$this->assertTrue($result);}/*** testValidatePostSimple method** @return void*/public function testValidatePostSimple() {$this->Controller->Security->startup($this->Controller);$key = $this->Controller->request->params['_Token']['key'];$fields = '69f493434187b867ea14b901fdf58b55d27c935d%3A';$unlocked = '';$this->Controller->request->data = $data = array('Model' => array('username' => '', 'password' => ''),'_Token' => compact('key', 'fields', 'unlocked'));$result = $this->Controller->Security->validatePost($this->Controller);$this->assertTrue($result);}/*** Tests hash validation for multiple records, including locked fields** @return void*/public function testValidatePostComplex() {$this->Controller->Security->startup($this->Controller);$key = $this->Controller->request->params['_Token']['key'];$fields = 'c9118120e680a7201b543f562e5301006ccfcbe2%3AAddresses.0.id%7CAddresses.1.id';$unlocked = '';$this->Controller->request->data = array('Addresses' => array('0' => array('id' => '123456', 'title' => '', 'first_name' => '', 'last_name' => '','address' => '', 'city' => '', 'phone' => '', 'primary' => ''),'1' => array('id' => '654321', 'title' => '', 'first_name' => '', 'last_name' => '','address' => '', 'city' => '', 'phone' => '', 'primary' => '')),'_Token' => compact('key', 'fields', 'unlocked'));$result = $this->Controller->Security->validatePost($this->Controller);$this->assertTrue($result);}/*** test ValidatePost with multiple select elements.** @return void*/public function testValidatePostMultipleSelect() {$this->Controller->Security->startup($this->Controller);$key = $this->Controller->request->params['_Token']['key'];$fields = '422cde416475abc171568be690a98cad20e66079%3A';$unlocked = '';$this->Controller->request->data = array('Tag' => array('Tag' => array(1, 2)),'_Token' => compact('key', 'fields', 'unlocked'),);$result = $this->Controller->Security->validatePost($this->Controller);$this->assertTrue($result);$this->Controller->request->data = array('Tag' => array('Tag' => array(1, 2, 3)),'_Token' => compact('key', 'fields', 'unlocked'),);$result = $this->Controller->Security->validatePost($this->Controller);$this->assertTrue($result);$this->Controller->request->data = array('Tag' => array('Tag' => array(1, 2, 3, 4)),'_Token' => compact('key', 'fields', 'unlocked'),);$result = $this->Controller->Security->validatePost($this->Controller);$this->assertTrue($result);$fields = '19464422eafe977ee729c59222af07f983010c5f%3A';$this->Controller->request->data = array('User.password' => 'bar', 'User.name' => 'foo', 'User.is_valid' => '1','Tag' => array('Tag' => array(1)),'_Token' => compact('key', 'fields', 'unlocked'),);$result = $this->Controller->Security->validatePost($this->Controller);$this->assertTrue($result);}/*** testValidatePostCheckbox method** First block tests un-checked checkbox* Second block tests checked checkbox** @return void*/public function testValidatePostCheckbox() {$this->Controller->Security->startup($this->Controller);$key = $this->Controller->request->params['_Token']['key'];$fields = 'a5475372b40f6e3ccbf9f8af191f20e1642fd877%3AModel.valid';$unlocked = '';$this->Controller->request->data = array('Model' => array('username' => '', 'password' => '', 'valid' => '0'),'_Token' => compact('key', 'fields', 'unlocked'));$result = $this->Controller->Security->validatePost($this->Controller);$this->assertTrue($result);$fields = '874439ca69f89b4c4a5f50fb9c36ff56a28f5d42%3A';$this->Controller->request->data = array('Model' => array('username' => '', 'password' => '', 'valid' => '0'),'_Token' => compact('key', 'fields', 'unlocked'));$result = $this->Controller->Security->validatePost($this->Controller);$this->assertTrue($result);$this->Controller->request->data = array();$this->Controller->Security->startup($this->Controller);$key = $this->Controller->request->params['_Token']['key'];$this->Controller->request->data = array('Model' => array('username' => '', 'password' => '', 'valid' => '0'),'_Token' => compact('key', 'fields', 'unlocked'));$result = $this->Controller->Security->validatePost($this->Controller);$this->assertTrue($result);}/*** testValidatePostHidden method** @return void*/public function testValidatePostHidden() {$this->Controller->Security->startup($this->Controller);$key = $this->Controller->request->params['_Token']['key'];$fields = '51ccd8cb0997c7b3d4523ecde5a109318405ef8c%3AModel.hidden%7CModel.other_hidden';$unlocked = '';$this->Controller->request->data = array('Model' => array('username' => '', 'password' => '', 'hidden' => '0','other_hidden' => 'some hidden value'),'_Token' => compact('key', 'fields', 'unlocked'));$result = $this->Controller->Security->validatePost($this->Controller);$this->assertTrue($result);}/*** testValidatePostWithDisabledFields method** @return void*/public function testValidatePostWithDisabledFields() {$this->Controller->Security->disabledFields = array('Model.username', 'Model.password');$this->Controller->Security->startup($this->Controller);$key = $this->Controller->request->params['_Token']['key'];$fields = 'ef1082968c449397bcd849f963636864383278b1%3AModel.hidden';$unlocked = '';$this->Controller->request->data = array('Model' => array('username' => '', 'password' => '', 'hidden' => '0'),'_Token' => compact('fields', 'key', 'unlocked'));$result = $this->Controller->Security->validatePost($this->Controller);$this->assertTrue($result);}/*** test validating post data with posted unlocked fields.** @return void*/public function testValidatePostDisabledFieldsInData() {$this->Controller->Security->startup($this->Controller);$key = $this->Controller->request->params['_Token']['key'];$unlocked = 'Model.username';$fields = array('Model.hidden', 'Model.password');$fields = urlencode(Security::hash(serialize($fields) . $unlocked . Configure::read('Security.salt')));$this->Controller->request->data = array('Model' => array('username' => 'mark','password' => 'sekret','hidden' => '0'),'_Token' => compact('fields', 'key', 'unlocked'));$result = $this->Controller->Security->validatePost($this->Controller);$this->assertTrue($result);}/*** test that missing 'unlocked' input causes failure** @return void*/public function testValidatePostFailNoDisabled() {$this->Controller->Security->startup($this->Controller);$key = $this->Controller->request->params['_Token']['key'];$fields = array('Model.hidden', 'Model.password', 'Model.username');$fields = urlencode(Security::hash(serialize($fields) . Configure::read('Security.salt')));$this->Controller->request->data = array('Model' => array('username' => 'mark','password' => 'sekret','hidden' => '0'),'_Token' => compact('fields', 'key'));$result = $this->Controller->Security->validatePost($this->Controller);$this->assertFalse($result);}/*** Test that validatePost fails when unlocked fields are changed.** @return*/public function testValidatePostFailDisabledFieldTampering() {$this->Controller->Security->startup($this->Controller);$key = $this->Controller->request->params['_Token']['key'];$unlocked = 'Model.username';$fields = array('Model.hidden', 'Model.password');$fields = urlencode(Security::hash(serialize($fields) . $unlocked . Configure::read('Security.salt')));// Tamper the values.$unlocked = 'Model.username|Model.password';$this->Controller->request->data = array('Model' => array('username' => 'mark','password' => 'sekret','hidden' => '0'),'_Token' => compact('fields', 'key', 'unlocked'));$result = $this->Controller->Security->validatePost($this->Controller);$this->assertFalse($result);}/*** testValidateHiddenMultipleModel method** @return void*/public function testValidateHiddenMultipleModel() {$this->Controller->Security->startup($this->Controller);$key = $this->Controller->request->params['_Token']['key'];$fields = 'a2d01072dc4660eea9d15007025f35a7a5b58e18%3AModel.valid%7CModel2.valid%7CModel3.valid';$unlocked = '';$this->Controller->request->data = array('Model' => array('username' => '', 'password' => '', 'valid' => '0'),'Model2' => array('valid' => '0'),'Model3' => array('valid' => '0'),'_Token' => compact('key', 'fields', 'unlocked'));$result = $this->Controller->Security->validatePost($this->Controller);$this->assertTrue($result);}/*** testValidateHasManyModel method** @return void*/public function testValidateHasManyModel() {$this->Controller->Security->startup($this->Controller);$key = $this->Controller->request->params['_Token']['key'];$fields = '51e3b55a6edd82020b3f29c9ae200e14bbeb7ee5%3AModel.0.hidden%7CModel.0.valid';$fields .= '%7CModel.1.hidden%7CModel.1.valid';$unlocked = '';$this->Controller->request->data = array('Model' => array(array('username' => 'username', 'password' => 'password','hidden' => 'value', 'valid' => '0'),array('username' => 'username', 'password' => 'password','hidden' => 'value', 'valid' => '0')),'_Token' => compact('key', 'fields', 'unlocked'));$result = $this->Controller->Security->validatePost($this->Controller);$this->assertTrue($result);}/*** testValidateHasManyRecordsPass method** @return void*/public function testValidateHasManyRecordsPass() {$this->Controller->Security->startup($this->Controller);$key = $this->Controller->request->params['_Token']['key'];$fields = '7a203edb3d345bbf38fe0dccae960da8842e11d7%3AAddress.0.id%7CAddress.0.primary%7C';$fields .= 'Address.1.id%7CAddress.1.primary';$unlocked = '';$this->Controller->request->data = array('Address' => array(0 => array('id' => '123','title' => 'home','first_name' => 'Bilbo','last_name' => 'Baggins','address' => '23 Bag end way','city' => 'the shire','phone' => 'N/A','primary' => '1',),1 => array('id' => '124','title' => 'home','first_name' => 'Frodo','last_name' => 'Baggins','address' => '50 Bag end way','city' => 'the shire','phone' => 'N/A','primary' => '1')),'_Token' => compact('key', 'fields', 'unlocked'));$result = $this->Controller->Security->validatePost($this->Controller);$this->assertTrue($result);}/*** Test that values like Foo.0.1** @return void*/public function testValidateNestedNumericSets() {$this->Controller->Security->startup($this->Controller);$key = $this->Controller->request->params['_Token']['key'];$unlocked = '';$hashFields = array('TaxonomyData');$fields = urlencode(Security::hash(serialize($hashFields) . $unlocked . Configure::read('Security.salt')));$this->Controller->request->data = array('TaxonomyData' => array(1 => array(array(2)),2 => array(array(3))),'_Token' => compact('key', 'fields', 'unlocked'));$result = $this->Controller->Security->validatePost($this->Controller);$this->assertTrue($result);}/*** testValidateHasManyRecords method** validatePost should fail, hidden fields have been changed.** @return void*/public function testValidateHasManyRecordsFail() {$this->Controller->Security->startup($this->Controller);$key = $this->Controller->request->params['_Token']['key'];$fields = '7a203edb3d345bbf38fe0dccae960da8842e11d7%3AAddress.0.id%7CAddress.0.primary%7C';$fields .= 'Address.1.id%7CAddress.1.primary';$unlocked = '';$this->Controller->request->data = array('Address' => array(0 => array('id' => '123','title' => 'home','first_name' => 'Bilbo','last_name' => 'Baggins','address' => '23 Bag end way','city' => 'the shire','phone' => 'N/A','primary' => '5',),1 => array('id' => '124','title' => 'home','first_name' => 'Frodo','last_name' => 'Baggins','address' => '50 Bag end way','city' => 'the shire','phone' => 'N/A','primary' => '1')),'_Token' => compact('key', 'fields', 'unlocked'));$result = $this->Controller->Security->validatePost($this->Controller);$this->assertFalse($result);}/*** testFormDisabledFields method** @return void*/public function testFormDisabledFields() {$this->Controller->Security->startup($this->Controller);$key = $this->Controller->request->params['_Token']['key'];$fields = '11842060341b9d0fc3808b90ba29fdea7054d6ad%3An%3A0%3A%7B%7D';$unlocked = '';$this->Controller->request->data = array('MyModel' => array('name' => 'some data'),'_Token' => compact('key', 'fields', 'unlocked'));$result = $this->Controller->Security->validatePost($this->Controller);$this->assertFalse($result);$this->Controller->Security->startup($this->Controller);$this->Controller->Security->disabledFields = array('MyModel.name');$key = $this->Controller->request->params['_Token']['key'];$this->Controller->request->data = array('MyModel' => array('name' => 'some data'),'_Token' => compact('key', 'fields', 'unlocked'));$result = $this->Controller->Security->validatePost($this->Controller);$this->assertTrue($result);}/*** testRadio method** @return void*/public function testRadio() {$this->Controller->Security->startup($this->Controller);$key = $this->Controller->request->params['_Token']['key'];$fields = '575ef54ca4fc8cab468d6d898e9acd3a9671c17e%3An%3A0%3A%7B%7D';$unlocked = '';$this->Controller->request->data = array('_Token' => compact('key', 'fields', 'unlocked'));$result = $this->Controller->Security->validatePost($this->Controller);$this->assertFalse($result);$this->Controller->request->data = array('_Token' => compact('key', 'fields', 'unlocked'),'Test' => array('test' => ''));$result = $this->Controller->Security->validatePost($this->Controller);$this->assertTrue($result);$this->Controller->request->data = array('_Token' => compact('key', 'fields', 'unlocked'),'Test' => array('test' => '1'));$result = $this->Controller->Security->validatePost($this->Controller);$this->assertTrue($result);$this->Controller->request->data = array('_Token' => compact('key', 'fields', 'unlocked'),'Test' => array('test' => '2'));$result = $this->Controller->Security->validatePost($this->Controller);$this->assertTrue($result);}/*** test that a requestAction's controller will have the _Token appended to* the params.** @return void* @see https://cakephp.lighthouseapp.com/projects/42648/tickets/68*/public function testSettingTokenForRequestAction() {$this->Controller->Security->startup($this->Controller);$key = $this->Controller->request->params['_Token']['key'];$this->Controller->params['requested'] = 1;unset($this->Controller->request->params['_Token']);$this->Controller->Security->startup($this->Controller);$this->assertEquals($this->Controller->request->params['_Token']['key'], $key);}/*** test that blackhole doesn't delete the _Token session key so repeat data submissions* stay blackholed.** @link https://cakephp.lighthouseapp.com/projects/42648/tickets/214* @return void*/public function testBlackHoleNotDeletingSessionInformation() {$this->Controller->Security->startup($this->Controller);$this->Controller->Security->blackHole($this->Controller, 'auth');$this->assertTrue($this->Controller->Security->Session->check('_Token'), '_Token was deleted by blackHole %s');}/*** test that csrf checks are skipped for request action.** @return void*/public function testCsrfSkipRequestAction() {$_SERVER['REQUEST_METHOD'] = 'POST';$this->Security->validatePost = false;$this->Security->csrfCheck = true;$this->Security->csrfExpires = '+10 minutes';$this->Controller->request->params['requested'] = 1;$this->Security->startup($this->Controller);$this->assertFalse($this->Controller->failed, 'fail() was called.');}/*** test setting** @return void*/public function testCsrfSettings() {$this->Security->validatePost = false;$this->Security->csrfCheck = true;$this->Security->csrfExpires = '+10 minutes';$this->Security->startup($this->Controller);$token = $this->Security->Session->read('_Token');$this->assertEquals(1, count($token['csrfTokens']), 'Missing the csrf token.');$this->assertEquals(strtotime('+10 minutes'), current($token['csrfTokens']), 'Token expiry does not match');$this->assertEquals(array('key', 'unlockedFields'), array_keys($this->Controller->request->params['_Token']), 'Keys don not match');}/*** Test setting multiple nonces, when startup() is called more than once, (ie more than one request.)** @return void*/public function testCsrfSettingMultipleNonces() {$this->Security->validatePost = false;$this->Security->csrfCheck = true;$this->Security->csrfExpires = '+10 minutes';$csrfExpires = strtotime('+10 minutes');$this->Security->startup($this->Controller);$this->Security->startup($this->Controller);$token = $this->Security->Session->read('_Token');$this->assertEquals(2, count($token['csrfTokens']), 'Missing the csrf token.');foreach ($token['csrfTokens'] as $expires) {$diff = $csrfExpires - $expires;$this->assertTrue($diff === 0 || $diff === 1, 'Token expiry does not match');}}/*** test that nonces are consumed by form submits.** @return void*/public function testCsrfNonceConsumption() {$this->Security->validatePost = false;$this->Security->csrfCheck = true;$this->Security->csrfExpires = '+10 minutes';$this->Security->Session->write('_Token.csrfTokens', array('nonce1' => strtotime('+10 minutes')));$this->Controller->request = $this->getMock('CakeRequest', array('is'));$this->Controller->request->expects($this->once())->method('is')->with(array('post', 'put'))->will($this->returnValue(true));$this->Controller->request->params['action'] = 'index';$this->Controller->request->data = array('_Token' => array('key' => 'nonce1'),'Post' => array('title' => 'Woot'));$this->Security->startup($this->Controller);$token = $this->Security->Session->read('_Token');$this->assertFalse(isset($token['csrfTokens']['nonce1']), 'Token was not consumed');}/*** test that expired values in the csrfTokens are cleaned up.** @return void*/public function testCsrfNonceVacuum() {$this->Security->validatePost = false;$this->Security->csrfCheck = true;$this->Security->csrfExpires = '+10 minutes';$this->Security->Session->write('_Token.csrfTokens', array('valid' => strtotime('+30 minutes'),'poof' => strtotime('-11 minutes'),'dust' => strtotime('-20 minutes')));$this->Security->startup($this->Controller);$tokens = $this->Security->Session->read('_Token.csrfTokens');$this->assertEquals(2, count($tokens), 'Too many tokens left behind');$this->assertNotEmpty('valid', $tokens, 'Valid token was removed.');}/*** test that when the key is missing the request is blackHoled** @return void*/public function testCsrfBlackHoleOnKeyMismatch() {$this->Security->validatePost = false;$this->Security->csrfCheck = true;$this->Security->csrfExpires = '+10 minutes';$this->Security->Session->write('_Token.csrfTokens', array('nonce1' => strtotime('+10 minutes')));$this->Controller->request = $this->getMock('CakeRequest', array('is'));$this->Controller->request->expects($this->once())->method('is')->with(array('post', 'put'))->will($this->returnValue(true));$this->Controller->request->params['action'] = 'index';$this->Controller->request->data = array('_Token' => array('key' => 'not the right value'),'Post' => array('title' => 'Woot'));$this->Security->startup($this->Controller);$this->assertTrue($this->Controller->failed, 'fail() was not called.');}/*** test that when the key is missing the request is blackHoled** @return void*/public function testCsrfBlackHoleOnExpiredKey() {$this->Security->validatePost = false;$this->Security->csrfCheck = true;$this->Security->csrfExpires = '+10 minutes';$this->Security->Session->write('_Token.csrfTokens', array('nonce1' => strtotime('-5 minutes')));$this->Controller->request = $this->getMock('CakeRequest', array('is'));$this->Controller->request->expects($this->once())->method('is')->with(array('post', 'put'))->will($this->returnValue(true));$this->Controller->request->params['action'] = 'index';$this->Controller->request->data = array('_Token' => array('key' => 'nonce1'),'Post' => array('title' => 'Woot'));$this->Security->startup($this->Controller);$this->assertTrue($this->Controller->failed, 'fail() was not called.');}/*** test that csrfUseOnce = false works.** @return void*/public function testCsrfNotUseOnce() {$this->Security->validatePost = false;$this->Security->csrfCheck = true;$this->Security->csrfUseOnce = false;$this->Security->csrfExpires = '+10 minutes';// Generate one token$this->Security->startup($this->Controller);$token = $this->Security->Session->read('_Token.csrfTokens');$this->assertEquals(1, count($token), 'Should only be one token.');$this->Security->startup($this->Controller);$tokenTwo = $this->Security->Session->read('_Token.csrfTokens');$this->assertEquals(1, count($tokenTwo), 'Should only be one token.');$this->assertEquals($token, $tokenTwo, 'Tokens should not be different.');$key = $this->Controller->request->params['_Token']['key'];$this->assertEquals(array($key), array_keys($token), '_Token.key and csrfToken do not match request will blackhole.');}/*** ensure that longer session tokens are not consumed** @return void*/public function testCsrfNotUseOnceValidationLeavingToken() {$this->Security->validatePost = false;$this->Security->csrfCheck = true;$this->Security->csrfUseOnce = false;$this->Security->csrfExpires = '+10 minutes';$this->Security->Session->write('_Token.csrfTokens', array('nonce1' => strtotime('+10 minutes')));$this->Controller->request = $this->getMock('CakeRequest', array('is'));$this->Controller->request->expects($this->once())->method('is')->with(array('post', 'put'))->will($this->returnValue(true));$this->Controller->request->params['action'] = 'index';$this->Controller->request->data = array('_Token' => array('key' => 'nonce1'),'Post' => array('title' => 'Woot'));$this->Security->startup($this->Controller);$token = $this->Security->Session->read('_Token');$this->assertTrue(isset($token['csrfTokens']['nonce1']), 'Token was consumed');}/*** Test generateToken()** @return void*/public function testGenerateToken() {$request = $this->Controller->request;$this->Security->generateToken($request);$this->assertNotEmpty($request->params['_Token']);$this->assertTrue(isset($request->params['_Token']['unlockedFields']));$this->assertTrue(isset($request->params['_Token']['key']));}/*** Test the limiting of CSRF tokens.** @return void*/public function testCsrfLimit() {$this->Security->csrfLimit = 3;$time = strtotime('+10 minutes');$tokens = array('1' => $time,'2' => $time,'3' => $time,'4' => $time,'5' => $time,);$this->Security->Session->write('_Token', array('csrfTokens' => $tokens));$this->Security->generateToken($this->Controller->request);$result = $this->Security->Session->read('_Token.csrfTokens');$this->assertFalse(isset($result['1']));$this->assertFalse(isset($result['2']));$this->assertFalse(isset($result['3']));$this->assertTrue(isset($result['4']));$this->assertTrue(isset($result['5']));}/*** Test unlocked actions** @return void*/public function testUnlockedActions() {$_SERVER['REQUEST_METHOD'] = 'POST';$this->Controller->request->data = array('data');$this->Controller->Security->unlockedActions = 'index';$this->Controller->Security->blackHoleCallback = null;$result = $this->Controller->Security->startup($this->Controller);$this->assertNull($result);}}