Subversion Repositories SmartDukaan

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
13532 anikendra 1
<?php
2
/**
3
 * SecurityComponentTest file
4
 *
5
 * CakePHP(tm) Tests <http://book.cakephp.org/2.0/en/development/testing.html>
6
 * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
7
 *
8
 * Licensed under The MIT License
9
 * For full copyright and license information, please see the LICENSE.txt
10
 * Redistributions of files must retain the above copyright notice
11
 *
12
 * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
13
 * @link          http://book.cakephp.org/2.0/en/development/testing.html CakePHP(tm) Tests
14
 * @package       Cake.Test.Case.Controller.Component
15
 * @since         CakePHP(tm) v 1.2.0.5435
16
 * @license       http://www.opensource.org/licenses/mit-license.php MIT License
17
 */
18
 
19
App::uses('SecurityComponent', 'Controller/Component');
20
App::uses('Controller', 'Controller');
21
 
22
/**
23
 * TestSecurityComponent
24
 *
25
 * @package       Cake.Test.Case.Controller.Component
26
 */
27
class TestSecurityComponent extends SecurityComponent {
28
 
29
/**
30
 * validatePost method
31
 *
32
 * @param Controller $controller
33
 * @return boolean
34
 */
35
	public function validatePost(Controller $controller) {
36
		return $this->_validatePost($controller);
37
	}
38
 
39
}
40
 
41
/**
42
 * SecurityTestController
43
 *
44
 * @package       Cake.Test.Case.Controller.Component
45
 */
46
class SecurityTestController extends Controller {
47
 
48
/**
49
 * components property
50
 *
51
 * @var array
52
 */
53
	public $components = array('Session', 'TestSecurity');
54
 
55
/**
56
 * failed property
57
 *
58
 * @var boolean false
59
 */
60
	public $failed = false;
61
 
62
/**
63
 * Used for keeping track of headers in test
64
 *
65
 * @var array
66
 */
67
	public $testHeaders = array();
68
 
69
/**
70
 * fail method
71
 *
72
 * @return void
73
 */
74
	public function fail() {
75
		$this->failed = true;
76
	}
77
 
78
/**
79
 * redirect method
80
 *
81
 * @param string|array $url
82
 * @param mixed $code
83
 * @param mixed $exit
84
 * @return void
85
 */
86
	public function redirect($url, $status = null, $exit = true) {
87
		return $status;
88
	}
89
 
90
/**
91
 * Convenience method for header()
92
 *
93
 * @param string $status
94
 * @return void
95
 */
96
	public function header($status) {
97
		$this->testHeaders[] = $status;
98
	}
99
 
100
}
101
 
102
class BrokenCallbackController extends Controller {
103
 
104
	public $name = 'UncallableCallback';
105
 
106
	public $components = array('Session', 'TestSecurity');
107
 
108
	public function index() {
109
	}
110
 
111
	protected function _fail() {
112
	}
113
 
114
}
115
 
116
/**
117
 * SecurityComponentTest class
118
 *
119
 * @package       Cake.Test.Case.Controller.Component
120
 */
