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