00001 <?php
00002
00008
00009 include_once(dirname(__FILE__).'/languages/languages.php');
00010
00011
00012 include_once(dirname(__FILE__).'/PGTStorage/pgt-main.php');
00013
00022 class CASClient
00023 {
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00052 function HTMLFilterOutput($str)
00053 {
00054 $str = str_replace('__CAS_VERSION__',$this->getServerVersion(),$str);
00055 $str = str_replace('__PHPCAS_VERSION__',phpCAS::getVersion(),$str);
00056 $str = str_replace('__SERVER_BASE_URL__',$this->getServerBaseURL(),$str);
00057 echo $str;
00058 }
00059
00068 var $_output_header = '';
00069
00079 function printHTMLHeader($title)
00080 {
00081 $this->HTMLFilterOutput(str_replace('__TITLE__',
00082 $title,
00083 (empty($this->_output_header)
00084 ? '<html><head><title>__TITLE__</title></head><body><h1>__TITLE__</h1>'
00085 : $this->_output_header)
00086 )
00087 );
00088 }
00089
00098 var $_output_footer = '';
00099
00107 function printHTMLFooter()
00108 {
00109 $this->HTMLFilterOutput(empty($this->_output_footer)
00110 ?('<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>')
00111 :$this->_output_footer);
00112 }
00113
00121 function setHTMLHeader($header)
00122 {
00123 $this->_output_header = $header;
00124 }
00125
00133 function setHTMLFooter($footer)
00134 {
00135 $this->_output_footer = $footer;
00136 }
00137
00139
00140
00141
00156 var $_lang = '';
00157
00165 function getLang()
00166 {
00167 if ( empty($this->_lang) )
00168 $this->setLang(PHPCAS_LANG_DEFAULT);
00169 return $this->_lang;
00170 }
00171
00181 var $_strings;
00182
00192 function getString($str)
00193 {
00194
00195 $this->getLang();
00196
00197 if ( !isset($this->_strings[$str]) ) {
00198 trigger_error('string `'.$str.'\' not defined for language `'.$this->getLang().'\'',E_USER_ERROR);
00199 }
00200 return $this->_strings[$str];
00201 }
00202
00212 function setLang($lang)
00213 {
00214
00215 include_once(dirname(__FILE__).'/languages/'.$lang.'.php');
00216
00217 if ( !is_array($this->_strings) ) {
00218 trigger_error('language `'.$lang.'\' is not implemented',E_USER_ERROR);
00219 }
00220 $this->_lang = $lang;
00221 }
00222
00224
00225
00226
00256 var $_server = array(
00257 'version' => -1,
00258 'hostname' => 'none',
00259 'port' => -1,
00260 'uri' => 'none'
00261 );
00262
00268 function getServerVersion()
00269 {
00270 return $this->_server['version'];
00271 }
00272
00278 function getServerHostname()
00279 { return $this->_server['hostname']; }
00280
00286 function getServerPort()
00287 { return $this->_server['port']; }
00288
00294 function getServerURI()
00295 { return $this->_server['uri']; }
00296
00302 function getServerBaseURL()
00303 {
00304
00305 if ( empty($this->_server['base_url']) ) {
00306 $this->_server['base_url'] = 'https:
00307 .$this->getServerHostname()
00308 .':'
00309 .$this->getServerPort()
00310 .$this->getServerURI();
00311 }
00312 return $this->_server['base_url'];
00313 }
00314
00321 function getServerLoginURL($gateway=false)
00322 {
00323 phpCAS::traceBegin();
00324
00325 if ( empty($this->_server['login_url']) ) {
00326 $this->_server['login_url'] = $this->getServerBaseURL();
00327 $this->_server['login_url'] .= 'login?service=';
00328
00329 $this->_server['login_url'] .= urlencode($this->getURL());
00330 if ($gateway) {
00331 $this->_server['login_url'] .= '&gateway=true';
00332 }
00333 }
00334 phpCAS::traceEnd($this->_server['login_url']);
00335 return $this->_server['login_url'];
00336 }
00337
00344 function setServerLoginURL($url)
00345 {
00346 return $this->_server['login_url'] = $url;
00347 }
00348
00354 function getServerServiceValidateURL()
00355 {
00356
00357 if ( empty($this->_server['service_validate_url']) ) {
00358 switch ($this->getServerVersion()) {
00359 case CAS_VERSION_1_0:
00360 $this->_server['service_validate_url'] = $this->getServerBaseURL().'validate';
00361 break;
00362 case CAS_VERSION_2_0:
00363 $this->_server['service_validate_url'] = $this->getServerBaseURL().'serviceValidate';
00364 break;
00365 }
00366 }
00367
00368 return $this->_server['service_validate_url'].'?service='.urlencode($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
00390 return $this->_server['proxy_validate_url'].'?service='.urlencode($this->getURL());
00391 }
00392
00398 function getServerProxyURL()
00399 {
00400
00401 if ( empty($this->_server['proxy_url']) ) {
00402 switch ($this->getServerVersion()) {
00403 case CAS_VERSION_1_0:
00404 $this->_server['proxy_url'] = '';
00405 break;
00406 case CAS_VERSION_2_0:
00407 $this->_server['proxy_url'] = $this->getServerBaseURL().'proxy';
00408 break;
00409 }
00410 }
00411 return $this->_server['proxy_url'];
00412 }
00413
00419 function getServerLogoutURL()
00420 {
00421
00422 if ( empty($this->_server['logout_url']) ) {
00423 $this->_server['logout_url'] = $this->getServerBaseURL().'logout';
00424 }
00425 return $this->_server['logout_url'];
00426 }
00427
00434 function setServerLogoutURL($url)
00435 {
00436 return $this->_server['logout_url'] = $url;
00437 }
00438
00444 function isHttps() {
00445
00446
00447 if ( isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
00448 return true;
00449 } else {
00450 return false;
00451 }
00452 }
00453
00454
00455
00456
00471 function CASClient(
00472 $server_version,
00473 $proxy,
00474 $server_hostname,
00475 $server_port,
00476 $server_uri,
00477 $start_session = true) {
00478
00479 phpCAS::traceBegin();
00480
00481
00482 if ($start_session) {
00483 session_start();
00484 }
00485
00486 $this->_proxy = $proxy;
00487
00488
00489 switch ($server_version) {
00490 case CAS_VERSION_1_0:
00491 if ( $this->isProxy() )
00492 phpCAS::error('CAS proxies are not supported in CAS '
00493 .$server_version);
00494 break;
00495 case CAS_VERSION_2_0:
00496 break;
00497 default:
00498 phpCAS::error('this version of CAS (`'
00499 .$server_version
00500 .'\') is not supported by phpCAS '
00501 .phpCAS::getVersion());
00502 }
00503 $this->_server['version'] = $server_version;
00504
00505
00506 if ( empty($server_hostname)
00507 || !preg_match('/[\.\d\-abcdefghijklmnopqrstuvwxyz]*/',$server_hostname) ) {
00508 phpCAS::error('bad CAS server hostname (`'.$server_hostname.'\')');
00509 }
00510 $this->_server['hostname'] = $server_hostname;
00511
00512
00513 if ( $server_port == 0
00514 || !is_int($server_port) ) {
00515 phpCAS::error('bad CAS server port (`'.$server_hostname.'\')');
00516 }
00517 $this->_server['port'] = $server_port;
00518
00519
00520 if ( !preg_match('/[\.\d\-_abcdefghijklmnopqrstuvwxyz\/]*/',$server_uri) ) {
00521 phpCAS::error('bad CAS server URI (`'.$server_uri.'\')');
00522 }
00523
00524 $server_uri = preg_replace('/\/\
00525 $this->_server['uri'] = $server_uri;
00526
00527
00528 if ( $this->isProxy() ) {
00529 $this->setCallbackMode(!empty($_GET['pgtIou'])&&!empty($_GET['pgtId']));
00530 }
00531
00532 if ( $this->isCallbackMode() ) {
00533
00534 if ( !$this->isHttps() ) {
00535 phpCAS::error('CAS proxies must be secured to use phpCAS; PGT\'s will not be received from the CAS server');
00536 }
00537 } else {
00538
00539 $ticket = (isset($_GET['ticket']) ? $_GET['ticket'] : null);
00540 switch ($this->getServerVersion()) {
00541 case CAS_VERSION_1_0:
00542 if( preg_match('/^ST-/',$ticket) ) {
00543 phpCAS::trace('ST \''.$ticket.'\' found');
00544
00545 $this->setST($ticket);
00546
00547 unset($_GET['ticket']);
00548 } else if ( !empty($ticket) ) {
00549
00550 phpCAS::error('ill-formed ticket found in the URL (ticket=`'.htmlentities($ticket).'\')');
00551 }
00552 break;
00553 case CAS_VERSION_2_0:
00554 if( preg_match('/^[SP]T-/',$ticket) ) {
00555 phpCAS::trace('ST or PT \''.$ticket.'\' found');
00556 $this->setPT($ticket);
00557 unset($_GET['ticket']);
00558 } else if ( !empty($ticket) ) {
00559
00560 phpCAS::error('ill-formed ticket found in the URL (ticket=`'.htmlentities($ticket).'\')');
00561 }
00562 break;
00563 }
00564 }
00565 phpCAS::traceEnd();
00566 }
00567
00570
00571
00572
00573
00574
00575
00588 var $_user = '';
00589
00597 function setUser($user)
00598 {
00599 $this->_user = $user;
00600 }
00601
00609 function getUser()
00610 {
00611 if ( empty($this->_user) ) {
00612 phpCAS::error('this method should be used only after '.__CLASS__.'::forceAuthentication() or '.__CLASS__.'::isAuthenticated()');
00613 }
00614 return $this->_user;
00615 }
00616
00623 function forceAuthentication()
00624 {
00625 phpCAS::traceBegin();
00626
00627 if ( $this->isAuthenticated() ) {
00628
00629 phpCAS::trace('no need to authenticate');
00630 $res = TRUE;
00631 } else {
00632
00633 unset($_SESSION['phpCAS']['auth_checked']);
00634 $this->redirectToCas(FALSE);
00635
00636 $res = FALSE;
00637 }
00638 phpCAS::traceEnd($res);
00639 return $res;
00640 }
00641
00648 var $_cache_times_for_auth_recheck = 0;
00649
00657 function setCacheTimesForAuthRequest($n)
00658 {
00659 $this->_cache_times_for_auth_recheck = n;
00660 }
00661
00667 function checkAuthentication()
00668 {
00669 phpCAS::traceBegin();
00670
00671 if ( $this->isAuthenticated() ) {
00672 phpCAS::trace('user is authenticated');
00673 $res = TRUE;
00674 } else if (isset($_SESSION['phpCAS']['auth_checked'])) {
00675
00676 unset($_SESSION['phpCAS']['auth_checked']);
00677 $res = FALSE;
00678 } else {
00679
00680
00681
00682
00683
00684 if (! isset($_SESSION['phpCAS']['unauth_count']) )
00685 $_SESSION['phpCAS']['unauth_count'] = -2;
00686
00687 if (($_SESSION['phpCAS']['unauth_count'] != -2 && $this->_cache_times_for_auth_recheck == -1)
00688 || ($_SESSION['phpCAS']['unauth_count'] >= 0 && $_SESSION['phpCAS']['unauth_count'] < $this->_cache_times_for_auth_recheck))
00689 {
00690 $res = FALSE;
00691
00692 if ($this->_cache_times_for_auth_recheck != -1)
00693 {
00694 $_SESSION['phpCAS']['unauth_count']++;
00695 phpCAS::trace('user is not authenticated (cached for '.$_SESSION['phpCAS']['unauth_count'].' times of '.$this->_cache_times_for_auth_recheck.')');
00696 }
00697 else
00698 {
00699 phpCAS::trace('user is not authenticated (cached for until login pressed)');
00700 }
00701 }
00702 else
00703 {
00704 $_SESSION['phpCAS']['unauth_count'] = 0;
00705 $_SESSION['phpCAS']['auth_checked'] = true;
00706 phpCAS::trace('user is not authenticated (cache reset)');
00707 $this->redirectToCas(TRUE);
00708
00709 $res = FALSE;
00710 }
00711 }
00712 phpCAS::traceEnd($res);
00713 return $res;
00714 }
00715
00724 function isAuthenticated()
00725 {
00726 phpCAS::traceBegin();
00727 $res = FALSE;
00728 $validate_url = '';
00729
00730 if ( $this->wasPreviouslyAuthenticated() ) {
00731
00732
00733 phpCAS::trace('user was already authenticated, no need to look for tickets');
00734 $res = TRUE;
00735 }
00736 elseif ( $this->hasST() ) {
00737
00738 phpCAS::trace('ST `'.$this->getST().'\' is present');
00739 $this->validateST($validate_url,$text_response,$tree_response);
00740 phpCAS::trace('ST `'.$this->getST().'\' was validated');
00741 if ( $this->isProxy() ) {
00742 $this->validatePGT($validate_url,$text_response,$tree_response);
00743 phpCAS::trace('PGT `'.$this->getPGT().'\' was validated');
00744 $_SESSION['phpCAS']['pgt'] = $this->getPGT();
00745 }
00746 $_SESSION['phpCAS']['user'] = $this->getUser();
00747 $res = TRUE;
00748 }
00749 elseif ( $this->hasPT() ) {
00750
00751 phpCAS::trace('PT `'.$this->getPT().'\' is present');
00752 $this->validatePT($validate_url,$text_response,$tree_response);
00753 phpCAS::trace('PT `'.$this->getPT().'\' was validated');
00754 if ( $this->isProxy() ) {
00755 $this->validatePGT($validate_url,$text_response,$tree_response);
00756 phpCAS::trace('PGT `'.$this->getPGT().'\' was validated');
00757 $_SESSION['phpCAS']['pgt'] = $this->getPGT();
00758 }
00759 $_SESSION['phpCAS']['user'] = $this->getUser();
00760 $res = TRUE;
00761 }
00762 else {
00763
00764 phpCAS::trace('no ticket found');
00765 }
00766
00767 phpCAS::traceEnd($res);
00768 return $res;
00769 }
00770
00776 function isSessionAuthenticated ()
00777 {
00778 return !empty($_SESSION['phpCAS']['user']);
00779 }
00780
00791 function wasPreviouslyAuthenticated()
00792 {
00793 phpCAS::traceBegin();
00794
00795 if ( $this->isCallbackMode() ) {
00796 $this->callback();
00797 }
00798
00799 $auth = FALSE;
00800
00801 if ( $this->isProxy() ) {
00802
00803 if ( $this->isSessionAuthenticated() && !empty($_SESSION['phpCAS']['pgt']) ) {
00804
00805 $this->setUser($_SESSION['phpCAS']['user']);
00806 $this->setPGT($_SESSION['phpCAS']['pgt']);
00807 phpCAS::trace('user = `'.$_SESSION['phpCAS']['user'].'\', PGT = `'.$_SESSION['phpCAS']['pgt'].'\'');
00808 $auth = TRUE;
00809 } elseif ( $this->isSessionAuthenticated() && empty($_SESSION['phpCAS']['pgt']) ) {
00810
00811 phpCAS::trace('username found (`'.$_SESSION['phpCAS']['user'].'\') but PGT is empty');
00812
00813 unset($_SESSION['phpCAS']);
00814 $this->setST('');
00815 $this->setPT('');
00816 } elseif ( !$this->isSessionAuthenticated() && !empty($_SESSION['phpCAS']['pgt']) ) {
00817
00818 phpCAS::trace('PGT found (`'.$_SESSION['phpCAS']['pgt'].'\') but username is empty');
00819
00820 unset($_SESSION['phpCAS']);
00821 $this->setST('');
00822 $this->setPT('');
00823 } else {
00824 phpCAS::trace('neither user not PGT found');
00825 }
00826 } else {
00827
00828 if ( $this->isSessionAuthenticated() ) {
00829
00830 $this->setUser($_SESSION['phpCAS']['user']);
00831 phpCAS::trace('user = `'.$_SESSION['phpCAS']['user'].'\'');
00832 $auth = TRUE;
00833 } else {
00834 phpCAS::trace('no user found');
00835 }
00836 }
00837
00838 phpCAS::traceEnd($auth);
00839 return $auth;
00840 }
00841
00848 function redirectToCas($gateway=false)
00849 {
00850 phpCAS::traceBegin();
00851 $cas_url = $this->getServerLoginURL($gateway);
00852 header('Location: '.$cas_url);
00853 $this->printHTMLHeader($this->getString(CAS_STR_AUTHENTICATION_WANTED));
00854 printf('<p>'.$this->getString(CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED).'</p>',$cas_url);
00855 $this->printHTMLFooter();
00856 phpCAS::traceExit();
00857 exit();
00858 }
00859
00865 function logout($url = "")
00866 {
00867 phpCAS::traceBegin();
00868 $cas_url = $this->getServerLogoutURL();
00869
00870
00871 if ( $url != "" ) {
00872 $url = '?service=' . $url;
00873 }
00874 header('Location: '.$cas_url . $url);
00875 session_unset();
00876 session_destroy();
00877 $this->printHTMLHeader($this->getString(CAS_STR_LOGOUT));
00878 printf('<p>'.$this->getString(CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED).'</p>',$cas_url);
00879 $this->printHTMLFooter();
00880 phpCAS::traceExit();
00881 exit();
00882 }
00883
00886
00887
00888
00889
00890
00891
00892
00893
00894
00908 var $_st = '';
00909
00915 function getST()
00916 { return $this->_st; }
00917
00923 function setST($st)
00924 { $this->_st = $st; }
00925
00931 function hasST()
00932 { return !empty($this->_st); }
00933
00936
00937
00938
00957 function validateST($validate_url,&$text_response,&$tree_response)
00958 {
00959 phpCAS::traceBegin();
00960
00961 $validate_url = $this->getServerServiceValidateURL().'&ticket='.$this->getST();
00962 if ( $this->isProxy() ) {
00963
00964 $validate_url .= '&pgtUrl='.$this->getCallbackURL();
00965 }
00966
00967
00968 if ( !$this->readURL($validate_url,'',$headers,$text_response,$err_msg) ) {
00969 phpCAS::trace('could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')');
00970 $this->authError('ST not validated',
00971 $validate_url,
00972 TRUE);
00973 }
00974
00975
00976 switch ($this->getServerVersion()) {
00977 case CAS_VERSION_1_0:
00978 if (preg_match('/^no\n/',$text_response)) {
00979 phpCAS::trace('ST has not been validated');
00980 $this->authError('ST not validated',
00981 $validate_url,
00982 FALSE,
00983 FALSE,
00984 $text_response);
00985 }
00986 if (!preg_match('/^yes\n/',$text_response)) {
00987 phpCAS::trace('ill-formed response');
00988 $this->authError('ST not validated',
00989 $validate_url,
00990 FALSE,
00991 TRUE,
00992 $text_response);
00993 }
00994
00995 $arr = preg_split('/\n/',$text_response);
00996 $this->setUser(trim($arr[1]));
00997 break;
00998 case CAS_VERSION_2_0:
00999
01000 if ( !($dom = domxml_open_mem($text_response))) {
01001 phpCAS::trace('domxml_open_mem() failed');
01002 $this->authError('ST not validated',
01003 $validate_url,
01004 FALSE,
01005 TRUE,
01006 $text_response);
01007 }
01008
01009 if ( !($tree_response = $dom->document_element()) ) {
01010 phpCAS::trace('document_element() failed');
01011 $this->authError('ST not validated',
01012 $validate_url,
01013 FALSE,
01014 TRUE,
01015 $text_response);
01016 }
01017
01018 if ( $tree_response->node_name() != 'serviceResponse' ) {
01019 phpCAS::trace('bad XML root node (should be `serviceResponse\' instead of `'.$tree_response->node_name().'\'');
01020 $this->authError('ST not validated',
01021 $validate_url,
01022 FALSE,
01023 TRUE,
01024 $text_response);
01025 }
01026 if ( sizeof($success_elements = $tree_response->get_elements_by_tagname("authenticationSuccess")) != 0) {
01027
01028 if ( sizeof($user_elements = $success_elements[0]->get_elements_by_tagname("user")) == 0) {
01029 phpCAS::trace('<authenticationSuccess> found, but no <user>');
01030 $this->authError('ST not validated',
01031 $validate_url,
01032 FALSE,
01033 TRUE,
01034 $text_response);
01035 }
01036 $user = trim($user_elements[0]->get_content());
01037 phpCAS::trace('user = `'.$user);
01038 $this->setUser($user);
01039
01040 } else if ( sizeof($failure_elements = $tree_response->get_elements_by_tagname("authenticationFailure")) != 0) {
01041 phpCAS::trace('<authenticationFailure> found');
01042
01043 $this->authError('ST not validated',
01044 $validate_url,
01045 FALSE,
01046 FALSE,
01047 $text_response,
01048 $failure_elements[0]->get_attribute('code'),
01049 trim($failure_elements[0]->get_content()));
01050 } else {
01051 phpCAS::trace('neither <authenticationSuccess> nor <authenticationFailure> found');
01052 $this->authError('ST not validated',
01053 $validate_url,
01054 FALSE,
01055 TRUE,
01056 $text_response);
01057 }
01058 break;
01059 }
01060
01061
01062 phpCAS::traceEnd(TRUE);
01063 return TRUE;
01064 }
01065
01068
01069
01070
01071
01072
01073
01074
01075
01076
01088 var $_proxy;
01089
01097 function isProxy()
01098 {
01099 return $this->_proxy;
01100 }
01101
01103
01104
01105
01118 var $_pgt = '';
01119
01125 function getPGT()
01126 { return $this->_pgt; }
01127
01133 function setPGT($pgt)
01134 { $this->_pgt = $pgt; }
01135
01141 function hasPGT()
01142 { return !empty($this->_pgt); }
01143
01146
01147
01148
01166 var $_callback_mode = FALSE;
01167
01175 function setCallbackMode($callback_mode)
01176 {
01177 $this->_callback_mode = $callback_mode;
01178 }
01179
01188 function isCallbackMode()
01189 {
01190 return $this->_callback_mode;
01191 }
01192
01201 var $_callback_url = '';
01202
01212 function getCallbackURL()
01213 {
01214
01215 if ( empty($this->_callback_url) ) {
01216 $final_uri = '';
01217
01218 $final_uri = 'https:
01219
01220
01221
01222 if(empty($_SERVER['HTTP_X_FORWARDED_SERVER'])){
01223
01224
01225
01226 if (empty($_SERVER['SERVER_NAME'])) {
01227 $final_uri .= $_SERVER['HTTP_HOST'];
01228 } else {
01229 $final_uri .= $_SERVER['SERVER_NAME'];
01230 }
01231 } else {
01232 $final_uri .= $_SERVER['HTTP_X_FORWARDED_SERVER'];
01233 }
01234 if ( ($this->isHttps() && $_SERVER['SERVER_PORT']!=443)
01235 || (!$this->isHttps() && $_SERVER['SERVER_PORT']!=80) ) {
01236 $final_uri .= ':';
01237 $final_uri .= $_SERVER['SERVER_PORT'];
01238 }
01239 $request_uri = $_SERVER['REQUEST_URI'];
01240 $request_uri = preg_replace('/\?.*$/','',$request_uri);
01241 $final_uri .= $request_uri;
01242 $this->setCallbackURL($final_uri);
01243 }
01244 return $this->_callback_url;
01245 }
01246
01254 function setCallbackURL($url)
01255 {
01256 return $this->_callback_url = $url;
01257 }
01258
01265 function callback()
01266 {
01267 phpCAS::traceBegin();
01268 $this->printHTMLHeader('phpCAS callback');
01269 $pgt_iou = $_GET['pgtIou'];
01270 $pgt = $_GET['pgtId'];
01271 phpCAS::trace('Storing PGT `'.$pgt.'\' (id=`'.$pgt_iou.'\')');
01272 echo '<p>Storing PGT `'.$pgt.'\' (id=`'.$pgt_iou.'\').</p>';
01273 $this->storePGT($pgt,$pgt_iou);
01274 $this->printHTMLFooter();
01275 phpCAS::traceExit();
01276 }
01277
01280
01281
01282
01296 var $_pgt_storage = null;
01297
01304 function initPGTStorage()
01305 {
01306
01307 if ( !is_object($this->_pgt_storage) ) {
01308 $this->setPGTStorageFile();
01309 }
01310
01311
01312 $this->_pgt_storage->init();
01313 }
01314
01323 function storePGT($pgt,$pgt_iou)
01324 {
01325
01326 $this->initPGTStorage();
01327
01328 $this->_pgt_storage->write($pgt,$pgt_iou);
01329 }
01330
01340 function loadPGT($pgt_iou)
01341 {
01342
01343 $this->initPGTStorage();
01344
01345 return $this->_pgt_storage->read($pgt_iou);
01346 }
01347
01357 function setPGTStorageFile($format='',
01358 $path='')
01359 {
01360
01361 if ( is_object($this->_pgt_storage) ) {
01362 phpCAS::error('PGT storage already defined');
01363 }
01364
01365
01366 $this->_pgt_storage = &new PGTStorageFile($this,$format,$path);
01367 }
01368
01386 function setPGTStorageDB($user,
01387 $password,
01388 $database_type,
01389 $hostname,
01390 $port,
01391 $database,
01392 $table)
01393 {
01394
01395 if ( is_object($this->_pgt_storage) ) {
01396 phpCAS::error('PGT storage already defined');
01397 }
01398
01399
01400 trigger_error('PGT storage into database is an experimental feature, use at your own risk',E_USER_WARNING);
01401
01402
01403 $this->_pgt_storage = & new PGTStorageDB($this,$user,$password,$database_type,$hostname,$port,$database,$table);
01404 }
01405
01406
01407
01408
01422 function validatePGT(&$validate_url,$text_response,$tree_response)
01423 {
01424 phpCAS::traceBegin();
01425 if ( sizeof($arr = $tree_response->get_elements_by_tagname("proxyGrantingTicket")) == 0) {
01426 phpCAS::trace('<proxyGrantingTicket> not found');
01427
01428 $this->authError('Ticket validated but no PGT Iou transmitted',
01429 $validate_url,
01430 FALSE,
01431 FALSE,
01432 $text_response);
01433 } else {
01434
01435 $pgt_iou = trim($arr[0]->get_content());
01436 $pgt = $this->loadPGT($pgt_iou);
01437 if ( $pgt == FALSE ) {
01438 phpCAS::trace('could not load PGT');
01439 $this->authError('PGT Iou was transmitted but PGT could not be retrieved',
01440 $validate_url,
01441 FALSE,
01442 FALSE,
01443 $text_response);
01444 }
01445 $this->setPGT($pgt);
01446 }
01447 phpCAS::traceEnd(TRUE);
01448 return TRUE;
01449 }
01450
01451
01452
01453
01454
01466 function retrievePT($target_service,&$err_code,&$err_msg)
01467 {
01468 phpCAS::traceBegin();
01469
01470
01471
01472
01473
01474 $err_msg = '';
01475
01476
01477
01478 $cas_url = $this->getServerProxyURL().'?targetService='.urlencode($target_service).'&pgt='.$this->getPGT();
01479
01480
01481 if ( !$this->readURL($cas_url,'',$headers,$cas_response,$err_msg) ) {
01482 phpCAS::trace('could not open URL \''.$cas_url.'\' to validate ('.$err_msg.')');
01483 $err_code = PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE;
01484 $err_msg = 'could not retrieve PT (no response from the CAS server)';
01485 phpCAS::traceEnd(FALSE);
01486 return FALSE;
01487 }
01488
01489 $bad_response = FALSE;
01490
01491 if ( !$bad_response ) {
01492
01493 if ( !($dom = @domxml_open_mem($cas_response))) {
01494 phpCAS::trace('domxml_open_mem() failed');
01495
01496 $bad_response = TRUE;
01497 }
01498 }
01499
01500 if ( !$bad_response ) {
01501
01502 if ( !($root = $dom->document_element()) ) {
01503 phpCAS::trace('document_element() failed');
01504
01505 $bad_response = TRUE;
01506 }
01507 }
01508
01509 if ( !$bad_response ) {
01510
01511 if ( $root->node_name() != 'serviceResponse' ) {
01512 phpCAS::trace('node_name() failed');
01513
01514 $bad_response = TRUE;
01515 }
01516 }
01517
01518 if ( !$bad_response ) {
01519
01520 if ( sizeof($arr = $root->get_elements_by_tagname("proxySuccess")) != 0) {
01521
01522 if ( sizeof($arr = $root->get_elements_by_tagname("proxyTicket")) != 0) {
01523 $err_code = PHPCAS_SERVICE_OK;
01524 $err_msg = '';
01525 phpCAS::trace('original PT: '.trim($arr[0]->get_content()));
01526 $pt = trim($arr[0]->get_content());
01527 phpCAS::traceEnd($pt);
01528 return $pt;
01529 } else {
01530 phpCAS::trace('<proxySuccess> was found, but not <proxyTicket>');
01531 }
01532 }
01533
01534 else if ( sizeof($arr = $root->get_elements_by_tagname("proxyFailure")) != 0) {
01535
01536 $err_code = PHPCAS_SERVICE_PT_FAILURE;
01537 $err_msg = 'PT retrieving failed (code=`'
01538 .$arr[0]->get_attribute('code')
01539 .'\', message=`'
01540 .trim($arr[0]->get_content())
01541 .'\')';
01542 phpCAS::traceEnd(FALSE);
01543 return FALSE;
01544 } else {
01545 phpCAS::trace('neither <proxySuccess> nor <proxyFailure> found');
01546 }
01547 }
01548
01549
01550 $err_code = PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE;
01551 $err_msg = 'Invalid response from the CAS server (response=`'.$cas_response.'\')';
01552
01553 phpCAS::traceEnd(FALSE);
01554 return FALSE;
01555 }
01556
01557
01558
01559
01560
01576 function readURL($url,$cookies,&$headers,&$body,&$err_msg)
01577 {
01578 phpCAS::traceBegin();
01579 $headers = '';
01580 $body = '';
01581 $err_msg = '';
01582
01583 $res = TRUE;
01584
01585
01586 $ch = curl_init($url);
01587
01588
01589 curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1);
01590
01591 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
01592
01593
01594 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
01595
01596 curl_setopt($ch, CURLOPT_HEADER, 1);
01597
01598 if ( is_array($cookies) ) {
01599 curl_setopt($ch,CURLOPT_COOKIE,implode(';',$cookies));
01600 }
01601
01602 $buf = curl_exec ($ch);
01603 if ( $buf === FALSE ) {
01604 phpCAS::trace('cur_exec() failed');
01605 $err_msg = 'CURL error #'.curl_errno($ch).': '.curl_error($ch);
01606
01607 curl_close ($ch);
01608 $res = FALSE;
01609 } else {
01610
01611 curl_close ($ch);
01612
01613
01614
01615 $pos = FALSE;
01616 for ($i=0; $i<strlen($buf); $i++) {
01617 if ( $buf[$i] == chr(13) )
01618 if ( $buf[$i+1] == chr(10) )
01619 if ( $buf[$i+2] == chr(13) )
01620 if ( $buf[$i+3] == chr(10) ) {
01621
01622 $pos = $i;
01623 break;
01624 }
01625 }
01626
01627 if ( $pos === FALSE ) {
01628
01629 $err_msg = 'no header found';
01630 phpCAS::trace($err_msg);
01631 $res = FALSE;
01632 } else {
01633
01634 $headers = preg_split ("/[\n\r]+/",substr($buf,0,$pos));
01635
01636 $body = substr($buf,$pos+4);
01637 }
01638 }
01639
01640 phpCAS::traceEnd($res);
01641 return $res;
01642 }
01643
01659 function serviceWeb($url,&$err_code,&$output)
01660 {
01661 phpCAS::traceBegin();
01662
01663 $pt = $this->retrievePT($url,$err_code,$output);
01664
01665 $res = TRUE;
01666
01667
01668 if ( !$pt ) {
01669
01670 phpCAS::trace('PT was not retrieved correctly');
01671 $res = FALSE;
01672 } else {
01673
01674 if ( is_array($_SESSION['phpCAS']['services'][$url]['cookies']) ) {
01675 foreach ( $_SESSION['phpCAS']['services'][$url]['cookies'] as $name => $val ) {
01676 $cookies[] = $name.'='.$val;
01677 }
01678 }
01679
01680
01681 if ( strstr($url,'?') === FALSE ) {
01682 $service_url = $url.'?ticket='.$pt;
01683 } else {
01684 $service_url = $url.'&ticket='.$pt;
01685 }
01686
01687 phpCAS::trace('reading URL`'.$service_url.'\'');
01688 if ( !$this->readURL($service_url,$cookies,$headers,$output,$err_msg) ) {
01689 phpCAS::trace('could not read URL`'.$service_url.'\'');
01690 $err_code = PHPCAS_SERVICE_NOT_AVAILABLE;
01691
01692 $output = sprintf($this->getString(CAS_STR_SERVICE_UNAVAILABLE),
01693 $service_url,
01694 $err_msg);
01695 $res = FALSE;
01696 } else {
01697
01698 phpCAS::trace('URL`'.$service_url.'\' has been read, storing cookies:');
01699 foreach ( $headers as $header ) {
01700
01701 if ( preg_match('/^Set-Cookie:/',$header) ) {
01702
01703 $header_val = preg_replace('/^Set-Cookie: */','',$header);
01704
01705 $name_val = strtok($header_val,'; ');
01706
01707 $cookie_name = strtok($name_val,'=');
01708 $cookie_val = strtok('=');
01709
01710 $_SESSION['phpCAS']['services'][$url]['cookies'][$cookie_name] = $cookie_val;
01711 phpCAS::trace($cookie_name.' -> '.$cookie_val);
01712 }
01713 }
01714 }
01715 }
01716
01717 phpCAS::traceEnd($res);
01718 return $res;
01719 }
01720
01739 function serviceMail($url,$flags,&$err_code,&$err_msg,&$pt)
01740 {
01741 phpCAS::traceBegin();
01742
01743 $pt = $this->retrievePT($target_service,$err_code,$output);
01744
01745 $stream = FALSE;
01746
01747
01748 if ( !$pt ) {
01749
01750 phpCAS::trace('PT was not retrieved correctly');
01751 } else {
01752 phpCAS::trace('opening IMAP URL `'.$url.'\'...');
01753 $stream = @imap_open($url,$this->getUser(),$pt,$flags);
01754 if ( !$stream ) {
01755 phpCAS::trace('could not open URL');
01756 $err_code = PHPCAS_SERVICE_NOT_AVAILABLE;
01757
01758 $err_msg = sprintf($this->getString(CAS_STR_SERVICE_UNAVAILABLE),
01759 $service_url,
01760 var_export(imap_errors(),TRUE));
01761 $pt = FALSE;
01762 $stream = FALSE;
01763 } else {
01764 phpCAS::trace('ok');
01765 }
01766 }
01767
01768 phpCAS::traceEnd($stream);
01769 return $stream;
01770 }
01771
01774
01775
01776
01777
01778
01779
01780
01781
01782
01796 var $_pt = '';
01797
01803 function getPT()
01804 {
01805 return 'ST'.substr($this->_pt, 2);
01806 }
01807
01813 function setPT($pt)
01814 { $this->_pt = $pt; }
01815
01821 function hasPT()
01822 { return !empty($this->_pt); }
01823
01825
01826
01827
01840 function validatePT(&$validate_url,&$text_response,&$tree_response)
01841 {
01842 phpCAS::traceBegin();
01843
01844 $validate_url = $this->getServerProxyValidateURL().'&ticket='.$this->getPT();
01845
01846 if ( $this->isProxy() ) {
01847
01848 $validate_url .= '&pgtUrl='.$this->getCallbackURL();
01849 }
01850
01851
01852 if ( !$this->readURL($validate_url,'',$headers,$text_response,$err_msg) ) {
01853 phpCAS::trace('could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')');
01854 $this->authError('PT not validated',
01855 $validate_url,
01856 TRUE);
01857 }
01858
01859
01860 if ( !($dom = domxml_open_mem($text_response))) {
01861
01862 $this->authError('PT not validated',
01863 $validate_url,
01864 FALSE,
01865 TRUE,
01866 $text_response);
01867 }
01868
01869 if ( !($tree_response = $dom->document_element()) ) {
01870
01871 $this->authError('PT not validated',
01872 $validate_url,
01873 FALSE,
01874 TRUE,
01875 $text_response);
01876 }
01877
01878 if ( $tree_response->node_name() != 'serviceResponse' ) {
01879
01880 $this->authError('PT not validated',
01881 $validate_url,
01882 FALSE,
01883 TRUE,
01884 $text_response);
01885 }
01886 if ( sizeof($arr = $tree_response->get_elements_by_tagname("authenticationSuccess")) != 0) {
01887
01888 if ( sizeof($arr = $tree_response->get_elements_by_tagname("user")) == 0) {
01889
01890 $this->authError('PT not validated',
01891 $validate_url,
01892 FALSE,
01893 TRUE,
01894 $text_response);
01895 }
01896 $this->setUser(trim($arr[0]->get_content()));
01897
01898 } else if ( sizeof($arr = $tree_response->get_elements_by_tagname("authenticationFailure")) != 0) {
01899
01900 $this->authError('PT not validated',
01901 $validate_url,
01902 FALSE,
01903 FALSE,
01904 $text_response,
01905 $arr[0]->get_attribute('code'),
01906 trim($arr[0]->get_content()));
01907 } else {
01908 $this->authError('PT not validated',
01909 $validate_url,
01910 FALSE,
01911 TRUE,
01912 $text_response);
01913 }
01914
01915
01916
01917 phpCAS::traceEnd(TRUE);
01918 return TRUE;
01919 }
01920
01923
01924
01925
01926
01927
01928
01934
01935
01936
01944 var $_url = '';
01945
01954 function getURL()
01955 {
01956 phpCAS::traceBegin();
01957
01958 if ( empty($this->_url) ) {
01959 $final_uri = '';
01960
01961 $final_uri = ($this->isHttps()) ? 'https' : 'http';
01962 $final_uri .= ':
01963
01964
01965
01966 if(empty($_SERVER['HTTP_X_FORWARDED_SERVER'])){
01967
01968
01969
01970 if (empty($_SERVER['SERVER_NAME'])) {
01971 $server_name = $_SERVER['HTTP_HOST'];
01972 } else {
01973 $server_name = $_SERVER['SERVER_NAME'];
01974 }
01975 } else {
01976 $server_name = $_SERVER['HTTP_X_FORWARDED_SERVER'];
01977 }
01978 $final_uri .= $server_name;
01979 if (!strpos($server_name, ':')) {
01980 if ( ($this->isHttps() && $_SERVER['SERVER_PORT']!=443)
01981 || (!$this->isHttps() && $_SERVER['SERVER_PORT']!=80) ) {
01982 $final_uri .= ':';
01983 $final_uri .= $_SERVER['SERVER_PORT'];
01984 }
01985 }
01986
01987 $final_uri .= strtok($_SERVER['REQUEST_URI'],"?");
01988 $cgi_params = '?'.strtok("?");
01989
01990 $cgi_params = preg_replace('/&ticket=[^&]*/','',$cgi_params);
01991 $cgi_params = preg_replace('/\?ticket=[^&;]*/','?',$cgi_params);
01992 $cgi_params = preg_replace('/\?%26/','?',$cgi_params);
01993 $cgi_params = preg_replace('/\?&/','?',$cgi_params);
01994 $cgi_params = preg_replace('/\?$/','',$cgi_params);
01995 $final_uri .= $cgi_params;
01996 $this->setURL($final_uri);
01997 }
01998 phpCAS::traceEnd($this->_url);
01999 return $this->_url;
02000 }
02001
02009 function setURL($url)
02010 {
02011 $this->_url = $url;
02012 }
02013
02014
02015
02016
02032 function authError($failure,$cas_url,$no_response,$bad_response='',$cas_response='',$err_code='',$err_msg='')
02033 {
02034 phpCAS::traceBegin();
02035
02036 $this->printHTMLHeader($this->getString(CAS_STR_AUTHENTICATION_FAILED));
02037 printf($this->getString(CAS_STR_YOU_WERE_NOT_AUTHENTICATED),$this->getURL(),$_SERVER['SERVER_ADMIN']);
02038 phpCAS::trace('CAS URL: '.$cas_url);
02039 phpCAS::trace('Authentication failure: '.$failure);
02040 if ( $no_response ) {
02041 phpCAS::trace('Reason: no response from the CAS server');
02042 } else {
02043 if ( $bad_response ) {
02044 phpCAS::trace('Reason: bad response from the CAS server');
02045 } else {
02046 switch ($this->getServerVersion()) {
02047 case CAS_VERSION_1_0:
02048 phpCAS::trace('Reason: CAS error');
02049 break;
02050 case CAS_VERSION_2_0:
02051 if ( empty($err_code) )
02052 phpCAS::trace('Reason: no CAS error');
02053 else
02054 phpCAS::trace('Reason: ['.$err_code.'] CAS error: '.$err_msg);
02055 break;
02056 }
02057 }
02058 phpCAS::trace('CAS response: '.$cas_response);
02059 }
02060 $this->printHTMLFooter();
02061 phpCAS::traceExit();
02062 exit();
02063 }
02064
02066 }
02067
02068 ?>