121
class SecurityComponentTest extends CakeTestCase {
122
 
123
/**
124
 * Controller property
125
 *
126
 * @var SecurityTestController
127
 */
128
	public $Controller;
129
 
130
/**
131
 * oldSalt property
132
 *
133
 * @var string
134
 */
135
	public $oldSalt;
136
 
137
/**
138
 * setUp method
139
 *
140
 * @return void
141
 */
142
	public function setUp() {
143
		parent::setUp();
144
 
145
		$request = new CakeRequest('posts/index', false);
146
		$request->addParams(array('controller' => 'posts', 'action' => 'index'));
147
		$this->Controller = new SecurityTestController($request);
148
		$this->Controller->Components->init($this->Controller);
149
		$this->Controller->Security = $this->Controller->TestSecurity;
150
		$this->Controller->Security->blackHoleCallback = 'fail';
151
		$this->Security = $this->Controller->Security;
152
		$this->Security->csrfCheck = false;
153
 
154
		Configure::write('Security.salt', 'foo!');
155
	}
156
 
157
/**
158
 * Tear-down method. Resets environment state.
159
 *
160
 * @return void
161
 */
162
	public function tearDown() {
163
		parent::tearDown();
164
		$this->Controller->Session->delete('_Token');
165
		unset($this->Controller->Security);
166
		unset($this->Controller->Component);
167
		unset($this->Controller);
168
	}
169
 
170
/**
171
 * Test that requests are still blackholed when controller has incorrect
172
 * visibility keyword in the blackhole callback
173
 *
174
 * @expectedException BadRequestException
175
 */
176
	public function testBlackholeWithBrokenCallback() {
177
		$request = new CakeRequest('posts/index', false);
178
		$request->addParams(array(
179
			'controller' => 'posts', 'action' => 'index')
180
		);
181
		$this->Controller = new BrokenCallbackController($request);
182
		$this->Controller->Components->init($this->Controller);
183
		$this->Controller->Security = $this->Controller->TestSecurity;
184
		$this->Controller->Security->blackHoleCallback = '_fail';
185
		$this->Controller->Security->startup($this->Controller);
186
		$this->Controller->Security->blackHole($this->Controller, 'csrf');
187
	}
188
 
189
/**
190
 * Ensure that directly requesting the blackholeCallback as the controller
191
 * action results in an exception.
192
 *
193
 * @return void
194
 */
195
	public function testExceptionWhenActionIsBlackholeCallback() {
196
		$this->Controller->request->addParams(array(
197
			'controller' => 'posts',
198
			'action' => 'fail'
199
		));
200
		$this->assertFalse($this->Controller->failed);
201
		$this->Controller->Security->startup($this->Controller);
202
		$this->assertTrue($this->Controller->failed, 'Request was blackholed.');
203
	}
204
 
205
/**
206
 * test that initialize can set properties.
207
 *
208
 * @return void
209
 */
210
	public function testConstructorSettingProperties() {
211
		$settings = array(
212
			'requirePost' => array('edit', 'update'),
213
			'requireSecure' => array('update_account'),
214
			'requireGet' => array('index'),
215
			'validatePost' => false,
216
		);
217
		$Security = new SecurityComponent($this->Controller->Components, $settings);
218
		$this->Controller->Security->initialize($this->Controller, $settings);
219
		$this->assertEquals($Security->requirePost, $settings['requirePost']);
220
		$this->assertEquals($Security->requireSecure, $settings['requireSecure']);
221
		$this->assertEquals($Security->requireGet, $settings['requireGet']);
222
		$this->assertEquals($Security->validatePost, $settings['validatePost']);
223
	}
224
 
225
/**
226
 * testStartup method
227
 *
228
 * @return void
229
 */
230
	public function testStartup() {
231
		$this->Controller->Security->startup($this->Controller);
232
		$result = $this->Controller->params['_Token']['key'];
233
		$this->assertNotNull($result);
234
		$this->assertTrue($this->Controller->Session->check('_Token'));
235
	}
236
 
237
/**
238
 * testRequirePostFail method
239
 *
240
 * @return void
241
 */
242
	public function testRequirePostFail() {
243
		$_SERVER['REQUEST_METHOD'] = 'GET';
244
		$this->Controller->request['action'] = 'posted';
245
		$this->Controller->Security->requirePost(array('posted'));
246
		$this->Controller->Security->startup($this->Controller);
247
		$this->assertTrue($this->Controller->failed);
248
	}
249
 
250
/**
251
 * testRequirePostSucceed method
252
 *
253
 * @return void
254
 */
255
	public function testRequirePostSucceed() {
256
		$_SERVER['REQUEST_METHOD'] = 'POST';
257
		$this->Controller->request['action'] = 'posted';
258
		$this->Controller->Security->requirePost('posted');
259
		$this->Security->startup($this->Controller);
260
		$this->assertFalse($this->Controller->failed);
261
	}
262
 
263
/**
264
 * testRequireSecureFail method
265
 *
266
 * @return void
267
 */
268
	public function testRequireSecureFail() {
269
		$_SERVER['HTTPS'] = 'off';
270
		$_SERVER['REQUEST_METHOD'] = 'POST';
271
		$this->Controller->request['action'] = 'posted';
272
		$this->Controller->Security->requireSecure(array('posted'));
273
		$this->Controller->Security->startup($this->Controller);
274
		$this->assertTrue($this->Controller->failed);
275
	}
276
 
277
/**
278
 * testRequireSecureSucceed method
279
 *
280
 * @return void
281
 */
282
	public function testRequireSecureSucceed() {
283
		$_SERVER['REQUEST_METHOD'] = 'Secure';
284
		$this->Controller->request['action'] = 'posted';
285
		$_SERVER['HTTPS'] = 'on';
286
		$this->Controller->Security->requireSecure('posted');
287
		$this->Controller->Security->startup($this->Controller);
288
		$this->assertFalse($this->Controller->failed);
289
	}
290
 
291
/**
292
 * testRequireAuthFail method
293
 *
294
 * @return void
295
 */
296
	public function testRequireAuthFail() {
297
		$_SERVER['REQUEST_METHOD'] = 'AUTH';
298
		$this->Controller->request['action'] = 'posted';
299
		$this->Controller->request->data = array('username' => 'willy', 'password' => 'somePass');
300
		$this->Controller->Security->requireAuth(array('posted'));
301
		$this->Controller->Security->startup($this->Controller);
302
		$this->assertTrue($this->Controller->failed);
303
 
304
		$this->Controller->Session->write('_Token', array('allowedControllers' => array()));
305
		$this->Controller->request->data = array('username' => 'willy', 'password' => 'somePass');
306
		$this->Controller->request['action'] = 'posted';
307
		$this->Controller->Security->requireAuth('posted');
308
		$this->Controller->Security->startup($this->Controller);
309
		$this->assertTrue($this->Controller->failed);
310
 
311
		$this->Controller->Session->write('_Token', array(
312
			'allowedControllers' => array('SecurityTest'), 'allowedActions' => array('posted2')
313
		));
314
		$this->Controller->request->data = array('username' => 'willy', 'password' => 'somePass');
315
		$this->Controller->request['action'] = 'posted';
316
		$this->Controller->Security->requireAuth('posted');
317
		$this->Controller->Security->startup($this->Controller);
318
		$this->assertTrue($this->Controller->failed);
319
	}
320
 
321
/**
322
 * testRequireAuthSucceed method
323
 *
324
 * @return void
325
 */
326
	public function testRequireAuthSucceed() {
327
		$_SERVER['REQUEST_METHOD'] = 'AUTH';
328
		$this->Controller->request['action'] = 'posted';
329
		$this->Controller->Security->requireAuth('posted');
330
		$this->Controller->Security->startup($this->Controller);
331
		$this->assertFalse($this->Controller->failed);
332
 
333
		$this->Controller->Security->Session->write('_Token', array(
334
			'allowedControllers' => array('SecurityTest'), 'allowedActions' => array('posted')
335
		));
336
		$this->Controller->request['controller'] = 'SecurityTest';
337
		$this->Controller->request['action'] = 'posted';
338
 
339
		$this->Controller->request->data = array(
340
			'username' => 'willy', 'password' => 'somePass', '_Token' => ''
341
		);
342
		$this->Controller->action = 'posted';
343
		$this->Controller->Security->requireAuth('posted');
344
		$this->Controller->Security->startup($this->Controller);
345
		$this->assertFalse($this->Controller->failed);
346
	}
347
 
348
/**
349
 * testRequirePostSucceedWrongMethod method
350
 *
351
 * @return void
352
 */
353
	public function testRequirePostSucceedWrongMethod() {
354
		$_SERVER['REQUEST_METHOD'] = 'GET';
355
		$this->Controller->request['action'] = 'getted';
356
		$this->Controller->Security->requirePost('posted');
357
		$this->Controller->Security->startup($this->Controller);
358
		$this->assertFalse($this->Controller->failed);
359
	}
360
 
361
/**
362
 * testRequireGetFail method
363
 *
364
 * @return void
365
 */
366
	public function testRequireGetFail() {
367
		$_SERVER['REQUEST_METHOD'] = 'POST';
368
		$this->Controller->request['action'] = 'getted';
369
		$this->Controller->Security->requireGet(array('getted'));
370
		$this->Controller->Security->startup($this->Controller);
371
		$this->assertTrue($this->Controller->failed);
372
	}
373
 
374
/**
375
 * testRequireGetSucceed method
376
 *
377
 * @return void
378
 */
379
	public function testRequireGetSucceed() {
380
		$_SERVER['REQUEST_METHOD'] = 'GET';
381
		$this->Controller->request['action'] = 'getted';
382
		$this->Controller->Security->requireGet('getted');
383
		$this->Controller->Security->startup($this->Controller);
384
		$this->assertFalse($this->Controller->failed);
385
	}
386
 
387
/**
388
 * testRequireGetSucceedWrongMethod method
389
 *
390
 * @return void
391
 */
392
	public function testRequireGetSucceedWrongMethod() {
393
		$_SERVER['REQUEST_METHOD'] = 'POST';
394
		$this->Controller->request['action'] = 'posted';
395
		$this->Security->requireGet('getted');
396
		$this->Security->startup($this->Controller);
397
		$this->assertFalse($this->Controller->failed);
398
	}
399
 
400
/**
401
 * testRequirePutFail method
402
 *
403
 * @return void
404
 */
405
	public function testRequirePutFail() {
406
		$_SERVER['REQUEST_METHOD'] = 'POST';
407
		$this->Controller->request['action'] = 'putted';
408
		$this->Controller->Security->requirePut(array('putted'));
409
		$this->Controller->Security->startup($this->Controller);
410
		$this->assertTrue($this->Controller->failed);
411
	}
412
 
413
/**
414
 * testRequirePutSucceed method
415
 *
416
 * @return void
417
 */
418
	public function testRequirePutSucceed() {
419
		$_SERVER['REQUEST_METHOD'] = 'PUT';
420
		$this->Controller->request['action'] = 'putted';
421
		$this->Controller->Security->requirePut('putted');
422
		$this->Controller->Security->startup($this->Controller);
423
		$this->assertFalse($this->Controller->failed);
424
	}
425
 
426
/**
427
 * testRequirePutSucceedWrongMethod method
428
 *
429
 * @return void
430
 */
431
	public function testRequirePutSucceedWrongMethod() {
432
		$_SERVER['REQUEST_METHOD'] = 'POST';
433
		$this->Controller->request['action'] = 'posted';
434
		$this->Controller->Security->requirePut('putted');
435
		$this->Controller->Security->startup($this->Controller);
436
		$this->assertFalse($this->Controller->failed);
437
	}
438
 
439
/**
440
 * testRequireDeleteFail method
441
 *
442
 * @return void
443
 */
444
	public function testRequireDeleteFail() {
445
		$_SERVER['REQUEST_METHOD'] = 'POST';
446
		$this->Controller->request['action'] = 'deleted';
447
		$this->Controller->Security->requireDelete(array('deleted', 'other_method'));
448
		$this->Controller->Security->startup($this->Controller);
449
		$this->assertTrue($this->Controller->failed);
450
	}
451
 
452
/**
453
 * testRequireDeleteSucceed method
454
 *
455
 * @return void
456
 */
457
	public function testRequireDeleteSucceed() {
458
		$_SERVER['REQUEST_METHOD'] = 'DELETE';
459
		$this->Controller->request['action'] = 'deleted';
460
		$this->Controller->Security->requireDelete('deleted');
461
		$this->Controller->Security->startup($this->Controller);
462
		$this->assertFalse($this->Controller->failed);
463
	}
464
 
465
/**
466
 * testRequireDeleteSucceedWrongMethod method
467
 *
468
 * @return void
469
 */
470
	public function testRequireDeleteSucceedWrongMethod() {
471
		$_SERVER['REQUEST_METHOD'] = 'POST';
472
		$this->Controller->request['action'] = 'posted';
473
		$this->Controller->Security->requireDelete('deleted');
474
		$this->Controller->Security->startup($this->Controller);
475
		$this->assertFalse($this->Controller->failed);
476
	}
477
 
478
/**
479
 * Simple hash validation test
480
 *
481
 * @return void
482
 */
483
	public function testValidatePost() {
484
		$this->Controller->Security->startup($this->Controller);
485
 
486
		$key = $this->Controller->request->params['_Token']['key'];
487
		$fields = 'a5475372b40f6e3ccbf9f8af191f20e1642fd877%3AModel.valid';
488
		$unlocked = '';
489
 
490
		$this->Controller->request->data = array(
491
			'Model' => array('username' => 'nate', 'password' => 'foo', 'valid' => '0'),
492
			'_Token' => compact('key', 'fields', 'unlocked')
493
		);
494
		$this->assertTrue($this->Controller->Security->validatePost($this->Controller));
495
	}
496
 
497
/**
498
 * Test that validatePost fails if you are missing the session information.
499
 *
500
 * @return void
501
 */
502
	public function testValidatePostNoSession() {
503
		$this->Controller->Security->startup($this->Controller);
504
		$this->Controller->Session->delete('_Token');
505
 
506
		$key = $this->Controller->params['_Token']['key'];
507
		$fields = 'a5475372b40f6e3ccbf9f8af191f20e1642fd877%3AModel.valid';
508
 
509
		$this->Controller->data = array(
510
			'Model' => array('username' => 'nate', 'password' => 'foo', 'valid' => '0'),
511
			'_Token' => compact('key', 'fields')
512
		);
513
		$this->assertFalse($this->Controller->Security->validatePost($this->Controller));
514
	}
515
 
516
/**
517
 * test that validatePost fails if any of its required fields are missing.
518
 *
519
 * @return void
520
 */
521
	public function testValidatePostFormHacking() {
522
		$this->Controller->Security->startup($this->Controller);
523
		$key = $this->Controller->params['_Token']['key'];
524
		$unlocked = '';
525
 
526
		$this->Controller->request->data = array(
527
			'Model' => array('username' => 'nate', 'password' => 'foo', 'valid' => '0'),
528
			'_Token' => compact('key', 'unlocked')
529
		);
530
		$result = $this->Controller->Security->validatePost($this->Controller);
531
		$this->assertFalse($result, 'validatePost passed when fields were missing. %s');
532
	}
533
 
534
/**
535
 * Test that objects can't be passed into the serialized string. This was a vector for RFI and LFI
536
 * attacks. Thanks to Felix Wilhelm
537
 *
538
 * @return void
539
 */
540
	public function testValidatePostObjectDeserialize() {
541
		$this->Controller->Security->startup($this->Controller);
542
		$key = $this->Controller->request->params['_Token']['key'];
543
		$fields = 'a5475372b40f6e3ccbf9f8af191f20e1642fd877';
544
		$unlocked = '';
545
 
546
		// a corrupted serialized object, so we can see if it ever gets to deserialize
547
		$attack = 'O:3:"App":1:{s:5:"__map";a:1:{s:3:"foo";s:7:"Hacked!";s:1:"fail"}}';
548
		$fields .= urlencode(':' . str_rot13($attack));
549
 
550
		$this->Controller->request->data = array(
551
			'Model' => array('username' => 'mark', 'password' => 'foo', 'valid' => '0'),
552
			'_Token' => compact('key', 'fields', 'unlocked')
553
		);
554
		$result = $this->Controller->Security->validatePost($this->Controller);
555
		$this->assertFalse($result, 'validatePost passed when key was missing. %s');
556
	}
557
 
558
/**
559
 * Tests validation of checkbox arrays
560
 *
561
 * @return void
562
 */
563
	public function testValidatePostArray() {
564
		$this->Controller->Security->startup($this->Controller);
565
 
566
		$key = $this->Controller->request->params['_Token']['key'];
567
		$fields = 'f7d573650a295b94e0938d32b323fde775e5f32b%3A';
568
		$unlocked = '';
569
 
570
		$this->Controller->request->data = array(
571
			'Model' => array('multi_field' => array('1', '3')),
572
			'_Token' => compact('key', 'fields', 'unlocked')
573
		);
574
		$this->assertTrue($this->Controller->Security->validatePost($this->Controller));
575
	}
576
 
577
/**
578
 * testValidatePostNoModel method
579
 *
580
 * @return void
581
 */
582
	public function testValidatePostNoModel() {
583
		$this->Controller->Security->startup($this->Controller);
584
 
585
		$key = $this->Controller->request->params['_Token']['key'];
586
		$fields = '540ac9c60d323c22bafe997b72c0790f39a8bdef%3A';
587
		$unlocked = '';
588
 
589
		$this->Controller->request->data = array(
590
			'anything' => 'some_data',
591
			'_Token' => compact('key', 'fields', 'unlocked')
592
		);
593
 
594
		$result = $this->Controller->Security->validatePost($this->Controller);
595
		$this->assertTrue($result);
596
	}
597
 
598
/**
599
 * testValidatePostSimple method
600
 *
601
 * @return void
602
 */
603
	public function testValidatePostSimple() {
604
		$this->Controller->Security->startup($this->Controller);
605
 
606
		$key = $this->Controller->request->params['_Token']['key'];
607
		$fields = '69f493434187b867ea14b901fdf58b55d27c935d%3A';
608
		$unlocked = '';
609
 
610
		$this->Controller->request->data = $data = array(
611
			'Model' => array('username' => '', 'password' => ''),
612
			'_Token' => compact('key', 'fields', 'unlocked')
613
		);
614
 
615
		$result = $this->Controller->Security->validatePost($this->Controller);
616
		$this->assertTrue($result);
617
	}
618
 
619
/**
620
 * Tests hash validation for multiple records, including locked fields
621
 *
622
 * @return void
623
 */
624
	public function testValidatePostComplex() {
625
		$this->Controller->Security->startup($this->Controller);
626
 
627
		$key = $this->Controller->request->params['_Token']['key'];
628
		$fields = 'c9118120e680a7201b543f562e5301006ccfcbe2%3AAddresses.0.id%7CAddresses.1.id';
629
		$unlocked = '';
630
 
631
		$this->Controller->request->data = array(
632
			'Addresses' => array(
633
				'0' => array(
634
					'id' => '123456', 'title' => '', 'first_name' => '', 'last_name' => '',
635
					'address' => '', 'city' => '', 'phone' => '', 'primary' => ''
636
				),
637
				'1' => array(
638
					'id' => '654321', 'title' => '', 'first_name' => '', 'last_name' => '',
639
					'address' => '', 'city' => '', 'phone' => '', 'primary' => ''
640
				)
641
			),
642
			'_Token' => compact('key', 'fields', 'unlocked')
643
		);
644
		$result = $this->Controller->Security->validatePost($this->Controller);
645
		$this->assertTrue($result);
646
	}
647
 
648
/**
649
 * test ValidatePost with multiple select elements.
650
 *
651
 * @return void
652
 */
653
	public function testValidatePostMultipleSelect() {
654
		$this->Controller->Security->startup($this->Controller);
655
 
656
		$key = $this->Controller->request->params['_Token']['key'];
657
		$fields = '422cde416475abc171568be690a98cad20e66079%3A';
658
		$unlocked = '';
659
 
660
		$this->Controller->request->data = array(
661
			'Tag' => array('Tag' => array(1, 2)),
662
			'_Token' => compact('key', 'fields', 'unlocked'),
663
		);
664
		$result = $this->Controller->Security->validatePost($this->Controller);
665
		$this->assertTrue($result);
666
 
667
		$this->Controller->request->data = array(
668
			'Tag' => array('Tag' => array(1, 2, 3)),
669
			'_Token' => compact('key', 'fields', 'unlocked'),
670
		);
671
		$result = $this->Controller->Security->validatePost($this->Controller);
672
		$this->assertTrue($result);
673
 
674
		$this->Controller->request->data = array(
675
			'Tag' => array('Tag' => array(1, 2, 3, 4)),
676
			'_Token' => compact('key', 'fields', 'unlocked'),
677
		);
678
		$result = $this->Controller->Security->validatePost($this->Controller);
679
		$this->assertTrue($result);
680
 
681
		$fields = '19464422eafe977ee729c59222af07f983010c5f%3A';
682
		$this->Controller->request->data = array(
683
			'User.password' => 'bar', 'User.name' => 'foo', 'User.is_valid' => '1',
684
			'Tag' => array('Tag' => array(1)),
685
			'_Token' => compact('key', 'fields', 'unlocked'),
686
		);
687
		$result = $this->Controller->Security->validatePost($this->Controller);
688
		$this->assertTrue($result);
689
	}
690
 
691
/**
692
 * testValidatePostCheckbox method
693
 *
694
 * First block tests un-checked checkbox
695
 * Second block tests checked checkbox
696
 *
697
 * @return void
698
 */
699
	public function testValidatePostCheckbox() {
700
		$this->Controller->Security->startup($this->Controller);
701
		$key = $this->Controller->request->params['_Token']['key'];
702
		$fields = 'a5475372b40f6e3ccbf9f8af191f20e1642fd877%3AModel.valid';
703
		$unlocked = '';
704
 
705
		$this->Controller->request->data = array(
706
			'Model' => array('username' => '', 'password' => '', 'valid' => '0'),
707
			'_Token' => compact('key', 'fields', 'unlocked')
708
		);
709
 
710
		$result = $this->Controller->Security->validatePost($this->Controller);
711
		$this->assertTrue($result);
712
 
713
		$fields = '874439ca69f89b4c4a5f50fb9c36ff56a28f5d42%3A';
714
 
715
		$this->Controller->request->data = array(
716
			'Model' => array('username' => '', 'password' => '', 'valid' => '0'),
717
			'_Token' => compact('key', 'fields', 'unlocked')
718
		);
719
 
720
		$result = $this->Controller->Security->validatePost($this->Controller);
721
		$this->assertTrue($result);
722
 
723
		$this->Controller->request->data = array();
724
		$this->Controller->Security->startup($this->Controller);
725
		$key = $this->Controller->request->params['_Token']['key'];
726
 
727
		$this->Controller->request->data = array(
728
			'Model' => array('username' => '', 'password' => '', 'valid' => '0'),
729
			'_Token' => compact('key', 'fields', 'unlocked')
730
		);
731
 
732
		$result = $this->Controller->Security->validatePost($this->Controller);
733
		$this->assertTrue($result);
734
	}
735
 
736
/**
737
 * testValidatePostHidden method
738
 *
739
 * @return void
740
 */
741
	public function testValidatePostHidden() {
742
		$this->Controller->Security->startup($this->Controller);
743
		$key = $this->Controller->request->params['_Token']['key'];
744
		$fields = '51ccd8cb0997c7b3d4523ecde5a109318405ef8c%3AModel.hidden%7CModel.other_hidden';
745
		$unlocked = '';
746
 
747
		$this->Controller->request->data = array(
748
			'Model' => array(
749
				'username' => '', 'password' => '', 'hidden' => '0',
750
				'other_hidden' => 'some hidden value'
751
			),
752
			'_Token' => compact('key', 'fields', 'unlocked')
753
		);
754
		$result = $this->Controller->Security->validatePost($this->Controller);
755
		$this->assertTrue($result);
756
	}
757
 
758
/**
759
 * testValidatePostWithDisabledFields method
760
 *
761
 * @return void
762
 */
763
	public function testValidatePostWithDisabledFields() {
764
		$this->Controller->Security->disabledFields = array('Model.username', 'Model.password');
765
		$this->Controller->Security->startup($this->Controller);
766
		$key = $this->Controller->request->params['_Token']['key'];
767
		$fields = 'ef1082968c449397bcd849f963636864383278b1%3AModel.hidden';
768
		$unlocked = '';
769
 
770
		$this->Controller->request->data = array(
771
			'Model' => array(
772
				'username' => '', 'password' => '', 'hidden' => '0'
773
			),
774
			'_Token' => compact('fields', 'key', 'unlocked')
775
		);
776
 
777
		$result = $this->Controller->Security->validatePost($this->Controller);
778
		$this->assertTrue($result);
779
	}
780
 
781
/**
782
 * test validating post data with posted unlocked fields.
783
 *
784
 * @return void
785
 */
786
	public function testValidatePostDisabledFieldsInData() {
787
		$this->Controller->Security->startup($this->Controller);
788
		$key = $this->Controller->request->params['_Token']['key'];
789
		$unlocked = 'Model.username';
790
		$fields = array('Model.hidden', 'Model.password');
791
		$fields = urlencode(Security::hash(serialize($fields) . $unlocked . Configure::read('Security.salt')));
792
 
793
		$this->Controller->request->data = array(
794
			'Model' => array(
795
				'username' => 'mark',
796
				'password' => 'sekret',
797
				'hidden' => '0'
798
			),
799
			'_Token' => compact('fields', 'key', 'unlocked')
800
		);
801
 
802
		$result = $this->Controller->Security->validatePost($this->Controller);
803
		$this->assertTrue($result);
804
	}
805
 
806
/**
807
 * test that missing 'unlocked' input causes failure
808
 *
809
 * @return void
810
 */
811
	public function testValidatePostFailNoDisabled() {
812
		$this->Controller->Security->startup($this->Controller);
813
		$key = $this->Controller->request->params['_Token']['key'];
814
		$fields = array('Model.hidden', 'Model.password', 'Model.username');
815
		$fields = urlencode(Security::hash(serialize($fields) . Configure::read('Security.salt')));
816
 
817
		$this->Controller->request->data = array(
818
			'Model' => array(
819
				'username' => 'mark',
820
				'password' => 'sekret',
821
				'hidden' => '0'
822
			),
823
			'_Token' => compact('fields', 'key')
824
		);
825
 
826
		$result = $this->Controller->Security->validatePost($this->Controller);
827
		$this->assertFalse($result);
828
	}
829
 
830
/**
831
 * Test that validatePost fails when unlocked fields are changed.
832
 *
833
 * @return
834
 */
835
	public function testValidatePostFailDisabledFieldTampering() {
836
		$this->Controller->Security->startup($this->Controller);
837
		$key = $this->Controller->request->params['_Token']['key'];
838
		$unlocked = 'Model.username';
839
		$fields = array('Model.hidden', 'Model.password');
840
		$fields = urlencode(Security::hash(serialize($fields) . $unlocked . Configure::read('Security.salt')));
841
 
842
		// Tamper the values.
843
		$unlocked = 'Model.username|Model.password';
844
 
845
		$this->Controller->request->data = array(
846
			'Model' => array(
847
				'username' => 'mark',
848
				'password' => 'sekret',
849
				'hidden' => '0'
850
			),
851
			'_Token' => compact('fields', 'key', 'unlocked')
852
		);
853
 
854
		$result = $this->Controller->Security->validatePost($this->Controller);
855
		$this->assertFalse($result);
856
	}
857
 
858
/**
859
 * testValidateHiddenMultipleModel method
860
 *
861
 * @return void
862
 */
863
	public function testValidateHiddenMultipleModel() {
864
		$this->Controller->Security->startup($this->Controller);
865
		$key = $this->Controller->request->params['_Token']['key'];
866
		$fields = 'a2d01072dc4660eea9d15007025f35a7a5b58e18%3AModel.valid%7CModel2.valid%7CModel3.valid';
867
		$unlocked = '';
868
 
869
		$this->Controller->request->data = array(
870
			'Model' => array('username' => '', 'password' => '', 'valid' => '0'),
871
			'Model2' => array('valid' => '0'),
872
			'Model3' => array('valid' => '0'),
873
			'_Token' => compact('key', 'fields', 'unlocked')
874
		);
875
		$result = $this->Controller->Security->validatePost($this->Controller);
876
		$this->assertTrue($result);
877
	}
878
 
879
/**
880
 * testValidateHasManyModel method
881
 *
882
 * @return void
883
 */
884
	public function testValidateHasManyModel() {
885
		$this->Controller->Security->startup($this->Controller);
886
		$key = $this->Controller->request->params['_Token']['key'];
887
		$fields = '51e3b55a6edd82020b3f29c9ae200e14bbeb7ee5%3AModel.0.hidden%7CModel.0.valid';
888
		$fields .= '%7CModel.1.hidden%7CModel.1.valid';
889
		$unlocked = '';
890
 
891
		$this->Controller->request->data = array(
892
			'Model' => array(
893
				array(
894
					'username' => 'username', 'password' => 'password',
895
					'hidden' => 'value', 'valid' => '0'
896
				),
897
				array(
898
					'username' => 'username', 'password' => 'password',
899
					'hidden' => 'value', 'valid' => '0'
900
				)
901
			),
902
			'_Token' => compact('key', 'fields', 'unlocked')
903
		);
904
 
905
		$result = $this->Controller->Security->validatePost($this->Controller);
906
		$this->assertTrue($result);
907
	}
908
 
909
/**
910
 * testValidateHasManyRecordsPass method
911
 *
912
 * @return void
913
 */
914
	public function testValidateHasManyRecordsPass() {
915
		$this->Controller->Security->startup($this->Controller);
916
		$key = $this->Controller->request->params['_Token']['key'];
917
		$fields = '7a203edb3d345bbf38fe0dccae960da8842e11d7%3AAddress.0.id%7CAddress.0.primary%7C';
918
		$fields .= 'Address.1.id%7CAddress.1.primary';
919
		$unlocked = '';
920
 
921
		$this->Controller->request->data = array(
922
			'Address' => array(
923
 
924
					'id' => '123',
925
					'title' => 'home',
926
					'first_name' => 'Bilbo',
927
					'last_name' => 'Baggins',
928
					'address' => '23 Bag end way',
929
					'city' => 'the shire',
930
					'phone' => 'N/A',
931
					'primary' => '1',
932
				),
933
				1 => array(
934
					'id' => '124',
935
					'title' => 'home',
936
					'first_name' => 'Frodo',
937
					'last_name' => 'Baggins',
938
					'address' => '50 Bag end way',
939
					'city' => 'the shire',
940
					'phone' => 'N/A',
941
					'primary' => '1'
942
				)
943
			),
944
			'_Token' => compact('key', 'fields', 'unlocked')
945
		);
946
 
947
		$result = $this->Controller->Security->validatePost($this->Controller);
948
		$this->assertTrue($result);
949
	}
