• Main Page
  • Related Pages
  • Modules
  • Classes
  • Files
  • Examples
  • File List
  • File Members

CAS/client.php

Go to the documentation of this file.
00001 <?php
00002 
00003 /*
00004  * Copyright © 2003-2010, The ESUP-Portail consortium & the JA-SIG Collaborative.
00005  * All rights reserved.
00006  * 
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted provided that the following conditions are met:
00009  * 
00010  *     * Redistributions of source code must retain the above copyright notice,
00011  *       this list of conditions and the following disclaimer.
00012  *     * Redistributions in binary form must reproduce the above copyright notice,
00013  *       this list of conditions and the following disclaimer in the documentation
00014  *       and/or other materials provided with the distribution.
00015  *     * Neither the name of the ESUP-Portail consortium & the JA-SIG
00016  *       Collaborative nor the names of its contributors may be used to endorse or
00017  *       promote products derived from this software without specific prior
00018  *       written permission.
00019 
00020  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00021  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00022  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00023  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
00024  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00025  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00026  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
00027  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00028  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00029  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00030  */
00031 
00037 // include internationalization stuff
00038 include_once(dirname(__FILE__).'/languages/languages.php');
00039 
00040 // include PGT storage classes
00041 include_once(dirname(__FILE__).'/PGTStorage/pgt-main.php');
00042 
00051 class CASClient
00052 {
00053         
00054         // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
00055         // XX                                                                    XX
00056         // XX                          CONFIGURATION                             XX
00057         // XX                                                                    XX
00058         // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
00059         
00060         // ########################################################################
00061         //  HTML OUTPUT
00062         // ########################################################################
00081         function HTMLFilterOutput($str)
00082                 {
00083                 $str = str_replace('__CAS_VERSION__',$this->getServerVersion(),$str);
00084                 $str = str_replace('__PHPCAS_VERSION__',phpCAS::getVersion(),$str);
00085                 $str = str_replace('__SERVER_BASE_URL__',$this->getServerBaseURL(),$str);
00086                 echo $str;
00087                 }
00088         
00097         var $_output_header = '';
00098         
00108         function printHTMLHeader($title)
00109                 {
00110                 $this->HTMLFilterOutput(str_replace('__TITLE__',
00111                         $title,
00112                         (empty($this->_output_header)
00113                                         ? '<html><head><title>__TITLE__</title></head><body><h1>__TITLE__</h1>'
00114                                                         : $this->_output_header)
00115                 )
00116                 );
00117                 }
00118         
00127         var $_output_footer = '';
00128         
00136         function printHTMLFooter()
00137                 {
00138                 $this->HTMLFilterOutput(empty($this->_output_footer)
00139                         ?('<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>')
00140                                         :$this->_output_footer);
00141                 }
00142         
00150         function setHTMLHeader($header)
00151                 {
00152                 $this->_output_header = $header;
00153                 }
00154         
00162         function setHTMLFooter($footer)
00163                 {
00164                 $this->_output_footer = $footer;
00165                 }
00166         
00168         // ########################################################################
00169         //  INTERNATIONALIZATION
00170         // ########################################################################
00185         var $_lang = '';
00186         
00194         function getLang()
00195                 {
00196                 if ( empty($this->_lang) )
00197                         $this->setLang(PHPCAS_LANG_DEFAULT);
00198                 return $this->_lang;
00199                 }
00200         
00210         var $_strings;
00211         
00221         function getString($str)
00222                 {
00223                 // call CASclient::getLang() to be sure the language is initialized
00224                 $this->getLang();
00225                 
00226                 if ( !isset($this->_strings[$str]) ) {
00227                         trigger_error('string `'.$str.'\' not defined for language `'.$this->getLang().'\'',E_USER_ERROR);
00228                 }
00229                 return $this->_strings[$str];
00230                 }
00231         
00241         function setLang($lang)
00242                 {
00243                 // include the corresponding language file
00244                 include_once(dirname(__FILE__).'/languages/'.$lang.'.php');
00245                 
00246                 if ( !is_array($this->_strings) ) {
00247                         trigger_error('language `'.$lang.'\' is not implemented',E_USER_ERROR);
00248                 }
00249                 $this->_lang = $lang;
00250                 }
00251         
00253         // ########################################################################
00254         //  CAS SERVER CONFIG
00255         // ########################################################################
00285         var $_server = array(
00286                 'version' => -1,
00287                 'hostname' => 'none',
00288                 'port' => -1,
00289                 'uri' => 'none'
00290         );
00291         
00297         function getServerVersion()
00298                 { 
00299                 return $this->_server['version']; 
00300                 }
00301         
00307         function getServerHostname()
00308                 { return $this->_server['hostname']; }
00309         
00315         function getServerPort()
00316                 { return $this->_server['port']; }
00317         
00323         function getServerURI()
00324                 { return $this->_server['uri']; }
00325         
00331         function getServerBaseURL()
00332                 { 
00333                         // the URL is build only when needed
00334                         if ( empty($this->_server['base_url']) ) {
00335                                 $this->_server['base_url'] = 'https://' . $this->getServerHostname();
00336                                 if ($this->getServerPort()!=443) {
00337                                         $this->_server['base_url'] .= ':'
00338                                         .$this->getServerPort();
00339                                 }
00340                                 $this->_server['base_url'] .= $this->getServerURI();
00341                         }
00342                         return $this->_server['base_url'];
00343                 }
00344         
00354         function getServerLoginURL($gateway=false,$renew=false) {
00355                 phpCAS::traceBegin();
00356                 // the URL is build only when needed
00357                 if ( empty($this->_server['login_url']) ) {
00358                         $this->_server['login_url'] = $this->getServerBaseURL();
00359                         $this->_server['login_url'] .= 'login?service=';
00360                         // $this->_server['login_url'] .= preg_replace('/&/','%26',$this->getURL());
00361                         $this->_server['login_url'] .= urlencode($this->getURL());
00362                         if($renew) {
00363                                 // It is recommended that when the "renew" parameter is set, its value be "true"
00364                                 $this->_server['login_url'] .= '&renew=true';
00365                         } elseif ($gateway) {
00366                                 // It is recommended that when the "gateway" parameter is set, its value be "true"
00367                                 $this->_server['login_url'] .= '&gateway=true';
00368                         }
00369                 }
00370                 phpCAS::traceEnd($this->_server['login_url']);
00371                 return $this->_server['login_url'];
00372         } 
00373         
00380         function setServerLoginURL($url)
00381                 {
00382                 return $this->_server['login_url'] = $url;
00383                 }
00384         
00385         
00392         function setServerServiceValidateURL($url)
00393                 {
00394                 return $this->_server['service_validate_url'] = $url;
00395                 }
00396         
00397         
00404         function setServerProxyValidateURL($url)
00405                 {
00406                 return $this->_server['proxy_validate_url'] = $url;
00407                 }
00408         
00409         
00416         function setServerSamlValidateURL($url)
00417                 {
00418                 return $this->_server['saml_validate_url'] = $url;
00419                 }
00420         
00421         
00427         function getServerServiceValidateURL()
00428                 { 
00429                 // the URL is build only when needed
00430                 if ( empty($this->_server['service_validate_url']) ) {
00431                         switch ($this->getServerVersion()) {
00432                                 case CAS_VERSION_1_0:
00433                                         $this->_server['service_validate_url'] = $this->getServerBaseURL().'validate';
00434                                         break;
00435                                 case CAS_VERSION_2_0:
00436                                         $this->_server['service_validate_url'] = $this->getServerBaseURL().'serviceValidate';
00437                                         break;
00438                         }
00439                 }
00440                 //      return $this->_server['service_validate_url'].'?service='.preg_replace('/&/','%26',$this->getURL()); 
00441                 return $this->_server['service_validate_url'].'?service='.urlencode($this->getURL()); 
00442                 }
00448         function getServerSamlValidateURL()
00449                 {
00450                 phpCAS::traceBegin();
00451                 // the URL is build only when needed
00452                 if ( empty($this->_server['saml_validate_url']) ) {
00453                         switch ($this->getServerVersion()) {
00454                                 case SAML_VERSION_1_1:
00455                                         $this->_server['saml_validate_url'] = $this->getServerBaseURL().'samlValidate';
00456                                         break;
00457                         }
00458                 }
00459                 phpCAS::traceEnd($this->_server['saml_validate_url'].'?TARGET='.urlencode($this->getURL()));
00460                 return $this->_server['saml_validate_url'].'?TARGET='.urlencode($this->getURL());
00461                 }
00467         function getServerProxyValidateURL()
00468                 { 
00469                 // the URL is build only when needed
00470                 if ( empty($this->_server['proxy_validate_url']) ) {
00471                         switch ($this->getServerVersion()) {
00472                                 case CAS_VERSION_1_0:
00473                                         $this->_server['proxy_validate_url'] = '';
00474                                         break;
00475                                 case CAS_VERSION_2_0:
00476                                         $this->_server['proxy_validate_url'] = $this->getServerBaseURL().'proxyValidate';
00477                                         break;
00478                         }
00479                 }
00480                 //      return $this->_server['proxy_validate_url'].'?service='.preg_replace('/&/','%26',$this->getURL()); 
00481                 return $this->_server['proxy_validate_url'].'?service='.urlencode($this->getURL()); 
00482                 }
00483         
00489         function getServerProxyURL()
00490                 { 
00491                 // the URL is build only when needed
00492                 if ( empty($this->_server['proxy_url']) ) {
00493                         switch ($this->getServerVersion()) {
00494                                 case CAS_VERSION_1_0:
00495                                         $this->_server['proxy_url'] = '';
00496                                         break;
00497                                 case CAS_VERSION_2_0:
00498                                         $this->_server['proxy_url'] = $this->getServerBaseURL().'proxy';
00499                                         break;
00500                         }
00501                 }
00502                 return $this->_server['proxy_url']; 
00503                 }
00504         
00510         function getServerLogoutURL()
00511                 { 
00512                 // the URL is build only when needed
00513                 if ( empty($this->_server['logout_url']) ) {
00514                         $this->_server['logout_url'] = $this->getServerBaseURL().'logout';
00515                 }
00516                 return $this->_server['logout_url']; 
00517                 }
00518         
00525         function setServerLogoutURL($url)
00526                 {
00527                 return $this->_server['logout_url'] = $url;
00528                 }
00529         
00533         var $_curl_options = array();
00534         
00538         function setExtraCurlOption($key, $value)
00539                 {
00540                 $this->_curl_options[$key] = $value;
00541                 }
00542         
00548         function isHttps() {
00549                 //if ( isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS']) ) {
00550                 //0.4.24 by Hinnack
00551                 if ( isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
00552                         return true;
00553                 } else {
00554                         return false;
00555                 }
00556         }
00557         
00558         // ########################################################################
00559         //  CONSTRUCTOR
00560         // ########################################################################
00575         function CASClient(
00576                                            $server_version,
00577                                            $proxy,
00578                                            $server_hostname,
00579                                            $server_port,
00580                                            $server_uri,
00581                                            $start_session = true) {
00582                 
00583                 phpCAS::traceBegin();
00584                 
00585                 // the redirect header() call and DOM parsing code from domxml-php4-php5.php won't work in PHP4 compatibility mode
00586                 if (version_compare(PHP_VERSION,'5','>=') && ini_get('zend.ze1_compatibility_mode')) {
00587                         phpCAS::error('phpCAS cannot support zend.ze1_compatibility_mode. Sorry.');
00588                 }
00589                 $this->_start_session = $start_session;
00590 
00591                 if ($this->_start_session && session_id() !== "")
00592                 {
00593                         phpCAS :: error("Another session was started before phpcas. Either disable the session" .
00594                                 " handling for phpcas in the client() call or modify your application to leave" .
00595                                 " session handling to phpcas");                 
00596                 }
00597                 // skip Session Handling for logout requests and if don't want it'
00598                 if ($start_session && !$this->isLogoutRequest())
00599                 {
00600                         phpCAS :: trace("Starting a new session");
00601                         session_start();
00602                 }
00603                 
00604                 
00605                 // are we in proxy mode ?
00606                 $this->_proxy = $proxy;
00607                 
00608                 //check version
00609                 switch ($server_version) {
00610                         case CAS_VERSION_1_0:
00611                                 if ( $this->isProxy() )
00612                                         phpCAS::error('CAS proxies are not supported in CAS '
00613                                                 .$server_version);
00614                                 break;
00615                         case CAS_VERSION_2_0:
00616                                 break;
00617                         case SAML_VERSION_1_1:
00618                                 break;
00619                         default:
00620                                 phpCAS::error('this version of CAS (`'
00621                                         .$server_version
00622                                         .'\') is not supported by phpCAS '
00623                                         .phpCAS::getVersion());
00624                 }
00625                 $this->_server['version'] = $server_version;
00626                 
00627                 // check hostname
00628                 if ( empty($server_hostname) 
00629                                 || !preg_match('/[\.\d\-abcdefghijklmnopqrstuvwxyz]*/',$server_hostname) ) {
00630                         phpCAS::error('bad CAS server hostname (`'.$server_hostname.'\')');
00631                 }
00632                 $this->_server['hostname'] = $server_hostname;
00633                 
00634                 // check port
00635                 if ( $server_port == 0 
00636                         || !is_int($server_port) ) {
00637                         phpCAS::error('bad CAS server port (`'.$server_hostname.'\')');
00638                 }
00639                 $this->_server['port'] = $server_port;
00640                 
00641                 // check URI
00642                 if ( !preg_match('/[\.\d\-_abcdefghijklmnopqrstuvwxyz\/]*/',$server_uri) ) {
00643                         phpCAS::error('bad CAS server URI (`'.$server_uri.'\')');
00644                 }
00645                 // add leading and trailing `/' and remove doubles      
00646                 $server_uri = preg_replace('/\/\//','/','/'.$server_uri.'/');
00647                 $this->_server['uri'] = $server_uri;
00648                 
00649                 // set to callback mode if PgtIou and PgtId CGI GET parameters are provided 
00650                 if ( $this->isProxy() ) {
00651                         $this->setCallbackMode(!empty($_GET['pgtIou'])&&!empty($_GET['pgtId']));
00652                 }
00653                 
00654                 if ( $this->isCallbackMode() ) {
00655                         //callback mode: check that phpCAS is secured
00656                         if ( !$this->isHttps() ) {
00657                                 phpCAS::error('CAS proxies must be secured to use phpCAS; PGT\'s will not be received from the CAS server');
00658                         }
00659                 } else {
00660                         //normal mode: get ticket and remove it from CGI parameters for developpers
00661                         $ticket = (isset($_GET['ticket']) ? $_GET['ticket'] : null);
00662                         switch ($this->getServerVersion()) {
00663                                 case CAS_VERSION_1_0: // check for a Service Ticket
00664                                         if( preg_match('/^ST-/',$ticket) ) {
00665                                                 phpCAS::trace('ST \''.$ticket.'\' found');
00666                                                 //ST present
00667                                                 $this->setST($ticket);
00668                                                 //ticket has been taken into account, unset it to hide it to applications
00669                                                 unset($_GET['ticket']);
00670                                         } else if ( !empty($ticket) ) {
00671                                                 //ill-formed ticket, halt
00672                                                 phpCAS::error('ill-formed ticket found in the URL (ticket=`'.htmlentities($ticket).'\')');
00673                                         }
00674                                         break;
00675                                 case CAS_VERSION_2_0: // check for a Service or Proxy Ticket
00676                                         if( preg_match('/^[SP]T-/',$ticket) ) {
00677                                                 phpCAS::trace('ST or PT \''.$ticket.'\' found');
00678                                                 $this->setPT($ticket);
00679                                                 unset($_GET['ticket']);
00680                                         } else if ( !empty($ticket) ) {
00681                                                 //ill-formed ticket, halt
00682                                                 phpCAS::error('ill-formed ticket found in the URL (ticket=`'.htmlentities($ticket).'\')');
00683                                         } 
00684                                         break;
00685                                 case SAML_VERSION_1_1: // SAML just does Service Tickets
00686                                         if( preg_match('/^[SP]T-/',$ticket) ) {
00687                                                 phpCAS::trace('SA \''.$ticket.'\' found');
00688                                                 $this->setSA($ticket);
00689                                                 unset($_GET['ticket']);
00690                                         } else if ( !empty($ticket) ) {
00691                                                 //ill-formed ticket, halt
00692                                                 phpCAS::error('ill-formed ticket found in the URL (ticket=`'.htmlentities($ticket).'\')');
00693                                         }
00694                                         break;
00695                         }
00696                 }
00697                 phpCAS::traceEnd();
00698         }
00699         
00702         // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
00703         // XX                                                                    XX
00704         // XX                           Session Handling                         XX
00705         // XX                                                                    XX
00706         // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
00707 
00713         var $_start_session = true;
00714 
00715         function setStartSession($session)
00716         {
00717                 $this->_start_session = session;
00718         }
00719 
00720         function getStartSession($session)
00721         {
00722                 $this->_start_session = session;
00723         }
00724 
00728         function renameSession($ticket)
00729         {
00730                 phpCAS::traceBegin();
00731                 if($this->_start_session){
00732                         if (!empty ($this->_user))
00733                         {
00734                                 $old_session = $_SESSION;
00735                                 session_destroy();
00736                                 // set up a new session, of name based on the ticket
00737                                 $session_id = preg_replace('/[^\w]/', '', $ticket);
00738                                 phpCAS :: trace("Session ID: ".$session_id);
00739                                 session_id($session_id);
00740                                 session_start();
00741                                 phpCAS :: trace("Restoring old session vars");
00742                                 $_SESSION = $old_session;
00743                         } else
00744                         {
00745                                 phpCAS :: error('Session should only be renamed after successfull authentication');
00746                         }
00747                 }else{
00748                         phpCAS :: trace("Skipping session rename since phpCAS is not handling the session.");                   
00749                 }
00750                 phpCAS::traceEnd();             
00751         }       
00752         
00753         // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
00754         // XX                                                                    XX
00755         // XX                           AUTHENTICATION                           XX
00756         // XX                                                                    XX
00757         // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
00758         
00771         var $_user = '';
00772         
00780         function setUser($user)
00781                 {
00782                 $this->_user = $user;
00783                 }
00784         
00792         function getUser()
00793                 {
00794                 if ( empty($this->_user) ) {
00795                         phpCAS::error('this method should be used only after '.__CLASS__.'::forceAuthentication() or '.__CLASS__.'::isAuthenticated()');
00796                 }
00797                 return $this->_user;
00798                 }
00799         
00800         
00801         
00802         /***********************************************************************************************************************
00803          * Atrributes section
00804          * 
00805          * @author Matthias Crauwels <matthias.crauwels@ugent.be>, Ghent University, Belgium
00806          * 
00807          ***********************************************************************************************************************/
00815         var $_attributes = array();
00816         
00817         function setAttributes($attributes)     
00818                 { $this->_attributes = $attributes; }
00819         
00820         function getAttributes() {
00821                 if ( empty($this->_user) ) { // if no user is set, there shouldn't be any attributes also...
00822                         phpCAS::error('this method should be used only after '.__CLASS__.'::forceAuthentication() or '.__CLASS__.'::isAuthenticated()');
00823                 }
00824                 return $this->_attributes;
00825         }
00826         
00827         function hasAttributes()
00828                 { return !empty($this->_attributes); }
00829         
00830         function hasAttribute($key)
00831                 { return (is_array($this->_attributes) && array_key_exists($key, $this->_attributes)); }
00832         
00833         function getAttribute($key)     {
00834                 if($this->hasAttribute($key)) {
00835                         return $this->_attributes[$key];
00836                 }
00837         }
00838         
00845         function renewAuthentication(){
00846                 phpCAS::traceBegin();
00847                 // Either way, the user is authenticated by CAS
00848                 if( isset( $_SESSION['phpCAS']['auth_checked'] ) )
00849                         unset($_SESSION['phpCAS']['auth_checked']);
00850                 if ( $this->isAuthenticated() ) {
00851                         phpCAS::trace('user already authenticated; renew');
00852                         $this->redirectToCas(false,true);
00853                 } else {
00854                         $this->redirectToCas();
00855                 }
00856                 phpCAS::traceEnd();
00857         }
00858         
00865         function forceAuthentication()
00866                 {
00867                 phpCAS::traceBegin();
00868                 
00869                 if ( $this->isAuthenticated() ) {
00870                         // the user is authenticated, nothing to be done.
00871                         phpCAS::trace('no need to authenticate');
00872                         $res = TRUE;
00873                 } else {
00874                         // the user is not authenticated, redirect to the CAS server
00875                         if (isset($_SESSION['phpCAS']['auth_checked'])) {
00876                                 unset($_SESSION['phpCAS']['auth_checked']);
00877                         }
00878                         $this->redirectToCas(FALSE/* no gateway */);    
00879                         // never reached
00880                         $res = FALSE;
00881                 }
00882                 phpCAS::traceEnd($res);
00883                 return $res;
00884                 }
00885         
00892         var $_cache_times_for_auth_recheck = 0;
00893         
00901         function setCacheTimesForAuthRecheck($n)
00902                 {
00903                 $this->_cache_times_for_auth_recheck = $n;
00904                 }
00905         
00911         function checkAuthentication()
00912                 {
00913                 phpCAS::traceBegin();
00914                 
00915                 if ( $this->isAuthenticated() ) {
00916                         phpCAS::trace('user is authenticated');
00917                         $res = TRUE;
00918                 } else if (isset($_SESSION['phpCAS']['auth_checked'])) {
00919                         // the previous request has redirected the client to the CAS server with gateway=true
00920                         unset($_SESSION['phpCAS']['auth_checked']);
00921                         $res = FALSE;
00922                 } else {
00923                         //        $_SESSION['phpCAS']['auth_checked'] = true;
00924                         //          $this->redirectToCas(TRUE/* gateway */);    
00925                         //          // never reached
00926                         //          $res = FALSE;
00927                         // avoid a check against CAS on every request
00928                         if (! isset($_SESSION['phpCAS']['unauth_count']) )
00929                                 $_SESSION['phpCAS']['unauth_count'] = -2; // uninitialized
00930                         
00931                         if (($_SESSION['phpCAS']['unauth_count'] != -2 && $this->_cache_times_for_auth_recheck == -1) 
00932                                         || ($_SESSION['phpCAS']['unauth_count'] >= 0 && $_SESSION['phpCAS']['unauth_count'] < $this->_cache_times_for_auth_recheck))
00933                         {
00934                                 $res = FALSE;
00935                                 
00936                                 if ($this->_cache_times_for_auth_recheck != -1)
00937                                 {
00938                                         $_SESSION['phpCAS']['unauth_count']++;
00939                                         phpCAS::trace('user is not authenticated (cached for '.$_SESSION['phpCAS']['unauth_count'].' times of '.$this->_cache_times_for_auth_recheck.')');
00940                                 }
00941                                 else
00942                                 {
00943                                         phpCAS::trace('user is not authenticated (cached for until login pressed)');
00944                                 }
00945                         }
00946                         else
00947                         {
00948                                 $_SESSION['phpCAS']['unauth_count'] = 0;
00949                                 $_SESSION['phpCAS']['auth_checked'] = true;
00950                                 phpCAS::trace('user is not authenticated (cache reset)');
00951                                 $this->redirectToCas(TRUE/* gateway */);        
00952                                 // never reached
00953                                 $res = FALSE;
00954                         }
00955                 }
00956                 phpCAS::traceEnd($res);
00957                 return $res;
00958                 }
00959         
00968         function isAuthenticated()
00969                 {
00970                 phpCAS::traceBegin();
00971                 $res = FALSE;
00972                 $validate_url = '';
00973                 
00974                 if ( $this->wasPreviouslyAuthenticated() ) {
00975                         if($this->hasST() || $this->hasPT() || $this->hasSA()){
00976                                 // User has a additional ticket but was already authenticated
00977                                 phpCAS::trace('ticket was present and will be discarded, use renewAuthenticate()');
00978                                 header('Location: '.$this->getURL());
00979                                 phpCAS::log( "Prepare redirect to remove ticket: ".$this->getURL() );
00980                                 phpCAS::traceExit();
00981                                 exit();
00982                         }else{
00983                                 // the user has already (previously during the session) been
00984                                 // authenticated, nothing to be done.
00985                                 phpCAS::trace('user was already authenticated, no need to look for tickets');
00986                                 $res = TRUE;
00987                         }
00988                 }
00989                 else {
00990                         if ( $this->hasST() ) {
00991                                 // if a Service Ticket was given, validate it
00992                                 phpCAS::trace('ST `'.$this->getST().'\' is present');
00993                                 $this->validateST($validate_url,$text_response,$tree_response); // if it fails, it halts
00994                                 phpCAS::trace('ST `'.$this->getST().'\' was validated');
00995                                 if ( $this->isProxy() ) {
00996                                         $this->validatePGT($validate_url,$text_response,$tree_response); // idem
00997                                         phpCAS::trace('PGT `'.$this->getPGT().'\' was validated');
00998                                         $_SESSION['phpCAS']['pgt'] = $this->getPGT();
00999                                 }
01000                                 $_SESSION['phpCAS']['user'] = $this->getUser();
01001                                 $res = TRUE;
01002                         }
01003                         elseif ( $this->hasPT() ) {
01004                                 // if a Proxy Ticket was given, validate it
01005                                 phpCAS::trace('PT `'.$this->getPT().'\' is present');
01006                                 $this->validatePT($validate_url,$text_response,$tree_response); // note: if it fails, it halts
01007                                 phpCAS::trace('PT `'.$this->getPT().'\' was validated');
01008                                 if ( $this->isProxy() ) {
01009                                         $this->validatePGT($validate_url,$text_response,$tree_response); // idem
01010                                         phpCAS::trace('PGT `'.$this->getPGT().'\' was validated');
01011                                         $_SESSION['phpCAS']['pgt'] = $this->getPGT();
01012                                 }
01013                                 $_SESSION['phpCAS']['user'] = $this->getUser();
01014                                 $res = TRUE;
01015                         }
01016                         elseif ( $this->hasSA() ) {
01017                                 // if we have a SAML ticket, validate it.
01018                                 phpCAS::trace('SA `'.$this->getSA().'\' is present');
01019                                 $this->validateSA($validate_url,$text_response,$tree_response); // if it fails, it halts
01020                                 phpCAS::trace('SA `'.$this->getSA().'\' was validated');
01021                                 $_SESSION['phpCAS']['user'] = $this->getUser();
01022                                 $_SESSION['phpCAS']['attributes'] = $this->getAttributes();
01023                                 $res = TRUE;
01024                         }
01025                         else {
01026                                 // no ticket given, not authenticated
01027                                 phpCAS::trace('no ticket found');
01028                         }
01029                         if ($res) {
01030                                 // if called with a ticket parameter, we need to redirect to the app without the ticket so that CAS-ification is transparent to the browser (for later POSTS)
01031                                 // most of the checks and errors should have been made now, so we're safe for redirect without masking error messages.
01032                                 // remove the ticket as a security precaution to prevent a ticket in the HTTP_REFERRER
01033                                 header('Location: '.$this->getURL());
01034                                 phpCAS::log( "Prepare redirect to : ".$this->getURL() );
01035                                 phpCAS::traceExit();
01036                                 exit();
01037                         }
01038                 }
01039                 
01040                 phpCAS::traceEnd($res);
01041                 return $res;
01042                 }
01043         
01049         function isSessionAuthenticated ()
01050                 {
01051                 return !empty($_SESSION['phpCAS']['user']);
01052                 }
01053         
01064         function wasPreviouslyAuthenticated()
01065                 {
01066                 phpCAS::traceBegin();
01067                 
01068                 if ( $this->isCallbackMode() ) {
01069                         $this->callback();
01070                 }
01071                 
01072                 $auth = FALSE;
01073                 
01074                 if ( $this->isProxy() ) {
01075                         // CAS proxy: username and PGT must be present
01076                         if ( $this->isSessionAuthenticated() && !empty($_SESSION['phpCAS']['pgt']) ) {
01077                                 // authentication already done
01078                                 $this->setUser($_SESSION['phpCAS']['user']);
01079                                 $this->setPGT($_SESSION['phpCAS']['pgt']);
01080                                 phpCAS::trace('user = `'.$_SESSION['phpCAS']['user'].'\', PGT = `'.$_SESSION['phpCAS']['pgt'].'\''); 
01081                                 $auth = TRUE;
01082                         } elseif ( $this->isSessionAuthenticated() && empty($_SESSION['phpCAS']['pgt']) ) {
01083                                 // these two variables should be empty or not empty at the same time
01084                                 phpCAS::trace('username found (`'.$_SESSION['phpCAS']['user'].'\') but PGT is empty');
01085                                 // unset all tickets to enforce authentication
01086                                 unset($_SESSION['phpCAS']);
01087                                 $this->setST('');
01088                                 $this->setPT('');
01089                         } elseif ( !$this->isSessionAuthenticated() && !empty($_SESSION['phpCAS']['pgt']) ) {
01090                                 // these two variables should be empty or not empty at the same time
01091                                 phpCAS::trace('PGT found (`'.$_SESSION['phpCAS']['pgt'].'\') but username is empty'); 
01092                                 // unset all tickets to enforce authentication
01093                                 unset($_SESSION['phpCAS']);
01094                                 $this->setST('');
01095                                 $this->setPT('');
01096                         } else {
01097                                 phpCAS::trace('neither user not PGT found'); 
01098                         }
01099                 } else {
01100                         // `simple' CAS client (not a proxy): username must be present
01101                         if ( $this->isSessionAuthenticated() ) {
01102                                 // authentication already done
01103                                 $this->setUser($_SESSION['phpCAS']['user']);
01104                                 if(isset($_SESSION['phpCAS']['attributes'])){
01105                                         $this->setAttributes($_SESSION['phpCAS']['attributes']);
01106                                 }
01107                                 phpCAS::trace('user = `'.$_SESSION['phpCAS']['user'].'\''); 
01108                                 $auth = TRUE;
01109                         } else {
01110                                 phpCAS::trace('no user found');
01111                         }
01112                 }
01113                 
01114                 phpCAS::traceEnd($auth);
01115                 return $auth;
01116                 }
01117         
01125         function redirectToCas($gateway=false,$renew=false){
01126                 phpCAS::traceBegin();
01127                 $cas_url = $this->getServerLoginURL($gateway,$renew);
01128                 header('Location: '.$cas_url);
01129                 phpCAS::log( "Redirect to : ".$cas_url );
01130                 
01131                 $this->printHTMLHeader($this->getString(CAS_STR_AUTHENTICATION_WANTED));
01132                 
01133                 printf('<p>'.$this->getString(CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED).'</p>',$cas_url);
01134                 $this->printHTMLFooter();
01135                 
01136                 phpCAS::traceExit();
01137                 exit();
01138         }
01139         
01140         
01146         function logout($params) {
01147                 phpCAS::traceBegin();
01148                 $cas_url = $this->getServerLogoutURL();
01149                 $paramSeparator = '?';
01150                 if (isset($params['url'])) {
01151                         $cas_url = $cas_url . $paramSeparator . "url=" . urlencode($params['url']); 
01152                         $paramSeparator = '&';
01153                 }
01154                 if (isset($params['service'])) {
01155                         $cas_url = $cas_url . $paramSeparator . "service=" . urlencode($params['service']); 
01156                 }
01157                 header('Location: '.$cas_url);
01158                 phpCAS::log( "Prepare redirect to : ".$cas_url );
01159                 
01160                 session_unset();
01161                 session_destroy();
01162                 
01163                 $this->printHTMLHeader($this->getString(CAS_STR_LOGOUT));
01164                 printf('<p>'.$this->getString(CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED).'</p>',$cas_url);
01165                 $this->printHTMLFooter();
01166                 
01167                 phpCAS::traceExit();
01168                 exit();
01169         }
01170         
01175         function isLogoutRequest() {
01176                 return !empty($_POST['logoutRequest']);
01177         }
01178         
01183         function isLogoutRequestAllowed() {
01184         }
01185         
01194         function handleLogoutRequests($check_client=true, $allowed_clients=false) {
01195                 phpCAS::traceBegin();
01196                 if (!$this->isLogoutRequest()) {
01197                         phpCAS::log("Not a logout request");
01198                         phpCAS::traceEnd();
01199                         return;
01200                 }
01201                 if(!$this->_start_session){
01202                         phpCAS::log("phpCAS can't handle logout requests if it does not manage the session.");
01203                 }
01204                 phpCAS::log("Logout requested");
01205                 phpCAS::log("SAML REQUEST: ".$_POST['logoutRequest']);
01206                 if ($check_client) {
01207                         if (!$allowed_clients) {
01208                                 $allowed_clients = array( $this->getServerHostname() ); 
01209                         }
01210                         $client_ip = $_SERVER['REMOTE_ADDR'];
01211                         $client = gethostbyaddr($client_ip);
01212                         phpCAS::log("Client: ".$client."/".$client_ip); 
01213                         $allowed = false;
01214                         foreach ($allowed_clients as $allowed_client) {
01215                                 if (($client == $allowed_client) or ($client_ip == $allowed_client)) { 
01216                                         phpCAS::log("Allowed client '".$allowed_client."' matches, logout request is allowed");
01217                                         $allowed = true;
01218                                         break;
01219                                 } else {
01220                                         phpCAS::log("Allowed client '".$allowed_client."' does not match");
01221                                 }
01222                         }
01223                         if (!$allowed) {
01224                                 phpCAS::error("Unauthorized logout request from client '".$client."'");
01225                                 printf("Unauthorized!");
01226                                 phpCAS::traceExit();
01227                                 exit();
01228                         }
01229                 } else {
01230                         phpCAS::log("No access control set");
01231                 }
01232                 // Extract the ticket from the SAML Request
01233                 preg_match("|<samlp:SessionIndex>(.*)</samlp:SessionIndex>|", $_POST['logoutRequest'], $tick, PREG_OFFSET_CAPTURE, 3);
01234                 $wrappedSamlSessionIndex = preg_replace('|<samlp:SessionIndex>|','',$tick[0][0]);
01235                 $ticket2logout = preg_replace('|</samlp:SessionIndex>|','',$wrappedSamlSessionIndex);
01236                 phpCAS::log("Ticket to logout: ".$ticket2logout);
01237                 $session_id = preg_replace('/[^\w]/','',$ticket2logout);
01238                 phpCAS::log("Session id: ".$session_id);
01239                 
01240                 // destroy a possible application session created before phpcas
01241                 if(session_id()  !== ""){
01242                         session_unset();
01243                         session_destroy();
01244                 }
01245                 // fix session ID
01246                 session_id($session_id);
01247                 $_COOKIE[session_name()]=$session_id;
01248                 $_GET[session_name()]=$session_id;
01249                 
01250                 // Overwrite session
01251                 session_start();        
01252                 session_unset();
01253                 session_destroy();
01254                 printf("Disconnected!");
01255                 phpCAS::traceExit();
01256                 exit();
01257         }
01258         
01261         // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
01262         // XX                                                                    XX
01263         // XX                  BASIC CLIENT FEATURES (CAS 1.0)                   XX
01264         // XX                                                                    XX
01265         // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
01266         
01267         // ########################################################################
01268         //  ST
01269         // ########################################################################
01283         var $_st = '';
01284         
01290         function getST()
01291                 { return $this->_st; }
01292         
01298         function setST($st)
01299                 { $this->_st = $st; }
01300         
01306         function hasST()
01307                 { return !empty($this->_st); }
01308         
01311         // ########################################################################
01312         //  ST VALIDATION
01313         // ########################################################################
01325         var $_cas_server_cert = '';
01326         
01333         var $_cas_server_ca_cert = '';
01334         
01341         var $_no_cas_server_validation = false;
01342         
01348         function setCasServerCert($cert)
01349                 {
01350                 $this->_cas_server_cert = $cert;
01351                 }
01352         
01358         function setCasServerCACert($cert)
01359                 {
01360                 $this->_cas_server_ca_cert = $cert;
01361                 }
01362         
01366         function setNoCasServerValidation()
01367                 {
01368                 $this->_no_cas_server_validation = true;
01369                 }
01370         
01384         function validateST($validate_url,&$text_response,&$tree_response)
01385                 {
01386                 phpCAS::traceBegin();
01387                 // build the URL to validate the ticket
01388                 $validate_url = $this->getServerServiceValidateURL().'&ticket='.$this->getST();
01389                 if ( $this->isProxy() ) {
01390                         // pass the callback url for CAS proxies
01391                         $validate_url .= '&pgtUrl='.urlencode($this->getCallbackURL());
01392                 }
01393                 
01394                 // open and read the URL
01395                 if ( !$this->readURL($validate_url,''/*cookies*/,$headers,$text_response,$err_msg) ) {
01396                         phpCAS::trace('could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')');
01397                         $this->authError('ST not validated',
01398                                 $validate_url,
01399                                 TRUE/*$no_response*/);
01400                 }
01401                 
01402                 // analyze the result depending on the version
01403                 switch ($this->getServerVersion()) {
01404                         case CAS_VERSION_1_0:
01405                                 if (preg_match('/^no\n/',$text_response)) {
01406                                         phpCAS::trace('ST has not been validated');
01407                                         $this->authError('ST not validated',
01408                                                 $validate_url,
01409                                                 FALSE/*$no_response*/,
01410                                                 FALSE/*$bad_response*/,
01411                                                 $text_response);
01412                                 }
01413                                 if (!preg_match('/^yes\n/',$text_response)) {
01414                                         phpCAS::trace('ill-formed response');
01415                                         $this->authError('ST not validated',
01416                                                 $validate_url,
01417                                                 FALSE/*$no_response*/,
01418                                                 TRUE/*$bad_response*/,
01419                                                 $text_response);
01420                                 }
01421                                 // ST has been validated, extract the user name
01422                                 $arr = preg_split('/\n/',$text_response);
01423                                 $this->setUser(trim($arr[1]));
01424                                 break;
01425                         case CAS_VERSION_2_0:
01426                                 // read the response of the CAS server into a DOM object
01427                                 if ( !($dom = domxml_open_mem($text_response))) {
01428                                         phpCAS::trace('domxml_open_mem() failed');
01429                                         $this->authError('ST not validated',
01430                                                 $validate_url,
01431                                                 FALSE/*$no_response*/,
01432                                                 TRUE/*$bad_response*/,
01433                                                 $text_response);
01434                                 }
01435                                 // read the root node of the XML tree
01436                                 if ( !($tree_response = $dom->document_element()) ) {
01437                                         phpCAS::trace('document_element() failed');
01438                                         $this->authError('ST not validated',
01439                                                 $validate_url,
01440                                                 FALSE/*$no_response*/,
01441                                                 TRUE/*$bad_response*/,
01442                                                 $text_response);
01443                                 }
01444                                 // insure that tag name is 'serviceResponse'
01445                                 if ( $tree_response->node_name() != 'serviceResponse' ) {
01446                                         phpCAS::trace('bad XML root node (should be `serviceResponse\' instead of `'.$tree_response->node_name().'\'');
01447                                         $this->authError('ST not validated',
01448                                                 $validate_url,
01449                                                 FALSE/*$no_response*/,
01450                                                 TRUE/*$bad_response*/,
01451                                                 $text_response);
01452                                 }
01453                                 if ( sizeof($success_elements = $tree_response->get_elements_by_tagname("authenticationSuccess")) != 0) {
01454                                         // authentication succeded, extract the user name
01455                                         if ( sizeof($user_elements = $success_elements[0]->get_elements_by_tagname("user")) == 0) {
01456                                                 phpCAS::trace('<authenticationSuccess> found, but no <user>');
01457                                                 $this->authError('ST not validated',
01458                                                         $validate_url,
01459                                                         FALSE/*$no_response*/,
01460                                                         TRUE/*$bad_response*/,
01461                                                         $text_response);
01462                                         }
01463                                         $user = trim($user_elements[0]->get_content());
01464                                         phpCAS::trace('user = `'.$user);
01465                                         $this->setUser($user);
01466                                         
01467                                 } else if ( sizeof($failure_elements = $tree_response->get_elements_by_tagname("authenticationFailure")) != 0) {
01468                                         phpCAS::trace('<authenticationFailure> found');
01469                                         // authentication failed, extract the error code and message
01470                                         $this->authError('ST not validated',
01471                                                 $validate_url,
01472                                                 FALSE/*$no_response*/,
01473                                                 FALSE/*$bad_response*/,
01474                                                 $text_response,
01475                                                 $failure_elements[0]->get_attribute('code')/*$err_code*/,
01476                                                 trim($failure_elements[0]->get_content())/*$err_msg*/);
01477                                 } else {
01478                                         phpCAS::trace('neither <authenticationSuccess> nor <authenticationFailure> found');
01479                                         $this->authError('ST not validated',
01480                                                 $validate_url,
01481                                                 FALSE/*$no_response*/,
01482                                                 TRUE/*$bad_response*/,
01483                                                 $text_response);
01484                                 }
01485                                 break;
01486                 }
01487                 $this->renameSession($this->getST());
01488                 // at this step, ST has been validated and $this->_user has been set,
01489                 phpCAS::traceEnd(TRUE);
01490                 return TRUE;
01491                 }
01492         
01493         // ########################################################################
01494         //  SAML VALIDATION
01495         // ########################################################################
01514         function validateSA($validate_url,&$text_response,&$tree_response)
01515                 {
01516                 phpCAS::traceBegin();
01517                 
01518                 // build the URL to validate the ticket
01519                 $validate_url = $this->getServerSamlValidateURL();
01520                 
01521                 // open and read the URL
01522                 if ( !$this->readURL($validate_url,''/*cookies*/,$headers,$text_response,$err_msg) ) {
01523                         phpCAS::trace('could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')');
01524                         $this->authError('SA not validated', $validate_url, TRUE/*$no_response*/);
01525                 }
01526                 
01527                 phpCAS::trace('server version: '.$this->getServerVersion());
01528                 
01529                 // analyze the result depending on the version
01530                 switch ($this->getServerVersion()) {
01531                         case SAML_VERSION_1_1:
01532                                 
01533                                 // read the response of the CAS server into a DOM object
01534                                 if ( !($dom = domxml_open_mem($text_response))) {
01535                                         phpCAS::trace('domxml_open_mem() failed');
01536                                         $this->authError('SA not validated',
01537                                                 $validate_url,
01538                                                 FALSE/*$no_response*/,
01539                                                 TRUE/*$bad_response*/,
01540                                                 $text_response);
01541                                 }
01542                                 // read the root node of the XML tree
01543                                 if ( !($tree_response = $dom->document_element()) ) {
01544                                         phpCAS::trace('document_element() failed');
01545                                         $this->authError('SA not validated',
01546                                                 $validate_url,
01547                                                 FALSE/*$no_response*/,
01548                                                 TRUE/*$bad_response*/,
01549                                                 $text_response);
01550                                 }
01551                                 // insure that tag name is 'Envelope'
01552                                 if ( $tree_response->node_name() != 'Envelope' ) {
01553                                         phpCAS::trace('bad XML root node (should be `Envelope\' instead of `'.$tree_response->node_name().'\'');
01554                                         $this->authError('SA not validated',
01555                                                 $validate_url,
01556                                                 FALSE/*$no_response*/,
01557                                                 TRUE/*$bad_response*/,
01558                                                 $text_response);
01559                                 }
01560                                 // check for the NameIdentifier tag in the SAML response
01561                                 if ( sizeof($success_elements = $tree_response->get_elements_by_tagname("NameIdentifier")) != 0) {
01562                                         phpCAS::trace('NameIdentifier found');
01563                                         $user = trim($success_elements[0]->get_content());
01564                                         phpCAS::trace('user = `'.$user.'`');
01565                                         $this->setUser($user);
01566                                         $this->setSessionAttributes($text_response);
01567                                 } else {
01568                                         phpCAS::trace('no <NameIdentifier> tag found in SAML payload');
01569                                         $this->authError('SA not validated',
01570                                                 $validate_url,
01571                                                 FALSE/*$no_response*/,
01572                                                 TRUE/*$bad_response*/,
01573                                                 $text_response);
01574                                 }
01575                                 break;
01576                 }
01577                 $this->renameSession($this->getSA());
01578                 // at this step, ST has been validated and $this->_user has been set,
01579                 phpCAS::traceEnd(TRUE);
01580                 return TRUE;
01581                 }
01582         
01592         function setSessionAttributes($text_response)
01593                 {
01594                 phpCAS::traceBegin();
01595                 
01596                 $result = FALSE;
01597                 
01598                 if (isset($_SESSION[SAML_ATTRIBUTES])) {
01599                         phpCAS::trace("session attrs already set.");  //testbml - do we care?
01600                 }
01601                 
01602                 $attr_array = array();
01603                 
01604                 if (($dom = domxml_open_mem($text_response))) {
01605                         $xPath = $dom->xpath_new_context();
01606                         $xPath->xpath_register_ns('samlp', 'urn:oasis:names:tc:SAML:1.0:protocol');
01607                         $xPath->xpath_register_ns('saml', 'urn:oasis:names:tc:SAML:1.0:assertion');
01608                         $nodelist = $xPath->xpath_eval("//saml:Attribute");
01609                         if($nodelist){
01610                                 $attrs = $nodelist->nodeset;
01611                                 foreach($attrs as $attr){
01612                                         $xres = $xPath->xpath_eval("saml:AttributeValue", $attr);
01613                                         $name = $attr->get_attribute("AttributeName");
01614                                         $value_array = array();
01615                                         foreach($xres->nodeset as $node){
01616                                                 $value_array[] = $node->get_content();
01617                                         }
01618                                         $attr_array[$name] = $value_array;
01619                                 }
01620                                 $_SESSION[SAML_ATTRIBUTES] = $attr_array;
01621                                 // UGent addition...
01622                                 foreach($attr_array as $attr_key => $attr_value) {
01623                                         if(count($attr_value) > 1) {
01624                                                 $this->_attributes[$attr_key] = $attr_value;
01625                                                 phpCAS::trace("* " . $attr_key . "=" . $attr_value);
01626                                         }
01627                                         else {
01628                                                 $this->_attributes[$attr_key] = $attr_value[0];
01629                                                 phpCAS::trace("* " . $attr_key . "=" . $attr_value[0]);
01630                                         }
01631                                 }
01632                                 $result = TRUE;
01633                         }else{
01634                                 phpCAS::trace("SAML Attributes are empty");
01635                                 $result = FALSE;
01636                         }
01637                 }
01638                 phpCAS::traceEnd($result);
01639                 return $result;
01640                 }
01641         
01644         // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
01645         // XX                                                                    XX
01646         // XX                     PROXY FEATURES (CAS 2.0)                       XX
01647         // XX                                                                    XX
01648         // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
01649         
01650         // ########################################################################
01651         //  PROXYING
01652         // ########################################################################
01664         var $_proxy;
01665         
01673         function isProxy()
01674                 {
01675                 return $this->_proxy;
01676                 }
01677         
01679         // ########################################################################
01680         //  PGT
01681         // ########################################################################
01694         var $_pgt = '';
01695         
01701         function getPGT()
01702                 { return $this->_pgt; }
01703         
01709         function setPGT($pgt)
01710                 { $this->_pgt = $pgt; }
01711         
01717         function hasPGT()
01718                 { return !empty($this->_pgt); }
01719         
01722         // ########################################################################
01723         //  CALLBACK MODE
01724         // ########################################################################
01742         var $_callback_mode = FALSE;
01743         
01751         function setCallbackMode($callback_mode)
01752                 {
01753                 $this->_callback_mode = $callback_mode;
01754                 }
01755         
01764         function isCallbackMode()
01765                 {
01766                 return $this->_callback_mode;
01767                 }
01768         
01777         var $_callback_url = '';
01778         
01788         function getCallbackURL()
01789                 {
01790                 // the URL is built when needed only
01791                 if ( empty($this->_callback_url) ) {
01792                         $final_uri = '';
01793                         // remove the ticket if present in the URL
01794                         $final_uri = 'https://';
01795                         /* replaced by Julien Marchal - v0.4.6
01796                          * $this->uri .= $_SERVER['SERVER_NAME'];
01797                          */
01798                         if(empty($_SERVER['HTTP_X_FORWARDED_SERVER'])){
01799                                 /* replaced by teedog - v0.4.12
01800                                  * $final_uri .= $_SERVER['SERVER_NAME'];
01801                                  */
01802                                 if (empty($_SERVER['SERVER_NAME'])) {
01803                                         $final_uri .= $_SERVER['HTTP_HOST'];
01804                                 } else {
01805                                         $final_uri .= $_SERVER['SERVER_NAME'];
01806                                 }
01807                         } else {
01808                                 $final_uri .= $_SERVER['HTTP_X_FORWARDED_SERVER'];
01809                         }
01810                         if ( ($this->isHttps() && $_SERVER['SERVER_PORT']!=443)
01811                                         || (!$this->isHttps() && $_SERVER['SERVER_PORT']!=80) ) {
01812                                 $final_uri .= ':';
01813                                 $final_uri .= $_SERVER['SERVER_PORT'];
01814                         }
01815                         $request_uri = $_SERVER['REQUEST_URI'];
01816                         $request_uri = preg_replace('/\?.*$/','',$request_uri);
01817                         $final_uri .= $request_uri;
01818                         $this->setCallbackURL($final_uri);
01819                 }
01820                 return $this->_callback_url;
01821                 }
01822         
01830         function setCallbackURL($url)
01831                 {
01832                 return $this->_callback_url = $url;
01833                 }
01834         
01841         function callback()
01842                 {
01843                 phpCAS::traceBegin();
01844                 if (preg_match('/PGTIOU-[\.\-\w]/', $_GET['pgtIou'])){
01845                         if(preg_match('/[PT]GT-[\.\-\w]/', $_GET['pgtId'])){
01846                                 $this->printHTMLHeader('phpCAS callback');
01847                                 $pgt_iou = $_GET['pgtIou'];
01848                                 $pgt = $_GET['pgtId'];
01849                                 phpCAS::trace('Storing PGT `'.$pgt.'\' (id=`'.$pgt_iou.'\')');
01850                                 echo '<p>Storing PGT `'.$pgt.'\' (id=`'.$pgt_iou.'\').</p>';
01851                                 $this->storePGT($pgt,$pgt_iou);
01852                                 $this->printHTMLFooter();
01853                         }else{
01854                                 phpCAS::error('PGT format invalid' . $_GET['pgtId']);
01855                         }
01856                 }else{
01857                         phpCAS::error('PGTiou format invalid' . $_GET['pgtIou']);
01858                 }
01859                 phpCAS::traceExit();
01860                 exit();
01861                 }
01862         
01865         // ########################################################################
01866         //  PGT STORAGE
01867         // ########################################################################
01881         var $_pgt_storage = null;
01882         
01889         function initPGTStorage()
01890                 {
01891                 // if no SetPGTStorageXxx() has been used, default to file
01892                 if ( !is_object($this->_pgt_storage) ) {
01893                         $this->setPGTStorageFile();
01894                 }
01895                 
01896                 // initializes the storage
01897                 $this->_pgt_storage->init();
01898                 }
01899         
01908         function storePGT($pgt,$pgt_iou)
01909                 {
01910                 // ensure that storage is initialized
01911                 $this->initPGTStorage();
01912                 // writes the PGT
01913                 $this->_pgt_storage->write($pgt,$pgt_iou);
01914                 }
01915         
01925         function loadPGT($pgt_iou)
01926                 {
01927                 // ensure that storage is initialized
01928                 $this->initPGTStorage();
01929                 // read the PGT
01930                 return $this->_pgt_storage->read($pgt_iou);
01931                 }
01932         
01942         function setPGTStorageFile($format='',
01943                 $path='')
01944                 {
01945                 // check that the storage has not already been set
01946                 if ( is_object($this->_pgt_storage) ) {
01947                         phpCAS::error('PGT storage already defined');
01948                 }
01949                 
01950                 // create the storage object
01951                 $this->_pgt_storage = new PGTStorageFile($this,$format,$path);
01952                 }
01953         
01954         // ########################################################################
01955         //  PGT VALIDATION
01956         // ########################################################################
01970         function validatePGT(&$validate_url,$text_response,$tree_response)
01971                 {
01972                 // here cannot use phpCAS::traceBegin(); alongside domxml-php4-to-php5.php
01973                 phpCAS::log('start validatePGT()');
01974                 if ( sizeof($arr = $tree_response->get_elements_by_tagname("proxyGrantingTicket")) == 0) {
01975                         phpCAS::trace('<proxyGrantingTicket> not found');
01976                         // authentication succeded, but no PGT Iou was transmitted
01977                         $this->authError('Ticket validated but no PGT Iou transmitted',
01978                                 $validate_url,
01979                                 FALSE/*$no_response*/,
01980                                 FALSE/*$bad_response*/,
01981                                 $text_response);
01982                 } else {
01983                         // PGT Iou transmitted, extract it
01984                         $pgt_iou = trim($arr[0]->get_content());
01985                         if(preg_match('/PGTIOU-[\.\-\w]/',$pgt_iou)){ 
01986                                 $pgt = $this->loadPGT($pgt_iou);
01987                                 if ( $pgt == FALSE ) {
01988                                         phpCAS::trace('could not load PGT');
01989                                         $this->authError('PGT Iou was transmitted but PGT could not be retrieved',
01990                                                 $validate_url,
01991                                                 FALSE/*$no_response*/,
01992                                                 FALSE/*$bad_response*/,
01993                                                 $text_response);
01994                                 }
01995                                 $this->setPGT($pgt);
01996                         }else{
01997                                 phpCAS::trace('PGTiou format error');
01998                                 $this->authError('PGT Iou was transmitted but has wrong fromat',
01999                                         $validate_url,
02000                                         FALSE/*$no_response*/,
02001                                         FALSE/*$bad_response*/,
02002                                         $text_response);
02003                         }
02004                         
02005                 }
02006                 // here, cannot use     phpCAS::traceEnd(TRUE); alongside domxml-php4-to-php5.php
02007                 phpCAS::log('end validatePGT()');
02008                 return TRUE;
02009                 }
02010         
02011         // ########################################################################
02012         //  PGT VALIDATION
02013         // ########################################################################
02014         
02026         function retrievePT($target_service,&$err_code,&$err_msg)
02027                 {
02028                 phpCAS::traceBegin();
02029                 
02030                 // by default, $err_msg is set empty and $pt to TRUE. On error, $pt is
02031                 // set to false and $err_msg to an error message. At the end, if $pt is FALSE 
02032                 // and $error_msg is still empty, it is set to 'invalid response' (the most
02033                 // commonly encountered error).
02034                 $err_msg = '';
02035                 
02036                 // build the URL to retrieve the PT
02037                 //      $cas_url = $this->getServerProxyURL().'?targetService='.preg_replace('/&/','%26',$target_service).'&pgt='.$this->getPGT();
02038                 $cas_url = $this->getServerProxyURL().'?targetService='.urlencode($target_service).'&pgt='.$this->getPGT();
02039                 
02040                 // open and read the URL
02041                 if ( !$this->readURL($cas_url,''/*cookies*/,$headers,$cas_response,$err_msg) ) {
02042                         phpCAS::trace('could not open URL \''.$cas_url.'\' to validate ('.$err_msg.')');
02043                         $err_code = PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE;
02044                         $err_msg = 'could not retrieve PT (no response from the CAS server)';
02045                         phpCAS::traceEnd(FALSE);
02046                         return FALSE;
02047                 }
02048                 
02049                 $bad_response = FALSE;
02050                 
02051                 if ( !$bad_response ) {
02052                         // read the response of the CAS server into a DOM object
02053                         if ( !($dom = @domxml_open_mem($cas_response))) {
02054                                 phpCAS::trace('domxml_open_mem() failed');
02055                                 // read failed
02056                                 $bad_response = TRUE;
02057                         } 
02058                 }
02059                 
02060                 if ( !$bad_response ) {
02061                         // read the root node of the XML tree
02062                         if ( !($root = $dom->document_element()) ) {
02063                                 phpCAS::trace('document_element() failed');
02064                                 // read failed
02065                                 $bad_response = TRUE;
02066                         } 
02067                 }
02068                 
02069                 if ( !$bad_response ) {
02070                         // insure that tag name is 'serviceResponse'
02071                         if ( $root->node_name() != 'serviceResponse' ) {
02072                                 phpCAS::trace('node_name() failed');
02073                                 // bad root node
02074                                 $bad_response = TRUE;
02075                         } 
02076                 }
02077                 
02078                 if ( !$bad_response ) {
02079                         // look for a proxySuccess tag
02080                         if ( sizeof($arr = $root->get_elements_by_tagname("proxySuccess")) != 0) {
02081                                 // authentication succeded, look for a proxyTicket tag
02082                                 if ( sizeof($arr = $root->get_elements_by_tagname("proxyTicket")) != 0) {
02083                                         $err_code = PHPCAS_SERVICE_OK;
02084                                         $err_msg = '';
02085                                         phpCAS::trace('original PT: '.trim($arr[0]->get_content()));
02086                                         $pt = trim($arr[0]->get_content());
02087                                         phpCAS::traceEnd($pt);
02088                                         return $pt;
02089                                 } else {
02090                                         phpCAS::trace('<proxySuccess> was found, but not <proxyTicket>');
02091                                 }
02092                         } 
02093                         // look for a proxyFailure tag
02094                         else if ( sizeof($arr = $root->get_elements_by_tagname("proxyFailure")) != 0) {
02095                                 // authentication failed, extract the error
02096                                 $err_code = PHPCAS_SERVICE_PT_FAILURE;
02097                                 $err_msg = 'PT retrieving failed (code=`'
02098                                         .$arr[0]->get_attribute('code')
02099                                         .'\', message=`'
02100                                         .trim($arr[0]->get_content())
02101                                         .'\')';
02102                                 phpCAS::traceEnd(FALSE);
02103                                 return FALSE;
02104                         } else {
02105                                 phpCAS::trace('neither <proxySuccess> nor <proxyFailure> found');
02106                         }
02107                 }
02108                 
02109                 // at this step, we are sure that the response of the CAS server was ill-formed
02110                 $err_code = PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE;
02111                 $err_msg = 'Invalid response from the CAS server (response=`'.$cas_response.'\')';
02112                 
02113                 phpCAS::traceEnd(FALSE);
02114                 return FALSE;
02115                 }
02116         
02117         // ########################################################################
02118         // ACCESS TO EXTERNAL SERVICES
02119         // ########################################################################
02120         
02136         function readURL($url,$cookies,&$headers,&$body,&$err_msg)
02137                 {
02138                 phpCAS::traceBegin();
02139                 $headers = '';
02140                 $body = '';
02141                 $err_msg = '';
02142                 
02143                 $res = TRUE;
02144                 
02145                 // initialize the CURL session
02146                 $ch = curl_init($url);
02147                 
02148                 if (version_compare(PHP_VERSION,'5.1.3','>=')) {
02149                         //only avaible in php5
02150                         curl_setopt_array($ch, $this->_curl_options);
02151                 } else {
02152                         foreach ($this->_curl_options as $key => $value) {
02153                                 curl_setopt($ch, $key, $value);
02154                         }
02155                 }
02156                 
02157                 if ($this->_cas_server_cert == '' && $this->_cas_server_ca_cert == '' && !$this->_no_cas_server_validation) {
02158                         phpCAS::error('one of the methods phpCAS::setCasServerCert(), phpCAS::setCasServerCACert() or phpCAS::setNoCasServerValidation() must be called.');
02159                 }
02160                 if ($this->_cas_server_cert != '' && $this->_cas_server_ca_cert != '') {
02161                         // This branch added by IDMS. Seems phpCAS implementor got a bit confused about the curl options CURLOPT_SSLCERT and CURLOPT_CAINFO
02162                         curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
02163                         curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1);
02164                         curl_setopt($ch, CURLOPT_SSLCERT, $this->_cas_server_cert);
02165                         curl_setopt($ch, CURLOPT_CAINFO, $this->_cas_server_ca_cert);
02166                         curl_setopt($ch, CURLOPT_VERBOSE, '1');
02167                         phpCAS::trace('CURL: Set all required opts for mutual authentication ------');
02168                 } else if ($this->_cas_server_cert != '' ) {
02169                         curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
02170                         curl_setopt($ch, CURLOPT_SSLCERT, $this->_cas_server_cert);
02171                 } else if ($this->_cas_server_ca_cert != '') {
02172                         curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
02173                         curl_setopt($ch, CURLOPT_CAINFO, $this->_cas_server_ca_cert);
02174                 } else {
02175                         curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1);
02176                         curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
02177                 }
02178                 
02179                 // return the CURL output into a variable
02180                 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
02181                 // get the HTTP header with a callback
02182                 $this->_curl_headers = array(); // empty the headers array
02183                 curl_setopt($ch, CURLOPT_HEADERFUNCTION, array($this, '_curl_read_headers'));
02184                 // add cookies headers
02185                 if ( is_array($cookies) ) {
02186                         curl_setopt($ch,CURLOPT_COOKIE,implode(';',$cookies));
02187                 }
02188                 // add extra stuff if SAML
02189                 if ($this->hasSA()) {
02190                         $more_headers = array ("soapaction: http://www.oasis-open.org/committees/security",
02191                                 "cache-control: no-cache",
02192                                 "pragma: no-cache",
02193                                 "accept: text/xml",
02194                                 "connection: keep-alive",
02195                         "content-type: text/xml");
02196                         
02197                         curl_setopt($ch, CURLOPT_HTTPHEADER, $more_headers);
02198                         curl_setopt($ch, CURLOPT_POST, 1);
02199                         $data = $this->buildSAMLPayload();
02200                         //phpCAS::trace('SAML Payload: '.print_r($data, TRUE));
02201                         curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
02202                 }
02203                 // perform the query
02204                 $buf = curl_exec ($ch);
02205                 //phpCAS::trace('CURL: Call completed. Response body is: \''.$buf.'\'');
02206                 if ( $buf === FALSE ) {
02207                         phpCAS::trace('curl_exec() failed');
02208                         $err_msg = 'CURL error #'.curl_errno($ch).': '.curl_error($ch);
02209                         //phpCAS::trace('curl error: '.$err_msg);
02210                         // close the CURL session
02211                         curl_close ($ch);
02212                         $res = FALSE;
02213                 } else {
02214                         // close the CURL session
02215                         curl_close ($ch);
02216                         
02217                         $headers = $this->_curl_headers;
02218                         $body = $buf;
02219                 }
02220                 
02221                 phpCAS::traceEnd($res);
02222                 return $res;
02223                 }
02224         
02232         function buildSAMLPayload()
02233                 {
02234                 phpCAS::traceBegin();
02235                 
02236                 //get the ticket
02237                 $sa = $this->getSA();
02238                 //phpCAS::trace("SA: ".$sa);
02239                 
02240                 $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;
02241                 
02242                 phpCAS::traceEnd($body);
02243                 return ($body);
02244                 }
02245         
02249         var $_curl_headers = array();
02250         function _curl_read_headers($ch, $header)
02251                 {
02252                 $this->_curl_headers[] = $header;
02253                 return strlen($header);
02254                 }
02255         
02271         function serviceWeb($url,&$err_code,&$output)
02272                 {
02273                 phpCAS::traceBegin();
02274                 // at first retrieve a PT
02275                 $pt = $this->retrievePT($url,$err_code,$output);
02276                 
02277                 $res = TRUE;
02278                 
02279                 // test if PT was retrieved correctly
02280                 if ( !$pt ) {
02281                         // note: $err_code and $err_msg are filled by CASClient::retrievePT()
02282                         phpCAS::trace('PT was not retrieved correctly');
02283                         $res = FALSE;
02284                 } else {
02285                         // add cookies if necessary
02286                         $cookies = $this->getCookies($url);
02287                         
02288                         // build the URL including the PT
02289                         if ( strstr($url,'?') === FALSE ) {
02290                                 $service_url = $url.'?ticket='.$pt;
02291                         } else {
02292                                 $service_url = $url.'&ticket='.$pt;
02293                         }
02294                         
02295                         phpCAS::trace('reading URL`'.$service_url.'\'');
02296                         if ( !$this->readURL($service_url,$cookies,$headers,$output,$err_msg) ) {
02297                                 phpCAS::trace('could not read URL`'.$service_url.'\'');
02298                                 $err_code = PHPCAS_SERVICE_NOT_AVAILABLE;
02299                                 // give an error message
02300                                 $output = sprintf($this->getString(CAS_STR_SERVICE_UNAVAILABLE),
02301                                         $service_url,
02302                                         $err_msg);
02303                                 $res = FALSE;
02304                         } else {
02305                                 // URL has been fetched, extract the cookies
02306                                 phpCAS::trace('URL`'.$service_url.'\' has been read, storing cookies:');
02307                                 $this->setCookies($headers,$url);
02308                                 // Check for a possible redirect (phpCAS authenticiation redirect after ticket removal)
02309                                 foreach($headers as $header){
02310                                         if (preg_match('/(Location:|URI:)(.*?)\n/', $header, $matches))
02311                                         {
02312                                                 $redirect_url = trim(array_pop($matches));
02313                                                 phpCAS :: trace('Found redirect:'.$redirect_url);
02314                                                 $cookies = $this->getCookies($redirect_url);
02315                                                 phpCAS::trace('reading URL`'.$redirect_url.'\'');
02316                                                 if ( !$this->readURL($redirect_url,$cookies,$headers,$output,$err_msg) ) {
02317                                                         phpCAS::trace('could not read URL`'.$redirect_url.'\'');
02318                                                         $err_code = PHPCAS_SERVICE_NOT_AVAILABLE;
02319                                                         // give an error message
02320                                                         $output = sprintf($this->getString(CAS_STR_SERVICE_UNAVAILABLE),
02321                                                                 $service_url,
02322                                                                 $err_msg);
02323                                                         $res = FALSE;
02324                                                 } else {
02325                                                         // URL has been fetched, extract the cookies
02326                                                         phpCAS::trace('URL`'.$redirect_url.'\' has been read, storing cookies:');
02327                                                         $this->setCookies($headers,$redirect_url);
02328                                                 }
02329                                                 break;
02330                                         }
02331                                 }
02332                         }
02333                 }
02334                 
02335                 phpCAS::traceEnd($res);
02336                 return $res;
02337                 }
02338         
02345         function setCookies($headers,$url){
02346                 phpCAS::traceBegin();
02347                 foreach ( $headers as $header ) {
02348                         // test if the header is a cookie
02349                         if ( preg_match('/^Set-Cookie:/',$header) ) {
02350                                 // the header is a cookie, remove the beginning
02351                                 $header_val = preg_replace('/^Set-Cookie: */','',$header);
02352                                 // extract interesting information
02353                                 $name_val = strtok($header_val,'; ');
02354                                 // extract the name and the value of the cookie
02355                                 $cookie_name = strtok($name_val,'=');
02356                                 $cookie_val = strtok('=');
02357                                 // store the cookie 
02358                                 $_SESSION['phpCAS']['services'][$url]['cookies'][$cookie_name] = $cookie_val;
02359                                 phpCAS::trace($cookie_name.' -> '.$cookie_val);
02360                         }
02361                 }
02362                 phpCAS::traceEnd();
02363         }
02364         
02369         function getCookies($url){
02370                 $cookies = array();
02371                 if ( isset($_SESSION['phpCAS']['services'][$url]['cookies']) && 
02372                                 is_array($_SESSION['phpCAS']['services'][$url]['cookies']) ) {
02373                         foreach ( $_SESSION['phpCAS']['services'][$url]['cookies'] as $name => $val ) { 
02374                                 $cookies[] = $name.'='.$val;
02375                         }
02376                 }
02377                 return $cookies;
02378         }
02379         
02399         function serviceMail($url,$service,$flags,&$err_code,&$err_msg,&$pt)
02400                 {
02401                 phpCAS::traceBegin();
02402                 // at first retrieve a PT
02403                 $pt = $this->retrievePT($service,$err_code,$output);
02404                 
02405                 $stream = FALSE;
02406                 
02407                 // test if PT was retrieved correctly
02408                 if ( !$pt ) {
02409                         // note: $err_code and $err_msg are filled by CASClient::retrievePT()
02410                         phpCAS::trace('PT was not retrieved correctly');
02411                 } else {
02412                         phpCAS::trace('opening IMAP URL `'.$url.'\'...');
02413                         $stream = @imap_open($url,$this->getUser(),$pt,$flags);
02414                         if ( !$stream ) {
02415                                 phpCAS::trace('could not open URL');
02416                                 $err_code = PHPCAS_SERVICE_NOT_AVAILABLE;
02417                                 // give an error message
02418                                 $err_msg = sprintf($this->getString(CAS_STR_SERVICE_UNAVAILABLE),
02419                                         $service_url,
02420                                         var_export(imap_errors(),TRUE));
02421                                 $pt = FALSE;
02422                                 $stream = FALSE;
02423                         } else {
02424                                 phpCAS::trace('ok');
02425                         }
02426                 }
02427                 
02428                 phpCAS::traceEnd($stream);
02429                 return $stream;
02430                 }
02431         
02434         // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
02435         // XX                                                                    XX
02436         // XX                  PROXIED CLIENT FEATURES (CAS 2.0)                 XX
02437         // XX                                                                    XX
02438         // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
02439         
02440         // ########################################################################
02441         //  PT
02442         // ########################################################################
02456         var $_pt = '';
02457         
02463         function getPT()
02464                 {
02465                 //      return 'ST'.substr($this->_pt, 2);
02466                 return $this->_pt;
02467                 }
02468         
02474         function setPT($pt)
02475                 { $this->_pt = $pt; }
02476         
02482         function hasPT()
02483                 { return !empty($this->_pt); }
02489         function getSA()
02490                 { return 'ST'.substr($this->_sa, 2); }
02491         
02497         function setSA($sa)
02498                 { $this->_sa = $sa; }
02499         
02505         function hasSA()
02506                 { return !empty($this->_sa); }
02507         
02509         // ########################################################################
02510         //  PT VALIDATION
02511         // ########################################################################
02524         function validatePT(&$validate_url,&$text_response,&$tree_response)
02525                 {
02526                 phpCAS::traceBegin();
02527                 // build the URL to validate the ticket
02528                 $validate_url = $this->getServerProxyValidateURL().'&ticket='.$this->getPT();
02529                 
02530                 if ( $this->isProxy() ) {
02531                         // pass the callback url for CAS proxies
02532                         $validate_url .= '&pgtUrl='.urlencode($this->getCallbackURL());
02533                 }
02534                 
02535                 // open and read the URL
02536                 if ( !$this->readURL($validate_url,''/*cookies*/,$headers,$text_response,$err_msg) ) {
02537                         phpCAS::trace('could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')');
02538                         $this->authError('PT not validated',
02539                                 $validate_url,
02540                                 TRUE/*$no_response*/);
02541                 }
02542                 
02543                 // read the response of the CAS server into a DOM object
02544                 if ( !($dom = domxml_open_mem($text_response))) {
02545                         // read failed
02546                         $this->authError('PT not validated',
02547                                 $validate_url,
02548                                 FALSE/*$no_response*/,
02549                                 TRUE/*$bad_response*/,
02550                                 $text_response);
02551                 }
02552                 // read the root node of the XML tree
02553                 if ( !($tree_response = $dom->document_element()) ) {
02554                         // read failed
02555                         $this->authError('PT not validated',
02556                                 $validate_url,
02557                                 FALSE/*$no_response*/,
02558                                 TRUE/*$bad_response*/,
02559                                 $text_response);
02560                 }
02561                 // insure that tag name is 'serviceResponse'
02562                 if ( $tree_response->node_name() != 'serviceResponse' ) {
02563                         // bad root node
02564                         $this->authError('PT not validated',
02565                                 $validate_url,
02566                                 FALSE/*$no_response*/,
02567                                 TRUE/*$bad_response*/,
02568                                 $text_response);
02569                 }
02570                 if ( sizeof($arr = $tree_response->get_elements_by_tagname("authenticationSuccess")) != 0) {
02571                         // authentication succeded, extract the user name
02572                         if ( sizeof($arr = $tree_response->get_elements_by_tagname("user")) == 0) {
02573                                 // no user specified => error
02574                                 $this->authError('PT not validated',
02575                                         $validate_url,
02576                                         FALSE/*$no_response*/,
02577                                         TRUE/*$bad_response*/,
02578                                         $text_response);
02579                         }
02580                         $this->setUser(trim($arr[0]->get_content()));
02581                         
02582                 } else if ( sizeof($arr = $tree_response->get_elements_by_tagname("authenticationFailure")) != 0) {
02583                         // authentication succeded, extract the error code and message
02584                         $this->authError('PT not validated',
02585                                 $validate_url,
02586                                 FALSE/*$no_response*/,
02587                                 FALSE/*$bad_response*/,
02588                                 $text_response,
02589                                 $arr[0]->get_attribute('code')/*$err_code*/,
02590                                 trim($arr[0]->get_content())/*$err_msg*/);
02591                 } else {
02592                         $this->authError('PT not validated',
02593                                 $validate_url,  
02594                                 FALSE/*$no_response*/,
02595                                 TRUE/*$bad_response*/,
02596                                 $text_response);
02597                 }
02598                 
02599                 $this->renameSession($this->getPT());
02600                 // at this step, PT has been validated and $this->_user has been set,
02601                 
02602                 phpCAS::traceEnd(TRUE);
02603                 return TRUE;
02604                 }
02605         
02608         // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
02609         // XX                                                                    XX
02610         // XX                               MISC                                 XX
02611         // XX                                                                    XX
02612         // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
02613         
02619         // ########################################################################
02620         //  URL
02621         // ########################################################################
02629         var $_url = '';
02630         
02639         function getURL()
02640                 {
02641                 phpCAS::traceBegin();
02642                 // the URL is built when needed only
02643                 if ( empty($this->_url) ) {
02644                         $final_uri = '';
02645                         // remove the ticket if present in the URL
02646                         $final_uri = ($this->isHttps()) ? 'https' : 'http';
02647                         $final_uri .= '://';
02648                         /* replaced by Julien Marchal - v0.4.6
02649                          * $this->_url .= $_SERVER['SERVER_NAME'];
02650                          */
02651                         if(empty($_SERVER['HTTP_X_FORWARDED_SERVER'])){
02652                                 /* replaced by teedog - v0.4.12
02653                                  * $this->_url .= $_SERVER['SERVER_NAME'];
02654                                  */
02655                                 if (empty($_SERVER['SERVER_NAME'])) {
02656                                         $server_name = $_SERVER['HTTP_HOST'];
02657                                 } else {
02658                                         $server_name = $_SERVER['SERVER_NAME'];
02659                                 }
02660                         } else {
02661                                 $server_name = $_SERVER['HTTP_X_FORWARDED_SERVER'];
02662                         }
02663                         $final_uri .= $server_name;
02664                         if (!strpos($server_name, ':')) {
02665                                 if ( ($this->isHttps() && $_SERVER['SERVER_PORT']!=443)
02666                                                 || (!$this->isHttps() && $_SERVER['SERVER_PORT']!=80) ) {
02667                                         $final_uri .= ':';
02668                                         $final_uri .= $_SERVER['SERVER_PORT'];
02669                                 }
02670                         }
02671                         
02672                         $request_uri    = explode('?', $_SERVER['REQUEST_URI'], 2);
02673                         $final_uri              .= $request_uri[0];
02674                         
02675                         if (isset($request_uri[1]) && $request_uri[1])
02676                         {
02677                                 $query_string   = $this->removeParameterFromQueryString('ticket', $request_uri[1]);
02678                                 
02679                                 // If the query string still has anything left, append it to the final URI
02680                                 if ($query_string !== '')
02681                                         $final_uri      .= "?$query_string";
02682                                 
02683                         }
02684                         
02685                         phpCAS::trace("Final URI: $final_uri");
02686                         $this->setURL($final_uri);
02687                 }
02688                 phpCAS::traceEnd($this->_url);
02689                 return $this->_url;
02690         }
02691         
02692 
02693                 
02703         function removeParameterFromQueryString($parameterName, $queryString)
02704         {
02705                 $parameterName  = preg_quote($parameterName);
02706                 return preg_replace("/&$parameterName(=[^&]*)?|^$parameterName(=[^&]*)?&?/", '', $queryString);
02707         }
02708 
02709         
02717         function setURL($url)
02718                 {
02719                 $this->_url = $url;
02720                 }
02721         
02722         // ########################################################################
02723         //  AUTHENTICATION ERROR HANDLING
02724         // ########################################################################
02740         function authError($failure,$cas_url,$no_response,$bad_response='',$cas_response='',$err_code='',$err_msg='')
02741                 {
02742                 phpCAS::traceBegin();
02743                 
02744                 $this->printHTMLHeader($this->getString(CAS_STR_AUTHENTICATION_FAILED));
02745                 printf($this->getString(CAS_STR_YOU_WERE_NOT_AUTHENTICATED),htmlentities($this->getURL()),$_SERVER['SERVER_ADMIN']);
02746                 phpCAS::trace('CAS URL: '.$cas_url);
02747                 phpCAS::trace('Authentication failure: '.$failure);
02748                 if ( $no_response ) {
02749                         phpCAS::trace('Reason: no response from the CAS server');
02750                 } else {
02751                         if ( $bad_response ) {
02752                                 phpCAS::trace('Reason: bad response from the CAS server');
02753                         } else {
02754                                 switch ($this->getServerVersion()) {
02755                                         case CAS_VERSION_1_0:
02756                                                 phpCAS::trace('Reason: CAS error');
02757                                                 break;
02758                                         case CAS_VERSION_2_0:
02759                                                 if ( empty($err_code) )
02760                                                         phpCAS::trace('Reason: no CAS error');
02761                                                 else
02762                                                         phpCAS::trace('Reason: ['.$err_code.'] CAS error: '.$err_msg);
02763                                                 break;
02764                                 }
02765                         }
02766                         phpCAS::trace('CAS response: '.$cas_response);
02767                 }
02768                 $this->printHTMLFooter();
02769                 phpCAS::traceExit();
02770                 exit();
02771                 }
02772         
02774 }
02775 
02776 ?>

Generated on Mon Oct 4 2010 08:11:25 for phpCAS by  doxygen 1.7.1