Search moodle.org's
Developer Documentation

  • Bug fixes for general core bugs in 3.11.x will end 9 May 2022 (12 months).
  • Bug fixes for security issues in 3.11.x will end 14 November 2022 (18 months).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.
  • Differences Between: [Versions 35 and 311] [Versions 36 and 311] [Versions 37 and 311] [Versions 38 and 311]

       1  <?php
       2  
       3  /**
       4   * Licensed to Jasig under one or more contributor license
       5   * agreements. See the NOTICE file distributed with this work for
       6   * additional information regarding copyright ownership.
       7   *
       8   * Jasig licenses this file to you under the Apache License,
       9   * Version 2.0 (the "License"); you may not use this file except in
      10   * compliance with the License. You may obtain a copy of the License at:
      11   *
      12   * http://www.apache.org/licenses/LICENSE-2.0
      13   *
      14   * Unless required by applicable law or agreed to in writing, software
      15   * distributed under the License is distributed on an "AS IS" BASIS,
      16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      17   * See the License for the specific language governing permissions and
      18   * limitations under the License.
      19   *
      20   *
      21   *
      22   * Interface class of the phpCAS library
      23   * PHP Version 5
      24   *
      25   * @file     CAS/CAS.php
      26   * @category Authentication
      27   * @package  PhpCAS
      28   * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>
      29   * @author   Olivier Berger <olivier.berger@it-sudparis.eu>
      30   * @author   Brett Bieber <brett.bieber@gmail.com>
      31   * @author   Joachim Fritschi <jfritschi@freenet.de>
      32   * @author   Adam Franco <afranco@middlebury.edu>
      33   * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
      34   * @link     https://wiki.jasig.org/display/CASC/phpCAS
      35   * @ingroup public
      36   */
      37  
      38  
      39  //
      40  // hack by Vangelis Haniotakis to handle the absence of $_SERVER['REQUEST_URI']
      41  // in IIS
      42  //
      43  if (!isset($_SERVER['REQUEST_URI']) && isset($_SERVER['SCRIPT_NAME']) && isset($_SERVER['QUERY_STRING'])) {
      44      $_SERVER['REQUEST_URI'] = $_SERVER['SCRIPT_NAME'] . '?' . $_SERVER['QUERY_STRING'];
      45  }
      46  
      47  // Add a E_USER_DEPRECATED for php versions <= 5.2
      48  if (!defined('E_USER_DEPRECATED')) {
      49      define('E_USER_DEPRECATED', E_USER_NOTICE);
      50  }
      51  
      52  
      53  // ########################################################################
      54  //  CONSTANTS
      55  // ########################################################################
      56  
      57  // ------------------------------------------------------------------------
      58  //  CAS VERSIONS
      59  // ------------------------------------------------------------------------
      60  
      61  /**
      62   * phpCAS version. accessible for the user by phpCAS::getVersion().
      63   */
      64  define('PHPCAS_VERSION', '1.3.8');
      65  
      66  /**
      67   * @addtogroup public
      68   * @{
      69   */
      70  
      71  /**
      72   * phpCAS supported protocols. accessible for the user by phpCAS::getSupportedProtocols().
      73   */
      74  
      75  /**
      76   * CAS version 1.0
      77   */
      78  define("CAS_VERSION_1_0", '1.0');
      79  /*!
      80   * CAS version 2.0
      81  */
      82  define("CAS_VERSION_2_0", '2.0');
      83  /**
      84   * CAS version 3.0
      85   */
      86  define("CAS_VERSION_3_0", '3.0');
      87  
      88  // ------------------------------------------------------------------------
      89  //  SAML defines
      90  // ------------------------------------------------------------------------
      91  
      92  /**
      93   * SAML protocol
      94   */
      95  define("SAML_VERSION_1_1", 'S1');
      96  
      97  /**
      98   * XML header for SAML POST
      99   */
     100  define("SAML_XML_HEADER", '<?xml version="1.0" encoding="UTF-8"?>');
     101  
     102  /**
     103   * SOAP envelope for SAML POST
     104   */
     105  define("SAML_SOAP_ENV", '<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/>');
     106  
     107  /**
     108   * SOAP body for SAML POST
     109   */
     110  define("SAML_SOAP_BODY", '<SOAP-ENV:Body>');
     111  
     112  /**
     113   * SAMLP request
     114   */
     115  define("SAMLP_REQUEST", '<samlp:Request xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol"  MajorVersion="1" MinorVersion="1" RequestID="_192.168.16.51.1024506224022" IssueInstant="2002-06-19T17:03:44.022Z">');
     116  define("SAMLP_REQUEST_CLOSE", '</samlp:Request>');
     117  
     118  /**
     119   * SAMLP artifact tag (for the ticket)
     120   */
     121  define("SAML_ASSERTION_ARTIFACT", '<samlp:AssertionArtifact>');
     122  
     123  /**
     124   * SAMLP close
     125   */
     126  define("SAML_ASSERTION_ARTIFACT_CLOSE", '</samlp:AssertionArtifact>');
     127  
     128  /**
     129   * SOAP body close
     130   */
     131  define("SAML_SOAP_BODY_CLOSE", '</SOAP-ENV:Body>');
     132  
     133  /**
     134   * SOAP envelope close
     135   */
     136  define("SAML_SOAP_ENV_CLOSE", '</SOAP-ENV:Envelope>');
     137  
     138  /**
     139   * SAML Attributes
     140   */
     141  define("SAML_ATTRIBUTES", 'SAMLATTRIBS');
     142  
     143  /**
     144   * SAML Attributes
     145   */
     146  define("DEFAULT_ERROR", 'Internal script failure');
     147  
     148  /** @} */
     149  /**
     150   * @addtogroup publicPGTStorage
     151   * @{
     152   */
     153  // ------------------------------------------------------------------------
     154  //  FILE PGT STORAGE
     155  // ------------------------------------------------------------------------
     156  /**
     157   * Default path used when storing PGT's to file
     158   */
     159  define("CAS_PGT_STORAGE_FILE_DEFAULT_PATH", session_save_path());
     160  /** @} */
     161  // ------------------------------------------------------------------------
     162  // SERVICE ACCESS ERRORS
     163  // ------------------------------------------------------------------------
     164  /**
     165   * @addtogroup publicServices
     166   * @{
     167   */
     168  
     169  /**
     170   * phpCAS::service() error code on success
     171   */
     172  define("PHPCAS_SERVICE_OK", 0);
     173  /**
     174   * phpCAS::service() error code when the PT could not retrieve because
     175   * the CAS server did not respond.
     176   */
     177  define("PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE", 1);
     178  /**
     179   * phpCAS::service() error code when the PT could not retrieve because
     180   * the response of the CAS server was ill-formed.
     181   */
     182  define("PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE", 2);
     183  /**
     184   * phpCAS::service() error code when the PT could not retrieve because
     185   * the CAS server did not want to.
     186   */
     187  define("PHPCAS_SERVICE_PT_FAILURE", 3);
     188  /**
     189   * phpCAS::service() error code when the service was not available.
     190   */
     191  define("PHPCAS_SERVICE_NOT_AVAILABLE", 4);
     192  
     193  // ------------------------------------------------------------------------
     194  // SERVICE TYPES
     195  // ------------------------------------------------------------------------
     196  /**
     197   * phpCAS::getProxiedService() type for HTTP GET
     198   */
     199  define("PHPCAS_PROXIED_SERVICE_HTTP_GET", 'CAS_ProxiedService_Http_Get');
     200  /**
     201   * phpCAS::getProxiedService() type for HTTP POST
     202   */
     203  define("PHPCAS_PROXIED_SERVICE_HTTP_POST", 'CAS_ProxiedService_Http_Post');
     204  /**
     205   * phpCAS::getProxiedService() type for IMAP
     206   */
     207  define("PHPCAS_PROXIED_SERVICE_IMAP", 'CAS_ProxiedService_Imap');
     208  
     209  
     210  /** @} */
     211  // ------------------------------------------------------------------------
     212  //  LANGUAGES
     213  // ------------------------------------------------------------------------
     214  /**
     215   * @addtogroup publicLang
     216   * @{
     217   */
     218  
     219  define("PHPCAS_LANG_ENGLISH", 'CAS_Languages_English');
     220  define("PHPCAS_LANG_FRENCH", 'CAS_Languages_French');
     221  define("PHPCAS_LANG_GREEK", 'CAS_Languages_Greek');
     222  define("PHPCAS_LANG_GERMAN", 'CAS_Languages_German');
     223  define("PHPCAS_LANG_JAPANESE", 'CAS_Languages_Japanese');
     224  define("PHPCAS_LANG_SPANISH", 'CAS_Languages_Spanish');
     225  define("PHPCAS_LANG_CATALAN", 'CAS_Languages_Catalan');
     226  define("PHPCAS_LANG_CHINESE_SIMPLIFIED", 'CAS_Languages_ChineseSimplified');
     227  
     228  /** @} */
     229  
     230  /**
     231   * @addtogroup internalLang
     232   * @{
     233   */
     234  
     235  /**
     236   * phpCAS default language (when phpCAS::setLang() is not used)
     237   */
     238  define("PHPCAS_LANG_DEFAULT", PHPCAS_LANG_ENGLISH);
     239  
     240  /** @} */
     241  // ------------------------------------------------------------------------
     242  //  DEBUG
     243  // ------------------------------------------------------------------------
     244  /**
     245   * @addtogroup publicDebug
     246   * @{
     247   */
     248  
     249  /**
     250   * The default directory for the debug file under Unix.
     251   * @return  string directory for the debug file
     252   */
     253  function gettmpdir() {
     254  if (!empty($_ENV['TMP'])) { return realpath($_ENV['TMP']); }
     255  if (!empty($_ENV['TMPDIR'])) { return realpath( $_ENV['TMPDIR']); }
     256  if (!empty($_ENV['TEMP'])) { return realpath( $_ENV['TEMP']); }
     257  return "/tmp";
     258  }
     259  define('DEFAULT_DEBUG_DIR', gettmpdir()."/");
     260  
     261  /** @} */
     262  
     263  // include the class autoloader
     264  require_once dirname(__FILE__) . '/CAS/Autoload.php';
     265  
     266  /**
     267   * The phpCAS class is a simple container for the phpCAS library. It provides CAS
     268   * authentication for web applications written in PHP.
     269   *
     270   * @ingroup public
     271   * @class phpCAS
     272   * @category Authentication
     273   * @package  PhpCAS
     274   * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>
     275   * @author   Olivier Berger <olivier.berger@it-sudparis.eu>
     276   * @author   Brett Bieber <brett.bieber@gmail.com>
     277   * @author   Joachim Fritschi <jfritschi@freenet.de>
     278   * @author   Adam Franco <afranco@middlebury.edu>
     279   * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
     280   * @link     https://wiki.jasig.org/display/CASC/phpCAS
     281   */
     282  
     283  class phpCAS
     284  {
     285  
     286      /**
     287       * This variable is used by the interface class phpCAS.
     288       *
     289       * @var CAS_Client
     290       * @hideinitializer
     291       */
     292      private static $_PHPCAS_CLIENT;
     293  
     294      /**
     295       * @var array
     296       * This variable is used to store where the initializer is called from
     297       * (to print a comprehensive error in case of multiple calls).
     298       *
     299       * @hideinitializer
     300       */
     301      private static $_PHPCAS_INIT_CALL;
     302  
     303      /**
     304       * @var array
     305       * This variable is used to store phpCAS debug mode.
     306       *
     307       * @hideinitializer
     308       */
     309      private static $_PHPCAS_DEBUG;
     310  
     311      /**
     312       * This variable is used to enable verbose mode
     313       * This pevents debug info to be show to the user. Since it's a security
     314       * feature the default is false
     315       *
     316       * @hideinitializer
     317       */
     318      private static $_PHPCAS_VERBOSE = false;
     319  
     320  
     321      // ########################################################################
     322      //  INITIALIZATION
     323      // ########################################################################
     324  
     325      /**
     326       * @addtogroup publicInit
     327       * @{
     328       */
     329  
     330      /**
     331       * phpCAS client initializer.
     332       *
     333       * @param string $server_version  the version of the CAS server
     334       * @param string $server_hostname the hostname of the CAS server
     335       * @param int    $server_port     the port the CAS server is running on
     336       * @param string $server_uri      the URI the CAS server is responding on
     337       * @param bool   $changeSessionID Allow phpCAS to change the session_id (Single
     338       * Sign Out/handleLogoutRequests is based on that change)
     339       *
     340       * @return void a newly created CAS_Client object
     341       * @note Only one of the phpCAS::client() and phpCAS::proxy functions should be
     342       * called, only once, and before all other methods (except phpCAS::getVersion()
     343       * and phpCAS::setDebug()).
     344       */
     345      public static function client($server_version, $server_hostname,
     346          $server_port, $server_uri, $changeSessionID = true
     347      ) {
     348          phpCAS :: traceBegin();
     349          if (is_object(self::$_PHPCAS_CLIENT)) {
     350              phpCAS :: error(self::$_PHPCAS_INIT_CALL['method'] . '() has already been called (at ' . self::$_PHPCAS_INIT_CALL['file'] . ':' . self::$_PHPCAS_INIT_CALL['line'] . ')');
     351          }
     352  
     353          // store where the initializer is called from
     354          $dbg = debug_backtrace();
     355          self::$_PHPCAS_INIT_CALL = array (
     356              'done' => true,
     357              'file' => $dbg[0]['file'],
     358              'line' => $dbg[0]['line'],
     359              'method' => __CLASS__ . '::' . __FUNCTION__
     360          );
     361  
     362          // initialize the object $_PHPCAS_CLIENT
     363          try {
     364              self::$_PHPCAS_CLIENT = new CAS_Client(
     365                  $server_version, false, $server_hostname, $server_port, $server_uri,
     366                  $changeSessionID
     367              );
     368          } catch (Exception $e) {
     369              phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
     370          }
     371          phpCAS :: traceEnd();
     372      }
     373  
     374      /**
     375       * phpCAS proxy initializer.
     376       *
     377       * @param string $server_version  the version of the CAS server
     378       * @param string $server_hostname the hostname of the CAS server
     379       * @param int    $server_port     the port the CAS server is running on
     380       * @param string $server_uri      the URI the CAS server is responding on
     381       * @param bool   $changeSessionID Allow phpCAS to change the session_id (Single
     382       * Sign Out/handleLogoutRequests is based on that change)
     383       *
     384       * @return void a newly created CAS_Client object
     385       * @note Only one of the phpCAS::client() and phpCAS::proxy functions should be
     386       * called, only once, and before all other methods (except phpCAS::getVersion()
     387       * and phpCAS::setDebug()).
     388       */
     389      public static function proxy($server_version, $server_hostname,
     390          $server_port, $server_uri, $changeSessionID = true
     391      ) {
     392          phpCAS :: traceBegin();
     393          if (is_object(self::$_PHPCAS_CLIENT)) {
     394              phpCAS :: error(self::$_PHPCAS_INIT_CALL['method'] . '() has already been called (at ' . self::$_PHPCAS_INIT_CALL['file'] . ':' . self::$_PHPCAS_INIT_CALL['line'] . ')');
     395          }
     396  
     397          // store where the initialzer is called from
     398          $dbg = debug_backtrace();
     399          self::$_PHPCAS_INIT_CALL = array (
     400              'done' => true,
     401              'file' => $dbg[0]['file'],
     402              'line' => $dbg[0]['line'],
     403              'method' => __CLASS__ . '::' . __FUNCTION__
     404          );
     405  
     406          // initialize the object $_PHPCAS_CLIENT
     407          try {
     408              self::$_PHPCAS_CLIENT = new CAS_Client(
     409                  $server_version, true, $server_hostname, $server_port, $server_uri,
     410                  $changeSessionID
     411              );
     412          } catch (Exception $e) {
     413              phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
     414          }
     415          phpCAS :: traceEnd();
     416      }
     417  
     418      /**
     419       * Answer whether or not the client or proxy has been initialized
     420       *
     421       * @return bool
     422       */
     423      public static function isInitialized ()
     424      {
     425          return (is_object(self::$_PHPCAS_CLIENT));
     426      }
     427  
     428      /** @} */
     429      // ########################################################################
     430      //  DEBUGGING
     431      // ########################################################################
     432  
     433      /**
     434       * @addtogroup publicDebug
     435       * @{
     436       */
     437  
     438      /**
     439       * Set/unset debug mode
     440       *
     441       * @param string $filename the name of the file used for logging, or false
     442       * to stop debugging.
     443       *
     444       * @return void
     445       */
     446      public static function setDebug($filename = '')
     447      {
     448          if ($filename != false && gettype($filename) != 'string') {
     449              phpCAS :: error('type mismatched for parameter $dbg (should be false or the name of the log file)');
     450          }
     451          if ($filename === false) {
     452              self::$_PHPCAS_DEBUG['filename'] = false;
     453  
     454          } else {
     455              if (empty ($filename)) {
     456                  if (preg_match('/^Win.*/', getenv('OS'))) {
     457                      if (isset ($_ENV['TMP'])) {
     458                          $debugDir = $_ENV['TMP'] . '/';
     459                      } else {
     460                          $debugDir = '';
     461                      }
     462                  } else {
     463                      $debugDir = DEFAULT_DEBUG_DIR;
     464                  }
     465                  $filename = $debugDir . 'phpCAS.log';
     466              }
     467  
     468              if (empty (self::$_PHPCAS_DEBUG['unique_id'])) {
     469                  self::$_PHPCAS_DEBUG['unique_id'] = substr(strtoupper(md5(uniqid(''))), 0, 4);
     470              }
     471  
     472              self::$_PHPCAS_DEBUG['filename'] = $filename;
     473              self::$_PHPCAS_DEBUG['indent'] = 0;
     474  
     475              phpCAS :: trace('START ('.date("Y-m-d H:i:s").') phpCAS-' . PHPCAS_VERSION . ' ******************');
     476          }
     477      }
     478  
     479      /**
     480       * Enable verbose errors messages in the website output
     481       * This is a security relevant since internal status info may leak an may
     482       * help an attacker. Default is therefore false
     483       *
     484       * @param bool $verbose enable verbose output
     485       *
     486       * @return void
     487       */
     488      public static function setVerbose($verbose)
     489      {
     490          if ($verbose === true) {
     491              self::$_PHPCAS_VERBOSE = true;
     492          } else {
     493              self::$_PHPCAS_VERBOSE = false;
     494          }
     495      }
     496  
     497  
     498      /**
     499       * Show is verbose mode is on
     500       *
     501       * @return bool verbose
     502       */
     503      public static function getVerbose()
     504      {
     505          return self::$_PHPCAS_VERBOSE;
     506      }
     507  
     508      /**
     509       * Logs a string in debug mode.
     510       *
     511       * @param string $str the string to write
     512       *
     513       * @return void
     514       * @private
     515       */
     516      public static function log($str)
     517      {
     518          $indent_str = ".";
     519  
     520  
     521          if (!empty(self::$_PHPCAS_DEBUG['filename'])) {
     522              // Check if file exists and modifiy file permissions to be only
     523              // readable by the webserver
     524              if (!file_exists(self::$_PHPCAS_DEBUG['filename'])) {
     525                  touch(self::$_PHPCAS_DEBUG['filename']);
     526                  // Chmod will fail on windows
     527                  @chmod(self::$_PHPCAS_DEBUG['filename'], 0600);
     528              }
     529              for ($i = 0; $i < self::$_PHPCAS_DEBUG['indent']; $i++) {
     530  
     531                  $indent_str .= '|    ';
     532              }
     533              // allow for multiline output with proper identing. Usefull for
     534              // dumping cas answers etc.
     535              $str2 = str_replace("\n", "\n" . self::$_PHPCAS_DEBUG['unique_id'] . ' ' . $indent_str, $str);
     536              error_log(self::$_PHPCAS_DEBUG['unique_id'] . ' ' . $indent_str . $str2 . "\n", 3, self::$_PHPCAS_DEBUG['filename']);
     537          }
     538  
     539      }
     540  
     541      /**
     542       * This method is used by interface methods to print an error and where the
     543       * function was originally called from.
     544       *
     545       * @param string $msg the message to print
     546       *
     547       * @return void
     548       * @private
     549       */
     550      public static function error($msg)
     551      {
     552          phpCAS :: traceBegin();
     553          $dbg = debug_backtrace();
     554          $function = '?';
     555          $file = '?';
     556          $line = '?';
     557          if (is_array($dbg)) {
     558              for ($i = 1; $i < sizeof($dbg); $i++) {
     559                  if (is_array($dbg[$i]) && isset($dbg[$i]['class']) ) {
     560                      if ($dbg[$i]['class'] == __CLASS__) {
     561                          $function = $dbg[$i]['function'];
     562                          $file = $dbg[$i]['file'];
     563                          $line = $dbg[$i]['line'];
     564                      }
     565                  }
     566              }
     567          }
     568          if (self::$_PHPCAS_VERBOSE) {
     569              echo "<br />\n<b>phpCAS error</b>: <font color=\"FF0000\"><b>" . __CLASS__ . "::" . $function . '(): ' . htmlentities($msg) . "</b></font> in <b>" . $file . "</b> on line <b>" . $line . "</b><br />\n";
     570          } else {
     571              echo "<br />\n<b>Error</b>: <font color=\"FF0000\"><b>". DEFAULT_ERROR ."</b><br />\n";
     572          }
     573          phpCAS :: trace($msg . ' in ' . $file . 'on line ' . $line );
     574          phpCAS :: traceEnd();
     575  
     576          throw new CAS_GracefullTerminationException(__CLASS__ . "::" . $function . '(): ' . $msg);
     577      }
     578  
     579      /**
     580       * This method is used to log something in debug mode.
     581       *
     582       * @param string $str string to log
     583       *
     584       * @return void
     585       */
     586      public static function trace($str)
     587      {
     588          $dbg = debug_backtrace();
     589          phpCAS :: log($str . ' [' . basename($dbg[0]['file']) . ':' . $dbg[0]['line'] . ']');
     590      }
     591  
     592      /**
     593       * This method is used to indicate the start of the execution of a function
     594       * in debug mode.
     595       *
     596       * @return void
     597       */
     598      public static function traceBegin()
     599      {
     600          $dbg = debug_backtrace();
     601          $str = '=> ';
     602          if (!empty ($dbg[1]['class'])) {
     603              $str .= $dbg[1]['class'] . '::';
     604          }
     605          $str .= $dbg[1]['function'] . '(';
     606          if (is_array($dbg[1]['args'])) {
     607              foreach ($dbg[1]['args'] as $index => $arg) {
     608                  if ($index != 0) {
     609                      $str .= ', ';
     610                  }
     611                  if (is_object($arg)) {
     612                      $str .= get_class($arg);
     613                  } else {
     614                      $str .= str_replace(array("\r\n", "\n", "\r"), "", var_export($arg, true));
     615                  }
     616              }
     617          }
     618          if (isset($dbg[1]['file'])) {
     619              $file = basename($dbg[1]['file']);
     620          } else {
     621              $file = 'unknown_file';
     622          }
     623          if (isset($dbg[1]['line'])) {
     624              $line = $dbg[1]['line'];
     625          } else {
     626              $line = 'unknown_line';
     627          }
     628          $str .= ') [' . $file . ':' . $line . ']';
     629          phpCAS :: log($str);
     630          if (!isset(self::$_PHPCAS_DEBUG['indent'])) {
     631              self::$_PHPCAS_DEBUG['indent'] = 0;
     632          } else {
     633              self::$_PHPCAS_DEBUG['indent']++;
     634          }
     635      }
     636  
     637      /**
     638       * This method is used to indicate the end of the execution of a function in
     639       * debug mode.
     640       *
     641       * @param mixed $res the result of the function
     642       *
     643       * @return void
     644       */
     645      public static function traceEnd($res = '')
     646      {
     647          if (empty(self::$_PHPCAS_DEBUG['indent'])) {
     648              self::$_PHPCAS_DEBUG['indent'] = 0;
     649          } else {
     650              self::$_PHPCAS_DEBUG['indent']--;
     651          }
     652          $str = '';
     653          if (is_object($res)) {
     654              $str .= '<= ' . get_class($res);
     655          } else {
     656              $str .= '<= ' . str_replace(array("\r\n", "\n", "\r"), "", var_export($res, true));
     657          }
     658  
     659          phpCAS :: log($str);
     660      }
     661  
     662      /**
     663       * This method is used to indicate the end of the execution of the program
     664       *
     665       * @return void
     666       */
     667      public static function traceExit()
     668      {
     669          phpCAS :: log('exit()');
     670          while (self::$_PHPCAS_DEBUG['indent'] > 0) {
     671              phpCAS :: log('-');
     672              self::$_PHPCAS_DEBUG['indent']--;
     673          }
     674      }
     675  
     676      /** @} */
     677      // ########################################################################
     678      //  INTERNATIONALIZATION
     679      // ########################################################################
     680      /**
     681      * @addtogroup publicLang
     682      * @{
     683      */
     684  
     685      /**
     686       * This method is used to set the language used by phpCAS.
     687       *
     688       * @param string $lang string representing the language.
     689       *
     690       * @return void
     691       *
     692       * @sa PHPCAS_LANG_FRENCH, PHPCAS_LANG_ENGLISH
     693       * @note Can be called only once.
     694       */
     695      public static function setLang($lang)
     696      {
     697          phpCAS::_validateClientExists();
     698  
     699          try {
     700              self::$_PHPCAS_CLIENT->setLang($lang);
     701          } catch (Exception $e) {
     702              phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
     703          }
     704      }
     705  
     706      /** @} */
     707      // ########################################################################
     708      //  VERSION
     709      // ########################################################################
     710      /**
     711      * @addtogroup public
     712      * @{
     713      */
     714  
     715      /**
     716       * This method returns the phpCAS version.
     717       *
     718       * @return string the phpCAS version.
     719       */
     720      public static function getVersion()
     721      {
     722          return PHPCAS_VERSION;
     723      }
     724  
     725      /**
     726       * This method returns supported protocols.
     727       *
     728       * @return array an array of all supported protocols. Use internal protocol name as array key.
     729       */
     730      public static function getSupportedProtocols()
     731      {
     732          $supportedProtocols = array();
     733          $supportedProtocols[CAS_VERSION_1_0] = 'CAS 1.0';
     734          $supportedProtocols[CAS_VERSION_2_0] = 'CAS 2.0';
     735          $supportedProtocols[CAS_VERSION_3_0] = 'CAS 3.0';
     736          $supportedProtocols[SAML_VERSION_1_1] = 'SAML 1.1';
     737  
     738          return $supportedProtocols;
     739      }
     740  
     741      /** @} */
     742      // ########################################################################
     743      //  HTML OUTPUT
     744      // ########################################################################
     745      /**
     746      * @addtogroup publicOutput
     747      * @{
     748      */
     749  
     750      /**
     751       * This method sets the HTML header used for all outputs.
     752       *
     753       * @param string $header the HTML header.
     754       *
     755       * @return void
     756       */
     757      public static function setHTMLHeader($header)
     758      {
     759          phpCAS::_validateClientExists();
     760  
     761          try {
     762              self::$_PHPCAS_CLIENT->setHTMLHeader($header);
     763          } catch (Exception $e) {
     764              phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
     765          }
     766      }
     767  
     768      /**
     769       * This method sets the HTML footer used for all outputs.
     770       *
     771       * @param string $footer the HTML footer.
     772       *
     773       * @return void
     774       */
     775      public static function setHTMLFooter($footer)
     776      {
     777          phpCAS::_validateClientExists();
     778  
     779          try {
     780              self::$_PHPCAS_CLIENT->setHTMLFooter($footer);
     781          } catch (Exception $e) {
     782              phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
     783          }
     784      }
     785  
     786      /** @} */
     787      // ########################################################################
     788      //  PGT STORAGE
     789      // ########################################################################
     790      /**
     791      * @addtogroup publicPGTStorage
     792      * @{
     793      */
     794  
     795      /**
     796       * This method can be used to set a custom PGT storage object.
     797       *
     798       * @param CAS_PGTStorage_AbstractStorage $storage a PGT storage object that inherits from the
     799       * CAS_PGTStorage_AbstractStorage class
     800       *
     801       * @return void
     802       */
     803      public static function setPGTStorage($storage)
     804      {
     805          phpCAS :: traceBegin();
     806          phpCAS::_validateProxyExists();
     807  
     808          try {
     809              self::$_PHPCAS_CLIENT->setPGTStorage($storage);
     810          } catch (Exception $e) {
     811              phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
     812          }
     813          phpCAS :: traceEnd();
     814      }
     815  
     816      /**
     817       * This method is used to tell phpCAS to store the response of the
     818       * CAS server to PGT requests in a database.
     819       *
     820       * @param string $dsn_or_pdo     a dsn string to use for creating a PDO
     821       * object or a PDO object
     822       * @param string $username       the username to use when connecting to the
     823       * database
     824       * @param string $password       the password to use when connecting to the
     825       * database
     826       * @param string $table          the table to use for storing and retrieving
     827       * PGT's
     828       * @param string $driver_options any driver options to use when connecting
     829       * to the database
     830       *
     831       * @return void
     832       */
     833      public static function setPGTStorageDb($dsn_or_pdo, $username='',
     834          $password='', $table='', $driver_options=null
     835      ) {
     836          phpCAS :: traceBegin();
     837          phpCAS::_validateProxyExists();
     838  
     839          try {
     840              self::$_PHPCAS_CLIENT->setPGTStorageDb($dsn_or_pdo, $username, $password, $table, $driver_options);
     841          } catch (Exception $e) {
     842              phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
     843          }
     844          phpCAS :: traceEnd();
     845      }
     846  
     847      /**
     848       * This method is used to tell phpCAS to store the response of the
     849       * CAS server to PGT requests onto the filesystem.
     850       *
     851       * @param string $path the path where the PGT's should be stored
     852       *
     853       * @return void
     854       */
     855      public static function setPGTStorageFile($path = '')
     856      {
     857          phpCAS :: traceBegin();
     858          phpCAS::_validateProxyExists();
     859  
     860          try {
     861              self::$_PHPCAS_CLIENT->setPGTStorageFile($path);
     862          } catch (Exception $e) {
     863              phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
     864          }
     865          phpCAS :: traceEnd();
     866      }
     867      /** @} */
     868      // ########################################################################
     869      // ACCESS TO EXTERNAL SERVICES
     870      // ########################################################################
     871      /**
     872      * @addtogroup publicServices
     873      * @{
     874      */
     875  
     876      /**
     877       * Answer a proxy-authenticated service handler.
     878       *
     879       * @param string $type The service type. One of
     880       * PHPCAS_PROXIED_SERVICE_HTTP_GET; PHPCAS_PROXIED_SERVICE_HTTP_POST;
     881       * PHPCAS_PROXIED_SERVICE_IMAP
     882       *
     883       * @return CAS_ProxiedService
     884       * @throws InvalidArgumentException If the service type is unknown.
     885       */
     886      public static function getProxiedService ($type)
     887      {
     888          phpCAS :: traceBegin();
     889          phpCAS::_validateProxyExists();
     890  
     891          try {
     892              $res = self::$_PHPCAS_CLIENT->getProxiedService($type);
     893          } catch (Exception $e) {
     894              phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
     895          }
     896  
     897          phpCAS :: traceEnd();
     898          return $res;
     899      }
     900  
     901      /**
     902       * Initialize a proxied-service handler with the proxy-ticket it should use.
     903       *
     904       * @param CAS_ProxiedService $proxiedService Proxied Service Handler
     905       *
     906       * @return void
     907       * @throws CAS_ProxyTicketException If there is a proxy-ticket failure.
     908       *	 	 The code of the Exception will be one of:
     909       *	 	 	 PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE
     910       *	 	 	 PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE
     911       *	 	 	 PHPCAS_SERVICE_PT_FAILURE
     912       */
     913      public static function initializeProxiedService (CAS_ProxiedService $proxiedService)
     914      {
     915          phpCAS::_validateProxyExists();
     916  
     917          try {
     918              self::$_PHPCAS_CLIENT->initializeProxiedService($proxiedService);
     919          } catch (Exception $e) {
     920              phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
     921          }
     922      }
     923  
     924      /**
     925       * This method is used to access an HTTP[S] service.
     926       *
     927       * @param string $url       the service to access.
     928       * @param int &$err_code an error code Possible values are
     929       * PHPCAS_SERVICE_OK (on success), PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE,
     930       * PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE, PHPCAS_SERVICE_PT_FAILURE,
     931       * PHPCAS_SERVICE_NOT_AVAILABLE.
     932       * @param string &$output   the output of the service (also used to give an
     933       * error message on failure).
     934       *
     935       * @return bool true on success, false otherwise (in this later case,
     936       * $err_code gives the reason why it failed and $output contains an error
     937       * message).
     938       */
     939      public static function serviceWeb($url, & $err_code, & $output)
     940      {
     941          phpCAS :: traceBegin();
     942          phpCAS::_validateProxyExists();
     943  
     944          try {
     945              $res = self::$_PHPCAS_CLIENT->serviceWeb($url, $err_code, $output);
     946          } catch (Exception $e) {
     947              phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
     948          }
     949  
     950          phpCAS :: traceEnd($res);
     951          return $res;
     952      }
     953  
     954      /**
     955       * This method is used to access an IMAP/POP3/NNTP service.
     956       *
     957       * @param string $url       a string giving the URL of the service,
     958       * including the mailing box for IMAP URLs, as accepted by imap_open().
     959       * @param string $service   a string giving for CAS retrieve Proxy ticket
     960       * @param string $flags     options given to imap_open().
     961       * @param int &$err_code an error code Possible values are
     962       * PHPCAS_SERVICE_OK (on success), PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE,
     963       * PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE, PHPCAS_SERVICE_PT_FAILURE,
     964       * PHPCAS_SERVICE_NOT_AVAILABLE.
     965       * @param string &$err_msg  an error message on failure
     966       * @param string &$pt       the Proxy Ticket (PT) retrieved from the CAS
     967       * server to access the URL on success, false on error).
     968       *
     969       * @return object|false IMAP stream on success, false otherwise (in this later
     970       * case, $err_code gives the reason why it failed and $err_msg contains an
     971       * error message).
     972       */
     973      public static function serviceMail($url, $service, $flags, & $err_code, & $err_msg, & $pt)
     974      {
     975          phpCAS :: traceBegin();
     976          phpCAS::_validateProxyExists();
     977  
     978          try {
     979              $res = self::$_PHPCAS_CLIENT->serviceMail($url, $service, $flags, $err_code, $err_msg, $pt);
     980          } catch (Exception $e) {
     981              phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
     982          }
     983  
     984          phpCAS :: traceEnd($res);
     985          return $res;
     986      }
     987  
     988      /** @} */
     989      // ########################################################################
     990      //  AUTHENTICATION
     991      // ########################################################################
     992      /**
     993      * @addtogroup publicAuth
     994      * @{
     995      */
     996  
     997      /**
     998       * Set the times authentication will be cached before really accessing the
     999       * CAS server in gateway mode:
    1000       * - -1: check only once, and then never again (until you pree login)
    1001       * - 0: always check
    1002       * - n: check every "n" time
    1003       *
    1004       * @param int $n an integer.
    1005       *
    1006       * @return void
    1007       */
    1008      public static function setCacheTimesForAuthRecheck($n)
    1009      {
    1010          phpCAS::_validateClientExists();
    1011  
    1012          try {
    1013              self::$_PHPCAS_CLIENT->setCacheTimesForAuthRecheck($n);
    1014          } catch (Exception $e) {
    1015              phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
    1016          }
    1017      }
    1018  
    1019  
    1020      /**
    1021       * Set a callback function to be run when receiving CAS attributes
    1022       *
    1023       * The callback function will be passed an $success_elements
    1024       * payload of the response (\DOMElement) as its first parameter.
    1025       *
    1026       * @param string $function       Callback function
    1027       * @param array  $additionalArgs optional array of arguments
    1028       *
    1029       * @return void
    1030       */
    1031      public static function setCasAttributeParserCallback($function, array $additionalArgs = array())
    1032      {
    1033          phpCAS::_validateClientExists();
    1034  
    1035          self::$_PHPCAS_CLIENT->setCasAttributeParserCallback($function, $additionalArgs);
    1036      }
    1037  
    1038      /**
    1039       * Set a callback function to be run when a user authenticates.
    1040       *
    1041       * The callback function will be passed a $logoutTicket as its first
    1042       * parameter, followed by any $additionalArgs you pass. The $logoutTicket
    1043       * parameter is an opaque string that can be used to map the session-id to
    1044       * logout request in order to support single-signout in applications that
    1045       * manage their own sessions (rather than letting phpCAS start the session).
    1046       *
    1047       * phpCAS::forceAuthentication() will always exit and forward client unless
    1048       * they are already authenticated. To perform an action at the moment the user
    1049       * logs in (such as registering an account, performing logging, etc), register
    1050       * a callback function here.
    1051       *
    1052       * @param callable $function       Callback function
    1053       * @param array  $additionalArgs optional array of arguments
    1054       *
    1055       * @return void
    1056       */
    1057      public static function setPostAuthenticateCallback ($function, array $additionalArgs = array())
    1058      {
    1059          phpCAS::_validateClientExists();
    1060  
    1061          self::$_PHPCAS_CLIENT->setPostAuthenticateCallback($function, $additionalArgs);
    1062      }
    1063  
    1064      /**
    1065       * Set a callback function to be run when a single-signout request is
    1066       * received. The callback function will be passed a $logoutTicket as its
    1067       * first parameter, followed by any $additionalArgs you pass. The
    1068       * $logoutTicket parameter is an opaque string that can be used to map a
    1069       * session-id to the logout request in order to support single-signout in
    1070       * applications that manage their own sessions (rather than letting phpCAS
    1071       * start and destroy the session).
    1072       *
    1073       * @param callable $function       Callback function
    1074       * @param array  $additionalArgs optional array of arguments
    1075       *
    1076       * @return void
    1077       */
    1078      public static function setSingleSignoutCallback ($function, array $additionalArgs = array())
    1079      {
    1080          phpCAS::_validateClientExists();
    1081  
    1082          self::$_PHPCAS_CLIENT->setSingleSignoutCallback($function, $additionalArgs);
    1083      }
    1084  
    1085      /**
    1086       * This method is called to check if the user is already authenticated
    1087       * locally or has a global cas session. A already existing cas session is
    1088       * determined by a cas gateway call.(cas login call without any interactive
    1089       * prompt)
    1090       *
    1091       * @return bool true when the user is authenticated, false when a previous
    1092       * gateway login failed or the function will not return if the user is
    1093       * redirected to the cas server for a gateway login attempt
    1094       */
    1095      public static function checkAuthentication()
    1096      {
    1097          phpCAS :: traceBegin();
    1098          phpCAS::_validateClientExists();
    1099  
    1100          $auth = self::$_PHPCAS_CLIENT->checkAuthentication();
    1101  
    1102          // store where the authentication has been checked and the result
    1103          self::$_PHPCAS_CLIENT->markAuthenticationCall($auth);
    1104  
    1105          phpCAS :: traceEnd($auth);
    1106          return $auth;
    1107      }
    1108  
    1109      /**
    1110       * This method is called to force authentication if the user was not already
    1111       * authenticated. If the user is not authenticated, halt by redirecting to
    1112       * the CAS server.
    1113       *
    1114       * @return bool Authentication
    1115       */
    1116      public static function forceAuthentication()
    1117      {
    1118          phpCAS :: traceBegin();
    1119          phpCAS::_validateClientExists();
    1120          $auth = self::$_PHPCAS_CLIENT->forceAuthentication();
    1121  
    1122          // store where the authentication has been checked and the result
    1123          self::$_PHPCAS_CLIENT->markAuthenticationCall($auth);
    1124  
    1125          /*      if (!$auth) {
    1126           phpCAS :: trace('user is not authenticated, redirecting to the CAS server');
    1127          self::$_PHPCAS_CLIENT->forceAuthentication();
    1128          } else {
    1129          phpCAS :: trace('no need to authenticate (user `' . phpCAS :: getUser() . '\' is already authenticated)');
    1130          }*/
    1131  
    1132          phpCAS :: traceEnd();
    1133          return $auth;
    1134      }
    1135  
    1136      /**
    1137       * This method is called to renew the authentication.
    1138       *
    1139       * @return void
    1140       **/
    1141      public static function renewAuthentication()
    1142      {
    1143          phpCAS :: traceBegin();
    1144          phpCAS::_validateClientExists();
    1145  
    1146          $auth = self::$_PHPCAS_CLIENT->renewAuthentication();
    1147  
    1148          // store where the authentication has been checked and the result
    1149          self::$_PHPCAS_CLIENT->markAuthenticationCall($auth);
    1150  
    1151          //self::$_PHPCAS_CLIENT->renewAuthentication();
    1152          phpCAS :: traceEnd();
    1153      }
    1154  
    1155      /**
    1156       * This method is called to check if the user is authenticated (previously or by
    1157       * tickets given in the URL).
    1158       *
    1159       * @return bool true when the user is authenticated.
    1160       */
    1161      public static function isAuthenticated()
    1162      {
    1163          phpCAS :: traceBegin();
    1164          phpCAS::_validateClientExists();
    1165  
    1166          // call the isAuthenticated method of the $_PHPCAS_CLIENT object
    1167          $auth = self::$_PHPCAS_CLIENT->isAuthenticated();
    1168  
    1169          // store where the authentication has been checked and the result
    1170          self::$_PHPCAS_CLIENT->markAuthenticationCall($auth);
    1171  
    1172          phpCAS :: traceEnd($auth);
    1173          return $auth;
    1174      }
    1175  
    1176      /**
    1177       * Checks whether authenticated based on $_SESSION. Useful to avoid
    1178       * server calls.
    1179       *
    1180       * @return bool true if authenticated, false otherwise.
    1181       * @since 0.4.22 by Brendan Arnold
    1182       */
    1183      public static function isSessionAuthenticated()
    1184      {
    1185          phpCAS::_validateClientExists();
    1186  
    1187          return (self::$_PHPCAS_CLIENT->isSessionAuthenticated());
    1188      }
    1189  
    1190      /**
    1191       * This method returns the CAS user's login name.
    1192       *
    1193       * @return string the login name of the authenticated user
    1194       * @warning should only be called after phpCAS::forceAuthentication()
    1195       * or phpCAS::checkAuthentication().
    1196       * */
    1197      public static function getUser()
    1198      {
    1199          phpCAS::_validateClientExists();
    1200  
    1201          try {
    1202              return self::$_PHPCAS_CLIENT->getUser();
    1203          } catch (Exception $e) {
    1204              phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
    1205          }
    1206      }
    1207  
    1208      /**
    1209       * Answer attributes about the authenticated user.
    1210       *
    1211       * @warning should only be called after phpCAS::forceAuthentication()
    1212       * or phpCAS::checkAuthentication().
    1213       *
    1214       * @return array
    1215       */
    1216      public static function getAttributes()
    1217      {
    1218          phpCAS::_validateClientExists();
    1219  
    1220          try {
    1221              return self::$_PHPCAS_CLIENT->getAttributes();
    1222          } catch (Exception $e) {
    1223              phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
    1224          }
    1225      }
    1226  
    1227      /**
    1228       * Answer true if there are attributes for the authenticated user.
    1229       *
    1230       * @warning should only be called after phpCAS::forceAuthentication()
    1231       * or phpCAS::checkAuthentication().
    1232       *
    1233       * @return bool
    1234       */
    1235      public static function hasAttributes()
    1236      {
    1237          phpCAS::_validateClientExists();
    1238  
    1239          try {
    1240              return self::$_PHPCAS_CLIENT->hasAttributes();
    1241          } catch (Exception $e) {
    1242              phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
    1243          }
    1244      }
    1245  
    1246      /**
    1247       * Answer true if an attribute exists for the authenticated user.
    1248       *
    1249       * @param string $key attribute name
    1250       *
    1251       * @return bool
    1252       * @warning should only be called after phpCAS::forceAuthentication()
    1253       * or phpCAS::checkAuthentication().
    1254       */
    1255      public static function hasAttribute($key)
    1256      {
    1257          phpCAS::_validateClientExists();
    1258  
    1259          try {
    1260              return self::$_PHPCAS_CLIENT->hasAttribute($key);
    1261          } catch (Exception $e) {
    1262              phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
    1263          }
    1264      }
    1265  
    1266      /**
    1267       * Answer an attribute for the authenticated user.
    1268       *
    1269       * @param string $key attribute name
    1270       *
    1271       * @return mixed string for a single value or an array if multiple values exist.
    1272       * @warning should only be called after phpCAS::forceAuthentication()
    1273       * or phpCAS::checkAuthentication().
    1274       */
    1275      public static function getAttribute($key)
    1276      {
    1277          phpCAS::_validateClientExists();
    1278  
    1279          try {
    1280              return self::$_PHPCAS_CLIENT->getAttribute($key);
    1281          } catch (Exception $e) {
    1282              phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
    1283          }
    1284      }
    1285  
    1286      /**
    1287       * Handle logout requests.
    1288       *
    1289       * @param bool  $check_client    additional safety check
    1290       * @param array $allowed_clients array of allowed clients
    1291       *
    1292       * @return void
    1293       */
    1294      public static function handleLogoutRequests($check_client = true, $allowed_clients = array())
    1295      {
    1296          phpCAS::_validateClientExists();
    1297  
    1298          return (self::$_PHPCAS_CLIENT->handleLogoutRequests($check_client, $allowed_clients));
    1299      }
    1300  
    1301      /**
    1302       * This method returns the URL to be used to login.
    1303       *
    1304       * @return string the login URL
    1305       */
    1306      public static function getServerLoginURL()
    1307      {
    1308          phpCAS::_validateClientExists();
    1309  
    1310          return self::$_PHPCAS_CLIENT->getServerLoginURL();
    1311      }
    1312  
    1313      /**
    1314       * Set the login URL of the CAS server.
    1315       *
    1316       * @param string $url the login URL
    1317       *
    1318       * @return void
    1319       * @since 0.4.21 by Wyman Chan
    1320       */
    1321      public static function setServerLoginURL($url = '')
    1322      {
    1323          phpCAS :: traceBegin();
    1324          phpCAS::_validateClientExists();
    1325  
    1326          try {
    1327              self::$_PHPCAS_CLIENT->setServerLoginURL($url);
    1328          } catch (Exception $e) {
    1329              phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
    1330          }
    1331  
    1332          phpCAS :: traceEnd();
    1333      }
    1334  
    1335      /**
    1336       * Set the serviceValidate URL of the CAS server.
    1337       * Used for all CAS versions of URL validations.
    1338       * Examples:
    1339       * CAS 1.0 http://www.exemple.com/validate
    1340       * CAS 2.0 http://www.exemple.com/validateURL
    1341       * CAS 3.0 http://www.exemple.com/p3/serviceValidate
    1342       *
    1343       * @param string $url the serviceValidate URL
    1344       *
    1345       * @return void
    1346       */
    1347      public static function setServerServiceValidateURL($url = '')
    1348      {
    1349          phpCAS :: traceBegin();
    1350          phpCAS::_validateClientExists();
    1351  
    1352          try {
    1353              self::$_PHPCAS_CLIENT->setServerServiceValidateURL($url);
    1354          } catch (Exception $e) {
    1355              phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
    1356          }
    1357  
    1358          phpCAS :: traceEnd();
    1359      }
    1360  
    1361      /**
    1362       * Set the proxyValidate URL of the CAS server.
    1363       * Used for all CAS versions of proxy URL validations
    1364       * Examples:
    1365       * CAS 1.0 http://www.exemple.com/
    1366       * CAS 2.0 http://www.exemple.com/proxyValidate
    1367       * CAS 3.0 http://www.exemple.com/p3/proxyValidate
    1368       *
    1369       * @param string $url the proxyValidate URL
    1370       *
    1371       * @return void
    1372       */
    1373      public static function setServerProxyValidateURL($url = '')
    1374      {
    1375          phpCAS :: traceBegin();
    1376          phpCAS::_validateClientExists();
    1377  
    1378          try {
    1379              self::$_PHPCAS_CLIENT->setServerProxyValidateURL($url);
    1380          } catch (Exception $e) {
    1381              phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
    1382          }
    1383  
    1384          phpCAS :: traceEnd();
    1385      }
    1386  
    1387      /**
    1388       * Set the samlValidate URL of the CAS server.
    1389       *
    1390       * @param string $url the samlValidate URL
    1391       *
    1392       * @return void
    1393       */
    1394      public static function setServerSamlValidateURL($url = '')
    1395      {
    1396          phpCAS :: traceBegin();
    1397          phpCAS::_validateClientExists();
    1398  
    1399          try {
    1400              self::$_PHPCAS_CLIENT->setServerSamlValidateURL($url);
    1401          } catch (Exception $e) {
    1402              phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
    1403          }
    1404  
    1405          phpCAS :: traceEnd();
    1406      }
    1407  
    1408      /**
    1409       * This method returns the URL to be used to logout.
    1410       *
    1411       * @return string the URL to use to log out
    1412       */
    1413      public static function getServerLogoutURL()
    1414      {
    1415          phpCAS::_validateClientExists();
    1416  
    1417          return self::$_PHPCAS_CLIENT->getServerLogoutURL();
    1418      }
    1419  
    1420      /**
    1421       * Set the logout URL of the CAS server.
    1422       *
    1423       * @param string $url the logout URL
    1424       *
    1425       * @return void
    1426       * @since 0.4.21 by Wyman Chan
    1427       */
    1428      public static function setServerLogoutURL($url = '')
    1429      {
    1430          phpCAS :: traceBegin();
    1431          phpCAS::_validateClientExists();
    1432  
    1433          try {
    1434              self::$_PHPCAS_CLIENT->setServerLogoutURL($url);
    1435          } catch (Exception $e) {
    1436              phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
    1437          }
    1438  
    1439          phpCAS :: traceEnd();
    1440      }
    1441  
    1442      /**
    1443       * This method is used to logout from CAS.
    1444       *
    1445       * @param string $params an array that contains the optional url and
    1446       * service parameters that will be passed to the CAS server
    1447       *
    1448       * @return void
    1449       */
    1450      public static function logout($params = "")
    1451      {
    1452          phpCAS :: traceBegin();
    1453          phpCAS::_validateClientExists();
    1454  
    1455          $parsedParams = array ();
    1456          if ($params != "") {
    1457              if (is_string($params)) {
    1458                  phpCAS :: error('method `phpCAS::logout($url)\' is now deprecated, use `phpCAS::logoutWithUrl($url)\' instead');
    1459              }
    1460              if (!is_array($params)) {
    1461                  phpCAS :: error('type mismatched for parameter $params (should be `array\')');
    1462              }
    1463              foreach ($params as $key => $value) {
    1464                  if ($key != "service" && $key != "url") {
    1465                      phpCAS :: error('only `url\' and `service\' parameters are allowed for method `phpCAS::logout($params)\'');
    1466                  }
    1467                  $parsedParams[$key] = $value;
    1468              }
    1469          }
    1470          self::$_PHPCAS_CLIENT->logout($parsedParams);
    1471          // never reached
    1472          phpCAS :: traceEnd();
    1473      }
    1474  
    1475      /**
    1476       * This method is used to logout from CAS. Halts by redirecting to the CAS
    1477       * server.
    1478       *
    1479       * @param string $service a URL that will be transmitted to the CAS server
    1480       *
    1481       * @return void
    1482       */
    1483      public static function logoutWithRedirectService($service)
    1484      {
    1485          phpCAS :: traceBegin();
    1486          phpCAS::_validateClientExists();
    1487  
    1488          if (!is_string($service)) {
    1489              phpCAS :: error('type mismatched for parameter $service (should be `string\')');
    1490          }
    1491          self::$_PHPCAS_CLIENT->logout(array ( "service" => $service ));
    1492          // never reached
    1493          phpCAS :: traceEnd();
    1494      }
    1495  
    1496      /**
    1497       * This method is used to logout from CAS. Halts by redirecting to the CAS
    1498       * server.
    1499       *
    1500       * @param string $url a URL that will be transmitted to the CAS server
    1501       *
    1502       * @return void
    1503       * @deprecated The url parameter has been removed from the CAS server as of
    1504       * version 3.3.5.1
    1505       */
    1506      public static function logoutWithUrl($url)
    1507      {
    1508          trigger_error('Function deprecated for cas servers >= 3.3.5.1', E_USER_DEPRECATED);
    1509          phpCAS :: traceBegin();
    1510          if (!is_object(self::$_PHPCAS_CLIENT)) {
    1511              phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');
    1512          }
    1513          if (!is_string($url)) {
    1514              phpCAS :: error('type mismatched for parameter $url (should be `string\')');
    1515          }
    1516          self::$_PHPCAS_CLIENT->logout(array ( "url" => $url ));
    1517          // never reached
    1518          phpCAS :: traceEnd();
    1519      }
    1520  
    1521      /**
    1522       * This method is used to logout from CAS. Halts by redirecting to the CAS
    1523       * server.
    1524       *
    1525       * @param string $service a URL that will be transmitted to the CAS server
    1526       * @param string $url     a URL that will be transmitted to the CAS server
    1527       *
    1528       * @return void
    1529       *
    1530       * @deprecated The url parameter has been removed from the CAS server as of
    1531       * version 3.3.5.1
    1532       */
    1533      public static function logoutWithRedirectServiceAndUrl($service, $url)
    1534      {
    1535          trigger_error('Function deprecated for cas servers >= 3.3.5.1', E_USER_DEPRECATED);
    1536          phpCAS :: traceBegin();
    1537          phpCAS::_validateClientExists();
    1538  
    1539          if (!is_string($service)) {
    1540              phpCAS :: error('type mismatched for parameter $service (should be `string\')');
    1541          }
    1542          if (!is_string($url)) {
    1543              phpCAS :: error('type mismatched for parameter $url (should be `string\')');
    1544          }
    1545          self::$_PHPCAS_CLIENT->logout(
    1546              array (
    1547                  "service" => $service,
    1548                  "url" => $url
    1549              )
    1550          );
    1551          // never reached
    1552          phpCAS :: traceEnd();
    1553      }
    1554  
    1555      /**
    1556       * Set the fixed URL that will be used by the CAS server to transmit the
    1557       * PGT. When this method is not called, a phpCAS script uses its own URL
    1558       * for the callback.
    1559       *
    1560       * @param string $url the URL
    1561       *
    1562       * @return void
    1563       */
    1564      public static function setFixedCallbackURL($url = '')
    1565      {
    1566          phpCAS :: traceBegin();
    1567          phpCAS::_validateProxyExists();
    1568  
    1569          try {
    1570              self::$_PHPCAS_CLIENT->setCallbackURL($url);
    1571          } catch (Exception $e) {
    1572              phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
    1573          }
    1574  
    1575          phpCAS :: traceEnd();
    1576      }
    1577  
    1578      /**
    1579       * Set the fixed URL that will be set as the CAS service parameter. When this
    1580       * method is not called, a phpCAS script uses its own URL.
    1581       *
    1582       * @param string $url the URL
    1583       *
    1584       * @return void
    1585       */
    1586      public static function setFixedServiceURL($url)
    1587      {
    1588          phpCAS :: traceBegin();
    1589          phpCAS::_validateProxyExists();
    1590  
    1591          try {
    1592              self::$_PHPCAS_CLIENT->setURL($url);
    1593          } catch (Exception $e) {
    1594              phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
    1595          }
    1596  
    1597          phpCAS :: traceEnd();
    1598      }
    1599  
    1600      /**
    1601       * Get the URL that is set as the CAS service parameter.
    1602       *
    1603       * @return string Service Url
    1604       */
    1605      public static function getServiceURL()
    1606      {
    1607          phpCAS::_validateProxyExists();
    1608          return (self::$_PHPCAS_CLIENT->getURL());
    1609      }
    1610  
    1611      /**
    1612       * Retrieve a Proxy Ticket from the CAS server.
    1613       *
    1614       * @param string $target_service Url string of service to proxy
    1615       * @param int &$err_code      error code
    1616       * @param string &$err_msg       error message
    1617       *
    1618       * @return string Proxy Ticket
    1619       */
    1620      public static function retrievePT($target_service, & $err_code, & $err_msg)
    1621      {
    1622          phpCAS::_validateProxyExists();
    1623  
    1624          try {
    1625              return (self::$_PHPCAS_CLIENT->retrievePT($target_service, $err_code, $err_msg));
    1626          } catch (Exception $e) {
    1627              phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
    1628          }
    1629      }
    1630  
    1631      /**
    1632       * Set the certificate of the CAS server CA and if the CN should be properly
    1633       * verified.
    1634       *
    1635       * @param string $cert        CA certificate file name
    1636       * @param bool   $validate_cn Validate CN in certificate (default true)
    1637       *
    1638       * @return void
    1639       */
    1640      public static function setCasServerCACert($cert, $validate_cn = true)
    1641      {
    1642          phpCAS :: traceBegin();
    1643          phpCAS::_validateClientExists();
    1644  
    1645          try {
    1646              self::$_PHPCAS_CLIENT->setCasServerCACert($cert, $validate_cn);
    1647          } catch (Exception $e) {
    1648              phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
    1649          }
    1650  
    1651          phpCAS :: traceEnd();
    1652      }
    1653  
    1654      /**
    1655       * Set no SSL validation for the CAS server.
    1656       *
    1657       * @return void
    1658       */
    1659      public static function setNoCasServerValidation()
    1660      {
    1661          phpCAS :: traceBegin();
    1662          phpCAS::_validateClientExists();
    1663  
    1664          phpCAS :: trace('You have configured no validation of the legitimacy of the cas server. This is not recommended for production use.');
    1665          self::$_PHPCAS_CLIENT->setNoCasServerValidation();
    1666          phpCAS :: traceEnd();
    1667      }
    1668  
    1669  
    1670      /**
    1671       * Disable the removal of a CAS-Ticket from the URL when authenticating
    1672       * DISABLING POSES A SECURITY RISK:
    1673       * We normally remove the ticket by an additional redirect as a security
    1674       * precaution to prevent a ticket in the HTTP_REFERRER or be carried over in
    1675       * the URL parameter
    1676       *
    1677       * @return void
    1678       */
    1679      public static function setNoClearTicketsFromUrl()
    1680      {
    1681          phpCAS :: traceBegin();
    1682          phpCAS::_validateClientExists();
    1683  
    1684          self::$_PHPCAS_CLIENT->setNoClearTicketsFromUrl();
    1685          phpCAS :: traceEnd();
    1686      }
    1687  
    1688      /** @} */
    1689  
    1690      /**
    1691       * Change CURL options.
    1692       * CURL is used to connect through HTTPS to CAS server
    1693       *
    1694       * @param string $key   the option key
    1695       * @param string $value the value to set
    1696       *
    1697       * @return void
    1698       */
    1699      public static function setExtraCurlOption($key, $value)
    1700      {
    1701          phpCAS :: traceBegin();
    1702          phpCAS::_validateClientExists();
    1703  
    1704          self::$_PHPCAS_CLIENT->setExtraCurlOption($key, $value);
    1705          phpCAS :: traceEnd();
    1706      }
    1707  
    1708      /**
    1709       * Set a salt/seed for the session-id hash to make it harder to guess.
    1710       *
    1711       * When $changeSessionID = true phpCAS will create a session-id that is derived
    1712       * from the service ticket. Doing so allows phpCAS to look-up and destroy the
    1713       * proper session on single-log-out requests. While the service tickets
    1714       * provided by the CAS server may include enough data to generate a strong
    1715       * hash, clients may provide an additional salt to ensure that session ids
    1716       * are not guessable if the session tickets do not have enough entropy.
    1717       *
    1718       * @param string $salt The salt to combine with the session ticket.
    1719       *
    1720       * @return void
    1721       */
    1722       public static function setSessionIdSalt($salt) {
    1723         phpCAS :: traceBegin();
    1724         phpCAS::_validateClientExists();
    1725         self::$_PHPCAS_CLIENT->setSessionIdSalt($salt);
    1726         phpCAS :: traceEnd();
    1727       }
    1728  
    1729      /**
    1730       * If you want your service to be proxied you have to enable it (default
    1731       * disabled) and define an accepable list of proxies that are allowed to
    1732       * proxy your service.
    1733       *
    1734       * Add each allowed proxy definition object. For the normal CAS_ProxyChain
    1735       * class, the constructor takes an array of proxies to match. The list is in
    1736       * reverse just as seen from the service. Proxies have to be defined in reverse
    1737       * from the service to the user. If a user hits service A and gets proxied via
    1738       * B to service C the list of acceptable on C would be array(B,A). The definition
    1739       * of an individual proxy can be either a string or a regexp (preg_match is used)
    1740       * that will be matched against the proxy list supplied by the cas server
    1741       * when validating the proxy tickets. The strings are compared starting from
    1742       * the beginning and must fully match with the proxies in the list.
    1743       * Example:
    1744       * 	 	 phpCAS::allowProxyChain(new CAS_ProxyChain(array(
    1745       *	 	 	 	 'https://app.example.com/'
    1746       *	 	 	 )));
    1747       * 	 	 phpCAS::allowProxyChain(new CAS_ProxyChain(array(
    1748       *	 	 	 	 '/^https:\/\/app[0-9]\.example\.com\/rest\//',
    1749       *	 	 	 	 'http://client.example.com/'
    1750       *	 	 	 )));
    1751       *
    1752       * For quick testing or in certain production screnarios you might want to
    1753       * allow allow any other valid service to proxy your service. To do so, add
    1754       * the "Any" chain:
    1755       *	 	 phpCAS::allowProxyChain(new CAS_ProxyChain_Any);
    1756       * THIS SETTING IS HOWEVER NOT RECOMMENDED FOR PRODUCTION AND HAS SECURITY
    1757       * IMPLICATIONS: YOU ARE ALLOWING ANY SERVICE TO ACT ON BEHALF OF A USER
    1758       * ON THIS SERVICE.
    1759       *
    1760       * @param CAS_ProxyChain_Interface $proxy_chain A proxy-chain that will be
    1761       * matched against the proxies requesting access
    1762       *
    1763       * @return void
    1764       */
    1765      public static function allowProxyChain(CAS_ProxyChain_Interface $proxy_chain)
    1766      {
    1767          phpCAS :: traceBegin();
    1768          phpCAS::_validateClientExists();
    1769  
    1770          if (self::$_PHPCAS_CLIENT->getServerVersion() !== CAS_VERSION_2_0
    1771              && self::$_PHPCAS_CLIENT->getServerVersion() !== CAS_VERSION_3_0
    1772          ) {
    1773              phpCAS :: error('this method can only be used with the cas 2.0/3.0 protocols');
    1774          }
    1775          self::$_PHPCAS_CLIENT->getAllowedProxyChains()->allowProxyChain($proxy_chain);
    1776          phpCAS :: traceEnd();
    1777      }
    1778  
    1779      /**
    1780       * Answer an array of proxies that are sitting in front of this application.
    1781       * This method will only return a non-empty array if we have received and
    1782       * validated a Proxy Ticket.
    1783       *
    1784       * @return array
    1785       * @access public
    1786       * @since 6/25/09
    1787       */
    1788      public static function getProxies ()
    1789      {
    1790          phpCAS::_validateProxyExists();
    1791  
    1792          return(self::$_PHPCAS_CLIENT->getProxies());
    1793      }
    1794  
    1795      // ########################################################################
    1796      // PGTIOU/PGTID and logoutRequest rebroadcasting
    1797      // ########################################################################
    1798  
    1799      /**
    1800       * Add a pgtIou/pgtId and logoutRequest rebroadcast node.
    1801       *
    1802       * @param string $rebroadcastNodeUrl The rebroadcast node URL. Can be
    1803       * hostname or IP.
    1804       *
    1805       * @return void
    1806       */
    1807      public static function addRebroadcastNode($rebroadcastNodeUrl)
    1808      {
    1809          phpCAS::traceBegin();
    1810          phpCAS::log('rebroadcastNodeUrl:'.$rebroadcastNodeUrl);
    1811          phpCAS::_validateClientExists();
    1812  
    1813          try {
    1814              self::$_PHPCAS_CLIENT->addRebroadcastNode($rebroadcastNodeUrl);
    1815          } catch (Exception $e) {
    1816              phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
    1817          }
    1818  
    1819          phpCAS::traceEnd();
    1820      }
    1821  
    1822      /**
    1823       * This method is used to add header parameters when rebroadcasting
    1824       * pgtIou/pgtId or logoutRequest.
    1825       *
    1826       * @param String $header Header to send when rebroadcasting.
    1827       *
    1828       * @return void
    1829       */
    1830      public static function addRebroadcastHeader($header)
    1831      {
    1832          phpCAS :: traceBegin();
    1833          phpCAS::_validateClientExists();
    1834  
    1835          try {
    1836              self::$_PHPCAS_CLIENT->addRebroadcastHeader($header);
    1837          } catch (Exception $e) {
    1838              phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
    1839          }
    1840  
    1841          phpCAS :: traceEnd();
    1842      }
    1843  
    1844      /**
    1845       * Checks if a client already exists
    1846       *
    1847       * @throws CAS_OutOfSequenceBeforeClientException
    1848       *
    1849       * @return void
    1850       */
    1851      private static function _validateClientExists()
    1852      {
    1853          if (!is_object(self::$_PHPCAS_CLIENT)) {
    1854              throw new CAS_OutOfSequenceBeforeClientException();
    1855          }
    1856      }
    1857  
    1858      /**
    1859       * Checks of a proxy client aready exists
    1860       *
    1861       * @throws CAS_OutOfSequenceBeforeProxyException
    1862       *
    1863       * @return void
    1864       */
    1865      private static function _validateProxyExists()
    1866      {
    1867          if (!is_object(self::$_PHPCAS_CLIENT)) {
    1868              throw new CAS_OutOfSequenceBeforeProxyException();
    1869          }
    1870      }
    1871  
    1872      /**
    1873       * For testing purposes, use this method to set the client to a test double
    1874       *
    1875       * @return void
    1876       */
    1877      public static function setCasClient(\CAS_Client $client)
    1878      {
    1879          self::$_PHPCAS_CLIENT = $client;
    1880      }
    1881  }
    1882  // ########################################################################
    1883  // DOCUMENTATION
    1884  // ########################################################################
    1885  
    1886  // ########################################################################
    1887  //  MAIN PAGE
    1888  
    1889  /**
    1890   * @mainpage
    1891   *
    1892   * The following pages only show the source documentation.
    1893   *
    1894   */
    1895  
    1896  // ########################################################################
    1897  //  MODULES DEFINITION
    1898  
    1899  /** @defgroup public User interface */
    1900  
    1901  /** @defgroup publicInit Initialization
    1902   *  @ingroup public */
    1903  
    1904  /** @defgroup publicAuth Authentication
    1905   *  @ingroup public */
    1906  
    1907  /** @defgroup publicServices Access to external services
    1908   *  @ingroup public */
    1909  
    1910  /** @defgroup publicConfig Configuration
    1911   *  @ingroup public */
    1912  
    1913  /** @defgroup publicLang Internationalization
    1914   *  @ingroup publicConfig */
    1915  
    1916  /** @defgroup publicOutput HTML output
    1917   *  @ingroup publicConfig */
    1918  
    1919  /** @defgroup publicPGTStorage PGT storage
    1920   *  @ingroup publicConfig */
    1921  
    1922  /** @defgroup publicDebug Debugging
    1923   *  @ingroup public */
    1924  
    1925  /** @defgroup internal Implementation */
    1926  
    1927  /** @defgroup internalAuthentication Authentication
    1928   *  @ingroup internal */
    1929  
    1930  /** @defgroup internalBasic CAS Basic client features (CAS 1.0, Service Tickets)
    1931   *  @ingroup internal */
    1932  
    1933  /** @defgroup internalProxy CAS Proxy features (CAS 2.0, Proxy Granting Tickets)
    1934   *  @ingroup internal */
    1935  
    1936  /** @defgroup internalSAML CAS SAML features (SAML 1.1)
    1937   *  @ingroup internal */
    1938  
    1939  /** @defgroup internalPGTStorage PGT storage
    1940   *  @ingroup internalProxy */
    1941  
    1942  /** @defgroup internalPGTStorageDb PGT storage in a database
    1943   *  @ingroup internalPGTStorage */
    1944  
    1945  /** @defgroup internalPGTStorageFile PGT storage on the filesystem
    1946   *  @ingroup internalPGTStorage */
    1947  
    1948  /** @defgroup internalCallback Callback from the CAS server
    1949   *  @ingroup internalProxy */
    1950  
    1951  /** @defgroup internalProxyServices Proxy other services
    1952   *  @ingroup internalProxy */
    1953  
    1954  /** @defgroup internalService CAS client features (CAS 2.0, Proxied service)
    1955   *  @ingroup internal */
    1956  
    1957  /** @defgroup internalConfig Configuration
    1958   *  @ingroup internal */
    1959  
    1960  /** @defgroup internalBehave Internal behaviour of phpCAS
    1961   *  @ingroup internalConfig */
    1962  
    1963  /** @defgroup internalOutput HTML output
    1964   *  @ingroup internalConfig */
    1965  
    1966  /** @defgroup internalLang Internationalization
    1967   *  @ingroup internalConfig
    1968   *
    1969   * To add a new language:
    1970   * - 1. define a new constant PHPCAS_LANG_XXXXXX in CAS/CAS.php
    1971   * - 2. copy any file from CAS/languages to CAS/languages/XXXXXX.php
    1972   * - 3. Make the translations
    1973   */
    1974  
    1975  /** @defgroup internalDebug Debugging
    1976   *  @ingroup internal */
    1977  
    1978  /** @defgroup internalMisc Miscellaneous
    1979   *  @ingroup internal */
    1980  
    1981  // ########################################################################
    1982  //  EXAMPLES
    1983  
    1984  /**
    1985   * @example example_simple.php
    1986   */
    1987  /**
    1988   * @example example_service.php
    1989   */
    1990  /**
    1991   * @example example_service_that_proxies.php
    1992   */
    1993  /**
    1994   * @example example_service_POST.php
    1995   */
    1996  /**
    1997   * @example example_proxy_serviceWeb.php
    1998   */
    1999  /**
    2000   * @example example_proxy_serviceWeb_chaining.php
    2001   */
    2002  /**
    2003   * @example example_proxy_POST.php
    2004   */
    2005  /**
    2006   * @example example_proxy_GET.php
    2007   */
    2008  /**
    2009   * @example example_lang.php
    2010   */
    2011  /**
    2012   * @example example_html.php
    2013   */
    2014  /**
    2015   * @example example_pgt_storage_file.php
    2016   */
    2017  /**
    2018   * @example example_pgt_storage_db.php
    2019   */
    2020  /**
    2021   * @example example_gateway.php
    2022   */
    2023  /**
    2024   * @example example_logout.php
    2025   */
    2026  /**
    2027   * @example example_rebroadcast.php
    2028   */
    2029  /**
    2030   * @example example_custom_urls.php
    2031   */
    2032  /**
    2033   * @example example_advanced_saml11.php
    2034   */