950
 
951
/**
952
 * Test that values like Foo.0.1
953
 *
954
 * @return void
955
 */
956
	public function testValidateNestedNumericSets() {
957
		$this->Controller->Security->startup($this->Controller);
958
		$key = $this->Controller->request->params['_Token']['key'];
959
		$unlocked = '';
960
		$hashFields = array('TaxonomyData');
961
		$fields = urlencode(Security::hash(serialize($hashFields) . $unlocked . Configure::read('Security.salt')));
962
 
963
		$this->Controller->request->data = array(
964
			'TaxonomyData' => array(
965
				1 => array(array(2)),
966
				2 => array(array(3))
967
			),
968
			'_Token' => compact('key', 'fields', 'unlocked')
969
		);
970
		$result = $this->Controller->Security->validatePost($this->Controller);
971
		$this->assertTrue($result);
972
	}
973
 
974
/**
975
 * testValidateHasManyRecords method
976
 *
977
 * validatePost should fail, hidden fields have been changed.
978
 *
979
 * @return void
980
 */
981
	public function testValidateHasManyRecordsFail() {
982
		$this->Controller->Security->startup($this->Controller);
983
		$key = $this->Controller->request->params['_Token']['key'];
984
		$fields = '7a203edb3d345bbf38fe0dccae960da8842e11d7%3AAddress.0.id%7CAddress.0.primary%7C';
985
		$fields .= 'Address.1.id%7CAddress.1.primary';
986
		$unlocked = '';
987
 
988
		$this->Controller->request->data = array(
989
			'Address' => array(
990
 
991
					'id' => '123',
992
					'title' => 'home',
993
					'first_name' => 'Bilbo',
994
					'last_name' => 'Baggins',
995
					'address' => '23 Bag end way',
996
					'city' => 'the shire',
997
					'phone' => 'N/A',
998
					'primary' => '5',
999
				),
1000
				1 => array(
1001
					'id' => '124',
1002
					'title' => 'home',
1003
					'first_name' => 'Frodo',
1004
					'last_name' => 'Baggins',
1005
					'address' => '50 Bag end way',
1006
					'city' => 'the shire',
1007
					'phone' => 'N/A',
1008
					'primary' => '1'
1009
				)
1010
			),
1011
			'_Token' => compact('key', 'fields', 'unlocked')
1012
		);
