Mercurial > hg > Members > shoshi > webvirt
diff cake/tests/cases/libs/controller/components/security.test.php @ 0:261e66bd5a0c
hg init
author | Shoshi TAMAKI <shoshi@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Sun, 24 Jul 2011 21:08:31 +0900 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cake/tests/cases/libs/controller/components/security.test.php Sun Jul 24 21:08:31 2011 +0900 @@ -0,0 +1,1286 @@ +<?php +/** + * SecurityComponentTest file + * + * PHP versions 4 and 5 + * + * CakePHP(tm) Tests <http://book.cakephp.org/view/1196/Testing> + * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The Open Group Test Suite License + * Redistributions of files must retain the above copyright notice. + * + * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests + * @package cake + * @subpackage cake.tests.cases.libs.controller.components + * @since CakePHP(tm) v 1.2.0.5435 + * @license http://www.opensource.org/licenses/opengroup.php The Open Group Test Suite License + */ +App::import('Component', 'Security'); + +/** +* TestSecurityComponent +* +* @package cake +* @subpackage cake.tests.cases.libs.controller.components +*/ +class TestSecurityComponent extends SecurityComponent { + +/** + * validatePost method + * + * @param Controller $controller + * @return unknown + */ + function validatePost(&$controller) { + return $this->_validatePost($controller); + } +} + +/** +* SecurityTestController +* +* @package cake +* @subpackage cake.tests.cases.libs.controller.components +*/ +class SecurityTestController extends Controller { + +/** + * name property + * + * @var string 'SecurityTest' + * @access public + */ + var $name = 'SecurityTest'; + +/** + * components property + * + * @var array + * @access public + */ + var $components = array('Session', 'TestSecurity'); + +/** + * failed property + * + * @var bool false + * @access public + */ + var $failed = false; + +/** + * Used for keeping track of headers in test + * + * @var array + * @access public + */ + var $testHeaders = array(); + +/** + * fail method + * + * @access public + * @return void + */ + function fail() { + $this->failed = true; + } + +/** + * redirect method + * + * @param mixed $option + * @param mixed $code + * @param mixed $exit + * @access public + * @return void + */ + function redirect($option, $code, $exit) { + return $code; + } + +/** + * Conveinence method for header() + * + * @param string $status + * @return void + * @access public + */ + function header($status) { + $this->testHeaders[] = $status; + } +} + +/** + * SecurityComponentTest class + * + * @package cake + * @subpackage cake.tests.cases.libs.controller.components + */ +class SecurityComponentTest extends CakeTestCase { + +/** + * Controller property + * + * @var SecurityTestController + * @access public + */ + var $Controller; + +/** + * oldSalt property + * + * @var string + * @access public + */ + var $oldSalt; + +/** + * setUp method + * + * @access public + * @return void + */ + function startTest() { + $this->Controller =& new SecurityTestController(); + $this->Controller->Component->init($this->Controller); + $this->Controller->Security =& $this->Controller->TestSecurity; + $this->Controller->Security->blackHoleCallback = 'fail'; + $this->oldSalt = Configure::read('Security.salt'); + Configure::write('Security.salt', 'foo!'); + } + +/** + * Tear-down method. Resets environment state. + * + * @access public + * @return void + */ + function endTest() { + Configure::write('Security.salt', $this->oldSalt); + $this->Controller->Session->delete('_Token'); + unset($this->Controller->Security); + unset($this->Controller->Component); + unset($this->Controller); + } + +/** + * test that initalize can set properties. + * + * @return void + */ + function testInitialize() { + $settings = array( + 'requirePost' => array('edit', 'update'), + 'requireSecure' => array('update_account'), + 'requireGet' => array('index'), + 'validatePost' => false, + 'loginUsers' => array( + 'mark' => 'password' + ), + 'requireLogin' => array('login'), + ); + $this->Controller->Security->initialize($this->Controller, $settings); + $this->assertEqual($this->Controller->Security->requirePost, $settings['requirePost']); + $this->assertEqual($this->Controller->Security->requireSecure, $settings['requireSecure']); + $this->assertEqual($this->Controller->Security->requireGet, $settings['requireGet']); + $this->assertEqual($this->Controller->Security->validatePost, $settings['validatePost']); + $this->assertEqual($this->Controller->Security->loginUsers, $settings['loginUsers']); + $this->assertEqual($this->Controller->Security->requireLogin, $settings['requireLogin']); + } + +/** + * testStartup method + * + * @access public + * @return void + */ + 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 + * + * @access public + * @return void + */ + function testRequirePostFail() { + $_SERVER['REQUEST_METHOD'] = 'GET'; + $this->Controller->action = 'posted'; + $this->Controller->Security->requirePost(array('posted')); + $this->Controller->Security->startup($this->Controller); + $this->assertTrue($this->Controller->failed); + } + +/** + * testRequirePostSucceed method + * + * @access public + * @return void + */ + function testRequirePostSucceed() { + $_SERVER['REQUEST_METHOD'] = 'POST'; + $this->Controller->action = 'posted'; + $this->Controller->Security->requirePost('posted'); + $this->Controller->Security->startup($this->Controller); + $this->assertFalse($this->Controller->failed); + } + +/** + * testRequireSecureFail method + * + * @access public + * @return void + */ + function testRequireSecureFail() { + $_SERVER['HTTPS'] = 'off'; + $_SERVER['REQUEST_METHOD'] = 'POST'; + $this->Controller->action = 'posted'; + $this->Controller->Security->requireSecure(array('posted')); + $this->Controller->Security->startup($this->Controller); + $this->assertTrue($this->Controller->failed); + } + +/** + * testRequireSecureSucceed method + * + * @access public + * @return void + */ + function testRequireSecureSucceed() { + $_SERVER['REQUEST_METHOD'] = 'Secure'; + $this->Controller->action = 'posted'; + $_SERVER['HTTPS'] = 'on'; + $this->Controller->Security->requireSecure('posted'); + $this->Controller->Security->startup($this->Controller); + $this->assertFalse($this->Controller->failed); + } + +/** + * testRequireAuthFail method + * + * @access public + * @return void + */ + function testRequireAuthFail() { + $_SERVER['REQUEST_METHOD'] = 'AUTH'; + $this->Controller->action = 'posted'; + $this->Controller->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', serialize(array('allowedControllers' => array()))); + $this->Controller->data = array('username' => 'willy', 'password' => 'somePass'); + $this->Controller->action = 'posted'; + $this->Controller->Security->requireAuth('posted'); + $this->Controller->Security->startup($this->Controller); + $this->assertTrue($this->Controller->failed); + + $this->Controller->Session->write('_Token', serialize(array( + 'allowedControllers' => array('SecurityTest'), 'allowedActions' => array('posted2') + ))); + $this->Controller->data = array('username' => 'willy', 'password' => 'somePass'); + $this->Controller->action = 'posted'; + $this->Controller->Security->requireAuth('posted'); + $this->Controller->Security->startup($this->Controller); + $this->assertTrue($this->Controller->failed); + } + +/** + * testRequireAuthSucceed method + * + * @access public + * @return void + */ + function testRequireAuthSucceed() { + $_SERVER['REQUEST_METHOD'] = 'AUTH'; + $this->Controller->action = 'posted'; + $this->Controller->Security->requireAuth('posted'); + $this->Controller->Security->startup($this->Controller); + $this->assertFalse($this->Controller->failed); + + $this->Controller->Security->Session->write('_Token', serialize(array( + 'allowedControllers' => array('SecurityTest'), 'allowedActions' => array('posted') + ))); + $this->Controller->params['controller'] = 'SecurityTest'; + $this->Controller->params['action'] = 'posted'; + + $this->Controller->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 + * + * @access public + * @return void + */ + function testRequirePostSucceedWrongMethod() { + $_SERVER['REQUEST_METHOD'] = 'GET'; + $this->Controller->action = 'getted'; + $this->Controller->Security->requirePost('posted'); + $this->Controller->Security->startup($this->Controller); + $this->assertFalse($this->Controller->failed); + } + +/** + * testRequireGetFail method + * + * @access public + * @return void + */ + function testRequireGetFail() { + $_SERVER['REQUEST_METHOD'] = 'POST'; + $this->Controller->action = 'getted'; + $this->Controller->Security->requireGet(array('getted')); + $this->Controller->Security->startup($this->Controller); + $this->assertTrue($this->Controller->failed); + } + +/** + * testRequireGetSucceed method + * + * @access public + * @return void + */ + function testRequireGetSucceed() { + $_SERVER['REQUEST_METHOD'] = 'GET'; + $this->Controller->action = 'getted'; + $this->Controller->Security->requireGet('getted'); + $this->Controller->Security->startup($this->Controller); + $this->assertFalse($this->Controller->failed); + } + +/** + * testRequireLogin method + * + * @access public + * @return void + */ + function testRequireLogin() { + $this->Controller->action = 'posted'; + $this->Controller->Security->requireLogin( + 'posted', + array('type' => 'basic', 'users' => array('admin' => 'password')) + ); + $_SERVER['PHP_AUTH_USER'] = 'admin'; + $_SERVER['PHP_AUTH_PW'] = 'password'; + $this->Controller->Security->startup($this->Controller); + $this->assertFalse($this->Controller->failed); + + + $this->Controller->action = 'posted'; + $this->Controller->Security->requireLogin( + array('posted'), + array('type' => 'basic', 'users' => array('admin' => 'password')) + ); + $_SERVER['PHP_AUTH_USER'] = 'admin2'; + $_SERVER['PHP_AUTH_PW'] = 'password'; + $this->Controller->Security->startup($this->Controller); + $this->assertTrue($this->Controller->failed); + + $this->Controller->action = 'posted'; + $this->Controller->Security->requireLogin( + 'posted', + array('type' => 'basic', 'users' => array('admin' => 'password')) + ); + $_SERVER['PHP_AUTH_USER'] = 'admin'; + $_SERVER['PHP_AUTH_PW'] = 'password2'; + $this->Controller->Security->startup($this->Controller); + $this->assertTrue($this->Controller->failed); + } + +/** + * testDigestAuth method + * + * @access public + * @return void + */ + function testDigestAuth() { + $skip = $this->skipIf((version_compare(PHP_VERSION, '5.1') == -1) XOR (!function_exists('apache_request_headers')), + "%s Cannot run Digest Auth test for PHP versions < 5.1" + ); + + if ($skip) { + return; + } + + $this->Controller->action = 'posted'; + $_SERVER['PHP_AUTH_DIGEST'] = $digest = <<<DIGEST + Digest username="Mufasa", + realm="testrealm@host.com", + nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", + uri="/dir/index.html", + qop=auth, + nc=00000001, + cnonce="0a4f113b", + response="460d0d3c6867c2f1ab85b1ada1aece48", + opaque="5ccc069c403ebaf9f0171e9517f40e41" +DIGEST; + $this->Controller->Security->requireLogin('posted', array( + 'type' => 'digest', 'users' => array('Mufasa' => 'password'), + 'realm' => 'testrealm@host.com' + )); + $this->Controller->Security->startup($this->Controller); + $this->assertFalse($this->Controller->failed); + } + +/** + * testRequireGetSucceedWrongMethod method + * + * @access public + * @return void + */ + function testRequireGetSucceedWrongMethod() { + $_SERVER['REQUEST_METHOD'] = 'POST'; + $this->Controller->action = 'posted'; + $this->Controller->Security->requireGet('getted'); + $this->Controller->Security->startup($this->Controller); + $this->assertFalse($this->Controller->failed); + } + +/** + * testRequirePutFail method + * + * @access public + * @return void + */ + function testRequirePutFail() { + $_SERVER['REQUEST_METHOD'] = 'POST'; + $this->Controller->action = 'putted'; + $this->Controller->Security->requirePut(array('putted')); + $this->Controller->Security->startup($this->Controller); + $this->assertTrue($this->Controller->failed); + } + +/** + * testRequirePutSucceed method + * + * @access public + * @return void + */ + function testRequirePutSucceed() { + $_SERVER['REQUEST_METHOD'] = 'PUT'; + $this->Controller->action = 'putted'; + $this->Controller->Security->requirePut('putted'); + $this->Controller->Security->startup($this->Controller); + $this->assertFalse($this->Controller->failed); + } + +/** + * testRequirePutSucceedWrongMethod method + * + * @access public + * @return void + */ + function testRequirePutSucceedWrongMethod() { + $_SERVER['REQUEST_METHOD'] = 'POST'; + $this->Controller->action = 'posted'; + $this->Controller->Security->requirePut('putted'); + $this->Controller->Security->startup($this->Controller); + $this->assertFalse($this->Controller->failed); + } + +/** + * testRequireDeleteFail method + * + * @access public + * @return void + */ + function testRequireDeleteFail() { + $_SERVER['REQUEST_METHOD'] = 'POST'; + $this->Controller->action = 'deleted'; + $this->Controller->Security->requireDelete(array('deleted', 'other_method')); + $this->Controller->Security->startup($this->Controller); + $this->assertTrue($this->Controller->failed); + } + +/** + * testRequireDeleteSucceed method + * + * @access public + * @return void + */ + function testRequireDeleteSucceed() { + $_SERVER['REQUEST_METHOD'] = 'DELETE'; + $this->Controller->action = 'deleted'; + $this->Controller->Security->requireDelete('deleted'); + $this->Controller->Security->startup($this->Controller); + $this->assertFalse($this->Controller->failed); + } + +/** + * testRequireDeleteSucceedWrongMethod method + * + * @access public + * @return void + */ + function testRequireDeleteSucceedWrongMethod() { + $_SERVER['REQUEST_METHOD'] = 'POST'; + $this->Controller->action = 'posted'; + $this->Controller->Security->requireDelete('deleted'); + $this->Controller->Security->startup($this->Controller); + $this->assertFalse($this->Controller->failed); + } + +/** + * testRequireLoginSettings method + * + * @access public + * @return void + */ + function testRequireLoginSettings() { + $this->Controller->Security->requireLogin( + 'add', 'edit', + array('type' => 'basic', 'users' => array('admin' => 'password')) + ); + $this->assertEqual($this->Controller->Security->requireLogin, array('add', 'edit')); + $this->assertEqual($this->Controller->Security->loginUsers, array('admin' => 'password')); + } + +/** + * testRequireLoginAllActions method + * + * @access public + * @return void + */ + function testRequireLoginAllActions() { + $this->Controller->Security->requireLogin( + array('type' => 'basic', 'users' => array('admin' => 'password')) + ); + $this->assertEqual($this->Controller->Security->requireLogin, array('*')); + $this->assertEqual($this->Controller->Security->loginUsers, array('admin' => 'password')); + } + +/** + * Simple hash validation test + * + * @access public + * @return void + */ + function testValidatePost() { + $this->Controller->Security->startup($this->Controller); + $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->assertTrue($this->Controller->Security->validatePost($this->Controller)); + } + +/** + * test that validatePost fails if any of its required fields are missing. + * + * @return void + */ + function testValidatePostFormHacking() { + $this->Controller->Security->startup($this->Controller); + $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') + ); + $result = $this->Controller->Security->validatePost($this->Controller); + $this->assertFalse($result, 'validatePost passed when fields were missing. %s'); + + $this->Controller->data = array( + 'Model' => array('username' => 'nate', 'password' => 'foo', 'valid' => '0'), + '_Token' => compact('fields') + ); + $result = $this->Controller->Security->validatePost($this->Controller); + $this->assertFalse($result, 'validatePost passed when key was 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 + */ + function testValidatePostObjectDeserialize() { + $this->Controller->Security->startup($this->Controller); + $key = $this->Controller->params['_Token']['key']; + $fields = 'a5475372b40f6e3ccbf9f8af191f20e1642fd877'; + + // 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->data = array( + 'Model' => array('username' => 'mark', 'password' => 'foo', 'valid' => '0'), + '_Token' => compact('key', 'fields') + ); + $result = $this->Controller->Security->validatePost($this->Controller); + $this->assertFalse($result, 'validatePost passed when key was missing. %s'); + } + +/** + * Tests validation of checkbox arrays + * + * @access public + * @return void + */ + function testValidatePostArray() { + $this->Controller->Security->startup($this->Controller); + $key = $this->Controller->params['_Token']['key']; + $fields = 'f7d573650a295b94e0938d32b323fde775e5f32b%3A'; + + $this->Controller->data = array( + 'Model' => array('multi_field' => array('1', '3')), + '_Token' => compact('key', 'fields') + ); + $this->assertTrue($this->Controller->Security->validatePost($this->Controller)); + } + +/** + * testValidatePostNoModel method + * + * @access public + * @return void + */ + function testValidatePostNoModel() { + $this->Controller->Security->startup($this->Controller); + $key = $this->Controller->params['_Token']['key']; + $fields = '540ac9c60d323c22bafe997b72c0790f39a8bdef%3A'; + + $this->Controller->data = array( + 'anything' => 'some_data', + '_Token' => compact('key', 'fields') + ); + + $result = $this->Controller->Security->validatePost($this->Controller); + $this->assertTrue($result); + } + +/** + * testValidatePostSimple method + * + * @access public + * @return void + */ + function testValidatePostSimple() { + $this->Controller->Security->startup($this->Controller); + $key = $this->Controller->params['_Token']['key']; + $fields = '69f493434187b867ea14b901fdf58b55d27c935d%3A'; + + $this->Controller->data = $data = array( + 'Model' => array('username' => '', 'password' => ''), + '_Token' => compact('key', 'fields') + ); + + $result = $this->Controller->Security->validatePost($this->Controller); + $this->assertTrue($result); + } + +/** + * Tests hash validation for multiple records, including locked fields + * + * @access public + * @return void + */ + function testValidatePostComplex() { + $this->Controller->Security->startup($this->Controller); + $key = $this->Controller->params['_Token']['key']; + $fields = 'c9118120e680a7201b543f562e5301006ccfcbe2%3AAddresses.0.id%7CAddresses.1.id'; + + $this->Controller->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') + ); + $result = $this->Controller->Security->validatePost($this->Controller); + $this->assertTrue($result); + } + +/** + * test ValidatePost with multiple select elements. + * + * @return void + */ + function testValidatePostMultipleSelect() { + $this->Controller->Security->startup($this->Controller); + $key = $this->Controller->params['_Token']['key']; + $fields = '422cde416475abc171568be690a98cad20e66079%3A'; + + $this->Controller->data = array( + 'Tag' => array('Tag' => array(1, 2)), + '_Token' => compact('key', 'fields'), + ); + $result = $this->Controller->Security->validatePost($this->Controller); + $this->assertTrue($result); + + $this->Controller->data = array( + 'Tag' => array('Tag' => array(1, 2, 3)), + '_Token' => compact('key', 'fields'), + ); + $result = $this->Controller->Security->validatePost($this->Controller); + $this->assertTrue($result); + + $this->Controller->data = array( + 'Tag' => array('Tag' => array(1, 2, 3, 4)), + '_Token' => compact('key', 'fields'), + ); + $result = $this->Controller->Security->validatePost($this->Controller); + $this->assertTrue($result); + + $fields = '19464422eafe977ee729c59222af07f983010c5f%3A'; + $this->Controller->data = array( + 'User.password' => 'bar', 'User.name' => 'foo', 'User.is_valid' => '1', + 'Tag' => array('Tag' => array(1)), '_Token' => compact('key', 'fields'), + ); + $result = $this->Controller->Security->validatePost($this->Controller); + $this->assertTrue($result); + } + +/** + * testValidatePostCheckbox method + * + * First block tests un-checked checkbox + * Second block tests checked checkbox + * + * @access public + * @return void + */ + function testValidatePostCheckbox() { + $this->Controller->Security->startup($this->Controller); + $key = $this->Controller->params['_Token']['key']; + $fields = 'a5475372b40f6e3ccbf9f8af191f20e1642fd877%3AModel.valid'; + + $this->Controller->data = array( + 'Model' => array('username' => '', 'password' => '', 'valid' => '0'), + '_Token' => compact('key', 'fields') + ); + + $result = $this->Controller->Security->validatePost($this->Controller); + $this->assertTrue($result); + + $fields = '874439ca69f89b4c4a5f50fb9c36ff56a28f5d42%3A'; + + $this->Controller->data = array( + 'Model' => array('username' => '', 'password' => '', 'valid' => '0'), + '_Token' => compact('key', 'fields') + ); + + $result = $this->Controller->Security->validatePost($this->Controller); + $this->assertTrue($result); + + + $this->Controller->data = array(); + $this->Controller->Security->startup($this->Controller); + $key = $this->Controller->params['_Token']['key']; + + $this->Controller->data = $data = array( + 'Model' => array('username' => '', 'password' => '', 'valid' => '0'), + '_Token' => compact('key', 'fields') + ); + + $result = $this->Controller->Security->validatePost($this->Controller); + $this->assertTrue($result); + } + +/** + * testValidatePostHidden method + * + * @access public + * @return void + */ + function testValidatePostHidden() { + $this->Controller->Security->startup($this->Controller); + $key = $this->Controller->params['_Token']['key']; + $fields = '51ccd8cb0997c7b3d4523ecde5a109318405ef8c%3AModel.hidden%7CModel.other_hidden'; + $fields .= ''; + + $this->Controller->data = array( + 'Model' => array( + 'username' => '', 'password' => '', 'hidden' => '0', + 'other_hidden' => 'some hidden value' + ), + '_Token' => compact('key', 'fields') + ); + $result = $this->Controller->Security->validatePost($this->Controller); + $this->assertTrue($result); + } + +/** + * testValidatePostWithDisabledFields method + * + * @access public + * @return void + */ + function testValidatePostWithDisabledFields() { + $this->Controller->Security->disabledFields = array('Model.username', 'Model.password'); + $this->Controller->Security->startup($this->Controller); + $key = $this->Controller->params['_Token']['key']; + $fields = 'ef1082968c449397bcd849f963636864383278b1%3AModel.hidden'; + + $this->Controller->data = array( + 'Model' => array( + 'username' => '', 'password' => '', 'hidden' => '0' + ), + '_Token' => compact('fields', 'key') + ); + + $result = $this->Controller->Security->validatePost($this->Controller); + $this->assertTrue($result); + } + +/** + * testValidateHiddenMultipleModel method + * + * @access public + * @return void + */ + function testValidateHiddenMultipleModel() { + $this->Controller->Security->startup($this->Controller); + $key = $this->Controller->params['_Token']['key']; + $fields = 'a2d01072dc4660eea9d15007025f35a7a5b58e18%3AModel.valid%7CModel2.valid%7CModel3.valid'; + + $this->Controller->data = array( + 'Model' => array('username' => '', 'password' => '', 'valid' => '0'), + 'Model2' => array('valid' => '0'), + 'Model3' => array('valid' => '0'), + '_Token' => compact('key', 'fields') + ); + $result = $this->Controller->Security->validatePost($this->Controller); + $this->assertTrue($result); + } + +/** + * testLoginValidation method + * + * @access public + * @return void + */ + function testLoginValidation() { + + } + +/** + * testValidateHasManyModel method + * + * @access public + * @return void + */ + function testValidateHasManyModel() { + $this->Controller->Security->startup($this->Controller); + $key = $this->Controller->params['_Token']['key']; + $fields = '51e3b55a6edd82020b3f29c9ae200e14bbeb7ee5%3AModel.0.hidden%7CModel.0.valid'; + $fields .= '%7CModel.1.hidden%7CModel.1.valid'; + + $this->Controller->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') + ); + + $result = $this->Controller->Security->validatePost($this->Controller); + $this->assertTrue($result); + } + +/** + * testValidateHasManyRecordsPass method + * + * @access public + * @return void + */ + function testValidateHasManyRecordsPass() { + $this->Controller->Security->startup($this->Controller); + $key = $this->Controller->params['_Token']['key']; + $fields = '7a203edb3d345bbf38fe0dccae960da8842e11d7%3AAddress.0.id%7CAddress.0.primary%7C'; + $fields .= 'Address.1.id%7CAddress.1.primary'; + + $this->Controller->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') + ); + + $result = $this->Controller->Security->validatePost($this->Controller); + $this->assertTrue($result); + } + +/** + * testValidateHasManyRecords method + * + * validatePost should fail, hidden fields have been changed. + * + * @access public + * @return void + */ + function testValidateHasManyRecordsFail() { + $this->Controller->Security->startup($this->Controller); + $key = $this->Controller->params['_Token']['key']; + $fields = '7a203edb3d345bbf38fe0dccae960da8842e11d7%3AAddress.0.id%7CAddress.0.primary%7C'; + $fields .= 'Address.1.id%7CAddress.1.primary'; + + $this->Controller->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') + ); + + $result = $this->Controller->Security->validatePost($this->Controller); + $this->assertFalse($result); + } + +/** + * testLoginRequest method + * + * @access public + * @return void + */ + function testLoginRequest() { + $this->Controller->Security->startup($this->Controller); + $realm = 'cakephp.org'; + $options = array('realm' => $realm, 'type' => 'basic'); + $result = $this->Controller->Security->loginRequest($options); + $expected = 'WWW-Authenticate: Basic realm="'.$realm.'"'; + $this->assertEqual($result, $expected); + + $this->Controller->Security->startup($this->Controller); + $options = array('realm' => $realm, 'type' => 'digest'); + $result = $this->Controller->Security->loginRequest($options); + $this->assertPattern('/realm="'.$realm.'"/', $result); + $this->assertPattern('/qop="auth"/', $result); + } + +/** + * testGenerateDigestResponseHash method + * + * @access public + * @return void + */ + function testGenerateDigestResponseHash() { + $this->Controller->Security->startup($this->Controller); + $realm = 'cakephp.org'; + $loginData = array('realm' => $realm, 'users' => array('Willy Smith' => 'password')); + $this->Controller->Security->requireLogin($loginData); + + $data = array( + 'username' => 'Willy Smith', + 'password' => 'password', + 'nonce' => String::uuid(), + 'nc' => 1, + 'cnonce' => 1, + 'realm' => $realm, + 'uri' => 'path_to_identifier', + 'qop' => 'testme' + ); + $_SERVER['REQUEST_METHOD'] = 'POST'; + + $result = $this->Controller->Security->generateDigestResponseHash($data); + $expected = md5( + md5($data['username'] . ':' . $loginData['realm'] . ':' . $data['password']) . ':' . + $data['nonce'] . ':' . $data['nc'] . ':' . $data['cnonce'] . ':' . $data['qop'] . ':' . + md5(env('REQUEST_METHOD') . ':' . $data['uri']) + ); + $this->assertIdentical($result, $expected); + } + +/** + * testLoginCredentials method + * + * @access public + * @return void + */ + function testLoginCredentials() { + $this->Controller->Security->startup($this->Controller); + $_SERVER['PHP_AUTH_USER'] = $user = 'Willy Test'; + $_SERVER['PHP_AUTH_PW'] = $pw = 'some password for the nice test'; + + $result = $this->Controller->Security->loginCredentials('basic'); + $expected = array('username' => $user, 'password' => $pw); + $this->assertIdentical($result, $expected); + + if (version_compare(PHP_VERSION, '5.1') != -1) { + $_SERVER['PHP_AUTH_DIGEST'] = $digest = <<<DIGEST + Digest username="Mufasa", + realm="testrealm@host.com", + nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", + uri="/dir/index.html", + qop=auth, + nc=00000001, + cnonce="0a4f113b", + response="6629fae49393a05397450978507c4ef1", + opaque="5ccc069c403ebaf9f0171e9517f40e41" +DIGEST; + $expected = array( + 'username' => 'Mufasa', + 'realm' => 'testrealm@host.com', + 'nonce' => 'dcd98b7102dd2f0e8b11d0f600bfb0c093', + 'uri' => '/dir/index.html', + 'qop' => 'auth', + 'nc' => '00000001', + 'cnonce' => '0a4f113b', + 'response' => '6629fae49393a05397450978507c4ef1', + 'opaque' => '5ccc069c403ebaf9f0171e9517f40e41' + ); + $result = $this->Controller->Security->loginCredentials('digest'); + $this->assertIdentical($result, $expected); + } + } + +/** + * testParseDigestAuthData method + * + * @access public + * @return void + */ + function testParseDigestAuthData() { + $this->Controller->Security->startup($this->Controller); + $digest = <<<DIGEST + Digest username="Mufasa", + realm="testrealm@host.com", + nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", + uri="/dir/index.html", + qop=auth, + nc=00000001, + cnonce="0a4f113b", + response="6629fae49393a05397450978507c4ef1", + opaque="5ccc069c403ebaf9f0171e9517f40e41" +DIGEST; + $expected = array( + 'username' => 'Mufasa', + 'realm' => 'testrealm@host.com', + 'nonce' => 'dcd98b7102dd2f0e8b11d0f600bfb0c093', + 'uri' => '/dir/index.html', + 'qop' => 'auth', + 'nc' => '00000001', + 'cnonce' => '0a4f113b', + 'response' => '6629fae49393a05397450978507c4ef1', + 'opaque' => '5ccc069c403ebaf9f0171e9517f40e41' + ); + $result = $this->Controller->Security->parseDigestAuthData($digest); + $this->assertIdentical($result, $expected); + + $result = $this->Controller->Security->parseDigestAuthData(''); + $this->assertNull($result); + } + +/** + * test parsing digest information with email addresses + * + * @return void + */ + function testParseDigestAuthEmailAddress() { + $this->Controller->Security->startup($this->Controller); + $digest = <<<DIGEST + Digest username="mark@example.com", + realm="testrealm@host.com", + nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", + uri="/dir/index.html", + qop=auth, + nc=00000001, + cnonce="0a4f113b", + response="6629fae49393a05397450978507c4ef1", + opaque="5ccc069c403ebaf9f0171e9517f40e41" +DIGEST; + $expected = array( + 'username' => 'mark@example.com', + 'realm' => 'testrealm@host.com', + 'nonce' => 'dcd98b7102dd2f0e8b11d0f600bfb0c093', + 'uri' => '/dir/index.html', + 'qop' => 'auth', + 'nc' => '00000001', + 'cnonce' => '0a4f113b', + 'response' => '6629fae49393a05397450978507c4ef1', + 'opaque' => '5ccc069c403ebaf9f0171e9517f40e41' + ); + $result = $this->Controller->Security->parseDigestAuthData($digest); + $this->assertIdentical($result, $expected); + } + +/** + * testFormDisabledFields method + * + * @access public + * @return void + */ + function testFormDisabledFields() { + $this->Controller->Security->startup($this->Controller); + $key = $this->Controller->params['_Token']['key']; + $fields = '11842060341b9d0fc3808b90ba29fdea7054d6ad%3An%3A0%3A%7B%7D'; + + $this->Controller->data = array( + 'MyModel' => array('name' => 'some data'), + '_Token' => compact('key', 'fields') + ); + $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->params['_Token']['key']; + + $this->Controller->data = array( + 'MyModel' => array('name' => 'some data'), + '_Token' => compact('key', 'fields') + ); + + $result = $this->Controller->Security->validatePost($this->Controller); + $this->assertTrue($result); + } + +/** + * testRadio method + * + * @access public + * @return void + */ + function testRadio() { + $this->Controller->Security->startup($this->Controller); + $key = $this->Controller->params['_Token']['key']; + $fields = '575ef54ca4fc8cab468d6d898e9acd3a9671c17e%3An%3A0%3A%7B%7D'; + + $this->Controller->data = array( + '_Token' => compact('key', 'fields') + ); + $result = $this->Controller->Security->validatePost($this->Controller); + $this->assertFalse($result); + + $this->Controller->data = array( + '_Token' => compact('key', 'fields'), + 'Test' => array('test' => '') + ); + $result = $this->Controller->Security->validatePost($this->Controller); + $this->assertTrue($result); + + $this->Controller->data = array( + '_Token' => compact('key', 'fields'), + 'Test' => array('test' => '1') + ); + $result = $this->Controller->Security->validatePost($this->Controller); + $this->assertTrue($result); + + $this->Controller->data = array( + '_Token' => compact('key', 'fields'), + 'Test' => array('test' => '2') + ); + $result = $this->Controller->Security->validatePost($this->Controller); + $this->assertTrue($result); + } + +/** + * testInvalidAuthHeaders method + * + * @access public + * @return void + */ + function testInvalidAuthHeaders() { + $this->Controller->Security->blackHoleCallback = null; + $_SERVER['PHP_AUTH_USER'] = 'admin'; + $_SERVER['PHP_AUTH_PW'] = 'password'; + $realm = 'cakephp.org'; + $loginData = array('type' => 'basic', 'realm' => $realm); + $this->Controller->Security->requireLogin($loginData); + $this->Controller->Security->startup($this->Controller); + + $expected = 'WWW-Authenticate: Basic realm="'.$realm.'"'; + $this->assertEqual(count($this->Controller->testHeaders), 1); + $this->assertEqual(current($this->Controller->testHeaders), $expected); + } + +/** + * 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 + */ + function testSettingTokenForRequestAction() { + $this->Controller->Security->startup($this->Controller); + $key = $this->Controller->params['_Token']['key']; + + $this->Controller->params['requested'] = 1; + unset($this->Controller->params['_Token']); + + $this->Controller->Security->startup($this->Controller); + $this->assertEqual($this->Controller->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 + */ + 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'); + } +}