00001 <?php
00002
00008
00009 include_once(dirname(__FILE__).'/languages/languages.php');
00010
00011
00012 include_once(dirname(__FILE__).'/PGTStorage/pgt-main.php');
00013
00014
00015 function hnodename($name)
00016 {
00017 if ($i = is_int(strpos($name, ":")))
00018 {
00019 return substr($name, $i);
00020 }
00021 else
00022 {
00023 return $name;
00024 }
00025 }
00026
00035 class CASClient
00036 {
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00065 function HTMLFilterOutput($str)
00066 {
00067 $str = str_replace('__CAS_VERSION__',$this->getServerVersion(),$str);
00068 $str = str_replace('__PHPCAS_VERSION__',phpCAS::getVersion(),$str);
00069 $str = str_replace('__SERVER_BASE_URL__',$this->getServerBaseURL(),$str);
00070 echo $str;
00071 }
00072
00081 var $_output_header = '';
00082
00092 function printHTMLHeader($title)
00093 {
00094 $this->HTMLFilterOutput(str_replace('__TITLE__',
00095 $title,
00096 (empty($this->_output_header)
00097 ? '<html><head><title>__TITLE__</title></head><body><h1>__TITLE__</h1>'
00098 : $this->output_header)
00099 )
00100 );
00101 }
00102
00111 var $_output_footer = '';
00112
00120 function printHTMLFooter()
00121 {
00122 $this->HTMLFilterOutput(empty($this->_output_footer)
00123 ?('<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>')
00124 :$this->_output_footer);
00125 }
00126
00134 function setHTMLHeader($header)
00135 {
00136 $this->_output_header = $header;
00137 }
00138
00146 function setHTMLFooter($footer)
00147 {
00148 $this->_output_footer = $footer;
00149 }
00150
00152
00153
00154
00169 var $_lang = '';
00170
00178 function getLang()
00179 {
00180 if ( empty($this->_lang) )
00181 $this->setLang(PHPCAS_LANG_DEFAULT);
00182 return $this->_lang;
00183 }
00184
00194 var $_strings;
00195
00205 function getString($str)
00206 {
00207
00208 $this->getLang();
00209
00210 if ( !isset($this->_strings[$str]) ) {
00211 trigger_error('string `'.$str.'\' not defined for language `'.$this->getLang().'\'',E_USER_ERROR);
00212 }
00213 return $this->_strings[$str];
00214 }
00215
00225 function setLang($lang)
00226 {
00227
00228 include_once(dirname(__FILE__).'/languages/'.$lang.'.php');
00229
00230 if ( !is_array($this->_strings) ) {
00231 trigger_error('language `'.$lang.'\' is not implemented',E_USER_ERROR);
00232 }
00233 $this->_lang = $lang;
00234 }
00235
00237 // ########################################################################
00238 // CAS SERVER CONFIG
00239 // ########################################################################
00269 var $_server = array(
00270 'version' => -1,
00271 'hostname' => 'none',
00272 'port' => -1,
00273 'uri' => 'none'
00274 );
00275
00281 function getServerVersion()
00282 {
00283 return $this->_server['version'];
00284 }
00285
00291 function getServerHostname()
00292 { return $this->_server['hostname']; }
00293
00299 function getServerPort()
00300 { return $this->_server['port']; }
00301
00307 function getServerURI()
00308 { return $this->_server['uri']; }
00309
00315 function getServerBaseURL()
00316 {
00317 // the URL is build only when needed
00318 if ( empty($this->_server['base_url']) ) {
00319 $this->_server['base_url'] = 'https:
00320 .$this->getServerHostname()
00321 .':'
00322 .$this->getServerPort()
00323 .$this->getServerURI();
00324 }
00325 return $this->_server['base_url'];
00326 }
00327
00334 function getServerLoginURL($gateway)
00335 {
00336 phpCAS::traceBegin();
00337
00338 if ( empty($this->_server['login_url']) ) {
00339 $this->_server['login_url'] = $this->getServerBaseURL();
00340 $this->_server['login_url'] .= 'login?service=';
00341 $this->_server['login_url'] .= preg_replace('/&/','%26',$this->getURL());
00342 if ($gateway) {
00343 $this->_server['login_url'] .= '&gateway=true';
00344 }
00345 }
00346 phpCAS::traceEnd($this->_server['login_url']);
00347 return $this->_server['login_url'];
00348 }
00349
00355 function getServerServiceValidateURL()
00356 {
00357
00358 if ( empty($this->_server['service_validate_url']) ) {
00359 switch ($this->getServerVersion()) {
00360 case CAS_VERSION_1_0:
00361 $this->_server['service_validate_url'] = $this->getServerBaseURL().'validate';
00362 break;
00363 case CAS_VERSION_2_0:
00364 $this->_server['service_validate_url'] = $this->getServerBaseURL().'serviceValidate';
00365 break;
00366 }
00367 }
00368 return $this->_server['service_validate_url'].'?service='.preg_replace('/&/','%26',$this->getURL());
00369 }
00370
00376 function getServerProxyValidateURL()
00377 {
00378
00379 if ( empty($this->_server['proxy_validate_url']) ) {
00380 switch ($this->getServerVersion()) {
00381 case CAS_VERSION_1_0:
00382 $this->_server['proxy_validate_url'] = '';
00383 break;
00384 case CAS_VERSION_2_0:
00385 $this->_server['proxy_validate_url'] = $this->getServerBaseURL().'proxyValidate';
00386 break;
00387 }
00388 }
00389 return $this->_server['proxy_validate_url'].'?service='.preg_replace('/&/','%26',$this->getURL());
00390 }
00391
00397 function getServerProxyURL()
00398 {
00399
00400 if ( empty($this->_server['proxy_url']) ) {
00401 switch ($this->getServerVersion()) {
00402 case CAS_VERSION_1_0:
00403 $this->_server['proxy_url'] = '';
00404 break;
00405 case CAS_VERSION_2_0:
00406 $this->_server['proxy_url'] = $this->getServerBaseURL().'proxy';
00407 break;
00408 }
00409 }
00410 return $this->_server['proxy_url'];
00411 }
00412
00418 function getServerLogoutURL()
00419 {
00420
00421 if ( empty($this->_server['logout_url']) ) {
00422 $this->_server['logout_url'] = $this->getServerBaseURL().'logout';
00423 }
00424 return $this->_server['logout_url'];
00425 }
00426
00427
00428
00429
00444 function CASClient($server_version,
00445 $proxy,
00446 $server_hostname,
00447 $server_port,
00448 $server_uri,
00449 $start_session = true)
00450 {
00451 phpCAS::traceBegin();
00452
00453
00454 if ($start_session) {
00455 session_start();
00456 }
00457
00458 $this->_proxy = $proxy;
00459
00460
00461 switch ($server_version) {
00462 case CAS_VERSION_1_0:
00463 if ( $this->isProxy() )
00464 phpCAS::error('CAS proxies are not supported in CAS '
00465 .$server_version);
00466 break;
00467 case CAS_VERSION_2_0:
00468 break;
00469 default:
00470 phpCAS::error('this version of CAS (`'
00471 .$server_version
00472 .'\') is not supported by phpCAS '
00473 .phpCAS::getVersion());
00474 }
00475 $this->_server['version'] = $server_version;
00476
00477 // check hostname
00478 if ( empty($server_hostname)
00479 || !preg_match('/[\.\d\-abcdefghijklmnopqrstuvwxyz]*/',$server_hostname) ) {
00480 phpCAS::error('bad CAS server hostname (`'.$server_hostname.'\')');
00481 }
00482 $this->_server['hostname'] = $server_hostname;
00483
00484
00485 if ( $server_port == 0
00486 || !is_int($server_port) ) {
00487 phpCAS::error('bad CAS server port (`'.$server_hostname.'\')');
00488 }
00489 $this->_server['port'] = $server_port;
00490
00491 // check URI
00492 if ( !preg_match('/[\.\d\-_abcdefghijklmnopqrstuvwxyz\/]*/',$server_uri) ) {
00493 phpCAS::error('bad CAS server URI (`'.$server_uri.'\')');
00494 }
00495
00496 $server_uri = preg_replace('/\/\//','/','/'.$server_uri.'/');
00497 $this->_server['uri'] = $server_uri;
00498
00499
00500 if ( $this->isProxy() ) {
00501 $this->setCallbackMode(!empty($_GET['pgtIou'])&&!empty($_GET['pgtId']));
00502 }
00503
00504 if ( $this->isCallbackMode() ) {
00505
00506 if ( $_SERVER['HTTPS'] != 'on' ) {
00507 phpCAS::error('CAS proxies must be secured to use phpCAS; PGT\'s will not be received from the CAS server');
00508 }
00509 } else {
00510
00511 $ticket = $_GET['ticket'];
00512
00513 if( preg_match('/^ST-/',$ticket)) {
00514 phpCAS::trace('ST \''.$ticket.'\' found');
00515 // ST present
00516 $this->setST($ticket);
00517 }
00518 // in a second time check for a Proxy Ticket (CAS >= 2.0)
00519 else if( ($this->getServerVersion()!=CAS_VERSION_1_0) && preg_match('/^PT-/',$ticket) ) {
00520 phpCAS::trace('PT \''.$ticket.'\' found');
00521 $this->setPT($ticket);
00522 }
00523 // ill-formed ticket, halt
00524 else if ( !empty($ticket) ) {
00525 phpCAS::error('ill-formed ticket found in the URL (ticket=`'.htmlentities($ticket).'\')');
00526 }
00527
00528 unset($_GET['ticket']);
00529 }
00530 phpCAS::traceEnd();
00531 }
00532
00535
00536
00537
00538
00539
00540
00553 var $_user = '';
00554
00562 function setUser($user)
00563 {
00564 $this->_user = $user;
00565 }
00566
00574 function getUser()
00575 {
00576 if ( empty($this->_user) ) {
00577 phpCAS::error('this method should be used only after '.__CLASS__.'::forceAuthentication() or '.__CLASS__.'::isAuthenticated()');
00578 }
00579 return $this->_user;
00580 }
00581
00588 function forceAuthentication()
00589 {
00590 phpCAS::traceBegin();
00591
00592 if ( $this->isAuthenticated() ) {
00593
00594 phpCAS::trace('no need to authenticate');
00595 $res = TRUE;
00596 } else {
00597
00598 unset($_SESSION['phpCAS']['auth_checked']);
00599 $this->redirectToCas(FALSE);
00600
00601 $res = FALSE;
00602 }
00603 phpCAS::traceEnd($res);
00604 return $res;
00605 }
00606
00612 function checkAuthentication()
00613 {
00614 phpCAS::traceBegin();
00615
00616 if ( $this->isAuthenticated() ) {
00617 phpCAS::trace('user is authenticated');
00618 $res = TRUE;
00619 } else if (isset($_SESSION['phpCAS']['auth_checked'])) {
00620
00621 unset($_SESSION['phpCAS']['auth_checked']);
00622 $res = FALSE;
00623 } else {
00624 $_SESSION['phpCAS']['auth_checked'] = true;
00625 $this->redirectToCas(TRUE);
00626
00627 $res = FALSE;
00628 }
00629 phpCAS::traceEnd($res);
00630 return $res;
00631 }
00632
00641 function isAuthenticated()
00642 {
00643 phpCAS::traceBegin();
00644 $res = FALSE;
00645 $validate_url = '';
00646
00647 if ( $this->wasPreviouslyAuthenticated() ) {
00648
00649
00650 phpCAS::trace('user was already authenticated, no need to look for tickets');
00651 $res = TRUE;
00652 } elseif ( $this->hasST() ) {
00653
00654 phpCAS::trace('ST `'.$this->getST().'\' is present');
00655 $this->validateST($validate_url,$text_response,$tree_response); // if it fails, it halts
00656 phpCAS::trace('ST `'.$this->getST().'\' was validated');
00657 if ( $this->isProxy() ) {
00658 $this->validatePGT($validate_url,$text_response,$tree_response);
00659 phpCAS::trace('PGT `'.$this->getPGT().'\' was validated');
00660 $_SESSION['phpCAS']['pgt'] = $this->getPGT();
00661 }
00662 $_SESSION['phpCAS']['user'] = $this->getUser();
00663 $res = TRUE;
00664 } elseif ( $this->hasPT() ) {
00665 // if a Proxy Ticket was given, validate it
00666 phpCAS::trace('PT `'.$this->getPT().'\' is present');
00667 $this->validatePT($validate_url,$text_response,$tree_response);
00668 phpCAS::trace('PT `'.$this->getPT().'\' was validated');
00669 if ( $this->isProxy() ) {
00670 $this->validatePGT($validate_url,$text_response,$tree_response); // idem
00671 phpCAS::trace('PGT `'.$this->getPGT().'\' was validated');
00672 $_SESSION['phpCAS']['pgt'] = $this->getPGT();
00673 }
00674 $_SESSION['phpCAS']['user'] = $this->getUser();
00675 $res = TRUE;
00676 } else {
00677
00678 phpCAS::trace('no ticket found');
00679 }
00680
00681 phpCAS::traceEnd($res);
00682 return $res;
00683 }
00684
00695 function wasPreviouslyAuthenticated()
00696 {
00697 phpCAS::traceBegin();
00698
00699 if ( $this->isCallbackMode() ) {
00700 $this->callback();
00701 }
00702
00703 $auth = FALSE;
00704
00705 if ( $this->isProxy() ) {
00706
00707 if ( !empty($_SESSION['phpCAS']['user']) && !empty($_SESSION['phpCAS']['pgt']) ) {
00708
00709 $this->setUser($_SESSION['phpCAS']['user']);
00710 $this->setPGT($_SESSION['phpCAS']['pgt']);
00711 phpCAS::trace('user = `'.$_SESSION['phpCAS']['user'].'\', PGT = `'.$_SESSION['phpCAS']['pgt'].'\'');
00712 $auth = TRUE;
00713 } elseif ( !empty($_SESSION['phpCAS']['user']) && empty($_SESSION['phpCAS']['pgt']) ) {
00714
00715 phpCAS::trace('username found (`'.$_SESSION['phpCAS']['user'].'\') but PGT is empty');
00716 // unset all tickets to enforce authentication
00717 unset($_SESSION['phpCAS']);
00718 $this->setST('');
00719 $this->setPT('');
00720 } elseif ( empty($_SESSION['phpCAS']['user']) && !empty($_SESSION['phpCAS']['pgt']) ) {
00721 // these two variables should be empty or not empty at the same time
00722 phpCAS::trace('PGT found (`'.$_SESSION['phpCAS']['pgt'].'\') but username is empty');
00723
00724 unset($_SESSION['phpCAS']);
00725 $this->setST('');
00726 $this->setPT('');
00727 } else {
00728 phpCAS::trace('neither user not PGT found');
00729 }
00730 } else {
00731
00732 if ( !empty($_SESSION['phpCAS']['user']) ) {
00733
00734 $this->setUser($_SESSION['phpCAS']['user']);
00735 phpCAS::trace('user = `'.$_SESSION['phpCAS']['user'].'\'');
00736 $auth = TRUE;
00737 } else {
00738 phpCAS::trace('no user found');
00739 }
00740 }
00741
00742 phpCAS::traceEnd($auth);
00743 return $auth;
00744 }
00745
00752 function redirectToCas($gateway)
00753 {
00754 phpCAS::traceBegin();
00755 $cas_url = $this->getServerLoginURL($gateway);
00756 header('Location: '.$cas_url);
00757 $this->printHTMLHeader($this->getString(CAS_STR_AUTHENTICATION_WANTED));
00758 printf('<p>'.$this->getString(CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED).'</p>',$cas_url);
00759 $this->printHTMLFooter();
00760 phpCAS::traceExit();
00761 exit();
00762 }
00763
00769 function logout($url = "")
00770 {
00771 phpCAS::traceBegin();
00772 $cas_url = $this->getServerLogoutURL();
00773
00774
00775 if ( $url != "" ) {
00776 $url = '?service=' . $url;
00777 }
00778 header('Location: '.$cas_url . $url);
00779 session_unset();
00780 session_destroy();
00781 $this->printHTMLHeader($this->getString(CAS_STR_LOGOUT));
00782 printf('<p>'.$this->getString(CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED).'</p>',$cas_url);
00783 $this->printHTMLFooter();
00784 phpCAS::traceExit();
00785 exit();
00786 }
00787
00790
00791
00792
00793
00794
00795
00796
00797
00798
00812 var $_st = '';
00813
00819 function getST()
00820 { return $this->_st; }
00821
00827 function setST($st)
00828 { $this->_st = $st; }
00829
00835 function hasST()
00836 { return !empty($this->_st); }
00837
00840
00841
00842
00861 function validateST($validate_url,&$text_response,&$tree_response)
00862 {
00863 phpCAS::traceBegin();
00864
00865 $validate_url = $this->getServerServiceValidateURL().'&ticket='.$this->getST();
00866 if ( $this->isProxy() ) {
00867
00868 $validate_url .= '&pgtUrl='.$this->getCallbackURL();
00869 }
00870
00871
00872 if ( !$this->readURL($validate_url,'',$headers,$text_response,$err_msg) ) {
00873 phpCAS::trace('could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')');
00874 $this->authError('ST not validated (1)',
00875 $validate_url,
00876 TRUE/*$no_response*/);
00877 }
00878
00879 // analyze the result depending on the version
00880 switch ($this->getServerVersion()) {
00881 case CAS_VERSION_1_0:
00882 if (preg_match('/^no\n/',$text_response)) {
00883 phpCAS::trace('ST has not been validated');
00884 $this->authError('ST not validated (2)',
00885 $validate_url,
00886 FALSE/*$no_response*/,
00887 FALSE/*$bad_response*/,
00888 $text_response);
00889 }
00890 if (!preg_match('/^yes\n/',$text_response)) {
00891 phpCAS::trace('ill-formed response');
00892 $this->authError('ST not validated (3)',
00893 $validate_url,
00894 FALSE/*$no_response*/,
00895 TRUE/*$bad_response*/,
00896 $text_response);
00897 }
00898 // ST has been validated, extract the user name
00899 $arr = preg_split('/\n/',$text_response);
00900 $this->setUser(trim($arr[1]));
00901 break;
00902 case CAS_VERSION_2_0:
00903 // read the response of the CAS server into a DOM object
00904 if ( !($dom = domxml_open_mem($text_response))) {
00905 phpCAS::trace('domxml_open_mem() failed');
00906 $this->authError('ST not validated (4)',
00907 $validate_url,
00908 FALSE/*$no_response*/,
00909 TRUE/*$bad_response*/,
00910 $text_response);
00911 }
00912 // read the root node of the XML tree
00913 if ( !($tree_response = $dom->document_element()) ) {
00914 phpCAS::trace('document_element() failed');
00915 $this->authError('ST not validated (5)',
00916 $validate_url,
00917 FALSE/*$no_response*/,
00918 TRUE/*$bad_response*/,
00919 $text_response);
00920 }
00921 // insure that tag name is 'serviceResponse'
00922 if ( hnodename($tree_response->node_name()) != 'serviceResponse' ) {
00923 phpCAS::trace('bad XML root node (should be `serviceResponse\' instead of `'.hnodename($tree_response->node_name()).'\'');
00924 $this->authError('ST not validated (6)',
00925 $validate_url,
00926 FALSE,
00927 TRUE,
00928 $text_response);
00929 }
00930 if ( sizeof($success_elements = $tree_response->get_elements_by_tagname("authenticationSuccess")) != 0) {
00931
00932 if ( sizeof($user_elements = $success_elements[0]->get_elements_by_tagname("user")) == 0) {
00933 phpCAS::trace('<authenticationSuccess> found, but no <user>');
00934 $this->authError('ST not validated (7)',
00935 $validate_url,
00936 FALSE,
00937 TRUE,
00938 $text_response);
00939 }
00940 $user = trim($user_elements[0]->get_content());
00941 phpCAS::trace('user = `'.$user);
00942 $this->setUser($user);
00943
00944 } else if ( sizeof($failure_elements = $tree_response->get_elements_by_tagname("authenticationFailure")) != 0) {
00945 phpCAS::trace('<authenticationFailure> found');
00946
00947 $this->authError('ST not validated (8)',
00948 $validate_url,
00949 FALSE,
00950 FALSE,
00951 $text_response,
00952 $failure_elements[0]->get_attribute('code'),
00953 trim($failure_elements[0]->get_content()));
00954 } else {
00955 phpCAS::trace('neither <authenticationSuccess> nor <authenticationFailure> found');
00956 $this->authError('ST not validated (9)',
00957 $validate_url,
00958 FALSE,
00959 TRUE,
00960 $text_response);
00961 }
00962 break;
00963 }
00964
00965
00966 phpCAS::traceEnd(TRUE);
00967 return TRUE;
00968 }
00969
00972
00973
00974
00975
00976
00977
00978
00979
00980
00992 var $_proxy;
00993
01001 function isProxy()
01002 {
01003 return $this->_proxy;
01004 }
01005
01007
01008
01009
01022 var $_pgt = '';
01023
01029 function getPGT()
01030 { return $this->_pgt; }
01031
01037 function setPGT($pgt)
01038 { $this->_pgt = $pgt; }
01039
01045 function hasPGT()
01046 { return !empty($this->_pgt); }
01047
01050
01051
01052
01070 var $_callback_mode = FALSE;
01071
01079 function setCallbackMode($callback_mode)
01080 {
01081 $this->_callback_mode = $callback_mode;
01082 }
01083
01092 function isCallbackMode()
01093 {
01094 return $this->_callback_mode;
01095 }
01096
01105 var $_callback_url = '';
01106
01116 function getCallbackURL()
01117 {
01118
01119 if ( empty($this->_callback_url) ) {
01120 $final_uri = '';
01121
01122 $final_uri = 'https://';
01123
01124
01125
01126 if(empty($_SERVER['HTTP_X_FORWARDED_SERVER'])){
01127
01128
01129
01130 if (empty($_SERVER['SERVER_NAME'])) {
01131 $final_uri .= $_SERVER['HTTP_HOST'];
01132 } else {
01133 $final_uri .= $_SERVER['SERVER_NAME'];
01134 }
01135 } else {
01136 $final_uri .= $_SERVER['HTTP_X_FORWARDED_SERVER'];
01137 }
01138 if ( ($_SERVER['HTTPS']=='on' && $_SERVER['SERVER_PORT']!=443)
01139 || ($_SERVER['HTTPS']!='on' && $_SERVER['SERVER_PORT']!=80) ) {
01140 $final_uri .= ':';
01141 $final_uri .= $_SERVER['SERVER_PORT'];
01142 }
01143 $request_uri = $_SERVER['REQUEST_URI'];
01144 $request_uri = preg_replace('/\?.*$/','',$request_uri);
01145 $final_uri .= $request_uri;
01146 $this->setCallbackURL($final_uri);
01147 }
01148 return $this->_callback_url;
01149 }
01150
01158 function setCallbackURL($url)
01159 {
01160 return $this->_callback_url = $url;
01161 }
01162
01169 function callback()
01170 {
01171 phpCAS::traceBegin();
01172 $this->printHTMLHeader('phpCAS callback');
01173 $pgt_iou = $_GET['pgtIou'];
01174 $pgt = $_GET['pgtId'];
01175 phpCAS::trace('Storing PGT `'.$pgt.'\' (id=`'.$pgt_iou.'\')');
01176 echo '<p>Storing PGT `'.$pgt.'\' (id=`'.$pgt_iou.'\').</p>';
01177 $this->storePGT($pgt,$pgt_iou);
01178 $this->printHTMLFooter();
01179 phpCAS::traceExit();
01180 }
01181
01184
01185
01186
01200 var $_pgt_storage = null;
01201
01208 function initPGTStorage()
01209 {
01210
01211 if ( !is_object($this->_pgt_storage) ) {
01212 $this->setPGTStorageFile();
01213 }
01214
01215
01216 $this->_pgt_storage->init();
01217 }
01218
01227 function storePGT($pgt,$pgt_iou)
01228 {
01229
01230 $this->initPGTStorage();
01231
01232 $this->_pgt_storage->write($pgt,$pgt_iou);
01233 }
01234
01244 function loadPGT($pgt_iou)
01245 {
01246
01247 $this->initPGTStorage();
01248
01249 return $this->_pgt_storage->read($pgt_iou);
01250 }
01251
01261 function setPGTStorageFile($format='',
01262 $path='')
01263 {
01264
01265 if ( is_object($this->_pgt_storage) ) {
01266 phpCAS::error('PGT storage already defined');
01267 }
01268
01269
01270 $this->_pgt_storage = &new PGTStorageFile($this,$format,$path);
01271 }
01272
01290 function setPGTStorageDB($user,
01291 $password,
01292 $database_type,
01293 $hostname,
01294 $port,
01295 $database,
01296 $table)
01297 {
01298
01299 if ( is_object($this->_pgt_storage) ) {
01300 phpCAS::error('PGT storage already defined');
01301 }
01302
01303
01304 trigger_error('PGT storage into database is an experimental feature, use at your own risk',E_USER_WARNING);
01305
01306
01307 $this->_pgt_storage = & new PGTStorageDB($this,$user,$password,$database_type,$hostname,$port,$database,$table);
01308 }
01309
01310
01311
01312
01326 function validatePGT(&$validate_url,$text_response,$tree_response)
01327 {
01328 phpCAS::traceBegin();
01329 if ( sizeof($arr = $tree_response->get_elements_by_tagname("proxyGrantingTicket")) == 0) {
01330 phpCAS::trace('<proxyGrantingTicket> not found');
01331
01332 $this->authError('Ticket validated but no PGT Iou transmitted',
01333 $validate_url,
01334 FALSE,
01335 FALSE,
01336 $text_response);
01337 } else {
01338
01339 $pgt_iou = trim($arr[0]->get_content());
01340 $pgt = $this->loadPGT($pgt_iou);
01341 if ( $pgt == FALSE ) {
01342 phpCAS::trace('could not load PGT');
01343 $this->authError('PGT Iou was transmitted but PGT could not be retrieved',
01344 $validate_url,
01345 FALSE,
01346 FALSE,
01347 $text_response);
01348 }
01349 $this->setPGT($pgt);
01350 }
01351 phpCAS::traceEnd(TRUE);
01352 return TRUE;
01353 }
01354
01355
01356
01357
01358
01370 function retrievePT($target_service,&$err_code,&$err_msg)
01371 {
01372 phpCAS::traceBegin();
01373
01374
01375
01376
01377
01378 $err_msg = '';
01379
01380
01381 $cas_url = $this->getServerProxyURL().'?targetService='.preg_replace('/&/','%26',$target_service).'&pgt='.$this->getPGT();
01382
01383
01384 if ( !$this->readURL($cas_url,'',$headers,$cas_response,$err_msg) ) {
01385 phpCAS::trace('could not open URL \''.$cas_url.'\' to validate ('.$err_msg.')');
01386 $err_code = PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE;
01387 $err_msg = 'could not retrieve PT (no response from the CAS server)';
01388 phpCAS::traceEnd(FALSE);
01389 return FALSE;
01390 }
01391
01392 $bad_response = FALSE;
01393
01394 if ( !$bad_response ) {
01395 // read the response of the CAS server into a DOM object
01396 if ( !($dom = @domxml_open_mem($cas_response))) {
01397 phpCAS::trace('domxml_open_mem() failed');
01398 // read failed
01399 $bad_response = TRUE;
01400 }
01401 }
01402
01403 if ( !$bad_response ) {
01404 // read the root node of the XML tree
01405 if ( !($root = $dom->document_element()) ) {
01406 phpCAS::trace('document_element() failed');
01407 // read failed
01408 $bad_response = TRUE;
01409 }
01410 }
01411
01412 if ( !$bad_response ) {
01413 // insure that tag name is 'serviceResponse'
01414 if ( hnodename($root->node_name()) != 'serviceResponse' ) {
01415 phpCAS::trace('node_name() failed');
01416 // bad root node
01417 $bad_response = TRUE;
01418 }
01419 }
01420
01421 if ( !$bad_response ) {
01422 // look for a proxySuccess tag
01423 if ( sizeof($arr = $root->get_elements_by_tagname("proxySuccess")) != 0) {
01424 // authentication succeded, look for a proxyTicket tag
01425 if ( sizeof($arr = $root->get_elements_by_tagname("proxyTicket")) != 0) {
01426 $err_code = PHPCAS_SERVICE_OK;
01427 $err_msg = '';
01428 $pt = trim($arr[0]->get_content());
01429 phpCAS::traceEnd($pt);
01430 return $pt;
01431 } else {
01432 phpCAS::trace('<proxySuccess> was found, but not <proxyTicket>');
01433 }
01434 }
01435 // look for a proxyFailure tag
01436 else if ( sizeof($arr = $root->get_elements_by_tagname("proxyFailure")) != 0) {
01437 // authentication failed, extract the error
01438 $err_code = PHPCAS_SERVICE_PT_FAILURE;
01439 $err_msg = 'PT retrieving failed (code=`'
01440 .$arr[0]->get_attribute('code')
01441 .'\', message=`'
01442 .trim($arr[0]->get_content())
01443 .'\')';
01444 phpCAS::traceEnd(FALSE);
01445 return FALSE;
01446 } else {
01447 phpCAS::trace('neither <proxySuccess> nor <proxyFailure> found');
01448 }
01449 }
01450
01451 // at this step, we are sure that the response of the CAS server was ill-formed
01452 $err_code = PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE;
01453 $err_msg = 'Invalid response from the CAS server (response=`'.$cas_response.'\')';
01454
01455 phpCAS::traceEnd(FALSE);
01456 return FALSE;
01457 }
01458
01459
01460
01461
01462
01478 function readURL($url,$cookies,&$headers,&$body,&$err_msg)
01479 {
01480 phpCAS::traceBegin();
01481 $headers = '';
01482 $body = '';
01483 $err_msg = '';
01484
01485 $res = TRUE;
01486
01487
01488 $ch = curl_init($url);
01489
01490
01491 curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1);
01492
01493 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
01494
01495
01496 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
01497
01498 curl_setopt($ch, CURLOPT_HEADER, 1);
01499
01500 if ( is_array($cookies) ) {
01501 curl_setopt($ch,CURLOPT_COOKIE,implode(';',$cookies));
01502 }
01503
01504 $buf = curl_exec ($ch);
01505 if ( $buf === FALSE ) {
01506 phpCAS::trace('cur_exec() failed');
01507 $err_msg = 'CURL error #'.curl_errno($ch).': '.curl_error($ch);
01508
01509 curl_close ($ch);
01510 $res = FALSE;
01511 } else {
01512
01513 curl_close ($ch);
01514
01515
01516
01517 $pos = FALSE;
01518 for ($i=0; $i<strlen($buf); $i++) {
01519 if ( $buf[$i] == chr(13) )
01520 if ( $buf[$i+1] == chr(10) )
01521 if ( $buf[$i+2] == chr(13) )
01522 if ( $buf[$i+3] == chr(10) ) {
01523
01524 $pos = $i;
01525 break;
01526 }
01527 }
01528
01529 if ( $pos === FALSE ) {
01530
01531 $err_msg = 'no header found';
01532 phpCAS::trace($err_msg);
01533 $res = FALSE;
01534 } else {
01535
01536 $headers = preg_split ("/[\n\r]+/",substr($buf,0,$pos));
01537
01538 $body = substr($buf,$pos+4);
01539 }
01540 }
01541
01542 phpCAS::traceEnd($res);
01543 return $res;
01544 }
01545
01561 function serviceWeb($url,&$err_code,&$output)
01562 {
01563 phpCAS::traceBegin();
01564
01565 $pt = $this->retrievePT($url,$err_code,$output);
01566
01567 $res = TRUE;
01568
01569
01570 if ( !$pt ) {
01571
01572 phpCAS::trace('PT was not retrieved correctly');
01573 $res = FALSE;
01574 } else {
01575
01576 if ( is_array($_SESSION['phpCAS']['services'][$url]['cookies']) ) {
01577 foreach ( $_SESSION['phpCAS']['services'][$url]['cookies'] as $name => $val ) {
01578 $cookies[] = $name.'='.$val;
01579 }
01580 }
01581
01582
01583 if ( strstr($url,'?') === FALSE ) {
01584 $service_url = $url.'?ticket='.$pt;
01585 } else {
01586 $service_url = $url.'&ticket='.$pt;
01587 }
01588
01589 phpCAS::trace('reading URL`'.$service_url.'\'');
01590 if ( !$this->readURL($service_url,$cookies,$headers,$output,$err_msg) ) {
01591 phpCAS::trace('could not read URL`'.$service_url.'\'');
01592 $err_code = PHPCAS_SERVICE_NOT_AVAILABLE;
01593
01594 $output = sprintf($this->getString(CAS_STR_SERVICE_UNAVAILABLE),
01595 $service_url,
01596 $err_msg);
01597 $res = FALSE;
01598 } else {
01599
01600 phpCAS::trace('URL`'.$service_url.'\' has been read, storing cookies:');
01601 foreach ( $headers as $header ) {
01602 // test if the header is a cookie
01603 if ( preg_match('/^Set-Cookie:/',$header) ) {
01604 // the header is a cookie, remove the beginning
01605 $header_val = preg_replace('/^Set-Cookie: */','',$header);
01606 // extract interesting information
01607 $name_val = strtok($header_val,'; ');
01608 // extract the name and the value of the cookie
01609 $cookie_name = strtok($name_val,'=');
01610 $cookie_val = strtok('=');
01611 // store the cookie
01612 $_SESSION['phpCAS']['services'][$url]['cookies'][$cookie_name] = $cookie_val;
01613 phpCAS::trace($cookie_name.' -> '.$cookie_val);
01614 }
01615 }
01616 }
01617 }
01618
01619 phpCAS::traceEnd($res);
01620 return $res;
01621 }
01622
01641 function serviceMail($url,$flags,&$err_code,&$err_msg,&$pt)
01642 {
01643 phpCAS::traceBegin();
01644 // at first retrieve a PT
01645 $pt = $this->retrievePT($target_service,$err_code,$output);
01646
01647 $stream = FALSE;
01648
01649 // test if PT was retrieved correctly
01650 if ( !$pt ) {
01651 // note: $err_code and $err_msg are filled by CASClient::retrievePT()
01652 phpCAS::trace('PT was not retrieved correctly');
01653 } else {
01654 phpCAS::trace('opening IMAP URL `'.$url.'\'...');
01655 $stream = @imap_open($url,$this->getUser(),$pt,$flags);
01656 if ( !$stream ) {
01657 phpCAS::trace('could not open URL');
01658 $err_code = PHPCAS_SERVICE_NOT_AVAILABLE;
01659
01660 $err_msg = sprintf($this->getString(CAS_STR_SERVICE_UNAVAILABLE),
01661 $service_url,
01662 var_export(imap_errors(),TRUE));
01663 $pt = FALSE;
01664 $stream = FALSE;
01665 } else {
01666 phpCAS::trace('ok');
01667 }
01668 }
01669
01670 phpCAS::traceEnd($stream);
01671 return $stream;
01672 }
01673
01676
01677
01678
01679
01680
01681
01682
01683
01684
01698 var $_pt = '';
01699
01705 function getPT()
01706 { return $this->_pt; }
01707
01713 function setPT($pt)
01714 { $this->_pt = $pt; }
01715
01721 function hasPT()
01722 { return !empty($this->_pt); }
01723
01725
01726
01727
01740 function validatePT(&$validate_url,&$text_response,&$tree_response)
01741 {
01742 phpCAS::traceBegin();
01743
01744 $validate_url = $this->getServerProxyValidateURL().'&ticket='.$this->getPT();
01745
01746 if ( $this->isProxy() ) {
01747
01748 $validate_url .= '&pgtUrl='.$this->getCallbackURL();
01749 }
01750
01751
01752 if ( !$this->readURL($validate_url,'',$headers,$text_response,$err_msg) ) {
01753 phpCAS::trace('could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')');
01754 $this->authError('PT not validated',
01755 $validate_url,
01756 TRUE/*$no_response*/);
01757 }
01758
01759 // read the response of the CAS server into a DOM object
01760 if ( !($dom = domxml_open_mem($text_response))) {
01761 // read failed
01762 $this->authError('PT not validated',
01763 $alidate_url,
01764 FALSE/*$no_response*/,
01765 TRUE/*$bad_response*/,
01766 $text_response);
01767 }
01768 // read the root node of the XML tree
01769 if ( !($tree_response = $dom->document_element()) ) {
01770 // read failed
01771 $this->authError('PT not validated',
01772 $validate_url,
01773 FALSE/*$no_response*/,
01774 TRUE/*$bad_response*/,
01775 $text_response);
01776 }
01777 // insure that tag name is 'serviceResponse'
01778 if ( hnodename($tree_response->node_name()) != 'serviceResponse' ) {
01779 // bad root node
01780 $this->authError('PT not validated',
01781 $validate_url,
01782 FALSE/*$no_response*/,
01783 TRUE/*$bad_response*/,
01784 $text_response);
01785 }
01786 if ( sizeof($arr = $tree_response->get_elements_by_tagname("authenticationSuccess")) != 0) {
01787 // authentication succeded, extract the user name
01788 if ( sizeof($arr = $tree_response->get_elements_by_tagname("user")) == 0) {
01789 // no user specified => error
01790 $this->authError('PT not validated',
01791 $validate_url,
01792 FALSE/*$no_response*/,
01793 TRUE/*$bad_response*/,
01794 $text_response);
01795 }
01796 $this->setUser(trim($arr[0]->get_content()));
01797
01798 } else if ( sizeof($arr = $tree_response->get_elements_by_tagname("authenticationFailure")) != 0) {
01799 // authentication succeded, extract the error code and message
01800 $this->authError('PT not validated',
01801 $validate_url,
01802 FALSE/*$no_response*/,
01803 FALSE/*$bad_response*/,
01804 $text_response,
01805 $arr[0]->get_attribute('code')/*$err_code*/,
01806 trim($arr[0]->get_content())/*$err_msg*/);
01807 } else {
01808 $this->authError('PT not validated',
01809 $validate_url,
01810 FALSE/*$no_response*/,
01811 TRUE/*$bad_response*/,
01812 $text_response);
01813 }
01814
01815 // at this step, PT has been validated and $this->_user has been set,
01816
01817 phpCAS::traceEnd(TRUE);
01818 return TRUE;
01819 }
01820
01823 // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
01824 // XX XX
01825 // XX MISC XX
01826 // XX XX
01827 // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
01828
01834 // ########################################################################
01835 // URL
01836 // ########################################################################
01844 var $_url = '';
01845
01854 function getURL()
01855 {
01856 phpCAS::traceBegin();
01857 // the URL is built when needed only
01858 if ( empty($this->_url) ) {
01859 $final_uri = '';
01860 // remove the ticket if present in the URL
01861 $final_uri = ($_SERVER['HTTPS'] == 'on') ? 'https' : 'http';
01862 $final_uri .= ':
01863
01864
01865
01866 if(empty($_SERVER['HTTP_X_FORWARDED_SERVER'])){
01867
01868
01869
01870 if (empty($_SERVER['SERVER_NAME'])) {
01871 $final_uri .= $_SERVER['HTTP_HOST'];
01872 } else {
01873 $final_uri .= $_SERVER['SERVER_NAME'];
01874 }
01875 } else {
01876 $final_uri .= $_SERVER['HTTP_X_FORWARDED_SERVER'];
01877 }
01878 if ( ($_SERVER['HTTPS']=='on' && $_SERVER['SERVER_PORT']!=443)
01879 || ($_SERVER['HTTPS']!='on' && $_SERVER['SERVER_PORT']!=80) ) {
01880 $final_uri .= ':';
01881 $final_uri .= $_SERVER['SERVER_PORT'];
01882 }
01883
01884 $final_uri .= strtok($_SERVER['REQUEST_URI'],"?");
01885 $cgi_params = '?'.strtok("?");
01886
01887 $cgi_params = preg_replace('/&ticket=[^&]*/','',$cgi_params);
01888 $cgi_params = preg_replace('/\?ticket=[^&;]*/','?',$cgi_params);
01889 $cgi_params = preg_replace('/\?$/','',$cgi_params);
01890 $final_uri .= $cgi_params;
01891 $this->setURL($final_uri);
01892 }
01893 phpCAS::traceEnd($this->_url);
01894 return $this->_url;
01895 }
01896
01904 function setURL($url)
01905 {
01906 $this->_url = $url;
01907 }
01908
01909
01910
01911
01927 function authError($failure,$cas_url,$no_response,$bad_response='',$cas_response='',$err_code='',$err_msg='')
01928 {
01929 phpCAS::traceBegin();
01930
01931 $this->printHTMLHeader($this->getString(CAS_STR_AUTHENTICATION_FAILED));
01932 printf($this->getString(CAS_STR_YOU_WERE_NOT_AUTHENTICATED),$this->getURL(),$_SERVER['SERVER_ADMIN']);
01933 phpCAS::trace('CAS URL: '.$cas_url);
01934 phpCAS::trace('Authentication failure: '.$failure);
01935 if ( $no_response ) {
01936 phpCAS::trace('Reason: no response from the CAS server');
01937 } else {
01938 if ( $bad_response ) {
01939 phpCAS::trace('Reason: bad response from the CAS server');
01940 } else {
01941 switch ($this->getServerVersion()) {
01942 case CAS_VERSION_1_0:
01943 phpCAS::trace('Reason: CAS error');
01944 break;
01945 case CAS_VERSION_2_0:
01946 if ( empty($err_code) )
01947 phpCAS::trace('Reason: no CAS error');
01948 else
01949 phpCAS::trace('Reason: ['.$err_code.'] CAS error: '.$err_msg);
01950 break;
01951 }
01952 }
01953 phpCAS::trace('CAS response: '.$cas_response);
01954 }
01955 $this->printHTMLFooter();
01956 phpCAS::traceExit();
01957 exit();
01958 }
01959
01961 }
01962
01963 ?>