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