9 include_once(dirname(__FILE__).
'/languages/languages.php');
12 include_once(dirname(__FILE__).
'/PGTStorage/pgt-main.php');
17 if ($i = is_int(strpos(
$name,
":")))
19 return substr(
$name, $i);
96 (empty($this->_output_header)
97 ?
'<html><head><title>__TITLE__</title></head><body><h1>__TITLE__</h1>'
98 : $this->output_header)
123 ?(
'<hr><address>phpCAS __PHPCAS_VERSION__ '.$this->
getString(
CAS_STR_USING_SERVER).
' <a href="__SERVER_BASE_URL__">__SERVER_BASE_URL__</a> (CAS __CAS_VERSION__)</a></address></body></html>')
124 :$this->_output_footer);
136 $this->_output_header = $header;
148 $this->_output_footer = $footer;
180 if ( empty($this->_lang) )
210 if ( !isset($this->
_strings[$str]) ) {
211 trigger_error(
'string `'.$str.
'\' not defined
for language `
'.$this->getLang().'\
'',E_USER_ERROR);
228 include_once(dirname(__FILE__).
'/languages/'.
$lang.
'.php');
231 trigger_error(
'language `'.
$lang.
'\' is not implemented
',E_USER_ERROR);
233 $this->_lang = $lang;
237 // ########################################################################
239 // ########################################################################
269 var $_server = array(
271 'hostname
' => 'none
',
281 function getServerVersion()
283 return $this->_server['version
'];
291 function getServerHostname()
292 { return $this->_server['hostname
']; }
299 function getServerPort()
300 { return $this->_server['port
']; }
307 function getServerURI()
308 { return $this->_server['uri
']; }
315 function getServerBaseURL()
317 // the URL is build only when needed
318 if ( empty($this->_server['base_url
']) ) {
319 $this->_server['base_url
'] = 'https:
320 .$this->getServerHostname()
322 .$this->getServerPort()
323 .$this->getServerURI();
325 return $this->_server[
'base_url'];
338 if ( empty($this->_server[
'login_url']) ) {
340 $this->_server[
'login_url'] .=
'login?service=';
341 $this->_server[
'login_url'] .= preg_replace(
'/&/',
'%26',$this->
getURL());
343 $this->_server[
'login_url'] .=
'&gateway=true';
347 return $this->_server[
'login_url'];
358 if ( empty($this->_server[
'service_validate_url']) ) {
361 $this->_server[
'service_validate_url'] = $this->
getServerBaseURL().
'validate';
364 $this->_server[
'service_validate_url'] = $this->
getServerBaseURL().
'serviceValidate';
368 return $this->_server[
'service_validate_url'].
'?service='.preg_replace(
'/&/',
'%26',$this->
getURL());
379 if ( empty($this->_server[
'proxy_validate_url']) ) {
382 $this->_server[
'proxy_validate_url'] =
'';
385 $this->_server[
'proxy_validate_url'] = $this->
getServerBaseURL().
'proxyValidate';
389 return $this->_server[
'proxy_validate_url'].
'?service='.preg_replace(
'/&/',
'%26',$this->
getURL());
400 if ( empty($this->_server[
'proxy_url']) ) {
403 $this->_server[
'proxy_url'] =
'';
410 return $this->_server[
'proxy_url'];
421 if ( empty($this->_server[
'logout_url']) ) {
424 return $this->_server[
'logout_url'];
449 $start_session =
true)
454 if ($start_session) {
461 switch ($server_version) {
472 .
'\') is not supported by
phpCAS '
473 .phpCAS::getVersion());
475 $this->_server['version
'] = $server_version;
478 if ( empty($server_hostname)
479 || !preg_match('/[\.\d\-abcdefghijklmnopqrstuvwxyz]*/
',$server_hostname) ) {
480 phpCAS::error('bad CAS server hostname (`
'.$server_hostname.'\
')');
482 $this->_server[
'hostname'] = $server_hostname;
485 if ( $server_port == 0
486 || !is_int($server_port) ) {
487 phpCAS::error(
'bad CAS server port (`'.$server_hostname.
'\')
');
489 $this->_server['port
'] = $server_port;
492 if ( !preg_match('/[\.\d\-_abcdefghijklmnopqrstuvwxyz\/]*/
',$server_uri) ) {
493 phpCAS::error('bad CAS server URI (`
'.$server_uri.'\
')');
496 $server_uri = preg_replace(
'/\/\//',
'/',
'/'.$server_uri.
'/');
497 $this->_server[
'uri'] = $server_uri;
506 if ( $_SERVER[
'HTTPS'] !=
'on' ) {
507 phpCAS::error(
'CAS proxies must be secured to use phpCAS; PGT\'s will not be received from the CAS server');
511 $ticket =
$_GET[
'ticket'];
513 if( preg_match(
'/^ST-/',$ticket)) {
516 $this->setST($ticket);
518 // in a second time check for a Proxy Ticket (CAS >= 2.0)
519 else if( ($this->getServerVersion()!=CAS_VERSION_1_0) && preg_match('/^PT-/
',$ticket) ) {
520 phpCAS::trace('PT \
''.$ticket.
'\' found
');
521 $this->setPT($ticket);
523 // ill-formed ticket, halt
524 else if ( !empty($ticket) ) {
525 phpCAS::error('ill-formed ticket found in the URL (ticket=`
'.htmlentities($ticket).'\
')');
528 unset(
$_GET[
'ticket']);
564 $this->_user =
$user;
576 if ( empty($this->_user) ) {
577 phpCAS::error(
'this method should be used only after '.__CLASS__.
'::forceAuthentication() or '.__CLASS__.
'::isAuthenticated()');
598 unset(
$_SESSION[
'phpCAS'][
'auth_checked']);
619 }
else if (isset(
$_SESSION[
'phpCAS'][
'auth_checked'])) {
621 unset(
$_SESSION[
'phpCAS'][
'auth_checked']);
624 $_SESSION[
'phpCAS'][
'auth_checked'] =
true;
650 phpCAS::trace(
'user was already authenticated, no need to look for tickets');
655 $this->validateST($validate_url,$text_response,$tree_response); // if it fails, it halts
656 phpCAS::trace('ST `
'.$this->getST().'\
' was validated');
658 $this->
validatePGT($validate_url,$text_response,$tree_response);
660 $_SESSION['phpCAS']['pgt
'] = $this->getPGT();
662 $_SESSION['phpCAS']['user
'] = $this->getUser();
664 } elseif ( $this->hasPT() ) {
665 // if a Proxy Ticket was given, validate it
666 phpCAS::trace('PT `
'.$this->getPT().'\
' is present');
667 $this->
validatePT($validate_url,$text_response,$tree_response);
669 if ( $this->isProxy() ) {
670 $this->validatePGT($validate_url,$text_response,$tree_response); // idem
671 phpCAS::trace('PGT `
'.$this->getPGT().'\
' was validated');
716 // unset all tickets to enforce authentication
717 unset($_SESSION['phpCAS']);
720 } elseif ( empty($_SESSION['phpCAS']['user
']) && !empty($_SESSION['phpCAS']['pgt
']) ) {
721 // these two variables should be empty or not empty at the same time
722 phpCAS::trace('PGT found (`
'.$_SESSION['phpCAS']['pgt
'].'\
') but username is empty');
732 if ( !empty(
$_SESSION[
'phpCAS'][
'user']) ) {
756 header(
'Location: '.$cas_url);
776 $url =
'?service=' . $url;
778 header(
'Location: '.$cas_url . $url);
828 { $this->_st = $st; }
836 {
return !empty($this->_st); }
861 function validateST($validate_url,&$text_response,&$tree_response)
868 $validate_url .=
'&pgtUrl='.$this->getCallbackURL();
872 if ( !$this->
readURL($validate_url,
'',$headers,$text_response,$err_msg) ) {
873 phpCAS::trace(
'could not open URL \''.$validate_url.
'\' to validate (
'.$err_msg.')
');
874 $this->authError('ST not validated (1)
',
876 TRUE/*$no_response*/);
879 // analyze the result depending on the version
880 switch ($this->getServerVersion()) {
881 case CAS_VERSION_1_0:
882 if (preg_match('/^no\
n/
',$text_response)) {
883 phpCAS::trace('ST has not been validated
');
884 $this->authError('ST not validated (2)
',
886 FALSE/*$no_response*/,
887 FALSE/*$bad_response*/,
890 if (!preg_match('/^yes\
n/
',$text_response)) {
891 phpCAS::trace('ill-formed response
');
892 $this->authError('ST not validated (3)
',
894 FALSE/*$no_response*/,
895 TRUE/*$bad_response*/,
898 // ST has been validated, extract the user name
899 $arr = preg_split('/\
n/
',$text_response);
900 $this->setUser(trim($arr[1]));
902 case CAS_VERSION_2_0:
903 // read the response of the CAS server into a DOM object
904 if ( !($dom = domxml_open_mem($text_response))) {
906 $this->authError('ST not validated (4)
',
908 FALSE/*$no_response*/,
909 TRUE/*$bad_response*/,
912 // read the root node of the XML tree
913 if ( !($tree_response = $dom->document_element()) ) {
914 phpCAS::trace('document_element() failed
');
915 $this->authError('ST not validated (5)
',
917 FALSE/*$no_response*/,
918 TRUE/*$bad_response*/,
921 // insure that tag name is 'serviceResponse
'
922 if ( hnodename($tree_response->node_name()) != 'serviceResponse
' ) {
923 phpCAS::trace('bad XML root node (should be `serviceResponse\
' instead of `'.
hnodename($tree_response->node_name()).
'\'');
930 if (
sizeof($success_elements = $tree_response->get_elements_by_tagname(
"authenticationSuccess")) != 0) {
932 if (
sizeof($user_elements = $success_elements[0]->get_elements_by_tagname(
"user")) == 0) {
933 phpCAS::trace(
'<authenticationSuccess> found, but no <user>');
940 $user = trim($user_elements[0]->get_content());
944 }
else if (
sizeof($failure_elements = $tree_response->get_elements_by_tagname(
"authenticationFailure")) != 0) {
952 $failure_elements[0]->get_attribute(
'code'),
953 trim($failure_elements[0]->get_content()));
955 phpCAS::trace(
'neither <authenticationSuccess> nor <authenticationFailure> found');
1003 return $this->_proxy;
1030 {
return $this->_pgt; }
1037 function setPGT($pgt)
1038 { $this->_pgt = $pgt; }
1046 {
return !empty($this->_pgt); }
1070 var $_callback_mode = FALSE;
1079 function setCallbackMode($callback_mode)
1081 $this->_callback_mode = $callback_mode;
1092 function isCallbackMode()
1094 return $this->_callback_mode;
1105 var $_callback_url =
'';
1116 function getCallbackURL()
1119 if ( empty($this->_callback_url) ) {
1122 $final_uri =
'https://';
1126 if(empty($_SERVER[
'HTTP_X_FORWARDED_SERVER'])){
1130 if (empty($_SERVER[
'SERVER_NAME'])) {
1131 $final_uri .= $_SERVER[
'HTTP_HOST'];
1133 $final_uri .= $_SERVER[
'SERVER_NAME'];
1136 $final_uri .= $_SERVER[
'HTTP_X_FORWARDED_SERVER'];
1138 if ( ($_SERVER[
'HTTPS']==
'on' && $_SERVER[
'SERVER_PORT']!=443)
1139 || ($_SERVER[
'HTTPS']!=
'on' && $_SERVER[
'SERVER_PORT']!=80) ) {
1141 $final_uri .= $_SERVER[
'SERVER_PORT'];
1146 $this->setCallbackURL($final_uri);
1148 return $this->_callback_url;
1158 function setCallbackURL($url)
1160 return $this->_callback_url = $url;
1172 $this->printHTMLHeader(
'phpCAS callback');
1173 $pgt_iou =
$_GET[
'pgtIou'];
1174 $pgt =
$_GET[
'pgtId'];
1175 phpCAS::trace(
'Storing PGT `'.$pgt.
'\' (
id=`
'.$pgt_iou.'\
')');
1176 echo
'<p>Storing PGT `'.$pgt.
'\' (
id=`
'.$pgt_iou.'\
').</p>';
1177 $this->storePGT($pgt,$pgt_iou);
1178 $this->printHTMLFooter();
1200 var $_pgt_storage = null;
1208 function initPGTStorage()
1211 if ( !is_object($this->_pgt_storage) ) {
1212 $this->setPGTStorageFile();
1216 $this->_pgt_storage->init();
1227 function storePGT($pgt,$pgt_iou)
1230 $this->initPGTStorage();
1232 $this->_pgt_storage->write($pgt,$pgt_iou);
1244 function loadPGT($pgt_iou)
1247 $this->initPGTStorage();
1249 return $this->_pgt_storage->read($pgt_iou);
1261 function setPGTStorageFile($format=
'',
1265 if ( is_object($this->_pgt_storage) ) {
1299 if ( is_object($this->_pgt_storage) ) {
1304 trigger_error(
'PGT storage into database is an experimental feature, use at your own risk',E_USER_WARNING);
1326 function validatePGT(&$validate_url,$text_response,$tree_response)
1329 if (
sizeof($arr = $tree_response->get_elements_by_tagname(
"proxyGrantingTicket")) == 0) {
1332 $this->authError(
'Ticket validated but no PGT Iou transmitted',
1339 $pgt_iou = trim($arr[0]->get_content());
1340 $pgt = $this->loadPGT($pgt_iou);
1341 if ( $pgt == FALSE ) {
1343 $this->authError(
'PGT Iou was transmitted but PGT could not be retrieved',
1349 $this->setPGT($pgt);
1370 function retrievePT($target_service,&$err_code,&$err_msg)
1381 $cas_url = $this->getServerProxyURL().
'?targetService='.preg_replace(
'/&/',
'%26',$target_service).
'&pgt='.$this->getPGT();
1384 if ( !$this->readURL($cas_url,
'',$headers,$cas_response,$err_msg) ) {
1385 phpCAS::trace(
'could not open URL \''.$cas_url.
'\' to validate (
'.$err_msg.')
');
1386 $err_code = PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE;
1387 $err_msg = 'could not retrieve PT (no response from the CAS server)
';
1388 phpCAS::traceEnd(FALSE);
1392 $bad_response = FALSE;
1394 if ( !$bad_response ) {
1395 // read the response of the CAS server into a DOM object
1396 if ( !($dom = @domxml_open_mem($cas_response))) {
1399 $bad_response = TRUE;
1403 if ( !$bad_response ) {
1404 // read the root node of the XML tree
1405 if ( !($root = $dom->document_element()) ) {
1406 phpCAS::trace('document_element() failed
');
1408 $bad_response = TRUE;
1412 if ( !$bad_response ) {
1413 // insure that tag name is 'serviceResponse
'
1414 if ( hnodename($root->node_name()) != 'serviceResponse
' ) {
1415 phpCAS::trace('node_name() failed
');
1417 $bad_response = TRUE;
1421 if ( !$bad_response ) {
1422 // look for a proxySuccess tag
1423 if ( sizeof($arr = $root->get_elements_by_tagname("proxySuccess")) != 0) {
1424 // authentication succeded, look for a proxyTicket tag
1425 if ( sizeof($arr = $root->get_elements_by_tagname("proxyTicket")) != 0) {
1426 $err_code = PHPCAS_SERVICE_OK;
1428 $pt = trim($arr[0]->get_content());
1429 phpCAS::traceEnd($pt);
1432 phpCAS::trace('<proxySuccess> was found, but not <proxyTicket>
');
1435 // look for a proxyFailure tag
1436 else if ( sizeof($arr = $root->get_elements_by_tagname("proxyFailure")) != 0) {
1437 // authentication failed, extract the error
1438 $err_code = PHPCAS_SERVICE_PT_FAILURE;
1439 $err_msg = 'PT retrieving failed (code=`
'
1440 .$arr[0]->get_attribute('code
')
1442 .trim($arr[0]->get_content())
1444 phpCAS::traceEnd(FALSE);
1447 phpCAS::trace('neither <proxySuccess> nor <proxyFailure> found
');
1451 // at this step, we are sure that the response of the CAS server was ill-formed
1452 $err_code = PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE;
1453 $err_msg = 'Invalid response from the CAS server (response=`
'.$cas_response.'\
')';
1478 function readURL($url,$cookies,&$headers,&$body,&$err_msg)
1488 $ch = curl_init($url);
1491 curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1);
1493 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
1496 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
1498 curl_setopt($ch, CURLOPT_HEADER, 1);
1500 if ( is_array($cookies) ) {
1501 curl_setopt($ch,CURLOPT_COOKIE,implode(
';',$cookies));
1504 $buf = curl_exec ($ch);
1505 if ( $buf === FALSE ) {
1507 $err_msg =
'CURL error #'.curl_errno($ch).
': '.curl_error($ch);
1518 for ($i=0; $i<strlen($buf); $i++) {
1519 if ( $buf[$i] == chr(13) )
1520 if ( $buf[$i+1] == chr(10) )
1521 if ( $buf[$i+2] == chr(13) )
1522 if ( $buf[$i+3] == chr(10) ) {
1529 if ( $pos === FALSE ) {
1531 $err_msg =
'no header found';
1536 $headers = preg_split (
"/[\n\r]+/",substr($buf,0,$pos));
1538 $body = substr($buf,$pos+4);
1561 function serviceWeb($url,&$err_code,&$output)
1565 $pt = $this->retrievePT($url,$err_code,$output);
1576 if ( is_array(
$_SESSION[
'phpCAS'][
'services'][$url][
'cookies']) ) {
1577 foreach (
$_SESSION[
'phpCAS'][
'services'][$url][
'cookies'] as
$name => $val ) {
1578 $cookies[] =
$name.
'='.$val;
1583 if ( strstr($url,
'?') === FALSE ) {
1584 $service_url = $url.
'?ticket='.$pt;
1586 $service_url = $url.
'&ticket='.$pt;
1590 if ( !$this->readURL($service_url,$cookies,$headers,$output,$err_msg) ) {
1592 $err_code = PHPCAS_SERVICE_NOT_AVAILABLE;
1600 phpCAS::trace(
'URL`'.$service_url.
'\' has been read, storing cookies:
');
1601 foreach ( $headers as $header ) {
1602 // test if the header is a cookie
1603 if ( preg_match('/^Set-Cookie:/
',$header) ) {
1604 // the header is a cookie, remove the beginning
1605 $header_val = preg_replace('/^Set-Cookie: */
','',$header);
1606 // extract interesting information
1607 $name_val = strtok($header_val,';
');
1608 // extract the name and the value of the cookie
1609 $cookie_name = strtok($name_val,'=
');
1610 $cookie_val = strtok('=
');
1612 $_SESSION['phpCAS']['services
'][$url]['cookies
'][$cookie_name] = $cookie_val;
1613 phpCAS::trace($cookie_name.' ->
'.$cookie_val);
1619 phpCAS::traceEnd($res);
1641 function serviceMail($url,$flags,&$err_code,&$err_msg,&$pt)
1643 phpCAS::traceBegin();
1644 // at first retrieve a PT
1645 $pt = $this->retrievePT($target_service,$err_code,$output);
1649 // test if PT was retrieved correctly
1651 // note: $err_code and $err_msg are filled by CASClient::retrievePT()
1652 phpCAS::trace('PT was not retrieved correctly
');
1654 phpCAS::trace('opening IMAP URL `
'.$url.'\
'...');
1655 $stream = @imap_open($url,$this->getUser(),$pt,$flags);
1658 $err_code = PHPCAS_SERVICE_NOT_AVAILABLE;
1662 var_export(imap_errors(),TRUE));
1706 {
return $this->_pt; }
1714 { $this->_pt = $pt; }
1722 {
return !empty($this->_pt); }
1740 function validatePT(&$validate_url,&$text_response,&$tree_response)
1744 $validate_url = $this->getServerProxyValidateURL().
'&ticket='.$this->getPT();
1746 if ( $this->isProxy() ) {
1748 $validate_url .=
'&pgtUrl='.$this->getCallbackURL();
1752 if ( !$this->readURL($validate_url,
'',$headers,$text_response,$err_msg) ) {
1753 phpCAS::trace(
'could not open URL \''.$validate_url.
'\' to validate (
'.$err_msg.')
');
1754 $this->authError('PT not validated
',
1756 TRUE/*$no_response*/);
1759 // read the response of the CAS server into a DOM object
1760 if ( !($dom = domxml_open_mem($text_response))) {
1762 $this->authError('PT not validated
',
1764 FALSE/*$no_response*/,
1765 TRUE/*$bad_response*/,
1768 // read the root node of the XML tree
1769 if ( !($tree_response = $dom->document_element()) ) {
1771 $this->authError('PT not validated
',
1773 FALSE/*$no_response*/,
1774 TRUE/*$bad_response*/,
1777 // insure that tag name is 'serviceResponse
'
1778 if ( hnodename($tree_response->node_name()) != 'serviceResponse
' ) {
1780 $this->authError('PT not validated
',
1782 FALSE/*$no_response*/,
1783 TRUE/*$bad_response*/,
1786 if ( sizeof($arr = $tree_response->get_elements_by_tagname("authenticationSuccess")) != 0) {
1787 // authentication succeded, extract the user name
1788 if ( sizeof($arr = $tree_response->get_elements_by_tagname("user")) == 0) {
1789 // no user specified => error
1790 $this->authError('PT not validated
',
1792 FALSE/*$no_response*/,
1793 TRUE/*$bad_response*/,
1796 $this->setUser(trim($arr[0]->get_content()));
1798 } else if ( sizeof($arr = $tree_response->get_elements_by_tagname("authenticationFailure")) != 0) {
1799 // authentication succeded, extract the error code and message
1800 $this->authError('PT not validated
',
1802 FALSE/*$no_response*/,
1803 FALSE/*$bad_response*/,
1805 $arr[0]->get_attribute('code
')/*$err_code*/,
1806 trim($arr[0]->get_content())/*$err_msg*/);
1808 $this->authError('PT not validated
',
1810 FALSE/*$no_response*/,
1811 TRUE/*$bad_response*/,
1815 // at this step, PT has been validated and $this->_user has been set,
1817 phpCAS::traceEnd(TRUE);
1823 // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1827 // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1834 // ########################################################################
1836 // ########################################################################
1856 phpCAS::traceBegin();
1857 // the URL is built when needed only
1858 if ( empty($this->_url) ) {
1860 // remove the ticket if present in the URL
1861 $final_uri = ($_SERVER['HTTPS
'] == 'on
') ? 'https
' : 'http
';
1866 if(empty($_SERVER[
'HTTP_X_FORWARDED_SERVER'])){
1870 if (empty($_SERVER[
'SERVER_NAME'])) {
1871 $final_uri .= $_SERVER[
'HTTP_HOST'];
1873 $final_uri .= $_SERVER[
'SERVER_NAME'];
1876 $final_uri .= $_SERVER[
'HTTP_X_FORWARDED_SERVER'];
1878 if ( ($_SERVER[
'HTTPS']==
'on' && $_SERVER[
'SERVER_PORT']!=443)
1879 || ($_SERVER[
'HTTPS']!=
'on' && $_SERVER[
'SERVER_PORT']!=80) ) {
1881 $final_uri .= $_SERVER[
'SERVER_PORT'];
1884 $final_uri .= strtok($_SERVER[
'REQUEST_URI'],
"?");
1885 $cgi_params =
'?'.strtok(
"?");
1887 $cgi_params = preg_replace(
'/&ticket=[^&]*/',
'',$cgi_params);
1888 $cgi_params = preg_replace(
'/\?ticket=[^&;]*/',
'?',$cgi_params);
1889 $cgi_params = preg_replace(
'/\?$/',
'',$cgi_params);
1890 $final_uri .= $cgi_params;
1891 $this->setURL($final_uri);
1904 function setURL($url)
1927 function authError(
$failure,$cas_url,$no_response,$bad_response=
'',$cas_response=
'',$err_code=
'',$err_msg=
'')
1935 if ( $no_response ) {
1938 if ( $bad_response ) {
1941 switch ($this->getServerVersion()) {
1946 if ( empty($err_code) )
1949 phpCAS::trace(
'Reason: ['.$err_code.
'] CAS error: '.$err_msg);
1955 $this->printHTMLFooter();