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 // CAS SERVER CONFIG
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 // the URL is build only when needed
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
00324 function getServerLoginURL($gateway=false,$renew=false) {
00325 phpCAS::traceBegin();
00326
00327 if ( empty($this->_server['login_url']) ) {
00328 $this->_server['login_url'] = $this->getServerBaseURL();
00329 $this->_server['login_url'] .= 'login?service=';
00330
00331 $this->_server['login_url'] .= urlencode($this->getURL());
00332 if($renew) {
00333
00334 $this->_server['login_url'] .= '&renew=true';
00335 } elseif ($gateway) {
00336
00337 $this->_server['login_url'] .= '&gateway=true';
00338 }
00339 }
00340 phpCAS::traceEnd($this->_server['login_url']);
00341 return $this->_server['login_url'];
00342 }
00343
00350 function setServerLoginURL($url)
00351 {
00352 return $this->_server['login_url'] = $url;
00353 }
00354
00355
00362 function setServerServiceValidateURL($url)
00363 {
00364 return $this->_server['service_validate_url'] = $url;
00365 }
00366
00367
00374 function setServerProxyValidateURL($url)
00375 {
00376 return $this->_server['proxy_validate_url'] = $url;
00377 }
00378
00379
00386 function setServerSamlValidateURL($url)
00387 {
00388 return $this->_server['saml_validate_url'] = $url;
00389 }
00390
00391
00397 function getServerServiceValidateURL()
00398 {
00399
00400 if ( empty($this->_server['service_validate_url']) ) {
00401 switch ($this->getServerVersion()) {
00402 case CAS_VERSION_1_0:
00403 $this->_server['service_validate_url'] = $this->getServerBaseURL().'validate';
00404 break;
00405 case CAS_VERSION_2_0:
00406 $this->_server['service_validate_url'] = $this->getServerBaseURL().'serviceValidate';
00407 break;
00408 }
00409 }
00410
00411 return $this->_server['service_validate_url'].'?service='.urlencode($this->getURL());
00412 }
00418 function getServerSamlValidateURL()
00419 {
00420 phpCAS::traceBegin();
00421
00422 if ( empty($this->_server['saml_validate_url']) ) {
00423 switch ($this->getServerVersion()) {
00424 case SAML_VERSION_1_1:
00425 $this->_server['saml_validate_url'] = $this->getServerBaseURL().'samlValidate';
00426 break;
00427 }
00428 }
00429 phpCAS::traceEnd($this->_server['saml_validate_url'].'?TARGET='.urlencode($this->getURL()));
00430 return $this->_server['saml_validate_url'].'?TARGET='.urlencode($this->getURL());
00431 }
00437 function getServerProxyValidateURL()
00438 {
00439
00440 if ( empty($this->_server['proxy_validate_url']) ) {
00441 switch ($this->getServerVersion()) {
00442 case CAS_VERSION_1_0:
00443 $this->_server['proxy_validate_url'] = '';
00444 break;
00445 case CAS_VERSION_2_0:
00446 $this->_server['proxy_validate_url'] = $this->getServerBaseURL().'proxyValidate';
00447 break;
00448 }
00449 }
00450
00451 return $this->_server['proxy_validate_url'].'?service='.urlencode($this->getURL());
00452 }
00453
00459 function getServerProxyURL()
00460 {
00461
00462 if ( empty($this->_server['proxy_url']) ) {
00463 switch ($this->getServerVersion()) {
00464 case CAS_VERSION_1_0:
00465 $this->_server['proxy_url'] = '';
00466 break;
00467 case CAS_VERSION_2_0:
00468 $this->_server['proxy_url'] = $this->getServerBaseURL().'proxy';
00469 break;
00470 }
00471 }
00472 return $this->_server['proxy_url'];
00473 }
00474
00480 function getServerLogoutURL()
00481 {
00482
00483 if ( empty($this->_server['logout_url']) ) {
00484 $this->_server['logout_url'] = $this->getServerBaseURL().'logout';
00485 }
00486 return $this->_server['logout_url'];
00487 }
00488
00495 function setServerLogoutURL($url)
00496 {
00497 return $this->_server['logout_url'] = $url;
00498 }
00499
00503 var $_curl_options = array();
00504
00508 function setExtraCurlOption($key, $value)
00509 {
00510 $this->_curl_options[$key] = $value;
00511 }
00512
00518 function isHttps() {
00519
00520
00521 if ( isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
00522 return true;
00523 } else {
00524 return false;
00525 }
00526 }
00527
00528
00529
00530
00545 function CASClient(
00546 $server_version,
00547 $proxy,
00548 $server_hostname,
00549 $server_port,
00550 $server_uri,
00551 $start_session = true) {
00552
00553 phpCAS::traceBegin();
00554
00555
00556 if (version_compare(PHP_VERSION,'5','>=') && ini_get('zend.ze1_compatibility_mode')) {
00557 phpCAS::error('phpCAS cannot support zend.ze1_compatibility_mode. Sorry.');
00558 }
00559
00560 if ($start_session && !$this->isLogoutRequest()) {
00561 phpCAS::trace("Starting session handling");
00562
00563 if (empty($_GET['ticket'])){
00564 phpCAS::trace("No ticket found");
00565
00566 if (!isset($_SESSION)) {
00567 phpCAS::trace("No session found, creating new session");
00568 session_start();
00569 }
00570 }else{
00571 phpCAS::trace("Ticket found");
00572
00573 if (isset($_SESSION)) {
00574 phpCAS::trace("Old active session found, saving old data and destroying session");
00575 $old_session = $_SESSION;
00576 session_destroy();
00577 }else{
00578 session_start();
00579 phpCAS::trace("Starting possible old session to copy variables");
00580 $old_session = $_SESSION;
00581 session_destroy();
00582 }
00583
00584 $session_id = preg_replace('/[^\w]/','',$_GET['ticket']);
00585 phpCAS::LOG("Session ID: " . $session_id);
00586 session_id($session_id);
00587 session_start();
00588
00589 if(isset($old_session)){
00590 phpCAS::trace("Restoring old session vars");
00591 $_SESSION = $old_session;
00592 }
00593 }
00594 }else{
00595 phpCAS::trace("Skipping session creation");
00596 }
00597
00598
00599
00600 $this->_proxy = $proxy;
00601
00602
00603 switch ($server_version) {
00604 case CAS_VERSION_1_0:
00605 if ( $this->isProxy() )
00606 phpCAS::error('CAS proxies are not supported in CAS '
00607 .$server_version);
00608 break;
00609 case CAS_VERSION_2_0:
00610 break;
00611 case SAML_VERSION_1_1:
00612 break;
00613 default:
00614 phpCAS::error('this version of CAS (`'
00615 .$server_version
00616 .'\') is not supported by phpCAS '
00617 .phpCAS::getVersion());
00618 }
00619 $this->_server['version'] = $server_version;
00620
00621 // check hostname
00622 if ( empty($server_hostname)
00623 || !preg_match('/[\.\d\-abcdefghijklmnopqrstuvwxyz]*/',$server_hostname) ) {
00624 phpCAS::error('bad CAS server hostname (`'.$server_hostname.'\')');
00625 }
00626 $this->_server['hostname'] = $server_hostname;
00627
00628
00629 if ( $server_port == 0
00630 || !is_int($server_port) ) {
00631 phpCAS::error('bad CAS server port (`'.$server_hostname.'\')');
00632 }
00633 $this->_server['port'] = $server_port;
00634
00635 // check URI
00636 if ( !preg_match('/[\.\d\-_abcdefghijklmnopqrstuvwxyz\/]*/',$server_uri) ) {
00637 phpCAS::error('bad CAS server URI (`'.$server_uri.'\')');
00638 }
00639
00640 $server_uri = preg_replace('/\/\//','/','/'.$server_uri.'/');
00641 $this->_server['uri'] = $server_uri;
00642
00643
00644 if ( $this->isProxy() ) {
00645 $this->setCallbackMode(!empty($_GET['pgtIou'])&&!empty($_GET['pgtId']));
00646 }
00647
00648 if ( $this->isCallbackMode() ) {
00649
00650 if ( !$this->isHttps() ) {
00651 phpCAS::error('CAS proxies must be secured to use phpCAS; PGT\'s will not be received from the CAS server');
00652 }
00653 } else {
00654
00655 $ticket = (isset($_GET['ticket']) ? $_GET['ticket'] : null);
00656 switch ($this->getServerVersion()) {
00657 case CAS_VERSION_1_0:
00658 if( preg_match('/^ST-/',$ticket) ) {
00659 phpCAS::trace('ST \''.$ticket.'\' found');
00660 //ST present
00661 $this->setST($ticket);
00662 //ticket has been taken into account, unset it to hide it to applications
00663 unset($_GET['ticket']);
00664 } else if ( !empty($ticket) ) {
00665 //ill-formed ticket, halt
00666 phpCAS::error('ill-formed ticket found in the URL (ticket=`'.htmlentities($ticket).'\')');
00667 }
00668 break;
00669 case CAS_VERSION_2_0:
00670 if (preg_match('/^ST-/', $ticket)) {
00671 phpCAS::trace('ST \'' . $ticket . '\' found');
00672 $this->setST($ticket);
00673 unset ($_GET['ticket']);
00674 } else if (preg_match('/^PT-/', $ticket)) {
00675 phpCAS::trace('PT \'' . $ticket . '\' found');
00676 $this->setPT($ticket);
00677 unset($_GET['ticket']);
00678 } else if ( !empty($ticket) ) {
00679 //ill-formed ticket, halt
00680 phpCAS::error('ill-formed ticket found in the URL (ticket=`'.htmlentities($ticket).'\')');
00681 }
00682 break;
00683 case SAML_VERSION_1_1:
00684 if( preg_match('/^[SP]T-/',$ticket) ) {
00685 phpCAS::trace('SA \''.$ticket.'\' found');
00686 $this->setSA($ticket);
00687 unset($_GET['ticket']);
00688 } else if ( !empty($ticket) ) {
00689 //ill-formed ticket, halt
00690 phpCAS::error('ill-formed ticket found in the URL (ticket=`'.htmlentities($ticket).'\')');
00691 }
00692 break;
00693 }
00694 }
00695 phpCAS::traceEnd();
00696 }
00697
00700
00701
00702
00703
00704
00705
00718 var $_user = '';
00719
00727 function setUser($user)
00728 {
00729 $this->_user = $user;
00730 }
00731
00739 function getUser()
00740 {
00741 if ( empty($this->_user) ) {
00742 phpCAS::error('this method should be used only after '.__CLASS__.'::forceAuthentication() or '.__CLASS__.'::isAuthenticated()');
00743 }
00744 return $this->_user;
00745 }
00746
00747
00748
00749
00750
00751
00752
00753
00754
00762 var $_attributes = array();
00763
00764 function setAttributes($attributes)
00765 { $this->_attributes = $attributes; }
00766
00767 function getAttributes() {
00768 if ( empty($this->_user) ) {
00769 phpCAS::error('this method should be used only after '.__CLASS__.'::forceAuthentication() or '.__CLASS__.'::isAuthenticated()');
00770 }
00771 return $this->_attributes;
00772 }
00773
00774 function hasAttributes()
00775 { return !empty($this->_attributes); }
00776
00777 function hasAttribute($key)
00778 { return (is_array($this->_attributes) && array_key_exists($key, $this->_attributes)); }
00779
00780 function getAttribute($key) {
00781 if($this->hasAttribute($key)) {
00782 return $this->_attributes[$key];
00783 }
00784 }
00785
00792 function renewAuthentication(){
00793 phpCAS::traceBegin();
00794
00795 if( isset( $_SESSION['phpCAS']['auth_checked'] ) )
00796 unset($_SESSION['phpCAS']['auth_checked']);
00797 if ( $this->isAuthenticated() ) {
00798 phpCAS::trace('user already authenticated; renew');
00799 $this->redirectToCas(false,true);
00800 } else {
00801 $this->redirectToCas();
00802 }
00803 phpCAS::traceEnd();
00804 }
00805
00812 function forceAuthentication()
00813 {
00814 phpCAS::traceBegin();
00815
00816 if ( $this->isAuthenticated() ) {
00817
00818 phpCAS::trace('no need to authenticate');
00819 $res = TRUE;
00820 } else {
00821
00822 if (isset($_SESSION['phpCAS']['auth_checked'])) {
00823 unset($_SESSION['phpCAS']['auth_checked']);
00824 }
00825 $this->redirectToCas(FALSE);
00826
00827 $res = FALSE;
00828 }
00829 phpCAS::traceEnd($res);
00830 return $res;
00831 }
00832
00839 var $_cache_times_for_auth_recheck = 0;
00840
00848 function setCacheTimesForAuthRecheck($n)
00849 {
00850 $this->_cache_times_for_auth_recheck = $n;
00851 }
00852
00858 function checkAuthentication()
00859 {
00860 phpCAS::traceBegin();
00861
00862 if ( $this->isAuthenticated() ) {
00863 phpCAS::trace('user is authenticated');
00864 $res = TRUE;
00865 } else if (isset($_SESSION['phpCAS']['auth_checked'])) {
00866
00867 unset($_SESSION['phpCAS']['auth_checked']);
00868 $res = FALSE;
00869 } else {
00870
00871
00872
00873
00874
00875 if (! isset($_SESSION['phpCAS']['unauth_count']) )
00876 $_SESSION['phpCAS']['unauth_count'] = -2;
00877
00878 if (($_SESSION['phpCAS']['unauth_count'] != -2 && $this->_cache_times_for_auth_recheck == -1)
00879 || ($_SESSION['phpCAS']['unauth_count'] >= 0 && $_SESSION['phpCAS']['unauth_count'] < $this->_cache_times_for_auth_recheck))
00880 {
00881 $res = FALSE;
00882
00883 if ($this->_cache_times_for_auth_recheck != -1)
00884 {
00885 $_SESSION['phpCAS']['unauth_count']++;
00886 phpCAS::trace('user is not authenticated (cached for '.$_SESSION['phpCAS']['unauth_count'].' times of '.$this->_cache_times_for_auth_recheck.')');
00887 }
00888 else
00889 {
00890 phpCAS::trace('user is not authenticated (cached for until login pressed)');
00891 }
00892 }
00893 else
00894 {
00895 $_SESSION['phpCAS']['unauth_count'] = 0;
00896 $_SESSION['phpCAS']['auth_checked'] = true;
00897 phpCAS::trace('user is not authenticated (cache reset)');
00898 $this->redirectToCas(TRUE);
00899
00900 $res = FALSE;
00901 }
00902 }
00903 phpCAS::traceEnd($res);
00904 return $res;
00905 }
00906
00915 function isAuthenticated()
00916 {
00917 phpCAS::traceBegin();
00918 $res = FALSE;
00919 $validate_url = '';
00920
00921 if ( $this->wasPreviouslyAuthenticated() ) {
00922
00923
00924 phpCAS::trace('user was already authenticated, no need to look for tickets');
00925 $res = TRUE;
00926 }
00927 else {
00928 if ( $this->hasST() ) {
00929
00930 phpCAS::trace('ST `'.$this->getST().'\' is present');
00931 $this->validateST($validate_url,$text_response,$tree_response); // if it fails, it halts
00932 phpCAS::trace('ST `'.$this->getST().'\' was validated');
00933 if ( $this->isProxy() ) {
00934 $this->validatePGT($validate_url,$text_response,$tree_response);
00935 phpCAS::trace('PGT `'.$this->getPGT().'\' was validated');
00936 $_SESSION['phpCAS']['pgt'] = $this->getPGT();
00937 }
00938 $_SESSION['phpCAS']['user'] = $this->getUser();
00939 $res = TRUE;
00940 }
00941 elseif ( $this->hasPT() ) {
00942 // if a Proxy Ticket was given, validate it
00943 phpCAS::trace('PT `'.$this->getPT().'\' is present');
00944 $this->validatePT($validate_url,$text_response,$tree_response);
00945 phpCAS::trace('PT `'.$this->getPT().'\' was validated');
00946 if ( $this->isProxy() ) {
00947 $this->validatePGT($validate_url,$text_response,$tree_response); // idem
00948 phpCAS::trace('PGT `'.$this->getPGT().'\' was validated');
00949 $_SESSION['phpCAS']['pgt'] = $this->getPGT();
00950 }
00951 $_SESSION['phpCAS']['user'] = $this->getUser();
00952 $res = TRUE;
00953 }
00954 elseif ( $this->hasSA() ) {
00955
00956 phpCAS::trace('SA `'.$this->getSA().'\' is present');
00957 $this->validateSA($validate_url,$text_response,$tree_response); // if it fails, it halts
00958 phpCAS::trace('SA `'.$this->getSA().'\' was validated');
00959 $_SESSION['phpCAS']['user'] = $this->getUser();
00960 $_SESSION['phpCAS']['attributes'] = $this->getAttributes();
00961 $res = TRUE;
00962 }
00963 else {
00964
00965 phpCAS::trace('no ticket found');
00966 }
00967 if ($res) {
00968
00969
00970 header('Location: '.$this->getURL());
00971 phpCAS::log( "Prepare redirect to : ".$this->getURL() );
00972 }
00973 }
00974
00975 phpCAS::traceEnd($res);
00976 return $res;
00977 }
00978
00984 function isSessionAuthenticated ()
00985 {
00986 return !empty($_SESSION['phpCAS']['user']);
00987 }
00988
00999 function wasPreviouslyAuthenticated()
01000 {
01001 phpCAS::traceBegin();
01002
01003 if ( $this->isCallbackMode() ) {
01004 $this->callback();
01005 }
01006
01007 $auth = FALSE;
01008
01009 if ( $this->isProxy() ) {
01010
01011 if ( $this->isSessionAuthenticated() && !empty($_SESSION['phpCAS']['pgt']) ) {
01012
01013 $this->setUser($_SESSION['phpCAS']['user']);
01014 $this->setPGT($_SESSION['phpCAS']['pgt']);
01015 phpCAS::trace('user = `'.$_SESSION['phpCAS']['user'].'\', PGT = `'.$_SESSION['phpCAS']['pgt'].'\'');
01016 $auth = TRUE;
01017 } elseif ( $this->isSessionAuthenticated() && empty($_SESSION['phpCAS']['pgt']) ) {
01018
01019 phpCAS::trace('username found (`'.$_SESSION['phpCAS']['user'].'\') but PGT is empty');
01020 // unset all tickets to enforce authentication
01021 unset($_SESSION['phpCAS']);
01022 $this->setST('');
01023 $this->setPT('');
01024 } elseif ( !$this->isSessionAuthenticated() && !empty($_SESSION['phpCAS']['pgt']) ) {
01025 // these two variables should be empty or not empty at the same time
01026 phpCAS::trace('PGT found (`'.$_SESSION['phpCAS']['pgt'].'\') but username is empty');
01027
01028 unset($_SESSION['phpCAS']);
01029 $this->setST('');
01030 $this->setPT('');
01031 } else {
01032 phpCAS::trace('neither user not PGT found');
01033 }
01034 } else {
01035
01036 if ( $this->isSessionAuthenticated() ) {
01037
01038 $this->setUser($_SESSION['phpCAS']['user']);
01039 if(isset($_SESSION['phpCAS']['attributes'])){
01040 $this->setAttributes($_SESSION['phpCAS']['attributes']);
01041 }
01042 phpCAS::trace('user = `'.$_SESSION['phpCAS']['user'].'\'');
01043 $auth = TRUE;
01044 } else {
01045 phpCAS::trace('no user found');
01046 }
01047 }
01048
01049 phpCAS::traceEnd($auth);
01050 return $auth;
01051 }
01052
01060 function redirectToCas($gateway=false,$renew=false){
01061 phpCAS::traceBegin();
01062 $cas_url = $this->getServerLoginURL($gateway,$renew);
01063 header('Location: '.$cas_url);
01064 phpCAS::log( "Redirect to : ".$cas_url );
01065
01066 $this->printHTMLHeader($this->getString(CAS_STR_AUTHENTICATION_WANTED));
01067
01068 printf('<p>'.$this->getString(CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED).'</p>',$cas_url);
01069 $this->printHTMLFooter();
01070
01071 phpCAS::traceExit();
01072 exit();
01073 }
01074
01075
01076
01077
01078
01079
01080
01081
01082
01083
01084
01085
01086
01087
01088
01089
01090
01091
01092
01093
01094
01095
01096
01097
01098
01104 function logout($params) {
01105 phpCAS::traceBegin();
01106 $cas_url = $this->getServerLogoutURL();
01107 $paramSeparator = '?';
01108 if (isset($params['url'])) {
01109 $cas_url = $cas_url . $paramSeparator . "url=" . urlencode($params['url']);
01110 $paramSeparator = '&';
01111 }
01112 if (isset($params['service'])) {
01113 $cas_url = $cas_url . $paramSeparator . "service=" . urlencode($params['service']);
01114 }
01115 header('Location: '.$cas_url);
01116 phpCAS::log( "Prepare redirect to : ".$cas_url );
01117
01118 session_unset();
01119 session_destroy();
01120
01121 $this->printHTMLHeader($this->getString(CAS_STR_LOGOUT));
01122 printf('<p>'.$this->getString(CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED).'</p>',$cas_url);
01123 $this->printHTMLFooter();
01124
01125 phpCAS::traceExit();
01126 exit();
01127 }
01128
01133 function isLogoutRequest() {
01134 return !empty($_POST['logoutRequest']);
01135 }
01136
01141 function isLogoutRequestAllowed() {
01142 }
01143
01152 function handleLogoutRequests($check_client=true, $allowed_clients=false) {
01153 phpCAS::traceBegin();
01154 if (!$this->isLogoutRequest()) {
01155 phpCAS::log("Not a logout request");
01156 phpCAS::traceEnd();
01157 return;
01158 }
01159 phpCAS::log("Logout requested");
01160 phpCAS::log("SAML REQUEST: ".$_POST['logoutRequest']);
01161 if ($check_client) {
01162 if (!$allowed_clients) {
01163 $allowed_clients = array( $this->getServerHostname() );
01164 }
01165 $client_ip = $_SERVER['REMOTE_ADDR'];
01166 $client = gethostbyaddr($client_ip);
01167 phpCAS::log("Client: ".$client."/".$client_ip);
01168 $allowed = false;
01169 foreach ($allowed_clients as $allowed_client) {
01170 if (($client == $allowed_client) or ($client_ip == $allowed_client)) {
01171 phpCAS::log("Allowed client '".$allowed_client."' matches, logout request is allowed");
01172 $allowed = true;
01173 break;
01174 } else {
01175 phpCAS::log("Allowed client '".$allowed_client."' does not match");
01176 }
01177 }
01178 if (!$allowed) {
01179 phpCAS::error("Unauthorized logout request from client '".$client."'");
01180 printf("Unauthorized!");
01181 phpCAS::traceExit();
01182 exit();
01183 }
01184 } else {
01185 phpCAS::log("No access control set");
01186 }
01187
01188 preg_match("|<samlp:SessionIndex>(.*)</samlp:SessionIndex>|", $_POST['logoutRequest'], $tick, PREG_OFFSET_CAPTURE, 3);
01189 $wrappedSamlSessionIndex = preg_replace('|<samlp:SessionIndex>|','',$tick[0][0]);
01190 $ticket2logout = preg_replace('|</samlp:SessionIndex>|','',$wrappedSamlSessionIndex);
01191 phpCAS::log("Ticket to logout: ".$ticket2logout);
01192 $session_id = preg_replace('/[^\w]/','',$ticket2logout);
01193 phpCAS::log("Session id: ".$session_id);
01194
01195
01196 session_id($session_id);
01197 $_COOKIE[session_name()]=$session_id;
01198 $_GET[session_name()]=$session_id;
01199
01200
01201 session_start();
01202 session_unset();
01203 session_destroy();
01204 printf("Disconnected!");
01205 phpCAS::traceExit();
01206 exit();
01207 }
01208
01211
01212
01213
01214
01215
01216
01217
01218
01219
01233 var $_st = '';
01234
01240 function getST()
01241 { return $this->_st; }
01242
01248 function setST($st)
01249 { $this->_st = $st; }
01250
01256 function hasST()
01257 { return !empty($this->_st); }
01258
01261
01262
01263
01275 var $_cas_server_cert = '';
01276
01283 var $_cas_server_ca_cert = '';
01284
01291 var $_no_cas_server_validation = false;
01292
01298 function setCasServerCert($cert)
01299 {
01300 $this->_cas_server_cert = $cert;
01301 }
01302
01308 function setCasServerCACert($cert)
01309 {
01310 $this->_cas_server_ca_cert = $cert;
01311 }
01312
01316 function setNoCasServerValidation()
01317 {
01318 $this->_no_cas_server_validation = true;
01319 }
01320
01334 function validateST($validate_url,&$text_response,&$tree_response)
01335 {
01336 phpCAS::traceBegin();
01337
01338 $validate_url = $this->getServerServiceValidateURL().'&ticket='.$this->getST();
01339 if ( $this->isProxy() ) {
01340
01341 $validate_url .= '&pgtUrl='.$this->getCallbackURL();
01342 }
01343
01344
01345 if ( !$this->readURL($validate_url,'',$headers,$text_response,$err_msg) ) {
01346 phpCAS::trace('could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')');
01347 $this->authError('ST not validated',
01348 $validate_url,
01349 TRUE/*$no_response*/);
01350 }
01351
01352 // analyze the result depending on the version
01353 switch ($this->getServerVersion()) {
01354 case CAS_VERSION_1_0:
01355 if (preg_match('/^no\n/',$text_response)) {
01356 phpCAS::trace('ST has not been validated');
01357 $this->authError('ST not validated',
01358 $validate_url,
01359 FALSE/*$no_response*/,
01360 FALSE/*$bad_response*/,
01361 $text_response);
01362 }
01363 if (!preg_match('/^yes\n/',$text_response)) {
01364 phpCAS::trace('ill-formed response');
01365 $this->authError('ST not validated',
01366 $validate_url,
01367 FALSE/*$no_response*/,
01368 TRUE/*$bad_response*/,
01369 $text_response);
01370 }
01371 // ST has been validated, extract the user name
01372 $arr = preg_split('/\n/',$text_response);
01373 $this->setUser(trim($arr[1]));
01374 break;
01375 case CAS_VERSION_2_0:
01376 // read the response of the CAS server into a DOM object
01377 if ( !($dom = domxml_open_mem($text_response))) {
01378 phpCAS::trace('domxml_open_mem() failed');
01379 $this->authError('ST not validated',
01380 $validate_url,
01381 FALSE/*$no_response*/,
01382 TRUE/*$bad_response*/,
01383 $text_response);
01384 }
01385 // read the root node of the XML tree
01386 if ( !($tree_response = $dom->document_element()) ) {
01387 phpCAS::trace('document_element() failed');
01388 $this->authError('ST not validated',
01389 $validate_url,
01390 FALSE/*$no_response*/,
01391 TRUE/*$bad_response*/,
01392 $text_response);
01393 }
01394 // insure that tag name is 'serviceResponse'
01395 if ( $tree_response->node_name() != 'serviceResponse' ) {
01396 phpCAS::trace('bad XML root node (should be `serviceResponse\' instead of `'.$tree_response->node_name().'\'');
01397 $this->authError('ST not validated',
01398 $validate_url,
01399 FALSE,
01400 TRUE,
01401 $text_response);
01402 }
01403 if ( sizeof($success_elements = $tree_response->get_elements_by_tagname("authenticationSuccess")) != 0) {
01404
01405 if ( sizeof($user_elements = $success_elements[0]->get_elements_by_tagname("user")) == 0) {
01406 phpCAS::trace('<authenticationSuccess> found, but no <user>');
01407 $this->authError('ST not validated',
01408 $validate_url,
01409 FALSE,
01410 TRUE,
01411 $text_response);
01412 }
01413 $user = trim($user_elements[0]->get_content());
01414 phpCAS::trace('user = `'.$user);
01415 $this->setUser($user);
01416
01417 } else if ( sizeof($failure_elements = $tree_response->get_elements_by_tagname("authenticationFailure")) != 0) {
01418 phpCAS::trace('<authenticationFailure> found');
01419
01420 $this->authError('ST not validated',
01421 $validate_url,
01422 FALSE,
01423 FALSE,
01424 $text_response,
01425 $failure_elements[0]->get_attribute('code'),
01426 trim($failure_elements[0]->get_content()));
01427 } else {
01428 phpCAS::trace('neither <authenticationSuccess> nor <authenticationFailure> found');
01429 $this->authError('ST not validated',
01430 $validate_url,
01431 FALSE,
01432 TRUE,
01433 $text_response);
01434 }
01435 break;
01436 }
01437
01438
01439 phpCAS::traceEnd(TRUE);
01440 return TRUE;
01441 }
01442
01443
01444
01445
01464 function validateSA($validate_url,&$text_response,&$tree_response)
01465 {
01466 phpCAS::traceBegin();
01467
01468
01469 $validate_url = $this->getServerSamlValidateURL();
01470
01471
01472 if ( !$this->readURL($validate_url,'',$headers,$text_response,$err_msg) ) {
01473 phpCAS::trace('could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')');
01474 $this->authError('SA not validated', $validate_url, TRUE/*$no_response*/);
01475 }
01476
01477 phpCAS::trace('server version: '.$this->getServerVersion());
01478
01479 // analyze the result depending on the version
01480 switch ($this->getServerVersion()) {
01481 case SAML_VERSION_1_1:
01482
01483 // read the response of the CAS server into a DOM object
01484 if ( !($dom = domxml_open_mem($text_response))) {
01485 phpCAS::trace('domxml_open_mem() failed');
01486 $this->authError('SA not validated',
01487 $validate_url,
01488 FALSE/*$no_response*/,
01489 TRUE/*$bad_response*/,
01490 $text_response);
01491 }
01492 // read the root node of the XML tree
01493 if ( !($tree_response = $dom->document_element()) ) {
01494 phpCAS::trace('document_element() failed');
01495 $this->authError('SA not validated',
01496 $validate_url,
01497 FALSE/*$no_response*/,
01498 TRUE/*$bad_response*/,
01499 $text_response);
01500 }
01501 // insure that tag name is 'Envelope'
01502 if ( $tree_response->node_name() != 'Envelope' ) {
01503 phpCAS::trace('bad XML root node (should be `Envelope\' instead of `'.$tree_response->node_name().'\'');
01504 $this->authError('SA not validated',
01505 $validate_url,
01506 FALSE,
01507 TRUE,
01508 $text_response);
01509 }
01510
01511 if ( sizeof($success_elements = $tree_response->get_elements_by_tagname("NameIdentifier")) != 0) {
01512 phpCAS::trace('NameIdentifier found');
01513 $user = trim($success_elements[0]->get_content());
01514 phpCAS::trace('user = `'.$user.'`');
01515 $this->setUser($user);
01516 $this->setSessionAttributes($text_response);
01517 } else {
01518 phpCAS::trace('no <NameIdentifier> tag found in SAML payload');
01519 $this->authError('SA not validated',
01520 $validate_url,
01521 FALSE,
01522 TRUE,
01523 $text_response);
01524 }
01525 break;
01526 }
01527
01528
01529 phpCAS::traceEnd(TRUE);
01530 return TRUE;
01531 }
01532
01542 function setSessionAttributes($text_response)
01543 {
01544 phpCAS::traceBegin();
01545
01546 $result = FALSE;
01547
01548 if (isset($_SESSION[SAML_ATTRIBUTES])) {
01549 phpCAS::trace("session attrs already set.");
01550 }
01551
01552 $attr_array = array();
01553
01554 if (($dom = domxml_open_mem($text_response))) {
01555 $xPath = $dom->xpath_new_context();
01556 $xPath->xpath_register_ns('samlp', 'urn:oasis:names:tc:SAML:1.0:protocol');
01557 $xPath->xpath_register_ns('saml', 'urn:oasis:names:tc:SAML:1.0:assertion');
01558 $nodelist = $xPath->xpath_eval("//saml:Attribute");
01559 $attrs = $nodelist->nodeset;
01560 phpCAS::trace($text_response);
01561 foreach($attrs as $attr){
01562 $xres = $xPath->xpath_eval("saml:AttributeValue", $attr);
01563 $name = $attr->get_attribute("AttributeName");
01564 $value_array = array();
01565 foreach($xres->nodeset as $node){
01566 $value_array[] = $node->get_content();
01567
01568 }
01569 phpCAS::trace("* " . $name . "=" . $value_array);
01570 $attr_array[$name] = $value_array;
01571 }
01572 $_SESSION[SAML_ATTRIBUTES] = $attr_array;
01573
01574 foreach($attr_array as $attr_key => $attr_value) {
01575 if(count($attr_value) > 1) {
01576 $this->_attributes[$attr_key] = $attr_value;
01577 }
01578 else {
01579 $this->_attributes[$attr_key] = $attr_value[0];
01580 }
01581 }
01582 $result = TRUE;
01583 }
01584 phpCAS::traceEnd($result);
01585 return $result;
01586 }
01587
01590
01591
01592
01593
01594
01595
01596
01597
01598
01610 var $_proxy;
01611
01619 function isProxy()
01620 {
01621 return $this->_proxy;
01622 }
01623
01625
01626
01627
01640 var $_pgt = '';
01641
01647 function getPGT()
01648 { return $this->_pgt; }
01649
01655 function setPGT($pgt)
01656 { $this->_pgt = $pgt; }
01657
01663 function hasPGT()
01664 { return !empty($this->_pgt); }
01665
01668
01669
01670
01688 var $_callback_mode = FALSE;
01689
01697 function setCallbackMode($callback_mode)
01698 {
01699 $this->_callback_mode = $callback_mode;
01700 }
01701
01710 function isCallbackMode()
01711 {
01712 return $this->_callback_mode;
01713 }
01714
01723 var $_callback_url = '';
01724
01734 function getCallbackURL()
01735 {
01736
01737 if ( empty($this->_callback_url) ) {
01738 $final_uri = '';
01739
01740 $final_uri = 'https://';
01741
01742
01743
01744 if(empty($_SERVER['HTTP_X_FORWARDED_SERVER'])){
01745
01746
01747
01748 if (empty($_SERVER['SERVER_NAME'])) {
01749 $final_uri .= $_SERVER['HTTP_HOST'];
01750 } else {
01751 $final_uri .= $_SERVER['SERVER_NAME'];
01752 }
01753 } else {
01754 $final_uri .= $_SERVER['HTTP_X_FORWARDED_SERVER'];
01755 }
01756 if ( ($this->isHttps() && $_SERVER['SERVER_PORT']!=443)
01757 || (!$this->isHttps() && $_SERVER['SERVER_PORT']!=80) ) {
01758 $final_uri .= ':';
01759 $final_uri .= $_SERVER['SERVER_PORT'];
01760 }
01761 $request_uri = $_SERVER['REQUEST_URI'];
01762 $request_uri = preg_replace('/\?.*$/','',$request_uri);
01763 $final_uri .= $request_uri;
01764 $this->setCallbackURL($final_uri);
01765 }
01766 return $this->_callback_url;
01767 }
01768
01776 function setCallbackURL($url)
01777 {
01778 return $this->_callback_url = $url;
01779 }
01780
01787 function callback()
01788 {
01789 phpCAS::traceBegin();
01790 $this->printHTMLHeader('phpCAS callback');
01791 $pgt_iou = $_GET['pgtIou'];
01792 $pgt = $_GET['pgtId'];
01793 phpCAS::trace('Storing PGT `'.$pgt.'\' (id=`'.$pgt_iou.'\')');
01794 echo '<p>Storing PGT `'.$pgt.'\' (id=`'.$pgt_iou.'\').</p>';
01795 $this->storePGT($pgt,$pgt_iou);
01796 $this->printHTMLFooter();
01797 phpCAS::traceExit();
01798 exit();
01799 }
01800
01803
01804
01805
01819 var $_pgt_storage = null;
01820
01827 function initPGTStorage()
01828 {
01829
01830 if ( !is_object($this->_pgt_storage) ) {
01831 $this->setPGTStorageFile();
01832 }
01833
01834
01835 $this->_pgt_storage->init();
01836 }
01837
01846 function storePGT($pgt,$pgt_iou)
01847 {
01848
01849 $this->initPGTStorage();
01850
01851 $this->_pgt_storage->write($pgt,$pgt_iou);
01852 }
01853
01863 function loadPGT($pgt_iou)
01864 {
01865
01866 $this->initPGTStorage();
01867
01868 return $this->_pgt_storage->read($pgt_iou);
01869 }
01870
01880 function setPGTStorageFile($format='',
01881 $path='')
01882 {
01883
01884 if ( is_object($this->_pgt_storage) ) {
01885 phpCAS::error('PGT storage already defined');
01886 }
01887
01888
01889 $this->_pgt_storage = new PGTStorageFile($this,$format,$path);
01890 }
01891
01909 function setPGTStorageDB($user,
01910 $password,
01911 $database_type,
01912 $hostname,
01913 $port,
01914 $database,
01915 $table)
01916 {
01917
01918 if ( is_object($this->_pgt_storage) ) {
01919 phpCAS::error('PGT storage already defined');
01920 }
01921
01922
01923 trigger_error('PGT storage into database is an experimental feature, use at your own risk',E_USER_WARNING);
01924
01925
01926 $this->_pgt_storage = new PGTStorageDB($this,$user,$password,$database_type,$hostname,$port,$database,$table);
01927 }
01928
01929
01930
01931
01945 function validatePGT(&$validate_url,$text_response,$tree_response)
01946 {
01947
01948 phpCAS::log('start validatePGT()');
01949 if ( sizeof($arr = $tree_response->get_elements_by_tagname("proxyGrantingTicket")) == 0) {
01950 phpCAS::trace('<proxyGrantingTicket> not found');
01951
01952 $this->authError('Ticket validated but no PGT Iou transmitted',
01953 $validate_url,
01954 FALSE,
01955 FALSE,
01956 $text_response);
01957 } else {
01958
01959 $pgt_iou = trim($arr[0]->get_content());
01960 $pgt = $this->loadPGT($pgt_iou);
01961 if ( $pgt == FALSE ) {
01962 phpCAS::trace('could not load PGT');
01963 $this->authError('PGT Iou was transmitted but PGT could not be retrieved',
01964 $validate_url,
01965 FALSE,
01966 FALSE,
01967 $text_response);
01968 }
01969 $this->setPGT($pgt);
01970 }
01971
01972 phpCAS::log('end validatePGT()');
01973 return TRUE;
01974 }
01975
01976
01977
01978
01979
01991 function retrievePT($target_service,&$err_code,&$err_msg)
01992 {
01993 phpCAS::traceBegin();
01994
01995
01996
01997
01998
01999 $err_msg = '';
02000
02001
02002
02003 $cas_url = $this->getServerProxyURL().'?targetService='.urlencode($target_service).'&pgt='.$this->getPGT();
02004
02005
02006 if ( !$this->readURL($cas_url,'',$headers,$cas_response,$err_msg) ) {
02007 phpCAS::trace('could not open URL \''.$cas_url.'\' to validate ('.$err_msg.')');
02008 $err_code = PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE;
02009 $err_msg = 'could not retrieve PT (no response from the CAS server)';
02010 phpCAS::traceEnd(FALSE);
02011 return FALSE;
02012 }
02013
02014 $bad_response = FALSE;
02015
02016 if ( !$bad_response ) {
02017 // read the response of the CAS server into a DOM object
02018 if ( !($dom = @domxml_open_mem($cas_response))) {
02019 phpCAS::trace('domxml_open_mem() failed');
02020 // read failed
02021 $bad_response = TRUE;
02022 }
02023 }
02024
02025 if ( !$bad_response ) {
02026 // read the root node of the XML tree
02027 if ( !($root = $dom->document_element()) ) {
02028 phpCAS::trace('document_element() failed');
02029 // read failed
02030 $bad_response = TRUE;
02031 }
02032 }
02033
02034 if ( !$bad_response ) {
02035 // insure that tag name is 'serviceResponse'
02036 if ( $root->node_name() != 'serviceResponse' ) {
02037 phpCAS::trace('node_name() failed');
02038 // bad root node
02039 $bad_response = TRUE;
02040 }
02041 }
02042
02043 if ( !$bad_response ) {
02044 // look for a proxySuccess tag
02045 if ( sizeof($arr = $root->get_elements_by_tagname("proxySuccess")) != 0) {
02046 // authentication succeded, look for a proxyTicket tag
02047 if ( sizeof($arr = $root->get_elements_by_tagname("proxyTicket")) != 0) {
02048 $err_code = PHPCAS_SERVICE_OK;
02049 $err_msg = '';
02050 phpCAS::trace('original PT: '.trim($arr[0]->get_content()));
02051 $pt = trim($arr[0]->get_content());
02052 phpCAS::traceEnd($pt);
02053 return $pt;
02054 } else {
02055 phpCAS::trace('<proxySuccess> was found, but not <proxyTicket>');
02056 }
02057 }
02058 // look for a proxyFailure tag
02059 else if ( sizeof($arr = $root->get_elements_by_tagname("proxyFailure")) != 0) {
02060 // authentication failed, extract the error
02061 $err_code = PHPCAS_SERVICE_PT_FAILURE;
02062 $err_msg = 'PT retrieving failed (code=`'
02063 .$arr[0]->get_attribute('code')
02064 .'\', message=`'
02065 .trim($arr[0]->get_content())
02066 .'\')';
02067 phpCAS::traceEnd(FALSE);
02068 return FALSE;
02069 } else {
02070 phpCAS::trace('neither <proxySuccess> nor <proxyFailure> found');
02071 }
02072 }
02073
02074 // at this step, we are sure that the response of the CAS server was ill-formed
02075 $err_code = PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE;
02076 $err_msg = 'Invalid response from the CAS server (response=`'.$cas_response.'\')';
02077
02078 phpCAS::traceEnd(FALSE);
02079 return FALSE;
02080 }
02081
02082
02083
02084
02085
02101 function readURL($url,$cookies,&$headers,&$body,&$err_msg)
02102 {
02103 phpCAS::traceBegin();
02104 $headers = '';
02105 $body = '';
02106 $err_msg = '';
02107
02108 $res = TRUE;
02109
02110
02111 $ch = curl_init($url);
02112
02113 if (version_compare(PHP_VERSION,'5.1.3','>=')) {
02114
02115 curl_setopt_array($ch, $this->_curl_options);
02116 } else {
02117 foreach ($this->_curl_options as $key => $value) {
02118 curl_setopt($ch, $key, $value);
02119 }
02120 }
02121
02122 if ($this->_cas_server_cert == '' && $this->_cas_server_ca_cert == '' && !$this->_no_cas_server_validation) {
02123 phpCAS::error('one of the methods phpCAS::setCasServerCert(), phpCAS::setCasServerCACert() or phpCAS::setNoCasServerValidation() must be called.');
02124 }
02125 if ($this->_cas_server_cert != '' && $this->_cas_server_ca_cert != '') {
02126
02127 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
02128 curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1);
02129 curl_setopt($ch, CURLOPT_SSLCERT, $this->_cas_server_cert);
02130 curl_setopt($ch, CURLOPT_CAINFO, $this->_cas_server_ca_cert);
02131 curl_setopt($ch, CURLOPT_VERBOSE, '1');
02132 phpCAS::trace('CURL: Set all required opts for mutual authentication ------');
02133 } else if ($this->_cas_server_cert != '' ) {
02134 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
02135 curl_setopt($ch, CURLOPT_SSLCERT, $this->_cas_server_cert);
02136 } else if ($this->_cas_server_ca_cert != '') {
02137 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
02138 curl_setopt($ch, CURLOPT_CAINFO, $this->_cas_server_ca_cert);
02139 } else {
02140 curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1);
02141 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
02142 }
02143
02144
02145 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
02146
02147 $this->_curl_headers = array();
02148 curl_setopt($ch, CURLOPT_HEADERFUNCTION, array($this, '_curl_read_headers'));
02149
02150 if ( is_array($cookies) ) {
02151 curl_setopt($ch,CURLOPT_COOKIE,implode(';',$cookies));
02152 }
02153
02154 if ($this->hasSA()) {
02155 $more_headers = array ("soapaction: http://www.oasis-open.org/committees/security",
02156 "cache-control: no-cache",
02157 "pragma: no-cache",
02158 "accept: text/xml",
02159 "connection: keep-alive",
02160 "content-type: text/xml");
02161
02162 curl_setopt($ch, CURLOPT_HTTPHEADER, $more_headers);
02163 curl_setopt($ch, CURLOPT_POST, 1);
02164 $data = $this->buildSAMLPayload();
02165
02166 curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
02167 }
02168
02169 $buf = curl_exec ($ch);
02170
02171 if ( $buf === FALSE ) {
02172 phpCAS::trace('curl_exec() failed');
02173 $err_msg = 'CURL error #'.curl_errno($ch).': '.curl_error($ch);
02174
02175
02176 curl_close ($ch);
02177 $res = FALSE;
02178 } else {
02179
02180 curl_close ($ch);
02181
02182 $headers = $this->_curl_headers;
02183 $body = $buf;
02184 }
02185
02186 phpCAS::traceEnd($res);
02187 return $res;
02188 }
02189
02197 function buildSAMLPayload()
02198 {
02199 phpCAS::traceBegin();
02200
02201
02202 $sa = $this->getSA();
02203
02204
02205 $body=SAML_SOAP_ENV.SAML_SOAP_BODY.SAMLP_REQUEST.SAML_ASSERTION_ARTIFACT.$sa.SAML_ASSERTION_ARTIFACT_CLOSE.SAMLP_REQUEST_CLOSE.SAML_SOAP_BODY_CLOSE.SAML_SOAP_ENV_CLOSE;
02206
02207 phpCAS::traceEnd($body);
02208 return ($body);
02209 }
02210
02214 var $_curl_headers = array();
02215 function _curl_read_headers($ch, $header)
02216 {
02217 $this->_curl_headers[] = $header;
02218 return strlen($header);
02219 }
02220
02236 function serviceWeb($url,&$err_code,&$output)
02237 {
02238 phpCAS::traceBegin();
02239
02240 $pt = $this->retrievePT($url,$err_code,$output);
02241
02242 $res = TRUE;
02243
02244
02245 if ( !$pt ) {
02246
02247 phpCAS::trace('PT was not retrieved correctly');
02248 $res = FALSE;
02249 } else {
02250
02251 if ( is_array($_SESSION['phpCAS']['services'][$url]['cookies']) ) {
02252 foreach ( $_SESSION['phpCAS']['services'][$url]['cookies'] as $name => $val ) {
02253 $cookies[] = $name.'='.$val;
02254 }
02255 }
02256
02257
02258 if ( strstr($url,'?') === FALSE ) {
02259 $service_url = $url.'?ticket='.$pt;
02260 } else {
02261 $service_url = $url.'&ticket='.$pt;
02262 }
02263
02264 phpCAS::trace('reading URL`'.$service_url.'\'');
02265 if ( !$this->readURL($service_url,$cookies,$headers,$output,$err_msg) ) {
02266 phpCAS::trace('could not read URL`'.$service_url.'\'');
02267 $err_code = PHPCAS_SERVICE_NOT_AVAILABLE;
02268
02269 $output = sprintf($this->getString(CAS_STR_SERVICE_UNAVAILABLE),
02270 $service_url,
02271 $err_msg);
02272 $res = FALSE;
02273 } else {
02274
02275 phpCAS::trace('URL`'.$service_url.'\' has been read, storing cookies:');
02276 foreach ( $headers as $header ) {
02277 // test if the header is a cookie
02278 if ( preg_match('/^Set-Cookie:/',$header) ) {
02279 // the header is a cookie, remove the beginning
02280 $header_val = preg_replace('/^Set-Cookie: */','',$header);
02281 // extract interesting information
02282 $name_val = strtok($header_val,'; ');
02283 // extract the name and the value of the cookie
02284 $cookie_name = strtok($name_val,'=');
02285 $cookie_val = strtok('=');
02286 // store the cookie
02287 $_SESSION['phpCAS']['services'][$url]['cookies'][$cookie_name] = $cookie_val;
02288 phpCAS::trace($cookie_name.' -> '.$cookie_val);
02289 }
02290 }
02291 }
02292 }
02293
02294 phpCAS::traceEnd($res);
02295 return $res;
02296 }
02297
02317 function serviceMail($url,$service,$flags,&$err_code,&$err_msg,&$pt)
02318 {
02319 phpCAS::traceBegin();
02320 // at first retrieve a PT
02321 $pt = $this->retrievePT($service,$err_code,$output);
02322
02323 $stream = FALSE;
02324
02325 // test if PT was retrieved correctly
02326 if ( !$pt ) {
02327 // note: $err_code and $err_msg are filled by CASClient::retrievePT()
02328 phpCAS::trace('PT was not retrieved correctly');
02329 } else {
02330 phpCAS::trace('opening IMAP URL `'.$url.'\'...');
02331 $stream = @imap_open($url,$this->getUser(),$pt,$flags);
02332 if ( !$stream ) {
02333 phpCAS::trace('could not open URL');
02334 $err_code = PHPCAS_SERVICE_NOT_AVAILABLE;
02335
02336 $err_msg = sprintf($this->getString(CAS_STR_SERVICE_UNAVAILABLE),
02337 $service_url,
02338 var_export(imap_errors(),TRUE));
02339 $pt = FALSE;
02340 $stream = FALSE;
02341 } else {
02342 phpCAS::trace('ok');
02343 }
02344 }
02345
02346 phpCAS::traceEnd($stream);
02347 return $stream;
02348 }
02349
02352
02353
02354
02355
02356
02357
02358
02359
02360
02374 var $_pt = '';
02375
02381 function getPT()
02382 {
02383
02384 return $this->_pt;
02385 }
02386
02392 function setPT($pt)
02393 { $this->_pt = $pt; }
02394
02400 function hasPT()
02401 { return !empty($this->_pt); }
02407 function getSA()
02408 { return 'ST'.substr($this->_sa, 2); }
02409
02415 function setSA($sa)
02416 { $this->_sa = $sa; }
02417
02423 function hasSA()
02424 { return !empty($this->_sa); }
02425
02427
02428
02429
02442 function validatePT(&$validate_url,&$text_response,&$tree_response)
02443 {
02444 phpCAS::traceBegin();
02445
02446 $validate_url = $this->getServerProxyValidateURL().'&ticket='.$this->getPT();
02447
02448 if ( $this->isProxy() ) {
02449
02450 $validate_url .= '&pgtUrl='.$this->getCallbackURL();
02451 }
02452
02453
02454 if ( !$this->readURL($validate_url,'',$headers,$text_response,$err_msg) ) {
02455 phpCAS::trace('could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')');
02456 $this->authError('PT not validated',
02457 $validate_url,
02458 TRUE/*$no_response*/);
02459 }
02460
02461 // read the response of the CAS server into a DOM object
02462 if ( !($dom = domxml_open_mem($text_response))) {
02463 // read failed
02464 $this->authError('PT not validated',
02465 $validate_url,
02466 FALSE/*$no_response*/,
02467 TRUE/*$bad_response*/,
02468 $text_response);
02469 }
02470 // read the root node of the XML tree
02471 if ( !($tree_response = $dom->document_element()) ) {
02472 // read failed
02473 $this->authError('PT not validated',
02474 $validate_url,
02475 FALSE/*$no_response*/,
02476 TRUE/*$bad_response*/,
02477 $text_response);
02478 }
02479 // insure that tag name is 'serviceResponse'
02480 if ( $tree_response->node_name() != 'serviceResponse' ) {
02481 // bad root node
02482 $this->authError('PT not validated',
02483 $validate_url,
02484 FALSE/*$no_response*/,
02485 TRUE/*$bad_response*/,
02486 $text_response);
02487 }
02488 if ( sizeof($arr = $tree_response->get_elements_by_tagname("authenticationSuccess")) != 0) {
02489 // authentication succeded, extract the user name
02490 if ( sizeof($arr = $tree_response->get_elements_by_tagname("user")) == 0) {
02491 // no user specified => error
02492 $this->authError('PT not validated',
02493 $validate_url,
02494 FALSE/*$no_response*/,
02495 TRUE/*$bad_response*/,
02496 $text_response);
02497 }
02498 $this->setUser(trim($arr[0]->get_content()));
02499
02500 } else if ( sizeof($arr = $tree_response->get_elements_by_tagname("authenticationFailure")) != 0) {
02501 // authentication succeded, extract the error code and message
02502 $this->authError('PT not validated',
02503 $validate_url,
02504 FALSE/*$no_response*/,
02505 FALSE/*$bad_response*/,
02506 $text_response,
02507 $arr[0]->get_attribute('code')/*$err_code*/,
02508 trim($arr[0]->get_content())/*$err_msg*/);
02509 } else {
02510 $this->authError('PT not validated',
02511 $validate_url,
02512 FALSE/*$no_response*/,
02513 TRUE/*$bad_response*/,
02514 $text_response);
02515 }
02516
02517 // at this step, PT has been validated and $this->_user has been set,
02518
02519 phpCAS::traceEnd(TRUE);
02520 return TRUE;
02521 }
02522
02525 // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
02526 // XX XX
02527 // XX MISC XX
02528 // XX XX
02529 // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
02530
02536 // ########################################################################
02537 // URL
02538 // ########################################################################
02546 var $_url = '';
02547
02556 function getURL()
02557 {
02558 phpCAS::traceBegin();
02559 // the URL is built when needed only
02560 if ( empty($this->_url) ) {
02561 $final_uri = '';
02562 // remove the ticket if present in the URL
02563 $final_uri = ($this->isHttps()) ? 'https' : 'http';
02564 $final_uri .= ':
02565
02566
02567
02568 if(empty($_SERVER['HTTP_X_FORWARDED_SERVER'])){
02569
02570
02571
02572 if (empty($_SERVER['SERVER_NAME'])) {
02573 $server_name = $_SERVER['HTTP_HOST'];
02574 } else {
02575 $server_name = $_SERVER['SERVER_NAME'];
02576 }
02577 } else {
02578 $server_name = $_SERVER['HTTP_X_FORWARDED_SERVER'];
02579 }
02580 $final_uri .= $server_name;
02581 if (!strpos($server_name, ':')) {
02582 if ( ($this->isHttps() && $_SERVER['SERVER_PORT']!=443)
02583 || (!$this->isHttps() && $_SERVER['SERVER_PORT']!=80) ) {
02584 $final_uri .= ':';
02585 $final_uri .= $_SERVER['SERVER_PORT'];
02586 }
02587 }
02588
02589 $baseurl = split("\?", $_SERVER['REQUEST_URI'], 2);
02590 $final_uri .= $baseurl[0];
02591 $query_string = '';
02592 if ($_GET) {
02593 $kv = array();
02594 foreach ($_GET as $key => $value) {
02595 if($key !== "ticket"){
02596 $kv[] = urlencode($key). "=" . urlencode($value);
02597 }
02598 }
02599 $query_string = join("&", $kv);
02600 }
02601 if($query_string){
02602 $final_uri .= "?" . $query_string;
02603 }
02604 $this->setURL($final_uri);
02605 }
02606 phpCAS::traceEnd($this->_url);
02607 return $this->_url;
02608 }
02609
02617 function setURL($url)
02618 {
02619 $this->_url = $url;
02620 }
02621
02622
02623
02624
02640 function authError($failure,$cas_url,$no_response,$bad_response='',$cas_response='',$err_code='',$err_msg='')
02641 {
02642 phpCAS::traceBegin();
02643
02644 $this->printHTMLHeader($this->getString(CAS_STR_AUTHENTICATION_FAILED));
02645 printf($this->getString(CAS_STR_YOU_WERE_NOT_AUTHENTICATED),$this->getURL(),$_SERVER['SERVER_ADMIN']);
02646 phpCAS::trace('CAS URL: '.$cas_url);
02647 phpCAS::trace('Authentication failure: '.$failure);
02648 if ( $no_response ) {
02649 phpCAS::trace('Reason: no response from the CAS server');
02650 } else {
02651 if ( $bad_response ) {
02652 phpCAS::trace('Reason: bad response from the CAS server');
02653 } else {
02654 switch ($this->getServerVersion()) {
02655 case CAS_VERSION_1_0:
02656 phpCAS::trace('Reason: CAS error');
02657 break;
02658 case CAS_VERSION_2_0:
02659 if ( empty($err_code) )
02660 phpCAS::trace('Reason: no CAS error');
02661 else
02662 phpCAS::trace('Reason: ['.$err_code.'] CAS error: '.$err_msg);
02663 break;
02664 }
02665 }
02666 phpCAS::trace('CAS response: '.$cas_response);
02667 }
02668 $this->printHTMLFooter();
02669 phpCAS::traceExit();
02670 exit();
02671 }
02672
02674 }
02675
02676 ?>