108 (empty($this->_output_header)
109 ?
'<html><head><title>__TITLE__</title></head><body><h1>__TITLE__</h1>' 110 : $this->_output_header)
135 empty($this->_output_footer)?
137 '<hr><address>phpCAS __PHPCAS_VERSION__ ' 138 .$lang->getUsingServer()
139 .
' <a href="__SERVER_BASE_URL__">__SERVER_BASE_URL__</a> (CAS __CAS_VERSION__)</a></address></body></html>' 155 if (gettype($header) !=
'string')
158 $this->_output_header = $header;
171 if (gettype($footer) !=
'string')
174 $this->_output_footer = $footer;
206 if (gettype($lang) !=
'string')
213 '$className must implement the CAS_Languages_LanguageInterface' 216 $this->_lang = $lang;
227 return new $classname();
266 'hostname' =>
'none',
277 return $this->_server[
'version'];
287 return $this->_server[
'hostname'];
297 return $this->_server[
'port'];
307 return $this->_server[
'uri'];
318 if ( empty($this->_server[
'base_url']) ) {
321 $this->_server[
'base_url'] .=
':' 322 .$this->_getServerPort();
326 return $this->_server[
'base_url'];
343 if ( empty($this->_server[
'login_url']) ) {
346 $url = $this->_server[
'login_url'];
351 } elseif ($gateway) {
370 if (gettype($url) !=
'string')
373 return $this->_server[
'login_url'] = $url;
387 if (gettype($url) !=
'string')
390 return $this->_server[
'service_validate_url'] = $url;
404 if (gettype($url) !=
'string')
407 return $this->_server[
'proxy_validate_url'] = $url;
421 if (gettype($url) !=
'string')
424 return $this->_server[
'saml_validate_url'] = $url;
437 if ( empty($this->_server[
'service_validate_url']) ) {
449 .
'p3/serviceValidate';
454 $this->_server[
'service_validate_url'],
455 'service='.urlencode($this->
getURL())
469 if ( empty($this->_server[
'saml_validate_url']) ) {
478 $this->_server[
'saml_validate_url'],
479 'TARGET='.urlencode($this->
getURL())
494 if ( empty($this->_server[
'proxy_validate_url']) ) {
497 $this->_server[
'proxy_validate_url'] =
'';
500 $this->_server[
'proxy_validate_url'] = $this->
_getServerBaseURL().
'proxyValidate';
503 $this->_server[
'proxy_validate_url'] = $this->
_getServerBaseURL().
'p3/proxyValidate';
508 $this->_server[
'proxy_validate_url'],
509 'service='.urlencode($this->
getURL())
524 if ( empty($this->_server[
'proxy_url']) ) {
527 $this->_server[
'proxy_url'] =
'';
535 return $this->_server[
'proxy_url'];
546 if ( empty($this->_server[
'logout_url']) ) {
549 return $this->_server[
'logout_url'];
562 if (gettype($url) !=
'string')
565 return $this->_server[
'logout_url'] = $url;
583 $this->_curl_options[$key] = $value;
615 $obj =
new $className;
618 '$className must implement the CAS_Request_RequestInterface' 621 $this->_requestImplementation = $className;
642 $this->_clearTicketsFromUrl =
false;
668 $this->_casAttributeParserCallbackFunction = $function;
669 $this->_casAttributeParserCallbackArgs = $additionalArgs;
702 $this->_postAuthenticateCallbackFunction = $function;
703 $this->_postAuthenticateCallbackArgs = $additionalArgs;
732 $this->_signoutCallbackFunction = $function;
733 $this->_signoutCallbackArgs = $additionalArgs;
766 $dbg = debug_backtrace();
767 $this->_authentication_caller = array (
768 'file' => $dbg[1][
'file'],
769 'line' => $dbg[1][
'line'],
770 'method' => $dbg[1][
'class'] .
'::' . $dbg[1][
'function'],
771 'result' => (
boolean)
$auth 783 return !empty($this->_authentication_caller);
812 return $this->_authentication_caller[
'result'];
827 if (!$this->_authentication_caller[
'result']) {
829 'authentication was checked (by ' 833 .
') but the method returned false' 849 return $this->_authentication_caller[
'file'];
863 return $this->_authentication_caller[
'line'];
877 return $this->_authentication_caller[
'method'];
911 $changeSessionID =
true,
912 \SessionHandlerInterface $sessionHandler = null
915 if (gettype($server_version) !=
'string')
917 if (gettype($proxy) !=
'boolean')
919 if (gettype($server_hostname) !=
'string')
921 if (gettype($server_port) !=
'integer')
923 if (gettype($server_uri) !=
'string')
925 if (gettype($changeSessionID) !=
'boolean')
928 if (empty($sessionHandler)) {
940 if (session_id() ===
"") {
946 if (!isset($_SESSION[static::PHPCAS_SESSION_PREFIX])
947 || !is_array($_SESSION[static::PHPCAS_SESSION_PREFIX])) {
948 $_SESSION[static::PHPCAS_SESSION_PREFIX] = array();
959 $this->_proxy = $proxy;
968 $_SESSION[static::PHPCAS_SESSION_PREFIX][
'service_cookies']
974 if (isset($supportedProtocols[$server_version]) ===
false) {
976 'this version of CAS (`'.$server_version
977 .
'\') is not supported by
phpCAS '.phpCAS::getVersion() 981 if ($server_version === CAS_VERSION_1_0 && $this->isProxy()) { 983 'CAS proxies are not supported in
CAS '.$server_version 987 $this->_server['version
'] = $server_version; 990 if ( empty($server_hostname) 991 || !preg_match('/[\.\d\-a-z]*/
', $server_hostname) 993 phpCAS::error('bad
CAS server hostname (`
'.$server_hostname.'\
')');
995 $this->_server[
'hostname'] = $server_hostname;
998 if ( $server_port == 0
999 || !is_int($server_port)
1001 phpCAS::error(
'bad CAS server port (`'.$server_hostname.
'\')
'); 1003 $this->_server['port
'] = $server_port; 1006 if ( !preg_match('/[\.\d\-_a-z\/]*/
', $server_uri) ) { 1007 phpCAS::error('bad
CAS server URI (`
'.$server_uri.'\
')');
1010 if(strstr($server_uri,
'?') ===
false) $server_uri .=
'/';
1011 $server_uri = preg_replace(
'/\/\//',
'/',
'/'.$server_uri);
1012 $this->_server[
'uri'] = $server_uri;
1016 if(!empty($_GET[
'pgtIou'])&&!empty($_GET[
'pgtId'])) {
1019 } elseif (!empty($_POST[
'pgtIou'])&&!empty($_POST[
'pgtId'])) {
1034 'CAS proxies must be secured to use phpCAS; PGT\'s will not be received from the CAS server' 1040 $ticket = (isset($_GET[
'ticket']) ? $_GET[
'ticket'] : null);
1041 if (preg_match(
'/^[SP]T-/', $ticket) ) {
1043 $this->setTicket($ticket); 1044 unset($_GET['ticket
']); 1045 } else if ( !empty($ticket) ) { 1046 //ill-formed ticket, halt 1048 'ill-formed ticket found in the URL (ticket=`
' 1049 .htmlentities($ticket).'\
')' 1093 $this->_change_session_id = $allowed;
1115 $this->_sessionHandler = $sessionHandler;
1116 if (session_status() !== PHP_SESSION_ACTIVE) {
1117 return session_set_save_handler($this->_sessionHandler,
true);
1134 if (isset($_SESSION[static::PHPCAS_SESSION_PREFIX][$key])) {
1135 return $_SESSION[static::PHPCAS_SESSION_PREFIX][$key];
1155 return isset($_SESSION[static::PHPCAS_SESSION_PREFIX][$key]);
1170 $_SESSION[static::PHPCAS_SESSION_PREFIX][$key] = $value;
1182 if (isset($_SESSION[static::PHPCAS_SESSION_PREFIX][$key])) {
1183 unset($_SESSION[static::PHPCAS_SESSION_PREFIX][$key]);
1195 unset($_SESSION[static::PHPCAS_SESSION_PREFIX]);
1207 if (!is_string($key)) {
1208 throw new InvalidArgumentException(
'Session key must be a string.');
1225 if (!empty($this->_user)) {
1226 $old_session = $_SESSION;
1232 session_id($session_id);
1235 $_SESSION = $old_session;
1238 'Session should only be renamed after successfull authentication' 1243 "Skipping session rename since phpCAS is not handling the session." 1279 $this->_user = $user;
1309 if ( empty($this->_user) ) {
1311 'this method should be used only after '.__CLASS__
1312 .
'::forceAuthentication() or '.__CLASS__.
'::isAuthenticated()' 1336 $this->_attributes = $attributes;
1349 if ( empty($this->_user) ) {
1352 'this method should be used only after '.__CLASS__
1353 .
'::forceAuthentication() or '.__CLASS__.
'::isAuthenticated()' 1369 return !empty($this->_attributes);
1395 return (is_array($this->_attributes)
1396 && array_key_exists($key, $this->_attributes));
1412 return $this->_attributes[$key];
1482 if (gettype($n) !=
'integer')
1485 $this->_cache_times_for_auth_recheck = $n;
1513 if (($unauth_count != -2
1514 && $this->_cache_times_for_auth_recheck == -1)
1515 || ($unauth_count >= 0
1516 && $unauth_count < $this->_cache_times_for_auth_recheck)
1518 if ($this->_cache_times_for_auth_recheck != -1) {
1521 'user is not authenticated (cached for ' 1522 .$unauth_count.
' times of ' 1523 .$this->_cache_times_for_auth_recheck.
')' 1527 'user is not authenticated (cached for until login pressed)' 1561 'ticket was present and will be discarded, use renewAuthenticate()' 1563 if ($this->_clearTicketsFromUrl) {
1565 session_write_close();
1566 header(
'Location: '.$this->
getURL());
1572 'Already authenticated, but skipping ticket clearing since setNoClearTicketsFromUrl() was used.' 1580 'user was already authenticated, no need to look for tickets' 1594 'CAS 1.0 ticket `'.$this->
getTicket().
'\' is present
' 1596 $this->validateCAS10( 1597 $validate_url, $text_response, $tree_response, $renew 1598 ); // if it fails, it halts 1600 'CAS 1.0 ticket `
'.$this->getTicket().'\
' was validated' 1612 $this->validateCAS20( 1613 $validate_url, $text_response, $tree_response, $renew 1614 ); // note: if it fails, it halts 1616 'CAS '.$this->getServerVersion().' ticket `
'.$this->getTicket().'\
' was validated' 1620 $validate_url, $text_response, $tree_response
1623 $this->setSessionValue('pgt
', $this->_getPGT()); 1625 $this->setSessionValue('user
', $this->_getUser()); 1626 if (!empty($this->_attributes)) { 1627 $this->setSessionValue('attributes
', $this->_attributes); 1629 $proxies = $this->getProxies(); 1630 if (!empty($proxies)) { 1631 $this->setSessionValue('proxies
', $this->getProxies()); 1634 $logoutTicket = $this->getTicket(); 1636 case SAML_VERSION_1_1: 1637 // if we have a SAML ticket, validate it. 1639 'SAML 1.1 ticket `
'.$this->getTicket().'\
' is present' 1642 $validate_url, $text_response, $tree_response, $renew
1645 'SAML 1.1 ticket `'.$this->
getTicket().
'\' was validated
' 1647 $this->setSessionValue('user
', $this->_getUser()); 1648 $this->setSessionValue('attributes
', $this->_attributes); 1650 $logoutTicket = $this->getTicket(); 1653 phpCAS::trace('Protocoll error
'); 1657 // no ticket given, not authenticated 1658 phpCAS::trace('no ticket found
'); 1661 // Mark the auth-check as complete to allow post-authentication 1662 // callbacks to make use of phpCAS::getUser() and similar methods 1663 $this->markAuthenticationCall($res); 1666 // call the post-authenticate callback if registered. 1667 if ($this->_postAuthenticateCallbackFunction) { 1668 $args = $this->_postAuthenticateCallbackArgs; 1669 array_unshift($args, $logoutTicket); 1670 call_user_func_array( 1671 $this->_postAuthenticateCallbackFunction, $args 1675 // if called with a ticket parameter, we need to redirect to the 1676 // app without the ticket so that CAS-ification is transparent 1677 // to the browser (for later POSTS) most of the checks and 1678 // errors should have been made now, so we're safe
for redirect
1681 if ($this->_clearTicketsFromUrl) {
1683 session_write_close();
1684 header(
'Location: '.$this->
getURL());
1719 if ($this->
_rebroadcast&&!isset($_POST[
'rebroadcast'])) {
1740 .$this->getSessionValue('pgt
').'\
'' 1759 .
'\') but PGT is empty
' 1761 // unset all tickets to enforce authentication 1762 $this->clearSessionValues(); 1763 $this->setTicket(''); 1764 } elseif ( !$this->isSessionAuthenticated() 1765 && $this->getSessionValue('pgt
') 1767 // these two variables should be empty or not empty at the same time 1769 'PGT found (`
'.$this->getSessionValue('pgt
') 1770 .'\
') but username is empty' 1821 session_write_close();
1822 if (php_sapi_name() ===
'cli') {
1830 printf(
'<p>'. $lang->getShouldHaveBeenRedirected().
'</p>',
$cas_url);
1849 $paramSeparator =
'?';
1850 if (isset($params[
'url'])) {
1852 . urlencode($params[
'url']);
1853 $paramSeparator =
'&';
1855 if (isset($params[
'service'])) {
1857 . urlencode($params[
'service']);
1865 if (session_status() === PHP_SESSION_NONE) {
1873 printf(
'<p>'.$lang->getShouldHaveBeenRedirected().
'</p>',
$cas_url);
1886 return !empty($_POST[
'logoutRequest']);
1908 && is_null($this->_signoutCallbackFunction)
1911 "phpCAS can't handle logout requests if it is not allowed to change session_id." 1915 $decoded_logout_rq = urldecode($_POST[
'logoutRequest']);
1918 if ($check_client) {
1919 if ($allowed_clients === array()) {
1922 $client_ip = $_SERVER[
'REMOTE_ADDR'];
1923 $client = gethostbyaddr($client_ip);
1925 foreach ($allowed_clients as $allowed_client) {
1926 if ((
$client == $allowed_client)
1927 || ($client_ip == $allowed_client)
1930 "Allowed client '".$allowed_client
1931 .
"' matches, logout request is allowed" 1937 "Allowed client '".$allowed_client.
"' does not match" 1949 if ($this->
_rebroadcast && !isset($_POST[
'rebroadcast'])) {
1954 "|<samlp:SessionIndex>(.*)</samlp:SessionIndex>|",
1955 $decoded_logout_rq, $tick, PREG_OFFSET_CAPTURE, 3
1957 $wrappedSamlSessionIndex = preg_replace(
1958 '|<samlp:SessionIndex>|',
'', $tick[0][0]
1960 $ticket2logout = preg_replace(
1961 '|</samlp:SessionIndex>|',
'', $wrappedSamlSessionIndex
1966 if ($this->_signoutCallbackFunction) {
1968 array_unshift($args, $ticket2logout);
1969 call_user_func_array($this->_signoutCallbackFunction, $args);
1979 if (session_id() !==
"") {
1984 session_id($session_id);
1985 $_COOKIE[session_name()]=$session_id;
1986 $_GET[session_name()]=$session_id;
2048 $this->_ticket = $st;
2058 return !empty($this->_ticket);
2111 if (gettype($cert) !=
'string') {
2114 if (gettype($validate_cn) !=
'boolean') {
2117 if (!file_exists($cert)) {
2120 $this->_cas_server_ca_cert = $cert;
2121 $this->_cas_server_cn_validate = $validate_cn;
2131 $this->_no_cas_server_validation =
true;
2150 public function validateCAS10(&$validate_url,&$text_response,&$tree_response,$renew=
false)
2155 .
'&ticket='.urlencode($this->
getTicket());
2159 $validate_url .=
'&renew=true';
2163 if ( !$this->
_readURL($validate_url, $headers, $text_response, $err_msg) ) {
2165 'could not open URL \''.$validate_url.
'\' to validate (
'.$err_msg.')
' 2167 throw new CAS_AuthenticationException( 2168 $this, 'CAS 1.0 ticket not validated
', $validate_url, 2169 true/*$no_response*/ 2173 if (preg_match('/^no\n/
', $text_response)) { 2174 phpCAS::trace('Ticket has not been validated
'); 2175 throw new CAS_AuthenticationException( 2176 $this, 'ST not validated
', $validate_url, false/*$no_response*/, 2177 false/*$bad_response*/, $text_response 2179 } else if (!preg_match('/^yes\n/
', $text_response)) { 2180 phpCAS::trace('ill-formed response
'); 2181 throw new CAS_AuthenticationException( 2182 $this, 'Ticket not validated
', $validate_url, 2183 false/*$no_response*/, true/*$bad_response*/, $text_response 2186 // ticket has been validated, extract the user name 2187 $arr = preg_split('/\n/
', $text_response); 2188 $this->_setUser(trim($arr[1])); 2190 $this->_renameSession($this->getTicket()); 2192 // at this step, ticket has been validated and $this->_user has been set, 2193 phpCAS::traceEnd(true); 2200 // ######################################################################## 2202 // ######################################################################## 2226 public function validateSA(&$validate_url,&$text_response,&$tree_response,$renew=false) 2228 phpCAS::traceBegin(); 2230 // build the URL to validate the ticket 2231 $validate_url = $this->getServerSamlValidateURL(); 2235 $validate_url .= '&renew=
true'; 2238 // open and read the URL 2239 if ( !$this->_readURL($validate_url, $headers, $text_response, $err_msg) ) { 2241 'could not open URL \
''.$validate_url.
'\' to validate (
'.$err_msg.')
' 2243 throw new CAS_AuthenticationException( 2244 $this, 'SA not validated
', $validate_url, true/*$no_response*/ 2248 phpCAS::trace('server version:
'.$this->getServerVersion()); 2250 // analyze the result depending on the version 2251 switch ($this->getServerVersion()) { 2252 case SAML_VERSION_1_1: 2253 // create new DOMDocument Object 2254 $dom = new DOMDocument(); 2255 // Fix possible whitspace problems 2256 $dom->preserveWhiteSpace = false; 2257 // read the response of the CAS server into a DOM object 2258 if (!($dom->loadXML($text_response))) { 2259 phpCAS::trace('dom->loadXML() failed
'); 2260 throw new CAS_AuthenticationException( 2261 $this, 'SA not validated
', $validate_url, 2262 false/*$no_response*/, true/*$bad_response*/, 2266 // read the root node of the XML tree 2267 if (!($tree_response = $dom->documentElement)) { 2268 phpCAS::trace('documentElement() failed');
2270 $this, 'SA not validated', $validate_url,
2274 }
else if ( $tree_response->localName != 'Envelope' ) {
2277 'bad XML root node (should be `Envelope\' instead of `' 2278 .$tree_response->localName.
'\'' 2281 $this,
'SA not validated', $validate_url,
2285 }
else if ($tree_response->getElementsByTagName(
"NameIdentifier")->length != 0) {
2287 $success_elements = $tree_response->getElementsByTagName(
"NameIdentifier");
2289 $user = trim($success_elements->item(0)->nodeValue);
2295 phpCAS::trace(
'no <NameIdentifier> tag found in SAML payload');
2297 $this,
'SA not validated', $validate_url,
2325 $attr_array = array();
2328 $dom =
new DOMDocument();
2330 $dom->preserveWhiteSpace =
false;
2331 if (($dom->loadXML($text_response))) {
2332 $xPath =
new DOMXPath($dom);
2333 $xPath->registerNamespace(
'samlp',
'urn:oasis:names:tc:SAML:1.0:protocol');
2334 $xPath->registerNamespace(
'saml',
'urn:oasis:names:tc:SAML:1.0:assertion');
2335 $nodelist = $xPath->query(
"//saml:Attribute");
2338 foreach ($nodelist as $node) {
2339 $xres = $xPath->query(
"saml:AttributeValue", $node);
2340 $name = $node->getAttribute(
"AttributeName");
2341 $value_array = array();
2342 foreach ($xres as $node2) {
2343 $value_array[] = $node2->nodeValue;
2345 $attr_array[$name] = $value_array;
2348 foreach ($attr_array as $attr_key => $attr_value) {
2349 if (count($attr_value) > 1) {
2350 $this->_attributes[$attr_key] = $attr_value;
2351 phpCAS::trace(
"* " . $attr_key .
"=" . print_r($attr_value,
true));
2353 $this->_attributes[$attr_key] = $attr_value[0];
2453 return !empty($this->_pgt);
2488 $this->_callback_mode = $callback_mode;
2519 $this->_callback_mode_using_post = $callback_mode_using_post;
2551 if ( empty($this->_callback_url) ) {
2553 $final_uri =
'https://';
2555 $request_uri = $_SERVER[
'REQUEST_URI'];
2556 $request_uri = preg_replace(
'/\?.*$/',
'', $request_uri);
2557 $final_uri .= $request_uri;
2558 $this->_callback_url = $final_uri;
2575 if (gettype($url) !=
'string')
2578 return $this->_callback_url = $url;
2591 $pgtId = $_POST[
'pgtId'];
2592 $pgtIou = $_POST[
'pgtIou'];
2594 $pgtId = $_GET[
'pgtId'];
2595 $pgtIou = $_GET[
'pgtIou'];
2597 if (preg_match(
'/^PGTIOU-[\.\-\w]+$/', $pgtIou)) {
2598 if (preg_match(
'/^[PT]GT-[\.\-\w]+$/', $pgtId)) {
2599 phpCAS::trace(
'Storing PGT `'.$pgtId.
'\' (
id=`
'.$pgtIou.'\
')');
2600 $this->_storePGT($pgtId, $pgtIou);
2602 echo
'<?xml version="1.0" encoding="UTF-8"?>' .
"\r\n";
2603 echo
'<proxySuccess xmlns="http://www.yale.edu/tp/cas" />';
2607 echo
'<p>Storing PGT `'.$pgtId.
'\' (
id=`
'.$pgtIou.'\
').</p>';
2636 if (!array_key_exists(
'HTTP_ACCEPT', $_SERVER)) {
2639 if (strpos($_SERVER[
'HTTP_ACCEPT'],
'application/xml') ===
false && strpos($_SERVER[
'HTTP_ACCEPT'],
'text/xml') ===
false) {
2675 if ( !is_object($this->_pgt_storage) ) {
2680 $this->_pgt_storage->init();
2696 $this->_pgt_storage->write($pgt, $pgt_iou);
2712 return $this->_pgt_storage->read($pgt_iou);
2729 if ( is_object($this->_pgt_storage) ) {
2738 $this->_pgt_storage = $storage;
2759 $dsn_or_pdo, $username=
'', $password=
'', $table=
'',
$driver_options=null
2765 if (!(is_object($dsn_or_pdo) && $dsn_or_pdo instanceof PDO) && !is_string($dsn_or_pdo))
2767 if (gettype($username) !=
'string')
2769 if (gettype($password) !=
'string')
2771 if (gettype($table) !=
'string')
2796 if (gettype($path) !=
'string')
2823 private function _validatePGT(&$validate_url,$text_response,$tree_response)
2826 if ( $tree_response->getElementsByTagName(
"proxyGrantingTicket")->length == 0) {
2830 $this,
'Ticket validated but no PGT Iou transmitted',
2831 $validate_url,
false,
false,
2837 $tree_response->getElementsByTagName(
"proxyGrantingTicket")->item(0)->nodeValue
2839 if (preg_match(
'/^PGTIOU-[\.\-\w]+$/', $pgt_iou)) {
2841 if ( $pgt ==
false ) {
2845 'PGT Iou was transmitted but PGT could not be retrieved',
2846 $validate_url,
false,
2847 false, $text_response
2854 $this,
'PGT Iou was transmitted but has wrong format',
2855 $validate_url,
false,
false,
2880 if (gettype($target_service) !=
'string')
2893 .urlencode($target_service).
'&pgt='.$this->
_getPGT();
2898 'could not open URL \''.
$cas_url.
'\' to validate (
'.$err_msg.')
' 2900 $err_code = PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE; 2901 $err_msg = 'could not retrieve PT (no response from the
CAS server)
'; 2902 phpCAS::traceEnd(false); 2906 $bad_response = false; 2908 // create new DOMDocument object 2909 $dom = new DOMDocument(); 2910 // Fix possible whitspace problems 2911 $dom->preserveWhiteSpace = false; 2912 // read the response of the CAS server into a DOM object 2913 if ( !($dom->loadXML($cas_response))) { 2914 phpCAS::trace('dom->loadXML() failed
'); 2916 $bad_response = true; 2919 if ( !$bad_response ) { 2920 // read the root node of the XML tree 2921 if ( !($root = $dom->documentElement) ) { 2922 phpCAS::trace('documentElement failed
'); 2924 $bad_response = true; 2928 if ( !$bad_response ) { 2929 // insure that tag name is 'serviceResponse
' 2930 if ( $root->localName != 'serviceResponse
' ) { 2931 phpCAS::trace('localName failed
'); 2933 $bad_response = true; 2937 if ( !$bad_response ) { 2938 // look for a proxySuccess tag 2939 if ( $root->getElementsByTagName("proxySuccess")->length != 0) { 2940 $proxy_success_list = $root->getElementsByTagName("proxySuccess"); 2942 // authentication succeded, look for a proxyTicket tag 2943 if ( $proxy_success_list->item(0)->getElementsByTagName("proxyTicket")->length != 0) { 2944 $err_code = PHPCAS_SERVICE_OK; 2947 $proxy_success_list->item(0)->getElementsByTagName("proxyTicket")->item(0)->nodeValue 2949 phpCAS::trace('original PT:
'.trim($pt)); 2950 phpCAS::traceEnd($pt); 2953 phpCAS::trace('<proxySuccess> was found, but not <proxyTicket>
'); 2955 } else if ($root->getElementsByTagName("proxyFailure")->length != 0) { 2956 // look for a proxyFailure tag 2957 $proxy_failure_list = $root->getElementsByTagName("proxyFailure"); 2959 // authentication failed, extract the error 2960 $err_code = PHPCAS_SERVICE_PT_FAILURE; 2961 $err_msg = 'PT retrieving failed (code=`
' 2962 .$proxy_failure_list->item(0)->getAttribute('code
') 2964 .trim($proxy_failure_list->item(0)->nodeValue)
2966 phpCAS::traceEnd(false); 2969 phpCAS::trace('neither <proxySuccess> nor <proxyFailure> found
'); 2973 // at this step, we are sure that the response of the CAS server was 2975 $err_code = PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE; 2976 $err_msg = 'Invalid response from the
CAS server (response=`
' 2977 .$cas_response.'\
')';
3007 private function _readURL($url, &$headers, &$body, &$err_msg)
3011 $request =
new $className();
3013 if (count($this->_curl_options)) {
3014 $request->setCurlOptions($this->_curl_options);
3017 $request->setUrl($url);
3019 if (empty($this->_cas_server_ca_cert) && !$this->_no_cas_server_validation) {
3021 'one of the methods phpCAS::setCasServerCACert() or phpCAS::setNoCasServerValidation() must be called.' 3024 if ($this->_cas_server_ca_cert !=
'') {
3025 $request->setSslCaCert(
3026 $this->_cas_server_ca_cert, $this->_cas_server_cn_validate
3032 $request->addHeader(
"soapaction: http://www.oasis-open.org/committees/security");
3033 $request->addHeader(
"cache-control: no-cache");
3034 $request->addHeader(
"pragma: no-cache");
3035 $request->addHeader(
"accept: text/xml");
3036 $request->addHeader(
"connection: keep-alive");
3037 $request->addHeader(
"content-type: text/xml");
3038 $request->makePost();
3042 if ($request->send()) {
3043 $headers = $request->getResponseHeaders();
3044 $body = $request->getResponseBody();
3051 $err_msg = $request->getErrorMessage();
3070 .SAML_ASSERTION_ARTIFACT.$sa.SAML_ASSERTION_ARTIFACT_CLOSE
3071 .SAMLP_REQUEST_CLOSE.SAML_SOAP_BODY_CLOSE.SAML_SOAP_ENV_CLOSE;
3106 if (gettype($type) !=
'string')
3113 $request =
new $requestClass();
3114 if (count($this->_curl_options)) {
3115 $request->setCurlOptions($this->_curl_options);
3117 $proxiedService =
new $type($request, $this->_serviceCookieJar);
3119 $proxiedService->setCasClient($this);
3121 return $proxiedService;
3124 if ($proxiedService instanceof CAS_ProxiedService_Testable) {
3125 $proxiedService->setCasClient($this);
3127 return $proxiedService;
3130 "Unknown proxied-service type, $type." 3157 if (!is_string($url)) {
3159 "Proxied Service ".get_class($proxiedService)
3160 .
"->getServiceUrl() should have returned a string, returned a " 3161 .gettype($url).
" instead." 3164 $pt = $this->
retrievePT($url, $err_code, $err_msg);
3192 if (gettype($url) !=
'string')
3197 $service->setUrl($url);
3199 $output = $service->getResponseBody();
3203 $err_code = $e->getCode();
3204 $output = $e->getMessage();
3209 $lang->getServiceUnavailable(), $url, $e->getMessage()
3242 if (gettype($url) !=
'string')
3246 if (gettype($flags) !=
'integer')
3252 $service->setMailbox($url);
3253 $service->setOptions($flags);
3255 $stream = $service->open();
3257 $pt = $service->getImapProxyTicket();
3260 $err_msg = $e->getMessage();
3261 $err_code = $e->getCode();
3267 $lang->getServiceUnavailable(),
3329 $this->_proxies = $proxies;
3330 if (!empty($proxies)) {
3356 if (empty($this->_allowed_proxy_chains)) {
3385 public function validateCAS20(&$validate_url,&$text_response,&$tree_response, $renew=
false)
3405 $validate_url .=
'&renew=true';
3409 if ( !$this->
_readURL($validate_url, $headers, $text_response, $err_msg) ) {
3411 'could not open URL \''.$validate_url.
'\' to validate (
'.$err_msg.')
' 3413 throw new CAS_AuthenticationException( 3414 $this, 'Ticket not validated
', $validate_url, 3415 true/*$no_response*/ 3419 // create new DOMDocument object 3420 $dom = new DOMDocument(); 3421 // Fix possible whitspace problems 3422 $dom->preserveWhiteSpace = false; 3423 // CAS servers should only return data in utf-8 3424 $dom->encoding = "utf-8"; 3425 // read the response of the CAS server into a DOMDocument object 3426 if ( !($dom->loadXML($text_response))) { 3428 throw new CAS_AuthenticationException( 3429 $this, 'Ticket not validated
', $validate_url, 3430 false/*$no_response*/, true/*$bad_response*/, $text_response 3432 } else if ( !($tree_response = $dom->documentElement) ) { 3433 // read the root node of the XML tree 3435 throw new CAS_AuthenticationException( 3436 $this, 'Ticket not validated
', $validate_url, 3437 false/*$no_response*/, true/*$bad_response*/, $text_response 3439 } else if ($tree_response->localName != 'serviceResponse
') { 3440 // insure that tag name is 'serviceResponse
' 3442 throw new CAS_AuthenticationException( 3443 $this, 'Ticket not validated
', $validate_url, 3444 false/*$no_response*/, true/*$bad_response*/, $text_response 3446 } else if ( $tree_response->getElementsByTagName("authenticationFailure")->length != 0) { 3447 // authentication failed, extract the error code and message and throw exception 3448 $auth_fail_list = $tree_response 3449 ->getElementsByTagName("authenticationFailure"); 3450 throw new CAS_AuthenticationException( 3451 $this, 'Ticket not validated
', $validate_url, 3452 false/*$no_response*/, false/*$bad_response*/, 3454 $auth_fail_list->item(0)->getAttribute('code
')/*$err_code*/, 3455 trim($auth_fail_list->item(0)->nodeValue)/*$err_msg*/ 3457 } else if ($tree_response->getElementsByTagName("authenticationSuccess")->length != 0) { 3458 // authentication succeded, extract the user name 3459 $success_elements = $tree_response 3460 ->getElementsByTagName("authenticationSuccess"); 3461 if ( $success_elements->item(0)->getElementsByTagName("user")->length == 0) { 3462 // no user specified => error 3463 throw new CAS_AuthenticationException( 3464 $this, 'Ticket not validated
', $validate_url, 3465 false/*$no_response*/, true/*$bad_response*/, $text_response 3470 $success_elements->item(0)->getElementsByTagName("user")->item(0)->nodeValue 3473 $this->_readExtraAttributesCas20($success_elements); 3474 // Store the proxies we are sitting behind for authorization checking 3475 $proxyList = array(); 3476 if ( sizeof($arr = $success_elements->item(0)->getElementsByTagName("proxy")) > 0) { 3477 foreach ($arr as $proxyElem) { 3478 phpCAS::trace("Found Proxy: ".$proxyElem->nodeValue); 3479 $proxyList[] = trim($proxyElem->nodeValue); 3481 $this->_setProxies($proxyList); 3482 phpCAS::trace("Storing Proxy List"); 3484 // Check if the proxies in front of us are allowed 3485 if (!$this->getAllowedProxyChains()->isProxyListAllowed($proxyList)) { 3486 throw new CAS_AuthenticationException( 3487 $this, 'Proxy not allowed
', $validate_url, 3488 false/*$no_response*/, true/*$bad_response*/, 3496 throw new CAS_AuthenticationException( 3497 $this, 'Ticket not validated
', $validate_url, 3498 false/*$no_response*/, true/*$bad_response*/, 3503 $this->_renameSession($this->getTicket()); 3505 // at this step, Ticket has been validated and $this->_user has been set, 3507 phpCAS::traceEnd($result); 3610 private function _xml_to_array($root, $namespace = "cas") 3613 if ($root->hasAttributes()) { 3614 $attrs = $root->attributes; 3616 foreach ($attrs as $attr) { 3617 if ($attr->name === "name") { 3618 $pair['name
'] = $attr->value; 3619 } elseif ($attr->name === "value") { 3620 $pair['value
'] = $attr->value; 3622 $result[$attr->name] = $attr->value; 3624 if (array_key_exists('name
', $pair) && array_key_exists('value
', $pair)) { 3625 $result[$pair['name
']] = $pair['value
']; 3629 if ($root->hasChildNodes()) { 3630 $children = $root->childNodes; 3631 if ($children->length == 1) { 3632 $child = $children->item(0); 3633 if ($child->nodeType == XML_TEXT_NODE) { 3634 $result['_value
'] = $child->nodeValue; 3635 return (count($result) == 1) ? $result['_value
'] : $result; 3639 foreach ($children as $child) { 3640 $child_nodeName = str_ireplace($namespace . ":", "", $child->nodeName); 3641 if (in_array($child_nodeName, array("user", "proxies", "proxyGrantingTicket"))) { 3644 if (!isset($result[$child_nodeName])) { 3645 $res = $this->_xml_to_array($child, $namespace); 3647 $result[$child_nodeName] = $this->_xml_to_array($child, $namespace); 3650 if (!isset($groups[$child_nodeName])) { 3651 $result[$child_nodeName] = array($result[$child_nodeName]); 3652 $groups[$child_nodeName] = 1; 3654 $result[$child_nodeName][] = $this->_xml_to_array($child, $namespace); 3676 private function _parse_json_like_array_value($json_value) 3678 $parts = explode(",", trim($json_value, "[]")); 3681 foreach ($parts as $part) { 3682 $part = trim($part); 3683 if ($quote === '') { 3685 if ($this->_startsWith($part, '\
'')) {
3692 $part = ltrim($part, $quote);
3694 if ($quote !==
'') {
3697 $out[] = rtrim($value, $quote);
3747 if (!is_array($arr)) {
3755 foreach ($arr as $key => $val) {
3756 if (!is_array($val)) {
3759 switch (count($val)) {
3762 if (array_key_exists($key, $out)) {
3763 $value = $out[$key];
3764 if (!is_array($value)) {
3765 $out[$key] = array();
3766 $out[$key][] = $value;
3775 if (array_key_exists(
"name", $val) && array_key_exists(
"value", $val)) {
3776 $key = $val[
'name'];
3777 if (array_key_exists($key, $out)) {
3778 $value = $out[$key];
3779 if (!is_array($value)) {
3780 $out[$key] = array();
3781 $out[$key][] = $value;
3814 $extra_attributes = array();
3815 if ($this->_casAttributeParserCallbackFunction !== null
3816 && is_callable($this->_casAttributeParserCallbackFunction)
3818 array_unshift($this->_casAttributeParserCallbackArgs, $success_elements->item(0));
3820 $extra_attributes = call_user_func_array(
3821 $this->_casAttributeParserCallbackFunction,
3822 $this->_casAttributeParserCallbackArgs
3826 $attributes = $this->
_xml_to_array($success_elements->item(0));
3830 if (array_key_exists(
"attribute", $extra_attributes)) {
3831 $extra_attributes = $extra_attributes[
"attribute"];
3832 } elseif (array_key_exists(
"attributes", $extra_attributes)) {
3833 $extra_attributes = $extra_attributes[
"attributes"];
3854 if (isset($attributeArray[$name])) {
3856 if (!is_array($attributeArray[$name])) {
3857 $existingValue = $attributeArray[$name];
3858 $attributeArray[$name] = array($existingValue);
3861 $attributeArray[$name][] = trim($value);
3863 $attributeArray[$name] = trim($value);
3902 if (gettype($url) !=
'string')
3918 if ( empty($this->_url) ) {
3920 $final_uri = ($this->
_isHttps()) ?
'https' :
'http';
3921 $final_uri .=
'://';
3924 $request_uri = explode(
'?', $_SERVER[
'REQUEST_URI'], 2);
3925 $final_uri .= $request_uri[0];
3927 if (isset($request_uri[1]) && $request_uri[1]) {
3932 if ($query_string !==
'') {
3933 $final_uri .=
"?$query_string";
3938 $this->
setURL($final_uri);
3954 if (gettype($url) !=
'string')
3957 return $this->_server[
'base_url'] = $url;
3968 if (!empty($_SERVER[
'HTTP_X_FORWARDED_HOST'])) {
3970 $hosts = explode(
',', $_SERVER[
'HTTP_X_FORWARDED_HOST']);
3973 }
else if (!empty($_SERVER[
'HTTP_X_FORWARDED_SERVER'])) {
3974 $server_url = $_SERVER[
'HTTP_X_FORWARDED_SERVER'];
3976 if (empty($_SERVER[
'SERVER_NAME'])) {
3977 $server_url = $_SERVER[
'HTTP_HOST'];
3979 $server_url = $_SERVER[
'SERVER_NAME'];
3982 if (!strpos($server_url,
':')) {
3983 if (empty($_SERVER[
'HTTP_X_FORWARDED_PORT'])) {
3984 $server_port = $_SERVER[
'SERVER_PORT'];
3986 $ports = explode(
',', $_SERVER[
'HTTP_X_FORWARDED_PORT']);
3987 $server_port = $ports[0];
3990 if ( ($this->
_isHttps() && $server_port!=443)
3991 || (!$this->
_isHttps() && $server_port!=80)
3994 $server_url .= $server_port;
4007 if (!empty($_SERVER[
'HTTP_X_FORWARDED_PROTO'])) {
4008 return ($_SERVER[
'HTTP_X_FORWARDED_PROTO'] ===
'https');
4009 } elseif (!empty($_SERVER[
'HTTP_X_FORWARDED_PROTOCOL'])) {
4010 return ($_SERVER[
'HTTP_X_FORWARDED_PROTOCOL'] ===
'https');
4011 } elseif ( isset($_SERVER[
'HTTPS'])
4012 && !empty($_SERVER[
'HTTPS'])
4013 && strcasecmp($_SERVER[
'HTTPS'],
'off') !== 0
4033 $parameterName = preg_quote($parameterName);
4034 return preg_replace(
4035 "/&$parameterName(=[^&]*)?|^$parameterName(=[^&]*)?&?/",
4052 $url .= (strstr($url,
'?') ===
false) ?
'?' :
'&';
4067 return (strpos($text, $char) === 0);
4080 return (strpos(strrev($text), $char) === 0);
4098 return hash(
'sha256', $this->_sessionIdSalt . $ticket);
4116 $this->_sessionIdSalt = (string)$salt;
4142 $bad_response=
false,
4151 $lang->getYouWereNotAuthenticated(), htmlentities($this->
getURL()),
4152 isset($_SERVER[
'SERVER_ADMIN']) ? $_SERVER[
'SERVER_ADMIN']:
'' 4156 if ( $no_response ) {
4159 if ( $bad_response ) {
4168 if ( $err_code === -1 ) {
4172 'Reason: ['.$err_code.
'] CAS error: '.$err_msg
4213 if (preg_match(
"/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/", $nodeURL)) {
4218 return self::HOSTNAME;
4232 if ( !(
bool)preg_match(
"/^(http|https):\/\/([A-Z0-9][A-Z0-9_-]*(?:\.[A-Z0-9][A-Z0-9_-]*)+):?(\d+)?\/?/i", $rebroadcastNodeUrl))
4237 $this->_rebroadcast_nodes[] = $rebroadcastNodeUrl;
4255 if (gettype($header) !=
'string')
4258 $this->_rebroadcast_headers[] = $header;
4278 $rebroadcast_curl_options = array(
4279 CURLOPT_FAILONERROR => 1,
4280 CURLOPT_FOLLOWLOCATION => 1,
4281 CURLOPT_RETURNTRANSFER => 1,
4282 CURLOPT_CONNECTTIMEOUT => 1,
4283 CURLOPT_TIMEOUT => 4);
4286 if (!empty($_SERVER[
'SERVER_ADDR'])) {
4287 $ip = $_SERVER[
'SERVER_ADDR'];
4288 }
else if (!empty($_SERVER[
'LOCAL_ADDR'])) {
4290 $ip = $_SERVER[
'LOCAL_ADDR'];
4294 $dns = gethostbyaddr($ip);
4296 $multiClassName =
'CAS_Request_CurlMultiRequest';
4297 $multiRequest =
new $multiClassName();
4300 if ((($this->
_getNodeType($this->_rebroadcast_nodes[$i]) == self::HOSTNAME) && !empty($dns) && (stripos($this->_rebroadcast_nodes[$i], $dns) ===
false))
4301 || (($this->
_getNodeType($this->_rebroadcast_nodes[$i]) == self::IP) && !empty($ip) && (stripos($this->_rebroadcast_nodes[$i], $ip) ===
false))
4304 'Rebroadcast target URL: '.$this->_rebroadcast_nodes[$i]
4305 .$_SERVER[
'REQUEST_URI']
4308 $request =
new $className();
4310 $url = $this->_rebroadcast_nodes[$i].$_SERVER[
'REQUEST_URI'];
4311 $request->setUrl($url);
4313 if (count($this->_rebroadcast_headers)) {
4314 $request->addHeaders($this->_rebroadcast_headers);
4317 $request->makePost();
4318 if ($type == self::LOGOUT) {
4320 $request->setPostBody(
4321 'rebroadcast=false&logoutRequest='.$_POST[
'logoutRequest']
4323 }
else if ($type == self::PGTIOU) {
4325 $request->setPostBody(
'rebroadcast=false');
4328 $request->setCurlOptions($rebroadcast_curl_options);
4330 $multiRequest->addRequest($request);
4333 'Rebroadcast not sent to self: ' 4334 .$this->_rebroadcast_nodes[$i].
' == '.(!empty($ip)?$ip:
'')
4335 .
'/'.(!empty($dns)?$dns:
'')
4340 if ($multiRequest->getNumRequests() > 0) {
4341 $multiRequest->send();
getAuthenticationCallerFile()
$_cache_times_for_auth_recheck
setPGTStorageFile($path='')
const PHPCAS_SESSION_PREFIX
_xml_to_array($root, $namespace="cas")
setServerServiceValidateURL($url)
const PHPCAS_PROXIED_SERVICE_IMAP
_setCallbackModeUsingPost($callback_mode_using_post)
initializeProxiedService(CAS_ProxiedService $proxiedService)
_ensureAuthenticationCalled()
retrievePT($target_service, &$err_code, &$err_msg)
setCasAttributeParserCallback($function, array $additionalArgs=array())
setSingleSignoutCallback($function, array $additionalArgs=array())
if(isset( $_REQUEST[ 'logout']))
addRebroadcastHeader($header)
$_callback_mode_using_post
wasAuthenticationCalled()
__construct( $server_version, $proxy, $server_hostname, $server_port, $server_uri, $changeSessionID=true, \SessionHandlerInterface $sessionHandler=null)
_startsWith($text, $char)
_removeParameterFromQueryString($parameterName, $queryString)
wasAuthenticationCallSuccessful()
getServerProxyValidateURL()
_setChangeSessionID($allowed)
_validatePGT(&$validate_url, $text_response, $tree_response)
const PHPCAS_LANG_DEFAULT
$_signoutCallbackFunction
setRequestImplementation($className)
isAuthenticated($renew=false)
_wasPreviouslyAuthenticated()
$_postAuthenticateCallbackFunction
setProxyTicket($proxyTicket)
if(isset($_SERVER['HTTPS']) && $_SERVER['HTTPS']=='on') else
$_casAttributeParserCallbackArgs
_buildQueryUrl($url, $query)
const PHPCAS_PROXIED_SERVICE_HTTP_POST
static getSupportedProtocols()
markAuthenticationCall($auth)
getServerServiceValidateURL()
_readURL($url, &$headers, &$body, &$err_msg)
handleLogoutRequests($check_client=true, $allowed_clients=array())
redirectToCas($gateway=false, $renew=false)
const PHPCAS_SERVICE_NOT_AVAILABLE
setServerProxyValidateURL($url)
_setCallbackMode($callback_mode)
setSessionHandler(\SessionHandlerInterface $sessionHandler)
setPostAuthenticateCallback($function, array $additionalArgs=array())
_isCallbackModeUsingPost()
_addAttributeToArray(array &$attributeArray, $name, $value)
$_postAuthenticateCallbackArgs
validateCAS20(&$validate_url, &$text_response, &$tree_response, $renew=false)
setAttributes($attributes)
ensureAuthenticationCallSuccessful()
_sessionIdForTicket($ticket)
validateSA(&$validate_url, &$text_response, &$tree_response, $renew=false)
setNoCasServerValidation()
_readExtraAttributesCas20($success_elements)
getServerLoginURL($gateway=false, $renew=false)
$_no_cas_server_validation
getAuthenticationCallerLine()
setNoClearTicketsFromUrl()
setServerSamlValidateURL($url)
setCasServerCACert($cert, $validate_cn)
getAuthenticationCallerMethod()
if(isset($_REQUEST['logout'])) if(isset($_REQUEST['login'])) $auth
addRebroadcastNode($rebroadcastNodeUrl)
setCacheTimesForAuthRecheck($n)
const PHPCAS_PROXIED_SERVICE_HTTP_GET
setExtraCurlOption($key, $value)
_authError( $failure, $cas_url, $no_response=false, $bad_response=false, $cas_response='', $err_code=-1, $err_msg='')
_storePGT($pgt, $pgt_iou)
_setSessionAttributes($text_response)
getSessionValue($key, $default=null)
setPGTStorageDb( $dsn_or_pdo, $username='', $password='', $table='', $driver_options=null)
_parse_json_like_array_value($json_value)
serviceMail($url, $serviceUrl, $flags, &$err_code, &$err_msg, &$pt)
$_casAttributeParserCallbackFunction
getServerSamlValidateURL()
validateCAS10(&$validate_url, &$text_response, &$tree_response, $renew=false)
serviceWeb($url, &$err_code, &$output)
setSessionValue($key, $value)