Search code examples
unit-testingcakephpbasic-authenticationcakephp-3.xcakephp-3.2

How to unitTest CakePHP 3.x Controller Actions that require HTTP Basic Authentication?


I'am trying to authenticate a user by adding the PHP_AUTH_USER and PHP_AUTH_PW to the $_ENV-Variable, but this has no affect. I'am using the following configuration with memory-Storage:

$this->loadComponent('Auth', [
        'authenticate' => [
            'Basic' => [
                'fields' => ['username' => 'username', 'password' => 'password'],
                'userModel' => 'CmUsers'
            ],
        ],
        'storage' => 'Memory',
        'unauthorizedRedirect' => false
]);  

The Test fails with exception 'Cake\Network\Exception\UnauthorizedException' with message 'Unauthorized'.

public function testIndex()
{         
    $_ENV['PHP_AUTH_USER'] = 'ApiUser';  
    $_ENV['PHP_AUTH_PW'] = '123456';   

    $this->get('/index');                

    $this->assertResponseOk();                         
}

Does anyone have an idea how to add the authentication-data to the request?

If I follow the advice from @ndm and add the Authentication-Header...

$this->configRequest([
            'environment' => [
                'PHP_AUTH_USER' => 'ApiUser',
                'PHP_AUTH_PW' => '123456',                  
            ],
            'headers' => ['Authorization' => 'Basic ApiUser:123456']
]); 

... the envirement Variables looks like this:

[_environment:protected] => Array
    (
        [HTTP_AUTHORIZATION] => Basic ApiUser:123456
        [REQUEST_METHOD] => GET
        [PHP_AUTH_USER] => ApiUser
        [PHP_AUTH_PW] => 123456
        [HTTP_X_HTTP_METHOD_OVERRIDE] => 
        [ORIGINAL_REQUEST_METHOD] => GET
        [SERVER_PORT] => 
        [HTTPS] => 
        [HTTP_HOST] => 
    )

My Fixture looks like this:

public $records = [
    [
        'id' => 2,
        'username' => 'ApiUser',
        'password' => '123456',
        'role' => 'api-user',
        'created' => 1460710056,
        'modified' => 1460710056
    ],        
];

Unfortunately the request still gets blocked.


Solution

  • Integration test cases should never fiddle with superglobals, as they usually aren't touched by the test case in order to avoid polluting the test environment with non-CakePHP request related data.

    The test request can be configured via the \Cake\TestSuite\IntegrationTestCase::configRequest() method. It accepts an array which will basically just be passed to the \Cake\Network\Request constructor of the request object used by the test.

    Long story short, environment variables can be defined via the environment config key, like

    public function testIndex()
    {
        $this->configRequest([
            'environment' => [
                'PHP_AUTH_USER' => 'ApiUser',
                'PHP_AUTH_PW' => '123456'
            ]
        ]);  
    
        $this->get('/index');                
    
        $this->assertResponseOk();                         
    }
    

    See also