1013
 
1014
		$result = $this->Controller->Security->validatePost($this->Controller);
1015
		$this->assertFalse($result);
1016
	}
1017
 
1018
/**
1019
 * testFormDisabledFields method
1020
 *
1021
 * @return void
1022
 */
1023
	public function testFormDisabledFields() {
1024
		$this->Controller->Security->startup($this->Controller);
1025
		$key = $this->Controller->request->params['_Token']['key'];
1026
		$fields = '11842060341b9d0fc3808b90ba29fdea7054d6ad%3An%3A0%3A%7B%7D';
1027
		$unlocked = '';
1028
 
1029
		$this->Controller->request->data = array(
1030
			'MyModel' => array('name' => 'some data'),
1031
			'_Token' => compact('key', 'fields', 'unlocked')
1032
		);
1033
		$result = $this->Controller->Security->validatePost($this->Controller);
1034
		$this->assertFalse($result);
1035
 
1036
		$this->Controller->Security->startup($this->Controller);
1037
		$this->Controller->Security->disabledFields = array('MyModel.name');
1038
		$key = $this->Controller->request->params['_Token']['key'];
1039
 
1040
		$this->Controller->request->data = array(
1041
			'MyModel' => array('name' => 'some data'),
1042
			'_Token' => compact('key', 'fields', 'unlocked')
1043
		);
1044
 
1045
		$result = $this->Controller->Security->validatePost($this->Controller);
1046
		$this->assertTrue($result);
1047
	}
