Although Zend_Auth reference guide shows how to implement Basic HTTP Authentication, it does not show how to test it using PHPUnit. Therefore, in this post, a simple example of a Zend project, along with the associated PHPUnit test case is presented. The full source code of the project is available for download. The project's name is httpautheg.
So, lets assume that we want to restrict access to the actions called protectedAction and editAction in IndexController. We also want a simple action helper, called HTTPAuth that will do the authentication. Finally, we want a test case for IndexController that will perform the tests of incorrect and correct authentications, so that we do not have to worry that during further work on the project we will break something without noticing it.
The directory tree of the httpautheg project
HTTPAuth action helper
The helper has only one function called doBasicHTTPAuth that does the authentication, and returns false or true if authentication failed or succeeded, respectively.<?php
class My_Controller_Action_Helper_HTTPAuth extends Zend_Controller_Action_Helper_Abstract {
//put your code here
/**
* Perform Basic HTTP authentication
*
* @return boolean authentication successful or not
*/
public function doBasicHTTPAuth() {
$path = APPLICATION_PATH .'/configs/passwdBasic.txt';
$resolver = new Zend_Auth_Adapter_Http_Resolver_File($path);
$config = array(
'accept_schemes' => 'basic',
'realm' => 'Admin Area',
'digest_domains' => '/index',
'nonce_timeout' => 3600,
);
$adapter = new Zend_Auth_Adapter_Http($config);
$adapter->setBasicResolver($resolver);
$request = $this->getRequest();
$response = $this->getResponse();
$adapter->setRequest($request);
$adapter->setResponse($response);
$result = $adapter->authenticate();
if (!$result->isValid()) {
// Bad userame/password, or canceled password prompt
return false;
} else {
return true;
}
}
}
IndexController.php
In the preDispatch() function, public actions that do not require authentication are specified. For all other actions in the controller, basic HTTP Authentication using the above helper. For this example 'index' and 'failedauth' actions are public, while actions named 'protected' and 'edit' require authentication.<?php
class IndexController extends Zend_Controller_Action {
public function init() {
/* Initialize action controller here */
}
public function preDispatch() {
//any action not in this array will require Auth
$publicActions = array('index','failedauth');
$action = $this->getRequest()->getActionName();
if (!in_array($action, $publicActions)) {
//if requested action is non public one,
//then do authenticated
if ($this->_helper->_HTTPAuth->doBasicHTTPAuth() == false) {
$this->_forward('failedauth');
return;
}
}
}
public function indexAction() {
// public action
}
public function protectedAction() {
// protected action
}
public function editAction() {
// protected action
}
public function failedauthAction() {
//public action
}
}
PHPUnit test case IndexControllerTest.php
Testing of failed authentication is quite easy. The trick is with testing correct authentication, since we have to sent a correct HTTP header to the server. In our case, the username is 'admin' and the password is 'admin12', so before we dispatch the request for a protectedAction, we need to set a header as follows:$this->request->setHeader('Authorization','Basic YWRtaW46YWRtaW4xMg==');
where “YWRtaW46YWRtaW4xMg==” is a result of base64_encode("admin:admin12") function.The full code of the IndexControllerTest.php is
<?php
class IndexControllerTest extends ControllerTestCase {
/**
* Check if we go to index controller
*/
public function testIndexController() {
$this->dispatch('/');
$this->assertController('index');
$this->assertAction('index');
}
/**
* Prived an array with protected actions
*
* @return array
*/
public function getProtectedActions() {
return array(
array('/index/protected'),
array('/index/edit'),
);
}
/**
* Going to /index/protected should result in Www-Authenticate header
* and since we do not send header with correct passwors and user
* we should be forwarded to failedauth action and see 'Failed authentification'
*
* @dataProvider getProtectedActions
*/
public function testAccessWithoutAuth($action='/index/protected') {
$this->dispatch($action);
$this->assertHeader('Www-Authenticate');
$this->assertAction('failedauth');
$this->assertQueryContentContains('h1', 'Failed Authentication');
}
/**
* Going to /index/index, but this time we send a header
* with some inccorect password:username, codded as base64_encode.
* Since username and password are inccorect we should get 'Www-Authenticate'
* header.
*
* @dataProvider getProtectedActions
*
*/
public function testAccessWithInccorectAuthCredentials($action='/index/protected') {
//send header with inccorect user and password, e.g.
//YWRtaW46d3JvbnRwYXNzd29yZA== is equal to base64_encode("admin:wrontpassword")
$this->request->setHeader('Authorization','Basic YWRtaW46d3JvbnRwYXNzd29yZA==');
$this->dispatch($action);
$this->assertHeader('Www-Authenticate');
$this->assertNotQueryContentContains('h1', 'Successful Authentication');
}
/**
* Going to /index/index, but this time we send a header
* with CORRECT password:username, codded as base64_encode.
* Since username and password are ccorect we should not get 'Www-Authenticate'
* header and be able to see protected content.
*
* @dataProvider getProtectedActions
*/
public function testAccessWithCorrectAuthCredentials($action='/index/protected') {
//send header with correct user and password i.e.
//YWRtaW46YWRtaW4xMg== is equal to base64_encode("admin:admin12")
$this->request->setHeader('Authorization','Basic YWRtaW46YWRtaW4xMg==');
$this->dispatch($action);
$this->assertNotHeader('Www-Authenticate');
$this->assertQueryContentContains('h1', 'Successful Authentication');
if ($action == '/index/protected') {
$this->assertQueryContentContains('h2', 'Protected action');
} elseif ($action == '/index/edit') {
$this->assertQueryContentContains('h2', 'Edit action');
}
}
}
Some example screenshots
After clicking “Go to protected action” we are ask for credentials:Failed Authentication:
Successful access to protected action:
Execution of PHPUnit