Main Page | Modules | Class Hierarchy | Class List | File List | Class Members | File Members | Related Pages | Examples

/CAS/client.php

Go to the documentation of this file.
00001 <?php
00002 
00008 // include internationalization stuff
00009 include_once(dirname(__FILE__).'/languages/languages.php');
00010 
00011 // include PGT storage classes
00012 include_once(dirname(__FILE__).'/PGTStorage/pgt-main.php');
00013 
00022 class CASClient
00023 {
00024         
00025         // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
00026         // XX                                                                    XX
00027         // XX                          CONFIGURATION                             XX
00028         // XX                                                                    XX
00029         // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
00030         
00031         // ########################################################################
00032         //  HTML OUTPUT
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         //  INTERNATIONALIZATION
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                 // call CASclient::getLang() to be sure the language is initialized
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                 // include the corresponding language file
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                 // the URL is build only when needed
00327                 if ( empty($this->_server['login_url']) ) {
00328                         $this->_server['login_url'] = $this->getServerBaseURL();
00329                         $this->_server['login_url'] .= 'login?service=';
00330                         // $this->_server['login_url'] .= preg_replace('/&/','%26',$this->getURL());
00331                         $this->_server['login_url'] .= urlencode($this->getURL());
00332                         if($renew) {
00333                                 // It is recommended that when the "renew" parameter is set, its value be "true"
00334                                 $this->_server['login_url'] .= '&renew=true';
00335                         } elseif ($gateway) {
00336                                 // It is recommended that when the "gateway" parameter is set, its value be "true"
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         
00360         function getServerServiceValidateURL()
00361                 { 
00362                 // the URL is build only when needed
00363                 if ( empty($this->_server['service_validate_url']) ) {
00364                         switch ($this->getServerVersion()) {
00365                                 case CAS_VERSION_1_0:
00366                                         $this->_server['service_validate_url'] = $this->getServerBaseURL().'validate';
00367                                         break;
00368                                 case CAS_VERSION_2_0:
00369                                         $this->_server['service_validate_url'] = $this->getServerBaseURL().'serviceValidate';
00370                                         break;
00371                         }
00372                 }
00373                 //      return $this->_server['service_validate_url'].'?service='.preg_replace('/&/','%26',$this->getURL()); 
00374                 return $this->_server['service_validate_url'].'?service='.urlencode($this->getURL()); 
00375                 }
00376         
00382         function getServerProxyValidateURL()
00383                 { 
00384                 // the URL is build only when needed
00385                 if ( empty($this->_server['proxy_validate_url']) ) {
00386                         switch ($this->getServerVersion()) {
00387                                 case CAS_VERSION_1_0:
00388                                         $this->_server['proxy_validate_url'] = '';
00389                                         break;
00390                                 case CAS_VERSION_2_0:
00391                                         $this->_server['proxy_validate_url'] = $this->getServerBaseURL().'proxyValidate';
00392                                         break;
00393                         }
00394                 }
00395                 //      return $this->_server['proxy_validate_url'].'?service='.preg_replace('/&/','%26',$this->getURL()); 
00396                 return $this->_server['proxy_validate_url'].'?service='.urlencode($this->getURL()); 
00397                 }
00398         
00404         function getServerProxyURL()
00405                 { 
00406                 // the URL is build only when needed
00407                 if ( empty($this->_server['proxy_url']) ) {
00408                         switch ($this->getServerVersion()) {
00409                                 case CAS_VERSION_1_0:
00410                                         $this->_server['proxy_url'] = '';
00411                                         break;
00412                                 case CAS_VERSION_2_0:
00413                                         $this->_server['proxy_url'] = $this->getServerBaseURL().'proxy';
00414                                         break;
00415                         }
00416                 }
00417                 return $this->_server['proxy_url']; 
00418                 }
00419         
00425         function getServerLogoutURL()
00426                 { 
00427                 // the URL is build only when needed
00428                 if ( empty($this->_server['logout_url']) ) {
00429                         $this->_server['logout_url'] = $this->getServerBaseURL().'logout';
00430                 }
00431                 return $this->_server['logout_url']; 
00432                 }
00433         
00440         function setServerLogoutURL($url)
00441                 {
00442                 return $this->_server['logout_url'] = $url;
00443                 }
00444 
00448         var $_curl_options = array();
00449 
00453         function setExtraCurlOption($key, $value)
00454         {
00455                 $this->_curl_options[$key] = $value;
00456         }
00457  
00463         function isHttps() {
00464                 //if ( isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS']) ) {
00465                 //0.4.24 by Hinnack
00466                 if ( isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
00467                         return true;
00468                 } else {
00469                         return false;
00470                 }
00471         }
00472         
00473         // ########################################################################
00474         //  CONSTRUCTOR
00475         // ########################################################################
00490         function CASClient(
00491                                            $server_version,
00492                                            $proxy,
00493                                            $server_hostname,
00494                                            $server_port,
00495                                            $server_uri,
00496                                            $start_session = true) {
00497                 
00498                 phpCAS::traceBegin();
00499                 
00500                 if (!$this->isLogoutRequest() && !empty($_GET['ticket'])) {
00501             // copy old session vars and destroy the current session
00502             session_start();
00503             $old_session = $_SESSION;
00504             session_destroy();
00505             // set up a new session, of name based on the ticket
00506                         $session_id = preg_replace('|-|','',$_GET['ticket']);
00507                         phpCAS::LOG("Session ID: " . $session_id);
00508                         session_id($session_id);
00509             session_start();
00510             // restore old session vars
00511             $_SESSION = $old_session;
00512                 }
00513                 
00514                 //activate session mechanism if desired
00515                 if (!$this->isLogoutRequest() && $start_session) {
00516                         session_start();
00517                 }
00518                 
00519                 $this->_proxy = $proxy;
00520                 
00521                 //check version
00522                 switch ($server_version) {
00523                         case CAS_VERSION_1_0:
00524                                 if ( $this->isProxy() )
00525                                         phpCAS::error('CAS proxies are not supported in CAS '
00526                                                 .$server_version);
00527                                 break;
00528                         case CAS_VERSION_2_0:
00529                                 break;
00530                         default:
00531                                 phpCAS::error('this version of CAS (`'
00532                                         .$server_version
00533                                         .'\') is not supported by phpCAS '
00534                                         .phpCAS::getVersion());
00535                 }
00536                 $this->_server['version'] = $server_version;
00537                 
00538                 //check hostname
00539                 if ( empty($server_hostname) 
00540                                 || !preg_match('/[\.\d\-abcdefghijklmnopqrstuvwxyz]*/',$server_hostname) ) {
00541                         phpCAS::error('bad CAS server hostname (`'.$server_hostname.'\')');
00542                 }
00543                 $this->_server['hostname'] = $server_hostname;
00544                 
00545                 //check port
00546                 if ( $server_port == 0 
00547                         || !is_int($server_port) ) {
00548                         phpCAS::error('bad CAS server port (`'.$server_hostname.'\')');
00549                 }
00550                 $this->_server['port'] = $server_port;
00551                 
00552                 //check URI
00553                 if ( !preg_match('/[\.\d\-_abcdefghijklmnopqrstuvwxyz\/]*/',$server_uri) ) {
00554                         phpCAS::error('bad CAS server URI (`'.$server_uri.'\')');
00555                 }
00556                 //add leading and trailing `/' and remove doubles      
00557                 $server_uri = preg_replace('/\/\//','/','/'.$server_uri.'/');
00558                 $this->_server['uri'] = $server_uri;
00559                 
00560                 //set to callback mode if PgtIou and PgtId CGI GET parameters are provided 
00561                 if ( $this->isProxy() ) {
00562                         $this->setCallbackMode(!empty($_GET['pgtIou'])&&!empty($_GET['pgtId']));
00563                 }
00564                 
00565                 if ( $this->isCallbackMode() ) {
00566                         //callback mode: check that phpCAS is secured
00567                         if ( !$this->isHttps() ) {
00568                                 phpCAS::error('CAS proxies must be secured to use phpCAS; PGT\'s will not be received from the CAS server');
00569                         }
00570                 } else {
00571                         //normal mode: get ticket and remove it from CGI parameters for developpers
00572                         $ticket = (isset($_GET['ticket']) ? $_GET['ticket'] : null);
00573                         switch ($this->getServerVersion()) {
00574                                 case CAS_VERSION_1_0: // check for a Service Ticket
00575                                         if( preg_match('/^ST-/',$ticket) ) {
00576                                                 phpCAS::trace('ST \''.$ticket.'\' found');
00577                                                 //ST present
00578                                                 $this->setST($ticket);
00579                                                 //ticket has been taken into account, unset it to hide it to applications
00580                                                 unset($_GET['ticket']);
00581                                         } else if ( !empty($ticket) ) {
00582                                                 //ill-formed ticket, halt
00583                                                 phpCAS::error('ill-formed ticket found in the URL (ticket=`'.htmlentities($ticket).'\')');
00584                                         }
00585                                         break;
00586                                 case CAS_VERSION_2_0: // check for a Service or Proxy Ticket
00587                                         if( preg_match('/^[SP]T-/',$ticket) ) {
00588                                                 phpCAS::trace('ST or PT \''.$ticket.'\' found');
00589                                                 $this->setPT($ticket);
00590                                                 unset($_GET['ticket']);
00591                                         } else if ( !empty($ticket) ) {
00592                                                 //ill-formed ticket, halt
00593                                                 phpCAS::error('ill-formed ticket found in the URL (ticket=`'.htmlentities($ticket).'\')');
00594                                         } 
00595                                         break;
00596                         }
00597                 }
00598                 phpCAS::traceEnd();
00599         }
00600         
00603         // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
00604         // XX                                                                    XX
00605         // XX                           AUTHENTICATION                           XX
00606         // XX                                                                    XX
00607         // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
00608         
00621         var $_user = '';
00622         
00630         function setUser($user)
00631                 {
00632                 $this->_user = $user;
00633                 }
00634         
00642         function getUser()
00643                 {
00644                 if ( empty($this->_user) ) {
00645                         phpCAS::error('this method should be used only after '.__CLASS__.'::forceAuthentication() or '.__CLASS__.'::isAuthenticated()');
00646                 }
00647                 return $this->_user;
00648                 }
00649         
00656         function renewAuthentication(){
00657                 phpCAS::traceBegin();
00658                 // Either way, the user is authenticated by CAS
00659                 if( isset( $_SESSION['phpCAS']['auth_checked'] ) )
00660                         unset($_SESSION['phpCAS']['auth_checked']);
00661                 if ( $this->isAuthenticated() ) {
00662                         phpCAS::trace('user already authenticated; renew');
00663                         $this->redirectToCas(false,true);
00664                 } else {
00665                         $this->redirectToCas();
00666                 }
00667                 phpCAS::traceEnd();
00668         }
00669 
00676         function forceAuthentication()
00677                 {
00678                 phpCAS::traceBegin();
00679                 
00680                 if ( $this->isAuthenticated() ) {
00681                         // the user is authenticated, nothing to be done.
00682                         phpCAS::trace('no need to authenticate');
00683                         $res = TRUE;
00684                 } else {
00685                         // the user is not authenticated, redirect to the CAS server
00686                         if (isset($_SESSION['phpCAS']['auth_checked'])) {
00687                                 unset($_SESSION['phpCAS']['auth_checked']);
00688                         }
00689                         $this->redirectToCas(FALSE/* no gateway */);    
00690                         // never reached
00691                         $res = FALSE;
00692                 }
00693                 phpCAS::traceEnd($res);
00694                 return $res;
00695                 }
00696         
00703         var $_cache_times_for_auth_recheck = 0;
00704         
00712         function setCacheTimesForAuthRecheck($n)
00713                 {
00714                 $this->_cache_times_for_auth_recheck = $n;
00715                 }
00716         
00722         function checkAuthentication()
00723                 {
00724                 phpCAS::traceBegin();
00725                 
00726                 if ( $this->isAuthenticated() ) {
00727                         phpCAS::trace('user is authenticated');
00728                         $res = TRUE;
00729                 } else if (isset($_SESSION['phpCAS']['auth_checked'])) {
00730                         // the previous request has redirected the client to the CAS server with gateway=true
00731                         unset($_SESSION['phpCAS']['auth_checked']);
00732                         $res = FALSE;
00733                 } else {
00734                         //        $_SESSION['phpCAS']['auth_checked'] = true;
00735                         //          $this->redirectToCas(TRUE/* gateway */);    
00736                         //          // never reached
00737                         //          $res = FALSE;
00738                         // avoid a check against CAS on every request
00739                         if (! isset($_SESSION['phpCAS']['unauth_count']) )
00740                                 $_SESSION['phpCAS']['unauth_count'] = -2; // uninitialized
00741                         
00742                         if (($_SESSION['phpCAS']['unauth_count'] != -2 && $this->_cache_times_for_auth_recheck == -1) 
00743                                         || ($_SESSION['phpCAS']['unauth_count'] >= 0 && $_SESSION['phpCAS']['unauth_count'] < $this->_cache_times_for_auth_recheck))
00744                         {
00745                                 $res = FALSE;
00746                                 
00747                                 if ($this->_cache_times_for_auth_recheck != -1)
00748                                 {
00749                                         $_SESSION['phpCAS']['unauth_count']++;
00750                                         phpCAS::trace('user is not authenticated (cached for '.$_SESSION['phpCAS']['unauth_count'].' times of '.$this->_cache_times_for_auth_recheck.')');
00751                                 }
00752                                 else
00753                                 {
00754                                         phpCAS::trace('user is not authenticated (cached for until login pressed)');
00755                                 }
00756                         }
00757                         else
00758                         {
00759                                 $_SESSION['phpCAS']['unauth_count'] = 0;
00760                                 $_SESSION['phpCAS']['auth_checked'] = true;
00761                                 phpCAS::trace('user is not authenticated (cache reset)');
00762                                 $this->redirectToCas(TRUE/* gateway */);        
00763                                 // never reached
00764                                 $res = FALSE;
00765                         }
00766                 }
00767                 phpCAS::traceEnd($res);
00768                 return $res;
00769                 }
00770         
00779         function isAuthenticated()
00780                 {
00781                 phpCAS::traceBegin();
00782                 $res = FALSE;
00783                 $validate_url = '';
00784                 
00785                 if ( $this->wasPreviouslyAuthenticated() ) {
00786                         // the user has already (previously during the session) been 
00787                         // authenticated, nothing to be done.
00788                         phpCAS::trace('user was already authenticated, no need to look for tickets');
00789                         $res = TRUE;
00790                 } 
00791                 elseif ( $this->hasST() ) {
00792                         // if a Service Ticket was given, validate it
00793                         phpCAS::trace('ST `'.$this->getST().'\' is present');
00794                         $this->validateST($validate_url,$text_response,$tree_response); // if it fails, it halts
00795                         phpCAS::trace('ST `'.$this->getST().'\' was validated');
00796                         if ( $this->isProxy() ) {
00797                                 $this->validatePGT($validate_url,$text_response,$tree_response); // idem
00798                                 phpCAS::trace('PGT `'.$this->getPGT().'\' was validated');
00799                                 $_SESSION['phpCAS']['pgt'] = $this->getPGT();
00800                         }
00801                         $_SESSION['phpCAS']['user'] = $this->getUser();
00802                         $res = TRUE;
00803                 }
00804                 elseif ( $this->hasPT() ) {
00805                         // if a Proxy Ticket was given, validate it
00806                         phpCAS::trace('PT `'.$this->getPT().'\' is present');
00807                         $this->validatePT($validate_url,$text_response,$tree_response); // note: if it fails, it halts
00808                         phpCAS::trace('PT `'.$this->getPT().'\' was validated');
00809                         if ( $this->isProxy() ) {
00810                                 $this->validatePGT($validate_url,$text_response,$tree_response); // idem
00811                                 phpCAS::trace('PGT `'.$this->getPGT().'\' was validated');
00812                                 $_SESSION['phpCAS']['pgt'] = $this->getPGT();
00813                         }
00814                         $_SESSION['phpCAS']['user'] = $this->getUser();
00815                         $res = TRUE;
00816                 } 
00817                 else {
00818                         // no ticket given, not authenticated
00819                         phpCAS::trace('no ticket found');
00820                 }
00821                 
00822                 phpCAS::traceEnd($res);
00823                 return $res;
00824                 }
00825         
00831         function isSessionAuthenticated ()
00832                 {
00833                 return !empty($_SESSION['phpCAS']['user']);
00834                 }
00835         
00846         function wasPreviouslyAuthenticated()
00847                 {
00848                 phpCAS::traceBegin();
00849                 
00850                 if ( $this->isCallbackMode() ) {
00851                         $this->callback();
00852                 }
00853                 
00854                 $auth = FALSE;
00855                 
00856                 if ( $this->isProxy() ) {
00857                         // CAS proxy: username and PGT must be present
00858                         if ( $this->isSessionAuthenticated() && !empty($_SESSION['phpCAS']['pgt']) ) {
00859                                 // authentication already done
00860                                 $this->setUser($_SESSION['phpCAS']['user']);
00861                                 $this->setPGT($_SESSION['phpCAS']['pgt']);
00862                                 phpCAS::trace('user = `'.$_SESSION['phpCAS']['user'].'\', PGT = `'.$_SESSION['phpCAS']['pgt'].'\''); 
00863                                 $auth = TRUE;
00864                         } elseif ( $this->isSessionAuthenticated() && empty($_SESSION['phpCAS']['pgt']) ) {
00865                                 // these two variables should be empty or not empty at the same time
00866                                 phpCAS::trace('username found (`'.$_SESSION['phpCAS']['user'].'\') but PGT is empty');
00867                                 // unset all tickets to enforce authentication
00868                                 unset($_SESSION['phpCAS']);
00869                                 $this->setST('');
00870                                 $this->setPT('');
00871                         } elseif ( !$this->isSessionAuthenticated() && !empty($_SESSION['phpCAS']['pgt']) ) {
00872                                 // these two variables should be empty or not empty at the same time
00873                                 phpCAS::trace('PGT found (`'.$_SESSION['phpCAS']['pgt'].'\') but username is empty'); 
00874                                 // unset all tickets to enforce authentication
00875                                 unset($_SESSION['phpCAS']);
00876                                 $this->setST('');
00877                                 $this->setPT('');
00878                         } else {
00879                                 phpCAS::trace('neither user not PGT found'); 
00880                         }
00881                 } else {
00882                         // `simple' CAS client (not a proxy): username must be present
00883                         if ( $this->isSessionAuthenticated() ) {
00884                                 // authentication already done
00885                                 $this->setUser($_SESSION['phpCAS']['user']);
00886                                 phpCAS::trace('user = `'.$_SESSION['phpCAS']['user'].'\''); 
00887                                 $auth = TRUE;
00888                         } else {
00889                                 phpCAS::trace('no user found');
00890                         }
00891                 }
00892                 
00893                 phpCAS::traceEnd($auth);
00894                 return $auth;
00895                 }
00896         
00904         function redirectToCas($gateway=false,$renew=false){
00905                 phpCAS::traceBegin();
00906                 $cas_url = $this->getServerLoginURL($gateway,$renew);
00907                 header('Location: '.$cas_url);
00908                 phpCAS::log( "Redirect to : ".$cas_url );
00909                 
00910                 $this->printHTMLHeader($this->getString(CAS_STR_AUTHENTICATION_WANTED));
00911                 
00912                 printf('<p>'.$this->getString(CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED).'</p>',$cas_url);
00913                 $this->printHTMLFooter();
00914                 phpCAS::traceExit();
00915                 exit();
00916         }
00917 
00918 //      /**
00919 //       * This method is used to logout from CAS.
00920 //       * @param $url a URL that will be transmitted to the CAS server (to come back to when logged out)
00921 //       * @public
00922 //       */
00923 //      function logout($url = "") {
00924 //              phpCAS::traceBegin();
00925 //              $cas_url = $this->getServerLogoutURL();
00926 //              // v0.4.14 sebastien.gougeon at univ-rennes1.fr
00927 //              // header('Location: '.$cas_url);
00928 //              if ( $url != "" ) {
00929 //                      // Adam Moore 1.0.0RC2
00930 //                      $url = '?service=' . $url . '&url=' . $url;
00931 //              }
00932 //              header('Location: '.$cas_url . $url);
00933 //              session_unset();
00934 //              session_destroy();
00935 //              $this->printHTMLHeader($this->getString(CAS_STR_LOGOUT));
00936 //              printf('<p>'.$this->getString(CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED).'</p>',$cas_url);
00937 //              $this->printHTMLFooter();
00938 //              phpCAS::traceExit();
00939 //              exit();
00940 //      }
00941         
00947         function logout($params) {
00948                 phpCAS::traceBegin();
00949                 $cas_url = $this->getServerLogoutURL();
00950                 $paramSeparator = '?';
00951                 if (isset($params['url'])) {
00952                         $cas_url = $cas_url . $paramSeparator . "url=" . urlencode($params['url']); 
00953                         $paramSeparator = '&';
00954                 }
00955                 if (isset($params['service'])) {
00956                         $cas_url = $cas_url . $paramSeparator . "service=" . urlencode($params['service']); 
00957                 }
00958                 header('Location: '.$cas_url);
00959                 session_unset();
00960                 session_destroy();
00961                 $this->printHTMLHeader($this->getString(CAS_STR_LOGOUT));
00962                 printf('<p>'.$this->getString(CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED).'</p>',$cas_url);
00963                 $this->printHTMLFooter();
00964                 phpCAS::traceExit();
00965                 exit();
00966         }
00967         
00972         function isLogoutRequest() {
00973                 return !empty($_POST['logoutRequest']);
00974         }
00975         
00980         function isLogoutRequestAllowed() {
00981         }
00982         
00991         function handleLogoutRequests($check_client=true, $allowed_clients=false) {
00992                 phpCAS::traceBegin();
00993                 if (!$this->isLogoutRequest()) {
00994                         phpCAS::log("Not a logout request");
00995                         phpCAS::traceEnd();
00996                         return;
00997                 }
00998                 phpCAS::log("Logout requested");
00999                 phpCAS::log("SAML REQUEST: ".$_POST['logoutRequest']);
01000                 if ($check_client) {
01001                         if (!$allowed_clients) {
01002                                 $allowed_clients = array( $this->getServerHostname() ); 
01003                         }
01004                         $client_ip = $_SERVER['REMOTE_ADDR'];
01005                         $client = gethostbyaddr($client_ip);
01006                         phpCAS::log("Client: ".$client);
01007                         $allowed = false;
01008                         foreach ($allowed_clients as $allowed_client) {
01009                                 if ($client == $allowed_client) {
01010                                         phpCAS::log("Allowed client '".$allowed_client."' matches, logout request is allowed");
01011                                         $allowed = true;
01012                                         break;
01013                                 } else {
01014                                         phpCAS::log("Allowed client '".$allowed_client."' does not match");
01015                                 }
01016                         }
01017                         if (!$allowed) {
01018                                 phpCAS::error("Unauthorized logout request from client '".$client."'");
01019                             printf("Unauthorized!");
01020                                 phpCAS::traceExit();
01021                                 exit();
01022                         }
01023                 } else {
01024                         phpCAS::log("No access control set");
01025                 }
01026                 // Extract the ticket from the SAML Request
01027                 preg_match("|<samlp:SessionIndex>(.*)</samlp:SessionIndex>|", $_POST['logoutRequest'], $tick, PREG_OFFSET_CAPTURE, 3);
01028                 $wrappedSamlSessionIndex = preg_replace('|<samlp:SessionIndex>|','',$tick[0][0]);
01029                 $ticket2logout = preg_replace('|</samlp:SessionIndex>|','',$wrappedSamlSessionIndex);
01030                 phpCAS::log("Ticket to logout: ".$ticket2logout);
01031                 $session_id = preg_replace('|-|','',$ticket2logout);
01032                 phpCAS::log("Session id: ".$session_id);
01033                 // Overwrite session
01034                 $_COOKIE[session_name()]=$session_id;
01035                 session_start();        
01036                 session_unset();
01037             session_destroy();
01038             printf("Disconnected!");
01039                 phpCAS::traceExit();
01040                 exit();
01041         }
01042         
01045         // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
01046         // XX                                                                    XX
01047         // XX                  BASIC CLIENT FEATURES (CAS 1.0)                   XX
01048         // XX                                                                    XX
01049         // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
01050         
01051         // ########################################################################
01052         //  ST
01053         // ########################################################################
01067         var $_st = '';
01068         
01074         function getST()
01075                 { return $this->_st; }
01076         
01082         function setST($st)
01083                 { $this->_st = $st; }
01084         
01090         function hasST()
01091                 { return !empty($this->_st); }
01092         
01095         // ########################################################################
01096         //  ST VALIDATION
01097         // ########################################################################
01109         var $_cas_server_cert = '';
01110         
01117         var $_cas_server_ca_cert = '';
01118         
01125         var $_no_cas_server_validation = false;
01126         
01132         function setCasServerCert($cert)
01133                 {
01134                 $this->_cas_server_cert = $cert;
01135                 }
01136         
01142         function setCasServerCACert($cert)
01143                 {
01144                 $this->_cas_server_ca_cert = $cert;
01145                 }
01146         
01150         function setNoCasServerValidation()
01151                 {
01152                 $this->_no_cas_server_validation = true;
01153                 }
01154         
01168         function validateST($validate_url,&$text_response,&$tree_response)
01169                 {
01170                 phpCAS::traceBegin();
01171                 // build the URL to validate the ticket
01172                 $validate_url = $this->getServerServiceValidateURL().'&ticket='.$this->getST();
01173                 if ( $this->isProxy() ) {
01174                         // pass the callback url for CAS proxies
01175                         $validate_url .= '&pgtUrl='.$this->getCallbackURL();
01176                 }
01177                 
01178                 // open and read the URL
01179                 if ( !$this->readURL($validate_url,''/*cookies*/,$headers,$text_response,$err_msg) ) {
01180                         phpCAS::trace('could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')');
01181                         $this->authError('ST not validated',
01182                                 $validate_url,
01183                                 TRUE/*$no_response*/);
01184                 }
01185                 
01186                 // analyze the result depending on the version
01187                 switch ($this->getServerVersion()) {
01188                         case CAS_VERSION_1_0:
01189                                 if (preg_match('/^no\n/',$text_response)) {
01190                                         phpCAS::trace('ST has not been validated');
01191                                         $this->authError('ST not validated',
01192                                                 $validate_url,
01193                                                 FALSE/*$no_response*/,
01194                                                 FALSE/*$bad_response*/,
01195                                                 $text_response);
01196                                 }
01197                                 if (!preg_match('/^yes\n/',$text_response)) {
01198                                         phpCAS::trace('ill-formed response');
01199                                         $this->authError('ST not validated',
01200                                                 $validate_url,
01201                                                 FALSE/*$no_response*/,
01202                                                 TRUE/*$bad_response*/,
01203                                                 $text_response);
01204                                 }
01205                                 // ST has been validated, extract the user name
01206                                 $arr = preg_split('/\n/',$text_response);
01207                                 $this->setUser(trim($arr[1]));
01208                                 break;
01209                         case CAS_VERSION_2_0:
01210                                 // read the response of the CAS server into a DOM object
01211                                 if ( !($dom = domxml_open_mem($text_response))) {
01212                                         phpCAS::trace('domxml_open_mem() failed');
01213                                         $this->authError('ST not validated',
01214                                                 $validate_url,
01215                                                 FALSE/*$no_response*/,
01216                                                 TRUE/*$bad_response*/,
01217                                                 $text_response);
01218                                 }
01219                                 // read the root node of the XML tree
01220                                 if ( !($tree_response = $dom->document_element()) ) {
01221                                         phpCAS::trace('document_element() failed');
01222                                         $this->authError('ST not validated',
01223                                                 $validate_url,
01224                                                 FALSE/*$no_response*/,
01225                                                 TRUE/*$bad_response*/,
01226                                                 $text_response);
01227                                 }
01228                                 // insure that tag name is 'serviceResponse'
01229                                 if ( $tree_response->node_name() != 'serviceResponse' ) {
01230                                         phpCAS::trace('bad XML root node (should be `serviceResponse\' instead of `'.$tree_response->node_name().'\'');
01231                                         $this->authError('ST not validated',
01232                                                 $validate_url,
01233                                                 FALSE/*$no_response*/,
01234                                                 TRUE/*$bad_response*/,
01235                                                 $text_response);
01236                                 }
01237                                 if ( sizeof($success_elements = $tree_response->get_elements_by_tagname("authenticationSuccess")) != 0) {
01238                                         // authentication succeded, extract the user name
01239                                         if ( sizeof($user_elements = $success_elements[0]->get_elements_by_tagname("user")) == 0) {
01240                                                 phpCAS::trace('<authenticationSuccess> found, but no <user>');
01241                                                 $this->authError('ST not validated',
01242                                                         $validate_url,
01243                                                         FALSE/*$no_response*/,
01244                                                         TRUE/*$bad_response*/,
01245                                                         $text_response);
01246                                         }
01247                                         $user = trim($user_elements[0]->get_content());
01248                                         phpCAS::trace('user = `'.$user);
01249                                         $this->setUser($user);
01250                                         
01251                                 } else if ( sizeof($failure_elements = $tree_response->get_elements_by_tagname("authenticationFailure")) != 0) {
01252                                         phpCAS::trace('<authenticationFailure> found');
01253                                         // authentication failed, extract the error code and message
01254                                         $this->authError('ST not validated',
01255                                                 $validate_url,
01256                                                 FALSE/*$no_response*/,
01257                                                 FALSE/*$bad_response*/,
01258                                                 $text_response,
01259                                                 $failure_elements[0]->get_attribute('code')/*$err_code*/,
01260                                                 trim($failure_elements[0]->get_content())/*$err_msg*/);
01261                                 } else {
01262                                         phpCAS::trace('neither <authenticationSuccess> nor <authenticationFailure> found');
01263                                         $this->authError('ST not validated',
01264                                                 $validate_url,
01265                                                 FALSE/*$no_response*/,
01266                                                 TRUE/*$bad_response*/,
01267                                                 $text_response);
01268                                 }
01269                                 break;
01270                 }
01271                 
01272                 // at this step, ST has been validated and $this->_user has been set,
01273                 phpCAS::traceEnd(TRUE);
01274                 return TRUE;
01275                 }
01276         
01279         // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
01280         // XX                                                                    XX
01281         // XX                     PROXY FEATURES (CAS 2.0)                       XX
01282         // XX                                                                    XX
01283         // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
01284         
01285         // ########################################################################
01286         //  PROXYING
01287         // ########################################################################
01299         var $_proxy;
01300         
01308         function isProxy()
01309                 {
01310                 return $this->_proxy;
01311                 }
01312         
01314         // ########################################################################
01315         //  PGT
01316         // ########################################################################
01329         var $_pgt = '';
01330         
01336         function getPGT()
01337                 { return $this->_pgt; }
01338         
01344         function setPGT($pgt)
01345                 { $this->_pgt = $pgt; }
01346         
01352         function hasPGT()
01353                 { return !empty($this->_pgt); }
01354         
01357         // ########################################################################
01358         //  CALLBACK MODE
01359         // ########################################################################
01377         var $_callback_mode = FALSE;
01378         
01386         function setCallbackMode($callback_mode)
01387                 {
01388                 $this->_callback_mode = $callback_mode;
01389                 }
01390         
01399         function isCallbackMode()
01400                 {
01401                 return $this->_callback_mode;
01402                 }
01403         
01412         var $_callback_url = '';
01413         
01423         function getCallbackURL()
01424                 {
01425                 // the URL is built when needed only
01426                 if ( empty($this->_callback_url) ) {
01427                         $final_uri = '';
01428                         // remove the ticket if present in the URL
01429                         $final_uri = 'https://';
01430                         /* replaced by Julien Marchal - v0.4.6
01431                          * $this->uri .= $_SERVER['SERVER_NAME'];
01432                          */
01433                         if(empty($_SERVER['HTTP_X_FORWARDED_SERVER'])){
01434                                 /* replaced by teedog - v0.4.12
01435                                  * $final_uri .= $_SERVER['SERVER_NAME'];
01436                                  */
01437                                 if (empty($_SERVER['SERVER_NAME'])) {
01438                                         $final_uri .= $_SERVER['HTTP_HOST'];
01439                                 } else {
01440                                         $final_uri .= $_SERVER['SERVER_NAME'];
01441                                 }
01442                         } else {
01443                                 $final_uri .= $_SERVER['HTTP_X_FORWARDED_SERVER'];
01444                         }
01445                         if ( ($this->isHttps() && $_SERVER['SERVER_PORT']!=443)
01446                                         || (!$this->isHttps() && $_SERVER['SERVER_PORT']!=80) ) {
01447                                 $final_uri .= ':';
01448                                 $final_uri .= $_SERVER['SERVER_PORT'];
01449                         }
01450                         $request_uri = $_SERVER['REQUEST_URI'];
01451                         $request_uri = preg_replace('/\?.*$/','',$request_uri);
01452                         $final_uri .= $request_uri;
01453                         $this->setCallbackURL($final_uri);
01454                 }
01455                 return $this->_callback_url;
01456                 }
01457         
01465         function setCallbackURL($url)
01466                 {
01467                 return $this->_callback_url = $url;
01468                 }
01469         
01476         function callback()
01477                 {
01478                 phpCAS::traceBegin();
01479                 $this->printHTMLHeader('phpCAS callback');
01480                 $pgt_iou = $_GET['pgtIou'];
01481                 $pgt = $_GET['pgtId'];
01482                 phpCAS::trace('Storing PGT `'.$pgt.'\' (id=`'.$pgt_iou.'\')');
01483                 echo '<p>Storing PGT `'.$pgt.'\' (id=`'.$pgt_iou.'\').</p>';
01484                 $this->storePGT($pgt,$pgt_iou);
01485                 $this->printHTMLFooter();
01486                 phpCAS::traceExit();
01487                 }
01488         
01491         // ########################################################################
01492         //  PGT STORAGE
01493         // ########################################################################
01507         var $_pgt_storage = null;
01508         
01515         function initPGTStorage()
01516                 {
01517                 // if no SetPGTStorageXxx() has been used, default to file
01518                 if ( !is_object($this->_pgt_storage) ) {
01519                         $this->setPGTStorageFile();
01520                 }
01521                 
01522                 // initializes the storage
01523                 $this->_pgt_storage->init();
01524                 }
01525         
01534         function storePGT($pgt,$pgt_iou)
01535                 {
01536                 // ensure that storage is initialized
01537                 $this->initPGTStorage();
01538                 // writes the PGT
01539                 $this->_pgt_storage->write($pgt,$pgt_iou);
01540                 }
01541         
01551         function loadPGT($pgt_iou)
01552                 {
01553                 // ensure that storage is initialized
01554                 $this->initPGTStorage();
01555                 // read the PGT
01556                 return $this->_pgt_storage->read($pgt_iou);
01557                 }
01558         
01568         function setPGTStorageFile($format='',
01569                 $path='')
01570                 {
01571                 // check that the storage has not already been set
01572                 if ( is_object($this->_pgt_storage) ) {
01573                         phpCAS::error('PGT storage already defined');
01574                 }
01575                 
01576                 // create the storage object
01577                 $this->_pgt_storage = &new PGTStorageFile($this,$format,$path);
01578                 }
01579         
01597         function setPGTStorageDB($user,
01598                                                          $password,
01599                                                          $database_type,
01600                                                          $hostname,
01601                                                          $port,
01602                                                          $database,
01603                                                          $table)
01604                 {
01605                 // check that the storage has not already been set
01606                 if ( is_object($this->_pgt_storage) ) {
01607                         phpCAS::error('PGT storage already defined');
01608                 }
01609                 
01610                 // warn the user that he should use file storage...
01611                 trigger_error('PGT storage into database is an experimental feature, use at your own risk',E_USER_WARNING);
01612                 
01613                 // create the storage object
01614                 $this->_pgt_storage = & new PGTStorageDB($this,$user,$password,$database_type,$hostname,$port,$database,$table);
01615                 }
01616         
01617         // ########################################################################
01618         //  PGT VALIDATION
01619         // ########################################################################
01633         function validatePGT(&$validate_url,$text_response,$tree_response)
01634                 {
01635                 phpCAS::traceBegin();
01636                 if ( sizeof($arr = $tree_response->get_elements_by_tagname("proxyGrantingTicket")) == 0) {
01637                         phpCAS::trace('<proxyGrantingTicket> not found');
01638                         // authentication succeded, but no PGT Iou was transmitted
01639                         $this->authError('Ticket validated but no PGT Iou transmitted',
01640                                 $validate_url,
01641                                 FALSE/*$no_response*/,
01642                                 FALSE/*$bad_response*/,
01643                                 $text_response);
01644                 } else {
01645                         // PGT Iou transmitted, extract it
01646                         $pgt_iou = trim($arr[0]->get_content());
01647                         $pgt = $this->loadPGT($pgt_iou);
01648                         if ( $pgt == FALSE ) {
01649                                 phpCAS::trace('could not load PGT');
01650                                 $this->authError('PGT Iou was transmitted but PGT could not be retrieved',
01651                                         $validate_url,
01652                                         FALSE/*$no_response*/,
01653                                         FALSE/*$bad_response*/,
01654                                         $text_response);
01655                         }
01656                         $this->setPGT($pgt);
01657                 }
01658                 phpCAS::traceEnd(TRUE);
01659                 return TRUE;
01660                 }
01661         
01662         // ########################################################################
01663         //  PGT VALIDATION
01664         // ########################################################################
01665         
01677         function retrievePT($target_service,&$err_code,&$err_msg)
01678                 {
01679                 phpCAS::traceBegin();
01680                 
01681                 // by default, $err_msg is set empty and $pt to TRUE. On error, $pt is
01682                 // set to false and $err_msg to an error message. At the end, if $pt is FALSE 
01683                 // and $error_msg is still empty, it is set to 'invalid response' (the most
01684                 // commonly encountered error).
01685                 $err_msg = '';
01686                 
01687                 // build the URL to retrieve the PT
01688                 //      $cas_url = $this->getServerProxyURL().'?targetService='.preg_replace('/&/','%26',$target_service).'&pgt='.$this->getPGT();
01689                 $cas_url = $this->getServerProxyURL().'?targetService='.urlencode($target_service).'&pgt='.$this->getPGT();
01690                 
01691                 // open and read the URL
01692                 if ( !$this->readURL($cas_url,''/*cookies*/,$headers,$cas_response,$err_msg) ) {
01693                         phpCAS::trace('could not open URL \''.$cas_url.'\' to validate ('.$err_msg.')');
01694                         $err_code = PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE;
01695                         $err_msg = 'could not retrieve PT (no response from the CAS server)';
01696                         phpCAS::traceEnd(FALSE);
01697                         return FALSE;
01698                 }
01699                 
01700                 $bad_response = FALSE;
01701                 
01702                 if ( !$bad_response ) {
01703                         // read the response of the CAS server into a DOM object
01704                         if ( !($dom = @domxml_open_mem($cas_response))) {
01705                                 phpCAS::trace('domxml_open_mem() failed');
01706                                 // read failed
01707                                 $bad_response = TRUE;
01708                         } 
01709                 }
01710                 
01711                 if ( !$bad_response ) {
01712                         // read the root node of the XML tree
01713                         if ( !($root = $dom->document_element()) ) {
01714                                 phpCAS::trace('document_element() failed');
01715                                 // read failed
01716                                 $bad_response = TRUE;
01717                         } 
01718                 }
01719                 
01720                 if ( !$bad_response ) {
01721                         // insure that tag name is 'serviceResponse'
01722                         if ( $root->node_name() != 'serviceResponse' ) {
01723                                 phpCAS::trace('node_name() failed');
01724                                 // bad root node
01725                                 $bad_response = TRUE;
01726                         } 
01727                 }
01728                 
01729                 if ( !$bad_response ) {
01730                         // look for a proxySuccess tag
01731                         if ( sizeof($arr = $root->get_elements_by_tagname("proxySuccess")) != 0) {
01732                                 // authentication succeded, look for a proxyTicket tag
01733                                 if ( sizeof($arr = $root->get_elements_by_tagname("proxyTicket")) != 0) {
01734                                         $err_code = PHPCAS_SERVICE_OK;
01735                                         $err_msg = '';
01736                                         phpCAS::trace('original PT: '.trim($arr[0]->get_content()));
01737                                         $pt = trim($arr[0]->get_content());
01738                                         phpCAS::traceEnd($pt);
01739                                         return $pt;
01740                                 } else {
01741                                         phpCAS::trace('<proxySuccess> was found, but not <proxyTicket>');
01742                                 }
01743                         } 
01744                         // look for a proxyFailure tag
01745                         else if ( sizeof($arr = $root->get_elements_by_tagname("proxyFailure")) != 0) {
01746                                 // authentication failed, extract the error
01747                                 $err_code = PHPCAS_SERVICE_PT_FAILURE;
01748                                 $err_msg = 'PT retrieving failed (code=`'
01749                                         .$arr[0]->get_attribute('code')
01750                                         .'\', message=`'
01751                                         .trim($arr[0]->get_content())
01752                                         .'\')';
01753                                 phpCAS::traceEnd(FALSE);
01754                                 return FALSE;
01755                         } else {
01756                                 phpCAS::trace('neither <proxySuccess> nor <proxyFailure> found');
01757                         }
01758                 }
01759                 
01760                 // at this step, we are sure that the response of the CAS server was ill-formed
01761                 $err_code = PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE;
01762                 $err_msg = 'Invalid response from the CAS server (response=`'.$cas_response.'\')';
01763                 
01764                 phpCAS::traceEnd(FALSE);
01765                 return FALSE;
01766                 }
01767         
01768         // ########################################################################
01769         // ACCESS TO EXTERNAL SERVICES
01770         // ########################################################################
01771         
01787         function readURL($url,$cookies,&$headers,&$body,&$err_msg)
01788                 {
01789                 phpCAS::traceBegin();
01790                 $headers = '';
01791                 $body = '';
01792                 $err_msg = '';
01793                 
01794                 $res = TRUE;
01795                 
01796                 // initialize the CURL session
01797                 $ch = curl_init($url);
01798                 
01799                 if (version_compare(PHP_VERSION,'5','>=')) {
01800                         //only avaible in php5
01801                         curl_setopt_array($ch, $this->_curl_options);
01802                 } else {
01803                         foreach ($this->_curl_options as $key => $value) {
01804                                 curl_setopt($ch, $key, $value);
01805                         }
01806                 }
01807 
01808                 if ($this->_cas_server_cert == '' && $this->_cas_server_ca_cert == '' && !$this->_no_cas_server_validation) {
01809                         phpCAS::error('one of the methods phpCAS::setCasServerCert(), phpCAS::setCasServerCACert() or phpCAS::setNoCasServerValidation() must be called.');
01810                 }
01811                 if ($this->_cas_server_cert != '' ) {
01812                         curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
01813                         curl_setopt($ch, CURLOPT_SSLCERT, $this->_cas_server_cert);
01814                 } else if ($this->_cas_server_ca_cert != '') {
01815                         curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
01816                         curl_setopt($ch, CURLOPT_CAINFO, $this->_cas_server_ca_cert);
01817                 } else {
01818                         curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1);
01819                         curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
01820                 }
01821                 
01822                 // return the CURL output into a variable
01823                 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
01824                 // get the HTTP header with a callback
01825                 $this->_curl_headers = array(); // empty the headers array
01826                 curl_setopt($ch, CURLOPT_HEADERFUNCTION, array($this, '_curl_read_headers'));
01827                 // add cookies headers
01828                 if ( is_array($cookies) ) {
01829                         curl_setopt($ch,CURLOPT_COOKIE,implode(';',$cookies));
01830                 }
01831                 // perform the query
01832                 $buf = curl_exec ($ch);
01833                 if ( $buf === FALSE ) {
01834                         phpCAS::trace('curl_exec() failed');
01835                         $err_msg = 'CURL error #'.curl_errno($ch).': '.curl_error($ch);
01836                         // close the CURL session
01837                         curl_close ($ch);
01838                         $res = FALSE;
01839                 } else {
01840                         // close the CURL session
01841                         curl_close ($ch);
01842                         
01843                         $headers = $this->_curl_headers;
01844                         $body = $buf;
01845                 }
01846                 
01847                 phpCAS::traceEnd($res);
01848                 return $res;
01849         }
01850         
01854         var $_curl_headers = array();
01855         function _curl_read_headers($ch, $header)
01856         {
01857                 $this->_curl_headers[] = $header;
01858                 return strlen($header);
01859         }
01860 
01876         function serviceWeb($url,&$err_code,&$output)
01877                 {
01878                 phpCAS::traceBegin();
01879                 // at first retrieve a PT
01880                 $pt = $this->retrievePT($url,$err_code,$output);
01881                 
01882                 $res = TRUE;
01883                 
01884                 // test if PT was retrieved correctly
01885                 if ( !$pt ) {
01886                         // note: $err_code and $err_msg are filled by CASClient::retrievePT()
01887                         phpCAS::trace('PT was not retrieved correctly');
01888                         $res = FALSE;
01889                 } else {
01890                         // add cookies if necessary
01891                         if ( is_array($_SESSION['phpCAS']['services'][$url]['cookies']) ) {
01892                                 foreach ( $_SESSION['phpCAS']['services'][$url]['cookies'] as $name => $val ) { 
01893                                         $cookies[] = $name.'='.$val;
01894                                 }
01895                         }
01896                         
01897                         // build the URL including the PT
01898                         if ( strstr($url,'?') === FALSE ) {
01899                                 $service_url = $url.'?ticket='.$pt;
01900                         } else {
01901                                 $service_url = $url.'&ticket='.$pt;
01902                         }
01903                         
01904                         phpCAS::trace('reading URL`'.$service_url.'\'');
01905                         if ( !$this->readURL($service_url,$cookies,$headers,$output,$err_msg) ) {
01906                                 phpCAS::trace('could not read URL`'.$service_url.'\'');
01907                                 $err_code = PHPCAS_SERVICE_NOT_AVAILABLE;
01908                                 // give an error message
01909                                 $output = sprintf($this->getString(CAS_STR_SERVICE_UNAVAILABLE),
01910                                         $service_url,
01911                                         $err_msg);
01912                                 $res = FALSE;
01913                         } else {
01914                                 // URL has been fetched, extract the cookies
01915                                 phpCAS::trace('URL`'.$service_url.'\' has been read, storing cookies:');
01916                                 foreach ( $headers as $header ) {
01917                                         // test if the header is a cookie
01918                                         if ( preg_match('/^Set-Cookie:/',$header) ) {
01919                                                 // the header is a cookie, remove the beginning
01920                                                 $header_val = preg_replace('/^Set-Cookie: */','',$header);
01921                                                 // extract interesting information
01922                                                 $name_val = strtok($header_val,'; ');
01923                                                 // extract the name and the value of the cookie
01924                                                 $cookie_name = strtok($name_val,'=');
01925                                                 $cookie_val = strtok('=');
01926                                                 // store the cookie 
01927                                                 $_SESSION['phpCAS']['services'][$url]['cookies'][$cookie_name] = $cookie_val;
01928                                                 phpCAS::trace($cookie_name.' -> '.$cookie_val);
01929                                         }
01930                                 }
01931                         }
01932                 }
01933                 
01934                 phpCAS::traceEnd($res);
01935                 return $res;
01936                 }
01937         
01956         function serviceMail($url,$flags,&$err_code,&$err_msg,&$pt)
01957                 {
01958                 phpCAS::traceBegin();
01959                 // at first retrieve a PT
01960                 $pt = $this->retrievePT($target_service,$err_code,$output);
01961                 
01962                 $stream = FALSE;
01963                 
01964                 // test if PT was retrieved correctly
01965                 if ( !$pt ) {
01966                         // note: $err_code and $err_msg are filled by CASClient::retrievePT()
01967                         phpCAS::trace('PT was not retrieved correctly');
01968                 } else {
01969                         phpCAS::trace('opening IMAP URL `'.$url.'\'...');
01970                         $stream = @imap_open($url,$this->getUser(),$pt,$flags);
01971                         if ( !$stream ) {
01972                                 phpCAS::trace('could not open URL');
01973                                 $err_code = PHPCAS_SERVICE_NOT_AVAILABLE;
01974                                 // give an error message
01975                                 $err_msg = sprintf($this->getString(CAS_STR_SERVICE_UNAVAILABLE),
01976                                         $service_url,
01977                                         var_export(imap_errors(),TRUE));
01978                                 $pt = FALSE;
01979                                 $stream = FALSE;
01980                         } else {
01981                                 phpCAS::trace('ok');
01982                         }
01983                 }
01984                 
01985                 phpCAS::traceEnd($stream);
01986                 return $stream;
01987                 }
01988         
01991         // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
01992         // XX                                                                    XX
01993         // XX                  PROXIED CLIENT FEATURES (CAS 2.0)                 XX
01994         // XX                                                                    XX
01995         // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
01996         
01997         // ########################################################################
01998         //  PT
01999         // ########################################################################
02013         var $_pt = '';
02014         
02020         function getPT()
02021                 {
02022                 //      return 'ST'.substr($this->_pt, 2);
02023                 return $this->_pt;
02024                 }
02025         
02031         function setPT($pt)
02032                 { $this->_pt = $pt; }
02033         
02039         function hasPT()
02040                 { return !empty($this->_pt); }
02041         
02043         // ########################################################################
02044         //  PT VALIDATION
02045         // ########################################################################
02058         function validatePT(&$validate_url,&$text_response,&$tree_response)
02059                 {
02060                 phpCAS::traceBegin();
02061                 // build the URL to validate the ticket
02062                 $validate_url = $this->getServerProxyValidateURL().'&ticket='.$this->getPT();
02063                 
02064                 if ( $this->isProxy() ) {
02065                         // pass the callback url for CAS proxies
02066                         $validate_url .= '&pgtUrl='.$this->getCallbackURL();
02067                 }
02068                 
02069                 // open and read the URL
02070                 if ( !$this->readURL($validate_url,''/*cookies*/,$headers,$text_response,$err_msg) ) {
02071                         phpCAS::trace('could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')');
02072                         $this->authError('PT not validated',
02073                                 $validate_url,
02074                                 TRUE/*$no_response*/);
02075                 }
02076                 
02077                 // read the response of the CAS server into a DOM object
02078                 if ( !($dom = domxml_open_mem($text_response))) {
02079                         // read failed
02080                         $this->authError('PT not validated',
02081                                 $validate_url,
02082                                 FALSE/*$no_response*/,
02083                                 TRUE/*$bad_response*/,
02084                                 $text_response);
02085                 }
02086                 // read the root node of the XML tree
02087                 if ( !($tree_response = $dom->document_element()) ) {
02088                         // read failed
02089                         $this->authError('PT not validated',
02090                                 $validate_url,
02091                                 FALSE/*$no_response*/,
02092                                 TRUE/*$bad_response*/,
02093                                 $text_response);
02094                 }
02095                 // insure that tag name is 'serviceResponse'
02096                 if ( $tree_response->node_name() != 'serviceResponse' ) {
02097                         // bad root node
02098                         $this->authError('PT not validated',
02099                                 $validate_url,
02100                                 FALSE/*$no_response*/,
02101                                 TRUE/*$bad_response*/,
02102                                 $text_response);
02103                 }
02104                 if ( sizeof($arr = $tree_response->get_elements_by_tagname("authenticationSuccess")) != 0) {
02105                         // authentication succeded, extract the user name
02106                         if ( sizeof($arr = $tree_response->get_elements_by_tagname("user")) == 0) {
02107                                 // no user specified => error
02108                                 $this->authError('PT not validated',
02109                                         $validate_url,
02110                                         FALSE/*$no_response*/,
02111                                         TRUE/*$bad_response*/,
02112                                         $text_response);
02113                         }
02114                         $this->setUser(trim($arr[0]->get_content()));
02115                         
02116                 } else if ( sizeof($arr = $tree_response->get_elements_by_tagname("authenticationFailure")) != 0) {
02117                         // authentication succeded, extract the error code and message
02118                         $this->authError('PT not validated',
02119                                 $validate_url,
02120                                 FALSE/*$no_response*/,
02121                                 FALSE/*$bad_response*/,
02122                                 $text_response,
02123                                 $arr[0]->get_attribute('code')/*$err_code*/,
02124                                 trim($arr[0]->get_content())/*$err_msg*/);
02125                 } else {
02126                         $this->authError('PT not validated',
02127                                 $validate_url,  
02128                                 FALSE/*$no_response*/,
02129                                 TRUE/*$bad_response*/,
02130                                 $text_response);
02131                 }
02132                 
02133                 // at this step, PT has been validated and $this->_user has been set,
02134                 
02135                 phpCAS::traceEnd(TRUE);
02136                 return TRUE;
02137                 }
02138         
02141         // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
02142         // XX                                                                    XX
02143         // XX                               MISC                                 XX
02144         // XX                                                                    XX
02145         // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
02146         
02152         // ########################################################################
02153         //  URL
02154         // ########################################################################
02162         var $_url = '';
02163         
02172         function getURL()
02173                 {
02174                 phpCAS::traceBegin();
02175                 // the URL is built when needed only
02176                 if ( empty($this->_url) ) {
02177                         $final_uri = '';
02178                         // remove the ticket if present in the URL
02179                         $final_uri = ($this->isHttps()) ? 'https' : 'http';
02180                         $final_uri .= '://';
02181                         /* replaced by Julien Marchal - v0.4.6
02182                          * $this->_url .= $_SERVER['SERVER_NAME'];
02183                          */
02184                         if(empty($_SERVER['HTTP_X_FORWARDED_SERVER'])){
02185                                 /* replaced by teedog - v0.4.12
02186                                  * $this->_url .= $_SERVER['SERVER_NAME'];
02187                                  */
02188                                 if (empty($_SERVER['SERVER_NAME'])) {
02189                                         $server_name = $_SERVER['HTTP_HOST'];
02190                                 } else {
02191                                         $server_name = $_SERVER['SERVER_NAME'];
02192                                 }
02193                         } else {
02194                                 $server_name = $_SERVER['HTTP_X_FORWARDED_SERVER'];
02195                         }
02196                         $final_uri .= $server_name;
02197                         if (!strpos($server_name, ':')) {
02198                                 if ( ($this->isHttps() && $_SERVER['SERVER_PORT']!=443)
02199                                                 || (!$this->isHttps() && $_SERVER['SERVER_PORT']!=80) ) {
02200                                         $final_uri .= ':';
02201                                         $final_uri .= $_SERVER['SERVER_PORT'];
02202                                 }
02203                         }
02204                         
02205                         $final_uri .= strtok($_SERVER['REQUEST_URI'],"?");
02206                         $cgi_params = '?'.strtok("?");
02207                         // remove the ticket if present in the CGI parameters
02208                         $cgi_params = preg_replace('/&ticket=[^&]*/','',$cgi_params);
02209                         $cgi_params = preg_replace('/\?ticket=[^&;]*/','?',$cgi_params);
02210                         $cgi_params = preg_replace('/\?%26/','?',$cgi_params);
02211                         $cgi_params = preg_replace('/\?&/','?',$cgi_params);
02212                         $cgi_params = preg_replace('/\?$/','',$cgi_params);
02213                         $final_uri .= $cgi_params;
02214                         $this->setURL($final_uri);
02215                 }
02216                 phpCAS::traceEnd($this->_url);
02217                 return $this->_url;
02218                 }
02219         
02227         function setURL($url)
02228                 {
02229                 $this->_url = $url;
02230                 }
02231         
02232         // ########################################################################
02233         //  AUTHENTICATION ERROR HANDLING
02234         // ########################################################################
02250         function authError($failure,$cas_url,$no_response,$bad_response='',$cas_response='',$err_code='',$err_msg='')
02251                 {
02252                 phpCAS::traceBegin();
02253                 
02254                 $this->printHTMLHeader($this->getString(CAS_STR_AUTHENTICATION_FAILED));
02255                 printf($this->getString(CAS_STR_YOU_WERE_NOT_AUTHENTICATED),$this->getURL(),$_SERVER['SERVER_ADMIN']);
02256                 phpCAS::trace('CAS URL: '.$cas_url);
02257                 phpCAS::trace('Authentication failure: '.$failure);
02258                 if ( $no_response ) {
02259                         phpCAS::trace('Reason: no response from the CAS server');
02260                 } else {
02261                         if ( $bad_response ) {
02262                                 phpCAS::trace('Reason: bad response from the CAS server');
02263                         } else {
02264                                 switch ($this->getServerVersion()) {
02265                                         case CAS_VERSION_1_0:
02266                                                 phpCAS::trace('Reason: CAS error');
02267                                                 break;
02268                                         case CAS_VERSION_2_0:
02269                                                 if ( empty($err_code) )
02270                                                         phpCAS::trace('Reason: no CAS error');
02271                                                 else
02272                                                         phpCAS::trace('Reason: ['.$err_code.'] CAS error: '.$err_msg);
02273                                                 break;
02274                                 }
02275                         }
02276                         phpCAS::trace('CAS response: '.$cas_response);
02277                 }
02278                 $this->printHTMLFooter();
02279                 phpCAS::traceExit();
02280                 exit();
02281                 }
02282         
02284 }
02285 
02286 ?>

Generated on Tue Jul 1 18:10:05 2008 for phpCAS by doxygen 1.3.6