1048
 
1049
/**
1050
 * testRadio method
1051
 *
1052
 * @return void
1053
 */
1054
	public function testRadio() {
1055
		$this->Controller->Security->startup($this->Controller);
1056
		$key = $this->Controller->request->params['_Token']['key'];
1057
		$fields = '575ef54ca4fc8cab468d6d898e9acd3a9671c17e%3An%3A0%3A%7B%7D';
1058
		$unlocked = '';
1059
 
1060
		$this->Controller->request->data = array(
1061
			'_Token' => compact('key', 'fields', 'unlocked')
1062
		);
1063
		$result = $this->Controller->Security->validatePost($this->Controller);
1064
		$this->assertFalse($result);
1065
 
1066
		$this->Controller->request->data = array(
1067
			'_Token' => compact('key', 'fields', 'unlocked'),
1068
			'Test' => array('test' => '')
1069
		);
1070
		$result = $this->Controller->Security->validatePost($this->Controller);
1071
		$this->assertTrue($result);
1072
 
1073
		$this->Controller->request->data = array(
1074
			'_Token' => compact('key', 'fields', 'unlocked'),
1075
			'Test' => array('test' => '1')
1076
		);
1077
		$result = $this->Controller->Security->validatePost($this->Controller);
1078
		$this->assertTrue($result);
1079
 
1080
		$this->Controller->request->data = array(
1081
			'_Token' => compact('key', 'fields', 'unlocked'),
1082
			'Test' => array('test' => '2')
1083
		);
1084
		$result = $this->Controller->Security->validatePost($this->Controller);
1085
		$this->assertTrue($result);
1086
	}
