Commit 21d3f51b authored by Tim Steiner's avatar Tim Steiner
Browse files

Update the CAS Auth adapter to use the Unl_Cas class. This change will...

Update the CAS Auth adapter to use the Unl_Cas class.  This change will require changes if you use the CAS Auth Adapter.
parent ce94225d
......@@ -4,278 +4,50 @@ require_once 'Zend/Auth/Adapter/Interface.php';
class Unl_Auth_Adapter_Cas implements Zend_Auth_Adapter_Interface
{
/**
* Web service url
*
* @var string
*/
private $_serviceUrl;
/**
* CAS validation url
*
* @var string
*/
private $_casUrl;
/**
* Username returned by cas validation request
*
* @var string
*/
private $_username;
/**
* Cas ticket issued by cas login service
*
* @var string
*/
private $_ticket;
/**
* Whether or not to set either the gateway or renew parameters in the login request.
*
* @var int
* The Unl_Cas adapter to use to authenticate users.
* @var Unl_Cas
*/
private $_gatewayOrRenew;
const PARAM_GATEWAY = 1;
const PARAM_DEFAULT = 2;
const PARAM_RENEW = 3;
/**
* Session storage use to prevent infinate redirect loops when in gateway mode.
* @var Zend_Session_Namespace
*/
private $_session;
/**
* Cache used to store valid service tickets.
* @var Zend_Cache_Core
*/
private $_ticketCache;
protected $_adapter;
/**
* Constructor
*
* @param string $serviceUrl
* @param string $casValidateUrl
* @param string $ticket
* @param bool $forceLogin
* @return void
*/
public function __construct($serviceUrl, $casUrl, $ticket = null, $gatewayOrRenew = self::PARAM_DEFAULT)
{
$this->setServiceUrl($serviceUrl);
$this->_casUrl = $casUrl;
$this->_gatewayOrRenew = $gatewayOrRenew;
if ($ticket) {
$this->_ticket = $ticket;
} elseif (! empty($_GET["ticket"])) {
$this->_ticket = $_GET['ticket'];
}
$this->_session = new Zend_Session_Namespace(__CLASS__);
}
/**
* Set the service url
*
* This function appends all get variables but strips out the ticket
* The ticket parameter is appended by the CAS server, if it is left
* in the service URL will be different from the one sent to the CAS
* server. Because of this, authentication will fail.
*
* @param string $serviceUrl
*/
public function setServiceUrl($serviceUrl)
{
$params = array();
$paramString = "";
if (sizeof($_GET) > 0) {
foreach ($_GET as $key => $value) {
if ($key != "ticket") {
$params[] = $key . ($value != "" ? "=" . $value : "");
}
}
if(sizeof($params) > 0){
$paramString = "?" . implode("&", $params);
}
}
$paramString = '';
$this->_serviceUrl = urlencode($serviceUrl . $paramString);
}
/**
* Set the validation url
*
* @param string $validationUrl
* @param Unl_Cas $adapter
*/
public function setCasUrl($casUrl)
public function __construct(Unl_Cas $adapter)
{
$this->_casUrl = $casUrl;
}
/**
* Set the ticket to be validated
*
* @param string $ticket
*/
public function setTicket($ticket)
{
$this->_ticket = $ticket;
}
/**
* Returns authentication url
*
* @return string
*/
public function getServiceUrl()
{
return $this->_serviceUrl;
}
/**
* Returns validation service url
*
* @return string
*/
public function getCasUrl()
{
return $this->_casUrl;
}
/**
* Returns the username, if successfully authenticated
*
* @return string
*/
public function getUsername()
{
return $this->_username;
}
/**
* Returns the ticket to be validated
*
* @return string
*/
public function getTicket()
{
return $this->_ticket;
}
/**
* Sets the "renew" parameter in the login request, causing the CAS server
* to _always_ ask for the user to authenticate.
*
* @param bool $renew
*/
public function setRenew($renew = TRUE)
{
if ($renew) {
$this->_gatewayOrRenew = self::PARAM_RENEW;
} else {
$this->_gatewayOrRenew = self::PARAM_DEFAULT;
}
$this->setAdapter($adapter);
}
/**
* Returns whether or not the login request will have the "renew" parameter set.
* @return bool
* Changes the Unl_Cas adapter used by the object.
* @param Unl_Cas $adapter
*/
public function getRenew()
public function setAdapter(Unl_Cas $adapter)
{
return ($this->_gatewayOrRenew == self::PARAM_RENEW);
$this->_adapter = $adapter;
}
/**
* Alias to setRenew()
*
* @deprecated
* @param bool $forceLogin
* Gets the Unl_Cas adapter used by the object.
* @return Unl_Cas
*/
public function setForceLogin($forceLogin)
public function getAdapter()
{
return $this->setRenew($forceLogin);
}
/**
* Alias to getRenew()
*
* @deprecated
* @return bool
*/
public function getForceLogin()
{
return $this->_getRenew();
}
/**
* Sets the "gateway" parameter in the login request, causing the CAS server
* to _never_ ask for the user to authenticate.
* @param bool $gateway
*/
public function setGateway($gateway = TRUE)
{
if ($gateway) {
$this->_gatewayOrRenew = self::PARAM_GATEWAY;
} else {
$this->_gatewayOrRenew = self::PARAM_DEFAULT;
}
}
/**
* Returns whether or not the login request will have the "gateway" parameter set.
* @return bool
*/
public function getGateway()
{
return ($this->_gatewayOrRenew == self::PARAM_GATEWAY);
}
/**
* Returns the URL to the CAS login page.
* Intended usage: $this->_redirect($cas->getLoginUrl());
*/
public function getLoginUrl()
{
$location = $this->_casUrl . '/login?service=' . $this->_serviceUrl;
switch ($this->_gatewayOrRenew) {
case self::PARAM_GATEWAY:
$location .= '&gateway=true';
$this->_session->gatewayTried = TRUE;
break;
case self::PARAM_RENEW:
$location .= '&renew=true';
break;
}
return $location;
}
/**
* Returns the URL to the CAS logout page.
* Intended usage: $this->_redirect($cas->getLogoutUrl());
*/
public function getLogoutUrl()
{
return $this->_casUrl . '/logout';
return $this->_adapter;
}
/**
* Authenticates ticket
*
* This ticket it received from the CAS after
* user has authenticated. It must be supplied
* manually.
*
* @param string $ticket
* @param return Zend_Auth_Result
* @return Zend_Auth_Result
*/
public function authenticate()
{
if ($this->_ticket) {
if ($this->_validateTicket($this->_ticket)) {
return new Zend_Auth_Result(Zend_Auth_Result::SUCCESS, $this->getUsername(), array('Authentication successful.'));
if ($this->_adapter->getTicket()) {
if ($this->_adapter->validateTicket()) {
return new Zend_Auth_Result(Zend_Auth_Result::SUCCESS, $this->_adapter->getUsername(), array('Authentication successful.'));
} else {
return $this->_authenticationFailed('Invalid or expired CAS ticket.');
}
......@@ -284,117 +56,4 @@ class Unl_Auth_Adapter_Cas implements Zend_Auth_Adapter_Interface
}
}
/**
* Generate Zend_Http request for the validation service and get the response
*
* @param string $ticket
* @return bool
*/
private function _validateTicket($ticket)
{
require_once ('Zend/Http/Client.php');
$client = new Zend_Http_Client($this->_casUrl . '/serviceValidate?service=' . $this->_serviceUrl . '&ticket=' . $ticket);
$response = $client->request();
if ($response->isSuccessful() && $this->_parseResponse($response->getBody())) {
$this->_addValidTicket($ticket);
$this->_session->ticket = $ticket;
$this->_session->username = $this->getUsername();
return true;
}
return false;
}
/**
* Parse the Zend_Http response, determine success.
*
* @param string $response
* @return bool
*/
private function _parseResponse($response)
{
$xml = new DOMDocument();
if ($xml->loadXML($response)) {
if ($success = $xml->getElementsByTagName('authenticationSuccess')) {
if ($success->length > 0 && $uid = $success->item(0)->getElementsByTagName('user')) {
$this->_username = $uid->item(0)->nodeValue;
return true;
}
}
}
return false;
}
/**
* Helper function called when a failure result needs to be returned.
* @param $message Failure message
*/
private function _authenticationFailed($message)
{
return new Zend_Auth_Result(Zend_Auth_Result::FAILURE, null, array($message));
}
private function _addValidTicket($ticket)
{
$this->_getTicketCache()->save(time(), hash('sha512', $ticket));
}
private function _removeValidTicket($ticket)
{
echo 'Removing ticket ' . $ticket . PHP_EOL;
$this->_getTicketCache()->remove(hash('sha512', $ticket));
}
private function _isStillValidTicket($ticket)
{
return (bool) ($this->_getTicketCache()->load(hash('sha512', $ticket)));
}
private function _getTicketCache()
{
if (!$this->_ticketCache) {
$cache_dir = session_save_path();
if (!$cache_dir) {
$cache_dir = '/tmp';
}
$frontendOptions = array(
'lifetime' => 60*60,
'automatic_serialization' => TRUE
);
$backendOptions = array(
'cache_dir' => $cache_dir
);
$this->_ticketCache = Zend_Cache::factory('Core', 'File', $frontendOptions, $backendOptions);
}
return $this->_ticketCache;
}
public function setTicketCache(Zend_Cache_Core $cache)
{
$this->_ticketCache = $cache;
}
public function setTicketLifetime($lifetime)
{
$this->_getTicketCache()->setLifetime($lifetime);
}
public function isTicketExpired()
{
return !$this->_isStillValidTicket($this->_session->ticket);
}
public function handleLogoutRequest($saml)
{
$request = new DOMDocument();
if (!$request->loadXML($saml)) {
return;
}
$ticketNodes = $request->getElementsByTagName('SessionIndex');
if ($ticketNodes->length == 0) {
return;
}
$ticket = $ticketNodes->item(0)->textContent;
$this->_removeValidTicket($ticket);
exit;
}
}
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment