Nick
Nick

Reputation: 8309

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?

Upvotes: 6

Views: 1003

Answers (1)

Costa
Costa

Reputation: 4969

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

Upvotes: 1

Related Questions