1087
 
1088
/**
1089
 * test that a requestAction's controller will have the _Token appended to
1090
 * the params.
1091
 *
1092
 * @return void
1093
 * @see https://cakephp.lighthouseapp.com/projects/42648/tickets/68
1094
 */
1095
	public function testSettingTokenForRequestAction() {
1096
		$this->Controller->Security->startup($this->Controller);
1097
		$key = $this->Controller->request->params['_Token']['key'];
1098
 
1099
		$this->Controller->params['requested'] = 1;
1100
		unset($this->Controller->request->params['_Token']);
1101
 
1102
		$this->Controller->Security->startup($this->Controller);
1103
		$this->assertEquals($this->Controller->request->params['_Token']['key'], $key);
1104
	}
1105
 
1106
/**
1107
 * test that blackhole doesn't delete the _Token session key so repeat data submissions
1108
 * stay blackholed.
1109
 *
1110
 * @link https://cakephp.lighthouseapp.com/projects/42648/tickets/214
1111
 * @return void
1112
 */
1113
	public function testBlackHoleNotDeletingSessionInformation() {
1114
		$this->Controller->Security->startup($this->Controller);
1115
 
1116
		$this->Controller->Security->blackHole($this->Controller, 'auth');
1117
		$this->assertTrue($this->Controller->Security->Session->check('_Token'), '_Token was deleted by blackHole %s');
1118
	}
