diff --git a/library/Unl/Auth/Adapter/Cas.php b/library/Unl/Auth/Adapter/Cas.php index 6bc4d0f66479a57fb593d41d7c3044463460371c..ec7b8e99c7b77761303eee4ecd2426085cda221d 100644 --- a/library/Unl/Auth/Adapter/Cas.php +++ b/library/Unl/Auth/Adapter/Cas.php @@ -33,11 +33,21 @@ class Unl_Auth_Adapter_Cas implements Zend_Auth_Adapter_Interface private $_ticket; /** - * Whether or not to force a login. + * Whether or not to set either the gateway or renew parameters in the login request. * - * @var bool + * @var int */ - private $_forceLogin; + 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; + /** * Constructor * @@ -47,16 +57,17 @@ class Unl_Auth_Adapter_Cas implements Zend_Auth_Adapter_Interface * @param bool $forceLogin * @return void */ - public function __construct($serviceUrl, $casUrl, $ticket = null, $forceLogin = false) + public function __construct($serviceUrl, $casUrl, $ticket = null, $gatewayOrRenew = self::PARAM_DEFAULT) { $this->setServiceUrl($serviceUrl); $this->_casUrl = $casUrl; - $this->_forceLogin = $forceLogin; + $this->_gatewayOrRenew = $gatewayOrRenew; if ($ticket) { $this->_ticket = $ticket; } elseif (! empty($_GET["ticket"])) { $this->_ticket = $_GET['ticket']; } + $this->_session = new Zend_Session_Namespace(__CLASS__); } /** @@ -83,6 +94,7 @@ class Unl_Auth_Adapter_Cas implements Zend_Auth_Adapter_Interface $paramString = "?" . implode("&", $params); } } + $paramString = ''; $this->_serviceUrl = urlencode($serviceUrl . $paramString); } @@ -146,14 +158,110 @@ class Unl_Auth_Adapter_Cas implements Zend_Auth_Adapter_Interface 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; + } + } + + /** + * Returns whether or not the login request will have the "renew" parameter set. + * @return bool + */ + public function getRenew() + { + return ($this->_gatewayOrRenew == self::PARAM_RENEW); + } + + /** + * Alias to setRenew() + * + * @deprecated + * @param bool $forceLogin + */ public function setForceLogin($forceLogin) { - $this->_forceLogin = $forceLogin; + return $this->setRenew($forceLogin); } + /** + * Alias to getRenew() + * + * @deprecated + * @return bool + */ public function getForceLogin() { - return $this->_forceLogin; + 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'; + } + + /** + * This is a stop-gap measure until the CAS server handles the uni-wide cookie on its own. + * This should be called whenever you would redirect a user to the logout URL. + */ + public function clearIdentity() + { + $this->_authenticationFailed('N/A'); } /** @@ -170,13 +278,13 @@ class Unl_Auth_Adapter_Cas implements Zend_Auth_Adapter_Interface { if ($this->_ticket) { if ($this->_validateTicket($this->_ticket)) { + setcookie('sso', $this->getUsername(), 0, '/', '.unl.edu'); return new Zend_Auth_Result(Zend_Auth_Result::SUCCESS, $this->getUsername(), array('Authentication successful.')); } else { - return new Zend_Auth_Result(Zend_Auth_Result::FAILURE, null, array('Authentication failed.')); + return $this->_authenticationFailed('Invalid or expired CAS ticket.'); } } else { - header("Location: " . $this->_casUrl . "/login?service=" . $this->_serviceUrl . ($this->_forceLogin ? "&renew=true" : "")); - return new Zend_Auth_Result(Zend_Auth_Result::FAILURE, null, array('No CAS Ticktet.')); + return $this->_authenticationFailed('No CAS Ticktet.'); } } @@ -216,4 +324,14 @@ class Unl_Auth_Adapter_Cas implements Zend_Auth_Adapter_Interface } return false; } + + /** + * Helper function called when a failure result needs to be returned. + * @param $message Failure message + */ + private function _authenticationFailed($message) + { + setcookie('sso', '', 1, '/', '.unl.edu'); + return new Zend_Auth_Result(Zend_Auth_Result::FAILURE, null, array($message)); + } } \ No newline at end of file