Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CakePHP Controller Testing with the Security Component

Consider this code:

Controller Code

<?php
App::uses('AppController', 'Controller');

class UsersController extends AppController {

    public $components = array(
        'Security',
        'Session'
    );

    public function example() {
        if ($this->request->is('post')) {
            $this->set('some_var', true);
        }
    }
}

View Code

<?php

echo $this->Form->create();
echo $this->Form->input('name');
echo $this->Form->end('Submit');

Since I have the Security component in place, tampering with the form in any way (such as adding a field to it) will cause the request to be black-holed. I'd like to test this:

Test Code

<?php

class UsersControllerTest extends ControllerTestCase {

    public function testExamplePostValidData() {
        $this->Controller = $this->generate('Users', array(
            'components' => array(
                'Security'
            )
        ));

        $data = array(
            'User' => array(
                'name' => 'John Doe'
            )
        );

        $this->testAction('/users/example', array('data' => $data, 'method' => 'post'));
        $this->assertTrue($this->vars['some_var']);
    }

    public function testExamplePostInvalidData() {
        $this->Controller = $this->generate('Users', array(
            'components' => array(
                'Security'
            )
        ));

        $data = array(
            'User' => array(
                'name' => 'John Doe',
                'some_field' => 'The existence of this should cause the request to be black-holed.'
            )
        );

        $this->testAction('/users/example', array('data' => $data, 'method' => 'post'));
        $this->assertTrue($this->vars['some_var']);
    }
}

The second test testExamplePostInvalidData should fail because of some_field being in the $data array, but it passes! What am I doing wrong?

like image 327
Nick Avatar asked May 10 '13 17:05

Nick


1 Answers

By adding the 'some_field' in the data of ->testAction, the security component will assume that field is part of your app (since it's coming from your code, not a POST array) so it won't be seen as a "hack attempt".

Checking for blackholes is a little more convoluted. But Cake core tests already test the blackhole functionality, so if those tests pass, you don't need to check it in your app.

If you insist though, check out the core Cake tests for guidance:

Specifically:

/**
 * test that validatePost fails if any of its required fields are missing.
 *
 * @return void
 */
public function testValidatePostFormHacking() {
    $this->Controller->Security->startup($this->Controller);
    $key = $this->Controller->params['_Token']['key'];
    $unlocked = '';

    $this->Controller->request->data = array(
        'Model' => array('username' => 'nate', 'password' => 'foo', 'valid' => '0'),
        '_Token' => compact('key', 'unlocked')
    );
    $result = $this->Controller->Security->validatePost($this->Controller);
    $this->assertFalse($result, 'validatePost passed when fields were missing. %s');
}

Lots more examples in the file:
https://github.com/cakephp/cakephp/blob/master/lib/Cake/Test/Case/Controller/Component/SecurityComponentTest.php

like image 179
Costa Avatar answered Nov 15 '22 11:11

Costa