1119
 
1120
/**
1121
 * test that csrf checks are skipped for request action.
1122
 *
1123
 * @return void
1124
 */
1125
	public function testCsrfSkipRequestAction() {
1126
		$_SERVER['REQUEST_METHOD'] = 'POST';
1127
 
1128
		$this->Security->validatePost = false;
1129
		$this->Security->csrfCheck = true;
1130
		$this->Security->csrfExpires = '+10 minutes';
1131
		$this->Controller->request->params['requested'] = 1;
1132
		$this->Security->startup($this->Controller);
1133
 
1134
		$this->assertFalse($this->Controller->failed, 'fail() was called.');
1135
	}
1136
 
1137
/**
1138
 * test setting
1139
 *
1140
 * @return void
1141
 */
1142
	public function testCsrfSettings() {
1143
		$this->Security->validatePost = false;
1144
		$this->Security->csrfCheck = true;
1145
		$this->Security->csrfExpires = '+10 minutes';
1146
		$this->Security->startup($this->Controller);
1147
 
1148
		$token = $this->Security->Session->read('_Token');
1149
		$this->assertEquals(1, count($token['csrfTokens']), 'Missing the csrf token.');
1150
		$this->assertEquals(strtotime('+10 minutes'), current($token['csrfTokens']), 'Token expiry does not match');
1151
		$this->assertEquals(array('key', 'unlockedFields'), array_keys($this->Controller->request->params['_Token']), 'Keys don not match');
1152
	}
1153
 
1154
/**
1155
 * Test setting multiple nonces, when startup() is called more than once, (ie more than one request.)
1156
 *
1157
 * @return void
1158
 */
1159
	public function testCsrfSettingMultipleNonces() {
1160
		$this->Security->validatePost = false;
1161
		$this->Security->csrfCheck = true;
1162
		$this->Security->csrfExpires = '+10 minutes';
1163
		$csrfExpires = strtotime('+10 minutes');
1164
		$this->Security->startup($this->Controller);
1165
		$this->Security->startup($this->Controller);
1166
 
1167
		$token = $this->Security->Session->read('_Token');
1168
		$this->assertEquals(2, count($token['csrfTokens']), 'Missing the csrf token.');
1169
		foreach ($token['csrfTokens'] as $expires) {
1170
			$diff = $csrfExpires - $expires;
1171
			$this->assertTrue($diff === 0 || $diff === 1, 'Token expiry does not match');
1172
		}
1173
	}
1174
 
1175
/**
1176
 * test that nonces are consumed by form submits.
1177
 *
1178
 * @return void
1179
 */
1180
	public function testCsrfNonceConsumption() {
1181
		$this->Security->validatePost = false;
1182
		$this->Security->csrfCheck = true;
1183
		$this->Security->csrfExpires = '+10 minutes';
1184
 
1185
		$this->Security->Session->write('_Token.csrfTokens', array('nonce1' => strtotime('+10 minutes')));
1186
 
1187
		$this->Controller->request = $this->getMock('CakeRequest', array('is'));
1188
		$this->Controller->request->expects($this->once())->method('is')
1189
			->with(array('post', 'put'))
1190
			->will($this->returnValue(true));
1191
 
1192
		$this->Controller->request->params['action'] = 'index';
1193
		$this->Controller->request->data = array(
1194
			'_Token' => array(
1195
				'key' => 'nonce1'
1196
			),
1197
			'Post' => array(
1198
				'title' => 'Woot'
1199
			)
1200
		);
1201
		$this->Security->startup($this->Controller);
1202
		$token = $this->Security->Session->read('_Token');
1203
		$this->assertFalse(isset($token['csrfTokens']['nonce1']), 'Token was not consumed');
1204
	}
1205
 
1206
/**
1207
 * test that expired values in the csrfTokens are cleaned up.
1208
 *
1209
 * @return void
1210
 */
1211
	public function testCsrfNonceVacuum() {
1212
		$this->Security->validatePost = false;
1213
		$this->Security->csrfCheck = true;
1214
		$this->Security->csrfExpires = '+10 minutes';
1215
 
1216
		$this->Security->Session->write('_Token.csrfTokens', array(
1217
			'valid' => strtotime('+30 minutes'),
1218
			'poof' => strtotime('-11 minutes'),
1219
			'dust' => strtotime('-20 minutes')
1220
		));
1221
		$this->Security->startup($this->Controller);
1222
		$tokens = $this->Security->Session->read('_Token.csrfTokens');
1223
		$this->assertEquals(2, count($tokens), 'Too many tokens left behind');
1224
		$this->assertNotEmpty('valid', $tokens, 'Valid token was removed.');
1225
	}
1226
 
1227
/**
1228
 * test that when the key is missing the request is blackHoled
1229
 *
1230
 * @return void
1231
 */
