|
|
@@ -16,8 +16,10 @@ namespace Cake\Test\TestCase\Controller\Component;
|
|
|
|
|
|
use Cake\Controller\Component\SecurityComponent;
|
|
|
use Cake\Controller\Controller;
|
|
|
+use Cake\Controller\Exception\SecurityException;
|
|
|
use Cake\Core\Configure;
|
|
|
use Cake\Event\Event;
|
|
|
+use Cake\Network\Exception\BadRequestException;
|
|
|
use Cake\Network\Request;
|
|
|
use Cake\Network\Session;
|
|
|
use Cake\TestSuite\TestCase;
|
|
|
@@ -40,6 +42,17 @@ class TestSecurityComponent extends SecurityComponent
|
|
|
{
|
|
|
return $this->_validatePost($controller);
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * authRequired method
|
|
|
+ *
|
|
|
+ * @param Controller $controller
|
|
|
+ * @return bool
|
|
|
+ */
|
|
|
+ public function authRequired(Controller $controller)
|
|
|
+ {
|
|
|
+ return $this->_authRequired($controller);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -110,6 +123,8 @@ class SecurityTestController extends Controller
|
|
|
/**
|
|
|
* SecurityComponentTest class
|
|
|
*
|
|
|
+ * @property SecurityComponent Security
|
|
|
+ * @property SecurityTestController Controller
|
|
|
*/
|
|
|
class SecurityComponentTest extends TestCase
|
|
|
{
|
|
|
@@ -167,6 +182,17 @@ class SecurityComponentTest extends TestCase
|
|
|
unset($this->Controller);
|
|
|
}
|
|
|
|
|
|
+ public function validatePost($expectedException = null, $expectedExceptionMessage = null)
|
|
|
+ {
|
|
|
+ try {
|
|
|
+ return $this->Controller->Security->validatePost($this->Controller);
|
|
|
+ } catch (SecurityException $ex) {
|
|
|
+ $this->assertInstanceOf('Cake\\Controller\\Exception\\' . $expectedException, $ex);
|
|
|
+ $this->assertEquals($expectedExceptionMessage, $ex->getMessage());
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* Test that requests are still blackholed when controller has incorrect
|
|
|
* visibility keyword in the blackhole callback
|
|
|
@@ -389,12 +415,13 @@ class SecurityComponentTest extends TestCase
|
|
|
|
|
|
$fields = '68730b0747d4889ec2766f9117405f9635f5fd5e%3AModel.valid';
|
|
|
$unlocked = '';
|
|
|
+ $debug = '';
|
|
|
|
|
|
$this->Controller->request->data = [
|
|
|
'Model' => ['username' => 'nate', 'password' => 'foo', 'valid' => '0'],
|
|
|
- '_Token' => compact('fields', 'unlocked')
|
|
|
+ '_Token' => compact('fields', 'unlocked', 'debug'),
|
|
|
];
|
|
|
- $this->assertTrue($this->Controller->Security->validatePost($this->Controller));
|
|
|
+ $this->assertTrue($this->validatePost());
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -411,11 +438,16 @@ class SecurityComponentTest extends TestCase
|
|
|
|
|
|
$fields = 'an-invalid-token';
|
|
|
$unlocked = '';
|
|
|
+ $debug = urlencode(json_encode([
|
|
|
+ 'some-action',
|
|
|
+ [],
|
|
|
+ []
|
|
|
+ ]));
|
|
|
|
|
|
$this->Controller->request->env('REQUEST_METHOD', 'GET');
|
|
|
$this->Controller->request->data = [
|
|
|
'Model' => ['username' => 'nate', 'password' => 'foo', 'valid' => '0'],
|
|
|
- '_Token' => compact('fields', 'unlocked')
|
|
|
+ '_Token' => compact('fields', 'unlocked', 'debug')
|
|
|
];
|
|
|
$this->Controller->Security->startup($event);
|
|
|
$this->assertTrue($this->Controller->failed);
|
|
|
@@ -432,6 +464,33 @@ class SecurityComponentTest extends TestCase
|
|
|
$event = new Event('Controller.startup', $this->Controller);
|
|
|
$this->Controller->Security->startup($event);
|
|
|
$this->Security->session->delete('_Token');
|
|
|
+ $unlocked = '';
|
|
|
+ $debug = urlencode(json_encode([
|
|
|
+ '/articles/index',
|
|
|
+ [],
|
|
|
+ []
|
|
|
+ ]));
|
|
|
+
|
|
|
+ $fields = 'a5475372b40f6e3ccbf9f8af191f20e1642fd877%3AModel.valid';
|
|
|
+
|
|
|
+ $this->Controller->request->data = [
|
|
|
+ 'Model' => ['username' => 'nate', 'password' => 'foo', 'valid' => '0'],
|
|
|
+ '_Token' => compact('fields', 'unlocked', 'debug')
|
|
|
+ ];
|
|
|
+ $this->assertFalse($this->validatePost('SecurityException', 'Unexpected field \'Model.password\' in POST data, Unexpected field \'Model.username\' in POST data'));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Test that validatePost fails if you are missing unlocked in request data.
|
|
|
+ *
|
|
|
+ * @return void
|
|
|
+ * @triggers Controller.startup $this->Controller
|
|
|
+ */
|
|
|
+ public function testValidatePostNoUnlockedInRequestData()
|
|
|
+ {
|
|
|
+ $event = new Event('Controller.startup', $this->Controller);
|
|
|
+ $this->Controller->Security->startup($event);
|
|
|
+ $this->Security->session->delete('_Token');
|
|
|
|
|
|
$fields = 'a5475372b40f6e3ccbf9f8af191f20e1642fd877%3AModel.valid';
|
|
|
|
|
|
@@ -439,7 +498,7 @@ class SecurityComponentTest extends TestCase
|
|
|
'Model' => ['username' => 'nate', 'password' => 'foo', 'valid' => '0'],
|
|
|
'_Token' => compact('fields')
|
|
|
];
|
|
|
- $this->assertFalse($this->Controller->Security->validatePost($this->Controller));
|
|
|
+ $this->assertFalse($this->validatePost('SecurityException', '\'_Token.unlocked\' was not found in request data.'));
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -458,7 +517,7 @@ class SecurityComponentTest extends TestCase
|
|
|
'Model' => ['username' => 'nate', 'password' => 'foo', 'valid' => '0'],
|
|
|
'_Token' => compact('unlocked')
|
|
|
];
|
|
|
- $result = $this->Controller->Security->validatePost($this->Controller);
|
|
|
+ $result = $this->validatePost('SecurityException', '\'_Token.fields\' was not found in request data.');
|
|
|
$this->assertFalse($result, 'validatePost passed when fields were missing. %s');
|
|
|
}
|
|
|
|
|
|
@@ -475,6 +534,11 @@ class SecurityComponentTest extends TestCase
|
|
|
$this->Controller->Security->startup($event);
|
|
|
$fields = 'a5475372b40f6e3ccbf9f8af191f20e1642fd877';
|
|
|
$unlocked = '';
|
|
|
+ $debug = urlencode(json_encode([
|
|
|
+ '/articles/index',
|
|
|
+ ['Model.password', 'Model.username', 'Model.valid'],
|
|
|
+ []
|
|
|
+ ]));
|
|
|
|
|
|
// 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"}}';
|
|
|
@@ -482,9 +546,9 @@ class SecurityComponentTest extends TestCase
|
|
|
|
|
|
$this->Controller->request->data = [
|
|
|
'Model' => ['username' => 'mark', 'password' => 'foo', 'valid' => '0'],
|
|
|
- '_Token' => compact('fields', 'unlocked')
|
|
|
+ '_Token' => compact('fields', 'unlocked', 'debug')
|
|
|
];
|
|
|
- $result = $this->Controller->Security->validatePost($this->Controller);
|
|
|
+ $result = $this->validatePost('SecurityException', 'Bad Request');
|
|
|
$this->assertFalse($result, 'validatePost passed when key was missing. %s');
|
|
|
}
|
|
|
|
|
|
@@ -501,13 +565,14 @@ class SecurityComponentTest extends TestCase
|
|
|
|
|
|
$fields = '8e26ef05379e5402c2c619f37ee91152333a0264%3A';
|
|
|
$unlocked = '';
|
|
|
+ $debug = 'not used';
|
|
|
|
|
|
$this->Controller->request->data = [
|
|
|
'_csrfToken' => 'abc123',
|
|
|
'Model' => ['multi_field' => ['1', '3']],
|
|
|
- '_Token' => compact('fields', 'unlocked')
|
|
|
+ '_Token' => compact('fields', 'unlocked', 'debug')
|
|
|
];
|
|
|
- $this->assertTrue($this->Controller->Security->validatePost($this->Controller));
|
|
|
+ $this->assertTrue($this->validatePost());
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -523,18 +588,23 @@ class SecurityComponentTest extends TestCase
|
|
|
|
|
|
$fields = '8e26ef05379e5402c2c619f37ee91152333a0264%3A';
|
|
|
$unlocked = '';
|
|
|
+ $debug = urlencode(json_encode([
|
|
|
+ 'some-action',
|
|
|
+ [],
|
|
|
+ []
|
|
|
+ ]));
|
|
|
|
|
|
$this->Controller->request->data = [
|
|
|
'Model' => ['multi_field' => ['1', '3']],
|
|
|
- '_Token' => compact('fields', 'unlocked')
|
|
|
+ '_Token' => compact('fields', 'unlocked', 'debug')
|
|
|
];
|
|
|
- $this->assertTrue($this->Controller->Security->validatePost($this->Controller));
|
|
|
+ $this->assertTrue($this->validatePost());
|
|
|
|
|
|
$this->Controller->request->data = [
|
|
|
'Model' => ['multi_field' => [12 => '1', 20 => '3']],
|
|
|
- '_Token' => compact('fields', 'unlocked')
|
|
|
+ '_Token' => compact('fields', 'unlocked', 'debug')
|
|
|
];
|
|
|
- $this->assertTrue($this->Controller->Security->validatePost($this->Controller));
|
|
|
+ $this->assertTrue($this->validatePost());
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -549,12 +619,17 @@ class SecurityComponentTest extends TestCase
|
|
|
|
|
|
$fields = '4a221010dd7a23f7166cb10c38bc21d81341c387%3A';
|
|
|
$unlocked = '';
|
|
|
+ $debug = urlencode(json_encode([
|
|
|
+ 'some-action',
|
|
|
+ [],
|
|
|
+ []
|
|
|
+ ]));
|
|
|
|
|
|
$this->Controller->request->data = [
|
|
|
1 => 'value,',
|
|
|
- '_Token' => compact('fields', 'unlocked')
|
|
|
+ '_Token' => compact('fields', 'unlocked', 'debug')
|
|
|
];
|
|
|
- $this->assertTrue($this->Controller->Security->validatePost($this->Controller));
|
|
|
+ $this->assertTrue($this->validatePost());
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -570,13 +645,14 @@ class SecurityComponentTest extends TestCase
|
|
|
|
|
|
$fields = 'a1c3724b7ba85e7022413611e30ba2c6181d5aba%3A';
|
|
|
$unlocked = '';
|
|
|
+ $debug = 'not used';
|
|
|
|
|
|
$this->Controller->request->data = [
|
|
|
'anything' => 'some_data',
|
|
|
- '_Token' => compact('fields', 'unlocked')
|
|
|
+ '_Token' => compact('fields', 'unlocked', 'debug')
|
|
|
];
|
|
|
|
|
|
- $result = $this->Controller->Security->validatePost($this->Controller);
|
|
|
+ $result = $this->validatePost();
|
|
|
$this->assertTrue($result);
|
|
|
}
|
|
|
|
|
|
@@ -593,13 +669,14 @@ class SecurityComponentTest extends TestCase
|
|
|
|
|
|
$fields = 'b0914d06dfb04abf1fada53e16810e87d157950b%3A';
|
|
|
$unlocked = '';
|
|
|
+ $debug = 'not used';
|
|
|
|
|
|
$this->Controller->request->data = [
|
|
|
'Model' => ['username' => '', 'password' => ''],
|
|
|
- '_Token' => compact('fields', 'unlocked')
|
|
|
+ '_Token' => compact('fields', 'unlocked', 'debug')
|
|
|
];
|
|
|
|
|
|
- $result = $this->Controller->Security->validatePost($this->Controller);
|
|
|
+ $result = $this->validatePost();
|
|
|
$this->assertTrue($result);
|
|
|
}
|
|
|
|
|
|
@@ -616,6 +693,7 @@ class SecurityComponentTest extends TestCase
|
|
|
|
|
|
$fields = 'b65c7463e44a61d8d2eaecce2c265b406c9c4742%3AAddresses.0.id%7CAddresses.1.id';
|
|
|
$unlocked = '';
|
|
|
+ $debug = 'not used';
|
|
|
|
|
|
$this->Controller->request->data = [
|
|
|
'Addresses' => [
|
|
|
@@ -628,9 +706,9 @@ class SecurityComponentTest extends TestCase
|
|
|
'address' => '', 'city' => '', 'phone' => '', 'primary' => ''
|
|
|
]
|
|
|
],
|
|
|
- '_Token' => compact('fields', 'unlocked')
|
|
|
+ '_Token' => compact('fields', 'unlocked', 'debug')
|
|
|
];
|
|
|
- $result = $this->Controller->Security->validatePost($this->Controller);
|
|
|
+ $result = $this->validatePost();
|
|
|
$this->assertTrue($result);
|
|
|
}
|
|
|
|
|
|
@@ -647,35 +725,36 @@ class SecurityComponentTest extends TestCase
|
|
|
|
|
|
$fields = '8d8da68ba03b3d6e7e145b948abfe26741422169%3A';
|
|
|
$unlocked = '';
|
|
|
+ $debug = 'not used';
|
|
|
|
|
|
$this->Controller->request->data = [
|
|
|
'Tag' => ['Tag' => [1, 2]],
|
|
|
- '_Token' => compact('fields', 'unlocked'),
|
|
|
+ '_Token' => compact('fields', 'unlocked', 'debug'),
|
|
|
];
|
|
|
- $result = $this->Controller->Security->validatePost($this->Controller);
|
|
|
+ $result = $this->validatePost();
|
|
|
$this->assertTrue($result);
|
|
|
|
|
|
$this->Controller->request->data = [
|
|
|
'Tag' => ['Tag' => [1, 2, 3]],
|
|
|
- '_Token' => compact('fields', 'unlocked'),
|
|
|
+ '_Token' => compact('fields', 'unlocked', 'debug'),
|
|
|
];
|
|
|
- $result = $this->Controller->Security->validatePost($this->Controller);
|
|
|
+ $result = $this->validatePost();
|
|
|
$this->assertTrue($result);
|
|
|
|
|
|
$this->Controller->request->data = [
|
|
|
'Tag' => ['Tag' => [1, 2, 3, 4]],
|
|
|
- '_Token' => compact('fields', 'unlocked'),
|
|
|
+ '_Token' => compact('fields', 'unlocked', 'debug'),
|
|
|
];
|
|
|
- $result = $this->Controller->Security->validatePost($this->Controller);
|
|
|
+ $result = $this->validatePost();
|
|
|
$this->assertTrue($result);
|
|
|
|
|
|
$fields = 'eae2adda1628b771a30cc133342d16220c6520fe%3A';
|
|
|
$this->Controller->request->data = [
|
|
|
'User.password' => 'bar', 'User.name' => 'foo', 'User.is_valid' => '1',
|
|
|
'Tag' => ['Tag' => [1]],
|
|
|
- '_Token' => compact('fields', 'unlocked'),
|
|
|
+ '_Token' => compact('fields', 'unlocked', 'debug'),
|
|
|
];
|
|
|
- $result = $this->Controller->Security->validatePost($this->Controller);
|
|
|
+ $result = $this->validatePost();
|
|
|
$this->assertTrue($result);
|
|
|
}
|
|
|
|
|
|
@@ -694,23 +773,24 @@ class SecurityComponentTest extends TestCase
|
|
|
$this->Controller->Security->startup($event);
|
|
|
$fields = '68730b0747d4889ec2766f9117405f9635f5fd5e%3AModel.valid';
|
|
|
$unlocked = '';
|
|
|
+ $debug = 'not used';
|
|
|
|
|
|
$this->Controller->request->data = [
|
|
|
'Model' => ['username' => '', 'password' => '', 'valid' => '0'],
|
|
|
- '_Token' => compact('fields', 'unlocked')
|
|
|
+ '_Token' => compact('fields', 'unlocked', 'debug'),
|
|
|
];
|
|
|
|
|
|
- $result = $this->Controller->Security->validatePost($this->Controller);
|
|
|
+ $result = $this->validatePost();
|
|
|
$this->assertTrue($result);
|
|
|
|
|
|
$fields = 'f63e4a69b2edd31f064e8e602a04dd59307cfe9c%3A';
|
|
|
|
|
|
$this->Controller->request->data = [
|
|
|
'Model' => ['username' => '', 'password' => '', 'valid' => '0'],
|
|
|
- '_Token' => compact('fields', 'unlocked')
|
|
|
+ '_Token' => compact('fields', 'unlocked', 'debug'),
|
|
|
];
|
|
|
|
|
|
- $result = $this->Controller->Security->validatePost($this->Controller);
|
|
|
+ $result = $this->validatePost();
|
|
|
$this->assertTrue($result);
|
|
|
|
|
|
$this->Controller->request->data = [];
|
|
|
@@ -718,10 +798,10 @@ class SecurityComponentTest extends TestCase
|
|
|
|
|
|
$this->Controller->request->data = [
|
|
|
'Model' => ['username' => '', 'password' => '', 'valid' => '0'],
|
|
|
- '_Token' => compact('fields', 'unlocked')
|
|
|
+ '_Token' => compact('fields', 'unlocked', 'debug'),
|
|
|
];
|
|
|
|
|
|
- $result = $this->Controller->Security->validatePost($this->Controller);
|
|
|
+ $result = $this->validatePost();
|
|
|
$this->assertTrue($result);
|
|
|
}
|
|
|
|
|
|
@@ -737,15 +817,16 @@ class SecurityComponentTest extends TestCase
|
|
|
$this->Controller->Security->startup($event);
|
|
|
$fields = '973a8939a68ac014cc6f7666cec9aa6268507350%3AModel.hidden%7CModel.other_hidden';
|
|
|
$unlocked = '';
|
|
|
+ $debug = 'not used';
|
|
|
|
|
|
$this->Controller->request->data = [
|
|
|
'Model' => [
|
|
|
'username' => '', 'password' => '', 'hidden' => '0',
|
|
|
'other_hidden' => 'some hidden value'
|
|
|
],
|
|
|
- '_Token' => compact('fields', 'unlocked')
|
|
|
+ '_Token' => compact('fields', 'unlocked', 'debug'),
|
|
|
];
|
|
|
- $result = $this->Controller->Security->validatePost($this->Controller);
|
|
|
+ $result = $this->validatePost();
|
|
|
$this->assertTrue($result);
|
|
|
}
|
|
|
|
|
|
@@ -762,15 +843,16 @@ class SecurityComponentTest extends TestCase
|
|
|
$this->Controller->Security->startup($event);
|
|
|
$fields = '1c59acfbca98bd870c11fb544d545cbf23215880%3AModel.hidden';
|
|
|
$unlocked = '';
|
|
|
+ $debug = 'not used';
|
|
|
|
|
|
$this->Controller->request->data = [
|
|
|
'Model' => [
|
|
|
'username' => '', 'password' => '', 'hidden' => '0'
|
|
|
],
|
|
|
- '_Token' => compact('fields', 'unlocked')
|
|
|
+ '_Token' => compact('fields', 'unlocked', 'debug'),
|
|
|
];
|
|
|
|
|
|
- $result = $this->Controller->Security->validatePost($this->Controller);
|
|
|
+ $result = $this->validatePost();
|
|
|
$this->assertTrue($result);
|
|
|
}
|
|
|
|
|
|
@@ -787,6 +869,7 @@ class SecurityComponentTest extends TestCase
|
|
|
$unlocked = 'Model.username';
|
|
|
$fields = ['Model.hidden', 'Model.password'];
|
|
|
$fields = urlencode(Security::hash('/articles/index' . serialize($fields) . $unlocked . Security::salt()));
|
|
|
+ $debug = 'not used';
|
|
|
|
|
|
$this->Controller->request->data = [
|
|
|
'Model' => [
|
|
|
@@ -794,10 +877,10 @@ class SecurityComponentTest extends TestCase
|
|
|
'password' => 'sekret',
|
|
|
'hidden' => '0'
|
|
|
],
|
|
|
- '_Token' => compact('fields', 'unlocked')
|
|
|
+ '_Token' => compact('fields', 'unlocked', 'debug'),
|
|
|
];
|
|
|
|
|
|
- $result = $this->Controller->Security->validatePost($this->Controller);
|
|
|
+ $result = $this->validatePost();
|
|
|
$this->assertTrue($result);
|
|
|
}
|
|
|
|
|
|
@@ -823,8 +906,64 @@ class SecurityComponentTest extends TestCase
|
|
|
'_Token' => compact('fields')
|
|
|
];
|
|
|
|
|
|
- $result = $this->Controller->Security->validatePost($this->Controller);
|
|
|
+ $result = $this->validatePost('SecurityException', '\'_Token.unlocked\' was not found in request data.');
|
|
|
+ $this->assertFalse($result);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * test that missing 'debug' input causes failure
|
|
|
+ *
|
|
|
+ * @return void
|
|
|
+ * @triggers Controller.startup $this->Controller
|
|
|
+ */
|
|
|
+ public function testValidatePostFailNoDebug()
|
|
|
+ {
|
|
|
+ $event = new Event('Controller.startup', $this->Controller);
|
|
|
+ $this->Controller->Security->startup($event);
|
|
|
+ $fields = ['Model.hidden', 'Model.password', 'Model.username'];
|
|
|
+ $fields = urlencode(Security::hash(serialize($fields) . Security::salt()));
|
|
|
+ $unlocked = '';
|
|
|
+
|
|
|
+ $this->Controller->request->data = [
|
|
|
+ 'Model' => [
|
|
|
+ 'username' => 'mark',
|
|
|
+ 'password' => 'sekret',
|
|
|
+ 'hidden' => '0'
|
|
|
+ ],
|
|
|
+ '_Token' => compact('fields', 'unlocked')
|
|
|
+ ];
|
|
|
+
|
|
|
+ $result = $this->validatePost('SecurityException', '\'_Token.debug\' was not found in request data.');
|
|
|
+ $this->assertFalse($result);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * test that missing 'debug' input is not the problem when debug mode disabled
|
|
|
+ *
|
|
|
+ * @return void
|
|
|
+ * @triggers Controller.startup $this->Controller
|
|
|
+ */
|
|
|
+ public function testValidatePostFailNoDebugMode()
|
|
|
+ {
|
|
|
+ $event = new Event('Controller.startup', $this->Controller);
|
|
|
+ $this->Controller->Security->startup($event);
|
|
|
+ $fields = ['Model.hidden', 'Model.password', 'Model.username'];
|
|
|
+ $fields = urlencode(Security::hash(serialize($fields) . Security::salt()));
|
|
|
+ $unlocked = '';
|
|
|
+
|
|
|
+ $this->Controller->request->data = [
|
|
|
+ 'Model' => [
|
|
|
+ 'username' => 'mark',
|
|
|
+ 'password' => 'sekret',
|
|
|
+ 'hidden' => '0'
|
|
|
+ ],
|
|
|
+ '_Token' => compact('fields', 'unlocked')
|
|
|
+ ];
|
|
|
+ $debug = Configure::read('debug');
|
|
|
+ Configure::write('debug', false);
|
|
|
+ $result = $this->validatePost();
|
|
|
$this->assertFalse($result);
|
|
|
+ Configure::write('debug', $debug);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -840,6 +979,11 @@ class SecurityComponentTest extends TestCase
|
|
|
$unlocked = 'Model.username';
|
|
|
$fields = ['Model.hidden', 'Model.password'];
|
|
|
$fields = urlencode(Security::hash(serialize($fields) . $unlocked . Security::salt()));
|
|
|
+ $debug = urlencode(json_encode([
|
|
|
+ '/articles/index',
|
|
|
+ ['Model.hidden', 'Model.password'],
|
|
|
+ ['Model.username']
|
|
|
+ ]));
|
|
|
|
|
|
// Tamper the values.
|
|
|
$unlocked = 'Model.username|Model.password';
|
|
|
@@ -850,10 +994,10 @@ class SecurityComponentTest extends TestCase
|
|
|
'password' => 'sekret',
|
|
|
'hidden' => '0'
|
|
|
],
|
|
|
- '_Token' => compact('fields', 'unlocked')
|
|
|
+ '_Token' => compact('fields', 'unlocked', 'debug')
|
|
|
];
|
|
|
|
|
|
- $result = $this->Controller->Security->validatePost($this->Controller);
|
|
|
+ $result = $this->validatePost('SecurityException', 'Missing field \'Model.password\' in POST data, Unexpected unlocked field \'Model.password\' in POST data');
|
|
|
$this->assertFalse($result);
|
|
|
}
|
|
|
|
|
|
@@ -869,14 +1013,15 @@ class SecurityComponentTest extends TestCase
|
|
|
$this->Controller->Security->startup($event);
|
|
|
$fields = '075ca6c26c38a09a78d871201df89faf52cbbeb8%3AModel.valid%7CModel2.valid%7CModel3.valid';
|
|
|
$unlocked = '';
|
|
|
+ $debug = 'not used';
|
|
|
|
|
|
$this->Controller->request->data = [
|
|
|
'Model' => ['username' => '', 'password' => '', 'valid' => '0'],
|
|
|
'Model2' => ['valid' => '0'],
|
|
|
'Model3' => ['valid' => '0'],
|
|
|
- '_Token' => compact('fields', 'unlocked')
|
|
|
+ '_Token' => compact('fields', 'unlocked', 'debug'),
|
|
|
];
|
|
|
- $result = $this->Controller->Security->validatePost($this->Controller);
|
|
|
+ $result = $this->validatePost();
|
|
|
$this->assertTrue($result);
|
|
|
}
|
|
|
|
|
|
@@ -893,6 +1038,7 @@ class SecurityComponentTest extends TestCase
|
|
|
$fields = '24a753fb62ef7839389987b58e3f7108f564e529%3AModel.0.hidden%7CModel.0.valid';
|
|
|
$fields .= '%7CModel.1.hidden%7CModel.1.valid';
|
|
|
$unlocked = '';
|
|
|
+ $debug = 'not used';
|
|
|
|
|
|
$this->Controller->request->data = [
|
|
|
'Model' => [
|
|
|
@@ -905,10 +1051,10 @@ class SecurityComponentTest extends TestCase
|
|
|
'hidden' => 'value', 'valid' => '0'
|
|
|
]
|
|
|
],
|
|
|
- '_Token' => compact('fields', 'unlocked')
|
|
|
+ '_Token' => compact('fields', 'unlocked', 'debug'),
|
|
|
];
|
|
|
|
|
|
- $result = $this->Controller->Security->validatePost($this->Controller);
|
|
|
+ $result = $this->validatePost();
|
|
|
$this->assertTrue($result);
|
|
|
}
|
|
|
|
|
|
@@ -925,6 +1071,7 @@ class SecurityComponentTest extends TestCase
|
|
|
$fields = '8f7d82bf7656cf068822d9bdab109ebed1be1825%3AAddress.0.id%7CAddress.0.primary%7C';
|
|
|
$fields .= 'Address.1.id%7CAddress.1.primary';
|
|
|
$unlocked = '';
|
|
|
+ $debug = 'not used';
|
|
|
|
|
|
$this->Controller->request->data = [
|
|
|
'Address' => [
|
|
|
@@ -949,10 +1096,10 @@ class SecurityComponentTest extends TestCase
|
|
|
'primary' => '1'
|
|
|
]
|
|
|
],
|
|
|
- '_Token' => compact('fields', 'unlocked')
|
|
|
+ '_Token' => compact('fields', 'unlocked', 'debug'),
|
|
|
];
|
|
|
|
|
|
- $result = $this->Controller->Security->validatePost($this->Controller);
|
|
|
+ $result = $this->validatePost();
|
|
|
$this->assertTrue($result);
|
|
|
}
|
|
|
|
|
|
@@ -969,15 +1116,16 @@ class SecurityComponentTest extends TestCase
|
|
|
$unlocked = '';
|
|
|
$hashFields = ['TaxonomyData'];
|
|
|
$fields = urlencode(Security::hash('/articles/index' . serialize($hashFields) . $unlocked . Security::salt()));
|
|
|
+ $debug = 'not used';
|
|
|
|
|
|
$this->Controller->request->data = [
|
|
|
'TaxonomyData' => [
|
|
|
1 => [[2]],
|
|
|
2 => [[3]]
|
|
|
],
|
|
|
- '_Token' => compact('fields', 'unlocked')
|
|
|
+ '_Token' => compact('fields', 'unlocked', 'debug'),
|
|
|
];
|
|
|
- $result = $this->Controller->Security->validatePost($this->Controller);
|
|
|
+ $result = $this->validatePost();
|
|
|
$this->assertTrue($result);
|
|
|
}
|
|
|
|
|
|
@@ -996,6 +1144,28 @@ class SecurityComponentTest extends TestCase
|
|
|
$fields = '7a203edb3d345bbf38fe0dccae960da8842e11d7%3AAddress.0.id%7CAddress.0.primary%7C';
|
|
|
$fields .= 'Address.1.id%7CAddress.1.primary';
|
|
|
$unlocked = '';
|
|
|
+ $debug = urlencode(json_encode([
|
|
|
+ '/articles/index',
|
|
|
+ [
|
|
|
+ 'Address.0.address',
|
|
|
+ 'Address.0.city',
|
|
|
+ 'Address.0.first_name',
|
|
|
+ 'Address.0.last_name',
|
|
|
+ 'Address.0.phone',
|
|
|
+ 'Address.0.title',
|
|
|
+ 'Address.1.address',
|
|
|
+ 'Address.1.city',
|
|
|
+ 'Address.1.first_name',
|
|
|
+ 'Address.1.last_name',
|
|
|
+ 'Address.1.phone',
|
|
|
+ 'Address.1.title',
|
|
|
+ 'Address.0.id' => '123',
|
|
|
+ 'Address.0.primary' => '5',
|
|
|
+ 'Address.1.id' => '124',
|
|
|
+ 'Address.1.primary' => '1'
|
|
|
+ ],
|
|
|
+ []
|
|
|
+ ]));
|
|
|
|
|
|
$this->Controller->request->data = [
|
|
|
'Address' => [
|
|
|
@@ -1020,10 +1190,9 @@ class SecurityComponentTest extends TestCase
|
|
|
'primary' => '1'
|
|
|
]
|
|
|
],
|
|
|
- '_Token' => compact('fields', 'unlocked')
|
|
|
+ '_Token' => compact('fields', 'unlocked', 'debug'),
|
|
|
];
|
|
|
-
|
|
|
- $result = $this->Controller->Security->validatePost($this->Controller);
|
|
|
+ $result = $this->validatePost('SecurityException', 'Bad Request');
|
|
|
$this->assertFalse($result);
|
|
|
}
|
|
|
|
|
|
@@ -1040,12 +1209,17 @@ class SecurityComponentTest extends TestCase
|
|
|
$this->Controller->Security->startup($event);
|
|
|
$fields = '9da2b3fa2b5b8ac0bfbc1bbce145e58059629125%3An%3A0%3A%7B%7D';
|
|
|
$unlocked = '';
|
|
|
+ $debug = urlencode(json_encode([
|
|
|
+ '/articles/index',
|
|
|
+ [],
|
|
|
+ []
|
|
|
+ ]));
|
|
|
|
|
|
$this->Controller->request->data = [
|
|
|
'MyModel' => ['name' => 'some data'],
|
|
|
- '_Token' => compact('fields', 'unlocked')
|
|
|
+ '_Token' => compact('fields', 'unlocked', 'debug'),
|
|
|
];
|
|
|
- $result = $this->Controller->Security->validatePost($this->Controller);
|
|
|
+ $result = $this->validatePost('SecurityException', 'Unexpected field \'MyModel.name\' in POST data');
|
|
|
$this->assertFalse($result);
|
|
|
|
|
|
$this->Controller->Security->startup($event);
|
|
|
@@ -1053,10 +1227,10 @@ class SecurityComponentTest extends TestCase
|
|
|
|
|
|
$this->Controller->request->data = [
|
|
|
'MyModel' => ['name' => 'some data'],
|
|
|
- '_Token' => compact('fields', 'unlocked')
|
|
|
+ '_Token' => compact('fields', 'unlocked', 'debug'),
|
|
|
];
|
|
|
|
|
|
- $result = $this->Controller->Security->validatePost($this->Controller);
|
|
|
+ $result = $this->validatePost();
|
|
|
$this->assertTrue($result);
|
|
|
}
|
|
|
|
|
|
@@ -1072,32 +1246,37 @@ class SecurityComponentTest extends TestCase
|
|
|
$this->Controller->Security->startup($event);
|
|
|
$fields = 'c2226a8879c3f4b513691295fc2519a29c44c8bb%3An%3A0%3A%7B%7D';
|
|
|
$unlocked = '';
|
|
|
+ $debug = urlencode(json_encode([
|
|
|
+ '/articles/index',
|
|
|
+ [],
|
|
|
+ []
|
|
|
+ ]));
|
|
|
|
|
|
$this->Controller->request->data = [
|
|
|
- '_Token' => compact('fields', 'unlocked')
|
|
|
+ '_Token' => compact('fields', 'unlocked', 'debug'),
|
|
|
];
|
|
|
- $result = $this->Controller->Security->validatePost($this->Controller);
|
|
|
+ $result = $this->validatePost('SecurityException', 'Bad Request');
|
|
|
$this->assertFalse($result);
|
|
|
|
|
|
$this->Controller->request->data = [
|
|
|
- '_Token' => compact('fields', 'unlocked'),
|
|
|
+ '_Token' => compact('fields', 'unlocked', 'debug'),
|
|
|
'Test' => ['test' => '']
|
|
|
];
|
|
|
- $result = $this->Controller->Security->validatePost($this->Controller);
|
|
|
+ $result = $this->validatePost();
|
|
|
$this->assertTrue($result);
|
|
|
|
|
|
$this->Controller->request->data = [
|
|
|
- '_Token' => compact('fields', 'unlocked'),
|
|
|
+ '_Token' => compact('fields', 'unlocked', 'debug'),
|
|
|
'Test' => ['test' => '1']
|
|
|
];
|
|
|
- $result = $this->Controller->Security->validatePost($this->Controller);
|
|
|
+ $result = $this->validatePost();
|
|
|
$this->assertTrue($result);
|
|
|
|
|
|
$this->Controller->request->data = [
|
|
|
- '_Token' => compact('fields', 'unlocked'),
|
|
|
+ '_Token' => compact('fields', 'unlocked', 'debug'),
|
|
|
'Test' => ['test' => '2']
|
|
|
];
|
|
|
- $result = $this->Controller->Security->validatePost($this->Controller);
|
|
|
+ $result = $this->validatePost();
|
|
|
$this->assertTrue($result);
|
|
|
}
|
|
|
|
|
|
@@ -1114,12 +1293,18 @@ class SecurityComponentTest extends TestCase
|
|
|
|
|
|
$fields = 'b0914d06dfb04abf1fada53e16810e87d157950b%3A';
|
|
|
$unlocked = '';
|
|
|
+ $debug = urlencode(json_encode([
|
|
|
+ 'another-url',
|
|
|
+ ['Model.username', 'Model.password'],
|
|
|
+ []
|
|
|
+ ]));
|
|
|
+
|
|
|
|
|
|
$this->Controller->request->data = [
|
|
|
'Model' => ['username' => '', 'password' => ''],
|
|
|
- '_Token' => compact('fields', 'unlocked')
|
|
|
+ '_Token' => compact('fields', 'unlocked', 'debug')
|
|
|
];
|
|
|
- $this->assertTrue($this->Security->validatePost($this->Controller));
|
|
|
+ $this->assertTrue($this->validatePost());
|
|
|
|
|
|
$request = $this->getMock('Cake\Network\Request', ['here']);
|
|
|
$request->expects($this->at(0))
|
|
|
@@ -1131,8 +1316,8 @@ class SecurityComponentTest extends TestCase
|
|
|
$request->data = $this->Controller->request->data;
|
|
|
$this->Controller->request = $request;
|
|
|
|
|
|
- $this->assertFalse($this->Security->validatePost($this->Controller));
|
|
|
- $this->assertFalse($this->Security->validatePost($this->Controller));
|
|
|
+ $this->assertFalse($this->validatePost('SecurityException', 'URL mismatch in POST data (expected \'another-url\' but found \'/posts/index?page=1\')'));
|
|
|
+ $this->assertFalse($this->validatePost('SecurityException', 'URL mismatch in POST data (expected \'another-url\' but found \'/posts/edit/1\')'));
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -1181,4 +1366,207 @@ class SecurityComponentTest extends TestCase
|
|
|
$result = $this->Controller->Security->startup($event);
|
|
|
$this->assertNull($result);
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Test that debug token format is right
|
|
|
+ *
|
|
|
+ * @return void
|
|
|
+ * @triggers Controller.startup $this->Controller
|
|
|
+ */
|
|
|
+ public function testValidatePostDebugFormat()
|
|
|
+ {
|
|
|
+ $event = new Event('Controller.startup', $this->Controller);
|
|
|
+ $this->Controller->Security->startup($event);
|
|
|
+ $unlocked = 'Model.username';
|
|
|
+ $fields = ['Model.hidden', 'Model.password'];
|
|
|
+ $fields = urlencode(Security::hash(serialize($fields) . $unlocked . Security::salt()));
|
|
|
+ $debug = urlencode(json_encode([
|
|
|
+ '/articles/index',
|
|
|
+ ['Model.hidden', 'Model.password'],
|
|
|
+ ['Model.username'],
|
|
|
+ ['not expected']
|
|
|
+ ]));
|
|
|
+
|
|
|
+ $this->Controller->request->data = [
|
|
|
+ 'Model' => [
|
|
|
+ 'username' => 'mark',
|
|
|
+ 'password' => 'sekret',
|
|
|
+ 'hidden' => '0'
|
|
|
+ ],
|
|
|
+ '_Token' => compact('fields', 'unlocked', 'debug')
|
|
|
+ ];
|
|
|
+
|
|
|
+ $result = $this->validatePost('SecurityException', 'Invalid security debug token.');
|
|
|
+ $this->assertFalse($result);
|
|
|
+
|
|
|
+ $debug = urlencode(json_encode('not an array'));
|
|
|
+ $result = $this->validatePost('SecurityException', 'Invalid security debug token.');
|
|
|
+ $this->assertFalse($result);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * test blackhole will now throw passed exception if debug enabled
|
|
|
+ *
|
|
|
+ * @expectedException Cake\Controller\Exception\SecurityException
|
|
|
+ * @expectedExceptionMessage error description
|
|
|
+ * @return void
|
|
|
+ */
|
|
|
+ public function testBlackholeThrowsException()
|
|
|
+ {
|
|
|
+ $this->Security->config('blackHoleCallback', '');
|
|
|
+ $this->Security->blackHole($this->Controller, 'auth', new SecurityException('error description'));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * test blackhole will throw BadRequest if debug disabled
|
|
|
+ *
|
|
|
+ * @return void
|
|
|
+ */
|
|
|
+ public function testBlackholeThrowsBadRequest()
|
|
|
+ {
|
|
|
+ $this->Security->config('blackHoleCallback', '');
|
|
|
+ $debug = Configure::read('debug');
|
|
|
+ $message = '';
|
|
|
+
|
|
|
+ Configure::write('debug', false);
|
|
|
+ try {
|
|
|
+ $this->Security->blackHole($this->Controller, 'auth', new SecurityException('error description'));
|
|
|
+ } catch (BadRequestException $ex) {
|
|
|
+ $message = $ex->getMessage();
|
|
|
+ }
|
|
|
+ Configure::write('debug', $debug);
|
|
|
+ $this->assertEquals('The request has been black-holed', $message);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Test that validatePost fails with tampered fields and explanation
|
|
|
+ *
|
|
|
+ * @return void
|
|
|
+ * @triggers Controller.startup $this->Controller
|
|
|
+ */
|
|
|
+ public function testValidatePostFailTampering()
|
|
|
+ {
|
|
|
+ $event = new Event('Controller.startup', $this->Controller);
|
|
|
+ $this->Controller->Security->startup($event);
|
|
|
+ $unlocked = '';
|
|
|
+ $fields = ['Model.hidden' => 'value', 'Model.id' => '1'];
|
|
|
+ $debug = urlencode(json_encode([
|
|
|
+ '/articles/index',
|
|
|
+ $fields,
|
|
|
+ []
|
|
|
+ ]));
|
|
|
+ $fields = urlencode(Security::hash(serialize($fields) . $unlocked . Security::salt()));
|
|
|
+ $fields .= urlencode(':Model.hidden|Model.id');
|
|
|
+ $this->Controller->request->data = [
|
|
|
+ 'Model' => [
|
|
|
+ 'hidden' => 'tampered',
|
|
|
+ 'id' => '1',
|
|
|
+ ],
|
|
|
+ '_Token' => compact('fields', 'unlocked', 'debug')
|
|
|
+ ];
|
|
|
+
|
|
|
+ $result = $this->validatePost('SecurityException', 'Tampered field \'Model.hidden\' in POST data (expected value \'value\' but found \'tampered\')');
|
|
|
+ $this->assertFalse($result);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Auth required throws exception token not found
|
|
|
+ *
|
|
|
+ * @return void
|
|
|
+ * @expectedException Cake\Controller\Exception\AuthSecurityException
|
|
|
+ * @expectedExceptionMessage '_Token' was not found in request data.
|
|
|
+ * @triggers Controller.startup $this->Controller
|
|
|
+ */
|
|
|
+ public function testAuthRequiredThrowsExceptionTokenNotFoundPost()
|
|
|
+ {
|
|
|
+ $this->Controller->Security->config('requireAuth', ['protected']);
|
|
|
+ $this->Controller->request->params['action'] = 'protected';
|
|
|
+ $this->Controller->request->data = 'notEmpty';
|
|
|
+ $event = new Event('Controller.startup', $this->Controller);
|
|
|
+ $this->Controller->Security->startup($event);
|
|
|
+ $this->Controller->Security->authRequired($this->Controller);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Auth required throws exception token not found in Session
|
|
|
+ *
|
|
|
+ * @return void
|
|
|
+ * @expectedException Cake\Controller\Exception\AuthSecurityException
|
|
|
+ * @expectedExceptionMessage '_Token' was not found in session.
|
|
|
+ * @triggers Controller.startup $this->Controller
|
|
|
+ */
|
|
|
+ public function testAuthRequiredThrowsExceptionTokenNotFoundSession()
|
|
|
+ {
|
|
|
+ $this->Controller->Security->config('requireAuth', ['protected']);
|
|
|
+ $this->Controller->request->params['action'] = 'protected';
|
|
|
+ $this->Controller->request->data = ['_Token' => 'not empty'];
|
|
|
+ $event = new Event('Controller.startup', $this->Controller);
|
|
|
+ $this->Controller->Security->startup($event);
|
|
|
+ $this->Controller->Security->authRequired($this->Controller);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Auth required throws exception controller not allowed
|
|
|
+ *
|
|
|
+ * @return void
|
|
|
+ * @expectedException Cake\Controller\Exception\AuthSecurityException
|
|
|
+ * @expectedExceptionMessage Controller 'NotAllowed' was not found in allowed controllers: 'Allowed, AnotherAllowed'.
|
|
|
+ * @triggers Controller.startup $this->Controller
|
|
|
+ */
|
|
|
+ public function testAuthRequiredThrowsExceptionControllerNotAllowed()
|
|
|
+ {
|
|
|
+ $this->Controller->Security->config('requireAuth', ['protected']);
|
|
|
+ $this->Controller->request->params['controller'] = 'NotAllowed';
|
|
|
+ $this->Controller->request->params['action'] = 'protected';
|
|
|
+ $this->Controller->request->data = ['_Token' => 'not empty'];
|
|
|
+ $this->Controller->request->session()->write('_Token', [
|
|
|
+ 'allowedControllers' => ['Allowed', 'AnotherAllowed']
|
|
|
+ ]);
|
|
|
+ $event = new Event('Controller.startup', $this->Controller);
|
|
|
+ $this->Controller->Security->startup($event);
|
|
|
+ $this->Controller->Security->authRequired($this->Controller);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Auth required throws exception controller not allowed
|
|
|
+ *
|
|
|
+ * @return void
|
|
|
+ * @expectedException Cake\Controller\Exception\AuthSecurityException
|
|
|
+ * @expectedExceptionMessage Action 'NotAllowed::protected' was not found in allowed actions: 'index, view'.
|
|
|
+ * @triggers Controller.startup $this->Controller
|
|
|
+ */
|
|
|
+ public function testAuthRequiredThrowsExceptionActionNotAllowed()
|
|
|
+ {
|
|
|
+ $this->Controller->Security->config('requireAuth', ['protected']);
|
|
|
+ $this->Controller->request->params['controller'] = 'NotAllowed';
|
|
|
+ $this->Controller->request->params['action'] = 'protected';
|
|
|
+ $this->Controller->request->data = ['_Token' => 'not empty'];
|
|
|
+ $this->Controller->request->session()->write('_Token', [
|
|
|
+ 'allowedActions' => ['index', 'view']
|
|
|
+ ]);
|
|
|
+ $event = new Event('Controller.startup', $this->Controller);
|
|
|
+ $this->Controller->Security->startup($event);
|
|
|
+ $this->Controller->Security->authRequired($this->Controller);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Auth required throws exception controller not allowed
|
|
|
+ *
|
|
|
+ * @return void
|
|
|
+ * @triggers Controller.startup $this->Controller
|
|
|
+ */
|
|
|
+ public function testAuthRequired()
|
|
|
+ {
|
|
|
+ $this->Controller->Security->config('requireAuth', ['protected']);
|
|
|
+ $this->Controller->request->params['controller'] = 'Allowed';
|
|
|
+ $this->Controller->request->params['action'] = 'protected';
|
|
|
+ $this->Controller->request->data = ['_Token' => 'not empty'];
|
|
|
+ $this->Controller->request->session()->write('_Token', [
|
|
|
+ 'allowedActions' => ['protected'],
|
|
|
+ 'allowedControllers' => ['Allowed'],
|
|
|
+ ]);
|
|
|
+ $event = new Event('Controller.startup', $this->Controller);
|
|
|
+ $this->Controller->Security->startup($event);
|
|
|
+ $this->assertTrue($this->Controller->Security->authRequired($this->Controller));
|
|
|
+ }
|
|
|
}
|