EDIT: Sorry for the large amount of code here; I'm not sure exactly what's going on so I included more to be safe.
I've currently got a login page which farms out to a central authentication service. I'd like to do a permissions check on the user. If the user is not logged in, I'd like to redirect them to the login page, and have the login page redirect them to do whatever action it was they were originally doing, running the access check again. If they don't have permission, I want to redirect them to an access denied page.
Here's what I've done so far:
Added this line to my application.ini:
resources.frontController.actionHelperPaths.Cas_Controller_Action_Helper = APPLICATION_PATH "/controllers/helpers"
Created the file $/application/controllers/helpers/PermissionRequire.php:
<?php
/**
* This class is used in order to require that a user have a given privilege before continuing.
*
* @copyright 2011 Case Western Reserve University, College of Arts and Sciences
* @author Billy O'Neal III (bro4@case.edu)
*/
class Cas_Controller_Action_Helper_PermissionRequire extends Zend_Controller_Action_Helper_Abstract
{
/**
* Cleans up the supplied list of privileges. Strings are turned into the real privilege objects (Based on name),
* privilege objects are left alone.
*
* @static
* @param array|Privilege|string $privileges
* @return array
*/
private static function CleanPrivileges($privileges)
{
if (!is_array($privileges))
{
$privileges =
array
(
$privileges
);
}
$strings = array_filter($privileges, 'is_string');
$objects = array_filter($privileges, function($o)
{
return $o instanceof Privilege;
});
$databaseObjects = PrivilegeQuery::create()->filterByName($strings)->find();
return array_combine($objects, $databaseObjects);
}
/**
* Generic implementation for checking whether a user can visit a page.
* @param Privilege|string|array $privileges Any number of privileges which are required to access the given
* page. If ANY privilege is held by the user, access is allowed.
* @param AccessControlList The acl which is being checked. Defaults to the application.
*/
public function direct($privileges, $acl = null)
{
$privileges = self::CleanPrivileges($privileges);
if ($acl === null)
{
$acl = AccessControlListQuery::getApplication();
}
$redirector = $this->getActionController()->getHelper('redirector');
/** @var Zend_Controller_Action_Helper_Redirector $redirector */
$redirector->setCode(307);
if (Cas_Model_CurrentUser::IsLoggedIn() && (!Cas_Model_CurrentUser::AccessCheck($acl, $privileges)))
{
$redirector->gotoSimple('accessdenied', 'login');
}
else
{
$returnData = new Zend_Session_Namespace('Login');
$returnData->params = $this->getRequest()->getParams();
$redirector->setGotoSimple('login', 'login');
$redirector->redirectAndExit();
}
}
}
And here's the LoginController:
<?php
/**
* LoginController - Controls login access for users
*/
require_once 'CAS.php';
class LoginController extends Zend_Controller_Action
{
/**
* Logs in to the system, and redirects to the calling action.
*
* @return void
*/
public function loginAction()
{
//Authenticate with Login.Case.Edu.
phpCAS::client(CAS_VERSION_2_0, 'login.case.edu', 443, '/cas', false);
phpCAS::setNoCasServerValidation();
phpCAS::forceAuthentication();
$user = CaseIdUser::createFromLdap(phpCAS::getUser());
Cas_Model_CurrentUser::SetCurrentUser($user->getSecurityIdentifier());
$returnData = new Zend_Session_Namespace('Login');
/** @var array $params */
$redirector = $this->_helper->redirector;
/** @var Zend_Controller_Action_Helper_Redirector $redirector */
$redirector->setGotoRoute($returnData->params, 'default', true);
$returnData->unsetAll();
$redirector->redirectAndExit();
}
/**
* Logs the user out of the system, and redirects them to the index page.
*
* @return void
*/
public function logoutAction()
{
Cas_Model_CurrentUser::Logout();
$this->_helper->redirector->gotoRoute('index','index', 'default', true);
}
/**
* Returns an access denied view.
*
* @return void
*/
public function accessdeniedAction()
{
//Just display the view and punt.
}
}
The problem is that in the login controller when it's preparing the URL to redirect the user to, it seems "params" is null. Also, this won't work when there's POST data to the controller calling $this->_helper->permissionRequire(SOME PRIVILEGE).
Is there a better way of storing the entire state of a request, and coughing up a redirect which exactly matches that request?
P.S. Oh, and here's an example controller using that helper:
<?php
/**
* Serves as the index page; does nothing but display views.
*/
class IndexController extends Zend_Controller_Action
{
public function indexAction()
{
$renderer = $this->getHelper('ViewRenderer');
/** @var $renderer Zend_Controller_Action_Helper_ViewRenderer */
if (Cas_Model_CurrentUser::IsLoggedIn())
{
$this->_helper->permissionRequire(Cas_Model_Privilege::GetLogin());
$this->render('loggedin');
}
else
{
$this->render('loggedout');
}
}
}