1232
	public function testCsrfBlackHoleOnKeyMismatch() {
1233
		$this->Security->validatePost = false;
1234
		$this->Security->csrfCheck = true;
1235
		$this->Security->csrfExpires = '+10 minutes';
1236
 
1237
		$this->Security->Session->write('_Token.csrfTokens', array('nonce1' => strtotime('+10 minutes')));
1238
 
1239
		$this->Controller->request = $this->getMock('CakeRequest', array('is'));
1240
		$this->Controller->request->expects($this->once())->method('is')
1241
			->with(array('post', 'put'))
1242
			->will($this->returnValue(true));
1243
 
1244
		$this->Controller->request->params['action'] = 'index';
1245
		$this->Controller->request->data = array(
1246
			'_Token' => array(
1247
				'key' => 'not the right value'
1248
			),
1249
			'Post' => array(
1250
				'title' => 'Woot'
1251
			)
1252
		);
1253
		$this->Security->startup($this->Controller);
1254
		$this->assertTrue($this->Controller->failed, 'fail() was not called.');
1255
	}
1256
 
1257
/**
1258
 * test that when the key is missing the request is blackHoled
1259
 *
1260
 * @return void
1261
 */
1262
	public function testCsrfBlackHoleOnExpiredKey() {
1263
		$this->Security->validatePost = false;
1264
		$this->Security->csrfCheck = true;
1265
		$this->Security->csrfExpires = '+10 minutes';
1266
 
1267
		$this->Security->Session->write('_Token.csrfTokens', array('nonce1' => strtotime('-5 minutes')));
1268
 
1269
		$this->Controller->request = $this->getMock('CakeRequest', array('is'));
1270
		$this->Controller->request->expects($this->once())->method('is')
1271
			->with(array('post', 'put'))
1272
			->will($this->returnValue(true));
1273
 
1274
		$this->Controller->request->params['action'] = 'index';
1275
		$this->Controller->request->data = array(
1276
			'_Token' => array(
1277
				'key' => 'nonce1'
1278
			),
1279
			'Post' => array(
1280
				'title' => 'Woot'
1281
			)
1282
		);
1283
		$this->Security->startup($this->Controller);
1284
		$this->assertTrue($this->Controller->failed, 'fail() was not called.');
1285
	}
1286
 
1287
/**
1288
 * test that csrfUseOnce = false works.
1289
 *
1290
 * @return void
1291
 */
1292
	public function testCsrfNotUseOnce() {
1293
		$this->Security->validatePost = false;
1294
		$this->Security->csrfCheck = true;
1295
		$this->Security->csrfUseOnce = false;
1296
		$this->Security->csrfExpires = '+10 minutes';
1297
 
1298
		// Generate one token
1299
		$this->Security->startup($this->Controller);
1300
		$token = $this->Security->Session->read('_Token.csrfTokens');
1301
		$this->assertEquals(1, count($token), 'Should only be one token.');
1302
 
1303
		$this->Security->startup($this->Controller);
1304
		$tokenTwo = $this->Security->Session->read('_Token.csrfTokens');
1305
		$this->assertEquals(1, count($tokenTwo), 'Should only be one token.');
1306
		$this->assertEquals($token, $tokenTwo, 'Tokens should not be different.');
1307
 
1308
		$key = $this->Controller->request->params['_Token']['key'];
1309
		$this->assertEquals(array($key), array_keys($token), '_Token.key and csrfToken do not match request will blackhole.');
1310
	}
1311
 
1312
/**
1313
 * ensure that longer session tokens are not consumed
1314
 *
1315
 * @return void
1316
 */
1317
	public function testCsrfNotUseOnceValidationLeavingToken() {
1318
		$this->Security->validatePost = false;
1319
		$this->Security->csrfCheck = true;
1320
		$this->Security->csrfUseOnce = false;
1321
		$this->Security->csrfExpires = '+10 minutes';
1322
 
1323
		$this->Security->Session->write('_Token.csrfTokens', array('nonce1' => strtotime('+10 minutes')));
1324
 
1325
		$this->Controller->request = $this->getMock('CakeRequest', array('is'));
1326
		$this->Controller->request->expects($this->once())->method('is')
1327
			->with(array('post', 'put'))
1328
			->will($this->returnValue(true));
1329
 
1330
		$this->Controller->request->params['action'] = 'index';
1331
		$this->Controller->request->data = array(
1332
			'_Token' => array(
1333
				'key' => 'nonce1'
1334
			),
1335
			'Post' => array(
1336
				'title' => 'Woot'
1337
			)
1338
		);
1339
		$this->Security->startup($this->Controller);
1340
		$token = $this->Security->Session->read('_Token');
1341
		$this->assertTrue(isset($token['csrfTokens']['nonce1']), 'Token was consumed');
1342
	}
1343
 
1344
/**
1345
 * Test generateToken()
1346
 *
1347
 * @return void
1348
 */
1349
	public function testGenerateToken() {
1350
		$request = $this->Controller->request;
1351
		$this->Security->generateToken($request);
1352
 
1353
		$this->assertNotEmpty($request->params['_Token']);
1354
		$this->assertTrue(isset($request->params['_Token']['unlockedFields']));
1355
		$this->assertTrue(isset($request->params['_Token']['key']));
1356
	}
1357
 
1358
/**
1359
 * Test the limiting of CSRF tokens.
1360
 *
1361
 * @return void
1362
 */
1363
	public function testCsrfLimit() {
1364
		$this->Security->csrfLimit = 3;
1365
		$time = strtotime('+10 minutes');
1366
		$tokens = array(
1367
			'1' => $time,
1368
			'2' => $time,
1369
			'3' => $time,
1370
			'4' => $time,
1371
			'5' => $time,
1372
		);
1373
		$this->Security->Session->write('_Token', array('csrfTokens' => $tokens));
1374
		$this->Security->generateToken($this->Controller->request);
1375
		$result = $this->Security->Session->read('_Token.csrfTokens');
1376
 
1377
		$this->assertFalse(isset($result['1']));
1378
		$this->assertFalse(isset($result['2']));
1379
		$this->assertFalse(isset($result['3']));
1380
		$this->assertTrue(isset($result['4']));
1381
		$this->assertTrue(isset($result['5']));
1382
	}
1383
 
1384
/**
1385
 * Test unlocked actions
1386
 *
1387
 * @return void
1388
 */
1389
	public function testUnlockedActions() {
1390
		$_SERVER['REQUEST_METHOD'] = 'POST';
1391
		$this->Controller->request->data = array('data');
1392
		$this->Controller->Security->unlockedActions = 'index';
1393
		$this->Controller->Security->blackHoleCallback = null;
1394
		$result = $this->Controller->Security->startup($this->Controller);
1395
		$this->assertNull($result);
1396
	}
1397
}