cakephp2-php8/lib/Cake/Test/Case/Controller/Component/SecurityComponentTest.php
mark_story 9296f770d5 Adding SecurityComponent::$csrfLimit
This property allows you to control the number of tokens
that will be kept active.  Its possible to make really large
CSRF collection sizes.  Capping the number of tokens allows developers
to better control session sizes.
2011-12-03 20:13:17 -05:00

1320 lines
39 KiB
PHP

<?php
/**
* SecurityComponentTest file
*
* PHP 5
*
* CakePHP(tm) Tests <http://book.cakephp.org/view/1196/Testing>
* 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://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
* @package Cake.Test.Case.Controller.Component
* @since CakePHP(tm) v 1.2.0.5435
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
App::uses('SecurityComponent', 'Controller/Component');
App::uses('Controller', 'Controller');
/**
* TestSecurityComponent
*
* @package Cake.Test.Case.Controller.Component
* @package Cake.Test.Case.Controller.Component
*/
class TestSecurityComponent extends SecurityComponent {
/**
* validatePost method
*
* @param Controller $controller
* @return unknown
*/
public function validatePost($controller) {
return $this->_validatePost($controller);
}
}
/**
* SecurityTestController
*
* @package Cake.Test.Case.Controller.Component
* @package Cake.Test.Case.Controller.Component
*/
class SecurityTestController extends Controller {
/**
* name property
*
* @var string 'SecurityTest'
*/
public $name = 'SecurityTest';
/**
* components property
*
* @var array
*/
public $components = array('Session', 'TestSecurity');
/**
* failed property
*
* @var bool 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 mixed $option
* @param mixed $code
* @param mixed $exit
* @return void
*/
public function redirect($url, $status = null, $exit = true) {
return $status;
}
/**
* Conveinence method for header()
*
* @param string $status
* @return void
*/
public function header($status) {
$this->testHeaders[] = $status;
}
}
/**
* 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 initalize 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'];
$fields = 'a5475372b40f6e3ccbf9f8af191f20e1642fd877%3AModel.valid';
$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 = $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);
}
/**
* 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 http://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 http://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(count($token['csrfTokens']), 1, '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';
$this->Security->startup($this->Controller);
$this->Security->startup($this->Controller);
$token = $this->Security->Session->read('_Token');
$this->assertEquals(count($token['csrfTokens']), 2, 'Missing the csrf token.');
foreach ($token['csrfTokens'] as $key => $expires) {
$this->assertEquals(strtotime('+10 minutes'), $expires, '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('post')
->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('post')
->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('post')
->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);
$token2 = $this->Security->Session->read('_Token.csrfTokens');
$this->assertEquals(1, count($token2), 'Should only be one token.');
$this->assertEquals($token, $token2, '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('post')
->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']));
}
}